@@ -3,13 +3,13 @@ title: "Uniform Buffers and Bind Groups"
33document_id : " ubo-spec-2025-10-11"
44status : " draft"
55created : " 2025-10-11T00:00:00Z"
6- last_updated : " 2025-10-11T00 :00:00Z"
7- version : " 0.1.0 "
6+ last_updated : " 2025-10-13T00 :00:00Z"
7+ version : " 0.1.1 "
88engine_workspace_version : " 2023.1.30"
99wgpu_version : " 26.0.1"
1010shader_backend_default : " naga"
1111winit_version : " 0.29.10"
12- repo_commit : " 0fdc489f5560acf809ca9cd8440f086baab7bad5 "
12+ repo_commit : " a9ecb6df8188fb189e3221598b36f6cf757697bb "
1313owners : ["lambda-sh"]
1414reviewers : ["engine", "rendering"]
1515tags : ["spec", "rendering", "uniforms", "bind-groups", "wgpu"]
@@ -76,9 +76,8 @@ Per-frame commands: BeginRenderPass -> SetPipeline -> SetBindGroup -> Draw -> En
7676- Module: ` lambda_platform::wgpu::bind `
7777 - ` struct BindGroupLayout { raw: wgpu::BindGroupLayout, label: Option<String> } `
7878 - ` struct BindGroup { raw: wgpu::BindGroup, label: Option<String> } `
79- - ` enum Visibility { Vertex, Fragment, Compute, BothVF , All } `
79+ - ` enum Visibility { Vertex, Fragment, Compute, VertexAndFragment , All } `
8080 - Maps to ` wgpu::ShaderStages ` .
81- - ` enum BindingKind { Uniform { dynamic: bool }, /* future: SampledTexture, Sampler, Storage*/ } `
8281 - ` struct BindGroupLayoutBuilder { entries: Vec<wgpu::BindGroupLayoutEntry>, label: Option<String> } `
8382 - ` fn new() -> Self `
8483 - ` fn with_uniform(mut self, binding: u32, visibility: Visibility) -> Self `
@@ -93,23 +92,23 @@ Per-frame commands: BeginRenderPass -> SetPipeline -> SetBindGroup -> Draw -> En
9392 - ` fn build(self, device: &wgpu::Device) -> BindGroup `
9493
9594Validation and limits
96- - On ` build ` , validate against ` wgpu::Limits ` :
97- - ` max_uniform_buffer_binding_size ` for explicit sizes.
98- - ` min_uniform_buffer_offset_alignment ` for dynamic offsets (caller provides
99- aligned ` offset ` ; builder re-checks and errors if misaligned).
100- - ` max_bind_groups ` when composing pipeline layouts (exposed via helper).
101- - Return detailed error strings mapped into high-level errors in ` lambda-rs ` .
95+ - Current implementation defers validation to ` wgpu ` and backend validators.
96+ Builders do not perform explicit limit checks yet; invalid inputs will surface
97+ as ` wgpu ` validation errors at creation/bind time.
98+ - No explicit checks for ` max_uniform_buffer_binding_size ` in builders.
99+ - Dynamic offset alignment is not re-validated; callers must ensure offsets are
100+ multiples of ` min_uniform_buffer_offset_alignment ` .
101+ - Pipeline layout size (` max_bind_groups ` ) is not pre-validated by the builder.
102102
103103Helpers
104- - ` fn shader_stages(vis: Visibility) -> wgpu::ShaderStages `
105- - ` fn align_up(value: u64, align: u64) -> u64 `
104+ - No dedicated helpers are exposed in the platform layer yet.
106105
107106## High-Level API Design (lambda-rs)
108107
109108New module: ` lambda::render::bind `
110109- ` pub struct BindGroupLayout { /* holds Rc<wgpu::BindGroupLayout> */ } `
111110- ` pub struct BindGroup { /* holds Rc<wgpu::BindGroup> */ } `
112- - ` pub enum BindingVisibility { Vertex, Fragment, Compute, BothVF , All } `
111+ - ` pub enum BindingVisibility { Vertex, Fragment, Compute, VertexAndFragment , All } `
113112- ` pub struct BindGroupLayoutBuilder { /* mirrors platform builder */ } `
114113 - ` pub fn new() -> Self `
115114 - ` pub fn with_uniform(self, binding: u32, visibility: BindingVisibility) -> Self `
@@ -119,7 +118,7 @@ New module: `lambda::render::bind`
119118- ` pub struct BindGroupBuilder { /* mirrors platform builder */ } `
120119 - ` pub fn new() -> Self `
121120 - ` pub fn with_layout(self, layout: &BindGroupLayout) -> Self `
122- - ` pub fn with_uniform(self, binding: u32, buffer: &buffer::Buffer, offset: u64, size: Option<u64 >) -> Self `
121+ - ` pub fn with_uniform(self, binding: u32, buffer: &buffer::Buffer, offset: u64, size: Option<NonZeroU64 >) -> Self `
123122 - ` pub fn with_label(self, label: &str) -> Self `
124123 - ` pub fn build(self, rc: &RenderContext) -> BindGroup `
125124
@@ -167,6 +166,9 @@ impl<T> UniformBuffer<T> {
167166- Dynamic offsets must be multiples of
168167 ` limits.min_uniform_buffer_offset_alignment ` .
169168- Respect ` limits.max_uniform_buffer_binding_size ` when slicing UBOs.
169+ - Matrices are column‑major in GLSL/WGSL. If your CPU math builds row‑major
170+ matrices, either transpose before uploading to the GPU or mark GLSL uniform
171+ blocks with ` layout(row_major) ` to avoid unexpected transforms.
170172
171173## Example Usage
172174
@@ -242,20 +244,20 @@ let dyn_layout = BindGroupLayoutBuilder::new()
242244 . with_uniform_dynamic (0 , BindingVisibility :: Vertex )
243245 . build (& mut rc );
244246
245- let stride = align_up (core :: mem :: size_of :: <Globals >() as u64 ,
246- rc . device (). limits (). min_uniform_buffer_offset_alignment);
247+ let align = rc . device (). limits (). min_uniform_buffer_offset_alignment;
248+ let size = core :: mem :: size_of :: <Globals >() as u64 ;
249+ let stride = ((size + align - 1 ) / align ) * align ; // manual align-up
247250let offsets = vec! [0u32 , stride as u32 , (2 * stride ) as u32 ];
248251RC :: SetBindGroup { set : 0 , group : dyn_group_id , dynamic_offsets : offsets };
249252```
250253
251254## Error Handling
252255
253256- ` BufferBuilder ` already errors on zero length; keep behavior.
254- - New bind errors returned during ` build ` with clear messages:
255- - "uniform binding size exceeds max_uniform_buffer_binding_size"
256- - "dynamic offset not aligned to min_uniform_buffer_offset_alignment"
257- - "invalid binding index (duplicate or out of range)"
258- - "pipeline layouts exceed device.max_bind_groups"
257+ - Bind group and layout builders currently do not pre‑validate against device limits.
258+ Invalid sizes/offsets typically surface as ` wgpu ` validation errors during creation
259+ or when calling ` set_bind_group ` . Ensure dynamic offsets are aligned to device limits
260+ and uniform ranges respect ` max_uniform_buffer_binding_size ` .
259261
260262## Performance Notes
261263
@@ -278,7 +280,7 @@ Phase 1 (dynamic offsets)
278280- Add small helper to compute aligned strides.
279281
280282Phase 2 (ergonomics/testing)
281- - Optional ` UniformBuffer<T> ` wrapper with ` .write(&T) ` for convenience.
283+ - Optional ` UniformBuffer<T> ` wrapper with ` .write(&T) ` for convenience (not implemented yet) .
282284- Unit tests for builders and validation; integration test that animates a
283285 triangle with a camera UBO.
284286
@@ -307,5 +309,5 @@ File layout
307309
308310## Changelog
309311
310- - 2025-10-11 (v0.1.0 ) — Initial draft aligned to roadmap; specifies platform
311- and high-level APIs, commands, validation, examples, and phased delivery.
312+ - 2025-10-13 (v0.1.1 ) — Synced spec to implementation: renamed visibility enum variant to ` VertexAndFragment ` ; clarified that builders defer validation to ` wgpu ` ; updated ` with_uniform ` size type to ` Option<NonZeroU64> ` ; added note on GPU column‑major matrices and CPU transpose guidance; adjusted dynamic offset example.
313+ - 2025-10-11 (v0.1.0) — Initial draft aligned to roadmap; specifies platform and high-level APIs, commands, validation, examples, and phased delivery.
0 commit comments