Skip to content

Commit baa4ca8

Browse files
authored
chore(lambda-rs-platform): Abstract Buffer and Renderpass implementations in lambda-rs-platform
2 parents d3dc435 + 9e378aa commit baa4ca8

File tree

4 files changed

+348
-64
lines changed

4 files changed

+348
-64
lines changed
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
//! Buffer wrappers and builders for the platform layer.
2+
//!
3+
//! This module provides a thin wrapper over `wgpu::Buffer` plus a small
4+
//! builder that handles common initialization patterns and keeps label and
5+
//! usage metadata for debugging/inspection.
6+
7+
use crate::wgpu::{
8+
types as wgpu,
9+
types::util::DeviceExt,
10+
};
11+
12+
#[derive(Clone, Copy, Debug)]
13+
/// Platform buffer usage flags.
14+
pub struct Usage(pub(crate) wgpu::BufferUsages);
15+
16+
impl Usage {
17+
/// Vertex buffer usage.
18+
pub const VERTEX: Usage = Usage(wgpu::BufferUsages::VERTEX);
19+
/// Index buffer usage.
20+
pub const INDEX: Usage = Usage(wgpu::BufferUsages::INDEX);
21+
/// Uniform buffer usage.
22+
pub const UNIFORM: Usage = Usage(wgpu::BufferUsages::UNIFORM);
23+
/// Storage buffer usage.
24+
pub const STORAGE: Usage = Usage(wgpu::BufferUsages::STORAGE);
25+
/// Copy destination (for CPU-visible uploads).
26+
pub const COPY_DST: Usage = Usage(wgpu::BufferUsages::COPY_DST);
27+
28+
pub(crate) fn to_wgpu(self) -> wgpu::BufferUsages {
29+
return self.0;
30+
}
31+
}
32+
33+
impl std::ops::BitOr for Usage {
34+
type Output = Usage;
35+
fn bitor(self, rhs: Usage) -> Usage {
36+
return Usage(self.0 | rhs.0);
37+
}
38+
}
39+
40+
impl Default for Usage {
41+
fn default() -> Self {
42+
return Usage(wgpu::BufferUsages::VERTEX);
43+
}
44+
}
45+
46+
#[derive(Debug)]
47+
/// Wrapper around `wgpu::Buffer` with metadata.
48+
pub struct Buffer {
49+
pub(crate) raw: wgpu::Buffer,
50+
pub(crate) label: Option<String>,
51+
pub(crate) size: wgpu::BufferAddress,
52+
pub(crate) usage: wgpu::BufferUsages,
53+
}
54+
55+
impl Buffer {
56+
/// Borrow the underlying `wgpu::Buffer`.
57+
pub fn raw(&self) -> &wgpu::Buffer {
58+
return &self.raw;
59+
}
60+
61+
/// Optional debug label.
62+
pub fn label(&self) -> Option<&str> {
63+
return self.label.as_deref();
64+
}
65+
66+
/// Size in bytes at creation time.
67+
pub fn size(&self) -> wgpu::BufferAddress {
68+
return self.size;
69+
}
70+
71+
/// Usage flags used to create the buffer.
72+
pub fn usage(&self) -> wgpu::BufferUsages {
73+
return self.usage;
74+
}
75+
}
76+
77+
#[derive(Default)]
78+
/// Builder for creating a `Buffer` with optional initial contents.
79+
pub struct BufferBuilder {
80+
label: Option<String>,
81+
size: usize,
82+
usage: Usage,
83+
cpu_visible: bool,
84+
}
85+
86+
impl BufferBuilder {
87+
/// Create a new builder with zero size and VERTEX usage.
88+
pub fn new() -> Self {
89+
return Self {
90+
label: None,
91+
size: 0,
92+
usage: Usage::VERTEX,
93+
cpu_visible: false,
94+
};
95+
}
96+
97+
/// Attach a label for debugging/profiling.
98+
pub fn with_label(mut self, label: &str) -> Self {
99+
self.label = Some(label.to_string());
100+
return self;
101+
}
102+
103+
/// Set the total size in bytes. If zero, size is inferred from data length.
104+
pub fn with_size(mut self, size: usize) -> Self {
105+
self.size = size;
106+
return self;
107+
}
108+
109+
/// Set usage flags.
110+
pub fn with_usage(mut self, usage: Usage) -> Self {
111+
self.usage = usage;
112+
return self;
113+
}
114+
115+
/// Hint that buffer will be updated from CPU via queue writes.
116+
pub fn with_cpu_visible(mut self, cpu_visible: bool) -> Self {
117+
self.cpu_visible = cpu_visible;
118+
return self;
119+
}
120+
121+
/// Create a buffer initialized with `contents`.
122+
pub fn build_init(self, device: &wgpu::Device, contents: &[u8]) -> Buffer {
123+
let size = if self.size == 0 {
124+
contents.len()
125+
} else {
126+
self.size
127+
};
128+
129+
let mut usage = self.usage.to_wgpu();
130+
if self.cpu_visible {
131+
usage |= wgpu::BufferUsages::COPY_DST;
132+
}
133+
134+
let raw = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
135+
label: self.label.as_deref(),
136+
contents,
137+
usage,
138+
});
139+
140+
return Buffer {
141+
raw,
142+
label: self.label,
143+
size: size as wgpu::BufferAddress,
144+
usage,
145+
};
146+
}
147+
}
148+
149+
#[cfg(test)]
150+
mod tests {
151+
use super::*;
152+
153+
#[test]
154+
fn usage_bitor_combines_flags() {
155+
let u = Usage::VERTEX | Usage::INDEX | Usage::UNIFORM;
156+
let flags = u.to_wgpu();
157+
assert!(flags.contains(wgpu::BufferUsages::VERTEX));
158+
assert!(flags.contains(wgpu::BufferUsages::INDEX));
159+
assert!(flags.contains(wgpu::BufferUsages::UNIFORM));
160+
}
161+
}

crates/lambda-rs-platform/src/wgpu/mod.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use wgpu::rwh::{
1616
use crate::winit::WindowHandle;
1717

1818
pub mod bind;
19+
pub mod buffer;
1920

2021
#[derive(Debug, Clone)]
2122
/// Builder for creating a `wgpu::Instance` with consistent defaults.
@@ -342,6 +343,117 @@ impl Frame {
342343
}
343344
}
344345

346+
// ---------------------- Command Encoding Abstractions -----------------------
347+
348+
#[derive(Debug)]
349+
/// Thin wrapper around `wgpu::CommandEncoder` with convenience helpers.
350+
pub struct CommandEncoder {
351+
raw: wgpu::CommandEncoder,
352+
}
353+
354+
impl CommandEncoder {
355+
/// Create a new command encoder with an optional label.
356+
pub fn new(device: &wgpu::Device, label: Option<&str>) -> Self {
357+
let raw =
358+
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label });
359+
return Self { raw };
360+
}
361+
362+
/// Begin a render pass targeting a single color attachment with the provided
363+
/// load/store operations. Depth/stencil is not attached by this helper.
364+
pub fn begin_render_pass<'view>(
365+
&'view mut self,
366+
label: Option<&str>,
367+
view: &'view wgpu::TextureView,
368+
ops: wgpu::Operations<wgpu::Color>,
369+
) -> RenderPass<'view> {
370+
let color_attachment = wgpu::RenderPassColorAttachment {
371+
view,
372+
resolve_target: None,
373+
depth_slice: None,
374+
ops,
375+
};
376+
let color_attachments = [Some(color_attachment)];
377+
let pass = self.raw.begin_render_pass(&wgpu::RenderPassDescriptor {
378+
label,
379+
color_attachments: &color_attachments,
380+
depth_stencil_attachment: None,
381+
timestamp_writes: None,
382+
occlusion_query_set: None,
383+
});
384+
return RenderPass { raw: pass };
385+
}
386+
387+
/// Finish recording and return the command buffer.
388+
pub fn finish(self) -> wgpu::CommandBuffer {
389+
return self.raw.finish();
390+
}
391+
}
392+
393+
#[derive(Debug)]
394+
/// Wrapper around `wgpu::RenderPass<'_>` exposing the operations needed by the
395+
/// Lambda renderer without leaking raw `wgpu` types at the call sites.
396+
pub struct RenderPass<'a> {
397+
raw: wgpu::RenderPass<'a>,
398+
}
399+
400+
impl<'a> RenderPass<'a> {
401+
/// Set the active render pipeline.
402+
pub fn set_pipeline(&mut self, pipeline: &wgpu::RenderPipeline) {
403+
self.raw.set_pipeline(pipeline);
404+
}
405+
406+
/// Apply viewport state.
407+
pub fn set_viewport(
408+
&mut self,
409+
x: f32,
410+
y: f32,
411+
width: f32,
412+
height: f32,
413+
min_depth: f32,
414+
max_depth: f32,
415+
) {
416+
self
417+
.raw
418+
.set_viewport(x, y, width, height, min_depth, max_depth);
419+
}
420+
421+
/// Apply scissor rectangle.
422+
pub fn set_scissor_rect(&mut self, x: u32, y: u32, width: u32, height: u32) {
423+
self.raw.set_scissor_rect(x, y, width, height);
424+
}
425+
426+
/// Bind a group with optional dynamic offsets.
427+
pub fn set_bind_group(
428+
&mut self,
429+
set: u32,
430+
group: &wgpu::BindGroup,
431+
dynamic_offsets: &[u32],
432+
) {
433+
self.raw.set_bind_group(set, group, dynamic_offsets);
434+
}
435+
436+
/// Bind a vertex buffer slot.
437+
pub fn set_vertex_buffer(&mut self, slot: u32, buffer: &wgpu::Buffer) {
438+
self.raw.set_vertex_buffer(slot, buffer.slice(..));
439+
}
440+
441+
/// Upload push constants.
442+
pub fn set_push_constants(
443+
&mut self,
444+
stages: wgpu::ShaderStages,
445+
offset: u32,
446+
data: &[u8],
447+
) {
448+
self.raw.set_push_constants(stages, offset, data);
449+
}
450+
451+
/// Issue a non-indexed draw over a vertex range.
452+
pub fn draw(&mut self, vertices: std::ops::Range<u32>) {
453+
self.raw.draw(vertices, 0..1);
454+
}
455+
}
456+
345457
#[derive(Debug, Clone)]
346458
/// Builder for a `Gpu` (adapter, device, queue) with feature validation.
347459
pub struct GpuBuilder {

0 commit comments

Comments
 (0)