storageBuffer()
Function in Layout
Declare a bound array<Element> storage buffer from its element alone.
import { storageBuffer } from 'typeshade'
The signature, the description and the examples come from the compiler's own source at commit 26de7be8.
Syntax
function storageBuffer<H extends StructHandle>( name: string, element: H, at: { group: number; binding: number; access: 'read' },): StorageBuffer<ReturnType<H['of']>>;function storageBuffer<H extends StructHandle>( name: string, element: H, at: { group: number; binding: number; access: 'read_write' },): StorageBuffer<MutableView<ReturnType<H['of']>>>;function storageBuffer<T extends ShaderType>( name: string, element: T, at: { group: number; binding: number; access: 'read' },): StorageBuffer<ReadonlyNode<KeyOf<T>>>;function storageBuffer<T extends ShaderType>( name: string, element: T, at: { group: number; binding: number; access: 'read_write' },): StorageBuffer<Node<KeyOf<T>>>;Parameters
namestringthe emitted binding name, which is also the name a host binds by.
elementH extends StructHandlethe array’s element: a struct handle, or a scalar or vector type.
at{ group: number; binding: number; access: 'read' }the
groupandbindingslot, andaccess,'read'or'read_write'.
Return value
StorageBuffer<ReturnType<H['of']>>
the StorageBuffer handle described above.
Exceptions
UnsupportedFeatureErrorThis path only reads: a read_write binding throws UnsupportedFeatureError at GLSL emit, so a write is never silently dropped.
Description
The element is a
struct handle (structDecl or ioStruct) or a scalar or vector shader type. The handle derives the binding declaration, the access node, and a typed .at(i). The
array is runtime-length, sized by whatever buffer the host binds, so it takes no count.
.at(i) returns the element’s typed field proxy for a struct element, so buf.at(i).p0 is
a typed read with no .of() and no element-type argument. For a scalar element it returns
the element node directly. .binding goes in module({ bindings }), or pass the handle in
uses, which registers the element struct too.
access decides the element view’s write capability at the type level: 'read' hands out
read-only fields, so buf.at(i).p0.assign(...) is a tsc error, and 'read_write' hands
out mutable ones.
WebGL2 has no storage buffers, so on GLSL ES 3.00 the array is emitted as a data texture
and each read becomes a texelFetch. Nothing changes at the authoring site. This path
only reads: a read_write binding throws UnsupportedFeatureError at GLSL emit, so
a write is never silently dropped. A compute kernel’s output takes the compute-to-fragment
path; declare the kernel portable: true.
The host has one obligation the DSL cannot check for it: give that data texture the
internal format matching the element. array<u32> becomes a usampler2D and wants
R32UI, array<i32> an isampler2D and wants R32I, and the float case wants R32F. A
texture whose format disagrees with its sampler type is merely incomplete, which raises
nothing: texelFetch on it returns zero. Read the element off reflect(m), whose
per-binding textureElem reports it.
Carrying integers through an R32F texture and recovering them with floatBitsToUint is
unsafe even though it usually works. GLSL ES 3.00 permits an implementation to flush any
denormal to zero, and small integers are denormal f32 bit patterns (1u is 1.4e-45), so
that route can legally lose values.
Examples
Example
import { storageBuffer, structDecl, u32T, vec2fT } from 'typeshade'
const ShapeSegment = structDecl('ShapeSegment', { kind: u32T, p0: vec2fT, p1: vec2fT })const segments = storageBuffer('segments', ShapeSegment, { group: 0, binding: 9, access: 'read' })const seg = segments.at(i)seg.p0 // Node<'vec2<f32>'>
const featIds = storageBuffer('feat_ids', u32T, { group: 0, binding: 0, access: 'read' })featIds.at(i) // Node<'u32'>: an SSBO read on WGSL, a texelFetch on GLSLIn the guide
See also
Source
src/core/sot.ts, line 1092, at commit 26de7be8