Skip to content

Commit 4205948

Browse files
committed
[add] immediates, indexed draws, instanced draws, and ubo demos.
1 parent 2c1c247 commit 4205948

4 files changed

Lines changed: 1547 additions & 0 deletions

File tree

demos/render/src/bin/immediates.rs

Lines changed: 372 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,372 @@
1+
#![allow(clippy::needless_return)]
2+
3+
use lambda::{
4+
component::Component,
5+
events::{
6+
EventMask,
7+
WindowEvent,
8+
},
9+
logging,
10+
math::matrix::Matrix,
11+
render::{
12+
buffer::BufferBuilder,
13+
command::RenderCommand,
14+
mesh::{
15+
Mesh,
16+
MeshBuilder,
17+
},
18+
pipeline::RenderPipelineBuilder,
19+
render_pass::RenderPassBuilder,
20+
scene_math::{
21+
compute_model_view_projection_matrix_about_pivot,
22+
SimpleCamera,
23+
},
24+
shader::{
25+
Shader,
26+
ShaderBuilder,
27+
ShaderKind,
28+
VirtualShader,
29+
},
30+
vertex::{
31+
ColorFormat,
32+
VertexAttribute,
33+
VertexBuilder,
34+
VertexElement,
35+
},
36+
viewport,
37+
ResourceId,
38+
},
39+
runtime::start_runtime,
40+
runtimes::{
41+
application::ComponentResult,
42+
ApplicationRuntimeBuilder,
43+
},
44+
};
45+
46+
// ------------------------------ SHADER SOURCE --------------------------------
47+
48+
const VERTEX_SHADER_SOURCE: &str = r#"
49+
#version 450
50+
51+
layout (location = 0) in vec3 vertex_position;
52+
layout (location = 1) in vec3 vertex_normal;
53+
layout (location = 2) in vec3 vertex_color;
54+
55+
layout (location = 0) out vec3 frag_color;
56+
57+
layout ( push_constant ) uniform PushConstant {
58+
vec4 data;
59+
mat4 render_matrix;
60+
} push_constants;
61+
62+
void main() {
63+
gl_Position = push_constants.render_matrix * vec4(vertex_position, 1.0);
64+
frag_color = vertex_color;
65+
}
66+
67+
"#;
68+
69+
const FRAGMENT_SHADER_SOURCE: &str = r#"
70+
#version 450
71+
72+
layout (location = 0) in vec3 frag_color;
73+
74+
layout (location = 0) out vec4 fragment_color;
75+
76+
void main() {
77+
fragment_color = vec4(frag_color, 1.0);
78+
}
79+
80+
"#;
81+
82+
// ------------------------------ IMMEDIATES ----------------------------------
83+
84+
/// Immediate data structure passed to shaders via wgpu's immediates feature.
85+
/// In GLSL shaders, this is still declared as `push_constant` uniform block.
86+
#[repr(C)]
87+
#[derive(Debug, Clone, Copy)]
88+
pub struct ImmediateData {
89+
data: [f32; 4],
90+
render_matrix: [[f32; 4]; 4],
91+
}
92+
93+
pub fn immediate_data_to_bytes(immediate: &ImmediateData) -> &[u32] {
94+
let bytes = unsafe {
95+
let size_in_bytes = std::mem::size_of::<ImmediateData>();
96+
let size_in_u32 = size_in_bytes / std::mem::size_of::<u32>();
97+
let ptr = immediate as *const ImmediateData as *const u32;
98+
std::slice::from_raw_parts(ptr, size_in_u32)
99+
};
100+
101+
return bytes;
102+
}
103+
104+
// Model, view, and projection matrix computations are handled by `scene_math`.
105+
106+
// --------------------------------- COMPONENT ---------------------------------
107+
108+
const ROTATION_TURNS_PER_SECOND: f32 = 0.12;
109+
110+
pub struct ImmediatesExample {
111+
elapsed_seconds: f32,
112+
shader: Shader,
113+
fs: Shader,
114+
mesh: Option<Mesh>,
115+
render_pipeline: Option<ResourceId>,
116+
render_pass: Option<ResourceId>,
117+
width: u32,
118+
height: u32,
119+
}
120+
121+
impl Component<ComponentResult, String> for ImmediatesExample {
122+
fn on_attach(
123+
&mut self,
124+
render_context: &mut lambda::render::RenderContext,
125+
) -> Result<ComponentResult, String> {
126+
let render_pass = RenderPassBuilder::new().build(
127+
render_context.gpu(),
128+
render_context.surface_format(),
129+
render_context.depth_format(),
130+
);
131+
let immediate_data_size = std::mem::size_of::<ImmediateData>() as u32;
132+
133+
// Create triangle mesh.
134+
let vertices = [
135+
VertexBuilder::new()
136+
.with_position([1.0, 1.0, 0.0])
137+
.with_normal([0.0, 0.0, 0.0])
138+
.with_color([1.0, 0.0, 0.0])
139+
.build(),
140+
VertexBuilder::new()
141+
.with_position([-1.0, 1.0, 0.0])
142+
.with_normal([0.0, 0.0, 0.0])
143+
.with_color([0.0, 1.0, 0.0])
144+
.build(),
145+
VertexBuilder::new()
146+
.with_position([0.0, -1.0, 0.0])
147+
.with_normal([0.0, 0.0, 0.0])
148+
.with_color([0.0, 0.0, 1.0])
149+
.build(),
150+
];
151+
152+
let mut mesh_builder = MeshBuilder::new();
153+
vertices.iter().for_each(|vertex| {
154+
mesh_builder.with_vertex(*vertex);
155+
});
156+
157+
let mesh = mesh_builder
158+
.with_attributes(vec![
159+
VertexAttribute {
160+
location: 0,
161+
offset: 0,
162+
element: VertexElement {
163+
format: ColorFormat::Rgb32Sfloat,
164+
offset: 0,
165+
},
166+
},
167+
VertexAttribute {
168+
location: 1,
169+
offset: 0,
170+
element: VertexElement {
171+
format: ColorFormat::Rgb32Sfloat,
172+
offset: 12,
173+
},
174+
},
175+
VertexAttribute {
176+
location: 2,
177+
offset: 0,
178+
element: VertexElement {
179+
format: ColorFormat::Rgb32Sfloat,
180+
offset: 24,
181+
},
182+
},
183+
])
184+
.build();
185+
186+
logging::trace!("mesh: {:?}", mesh);
187+
188+
let pipeline = RenderPipelineBuilder::new()
189+
.with_culling(lambda::render::pipeline::CullingMode::None)
190+
.with_immediate_data(immediate_data_size)
191+
.with_buffer(
192+
BufferBuilder::build_from_mesh(&mesh, render_context.gpu())
193+
.expect("Failed to create buffer"),
194+
mesh.attributes().to_vec(),
195+
)
196+
.build(
197+
render_context.gpu(),
198+
render_context.surface_format(),
199+
render_context.depth_format(),
200+
&render_pass,
201+
&self.shader,
202+
Some(&self.fs),
203+
);
204+
205+
self.render_pass = Some(render_context.attach_render_pass(render_pass));
206+
self.render_pipeline = Some(render_context.attach_pipeline(pipeline));
207+
self.mesh = Some(mesh);
208+
209+
return Ok(ComponentResult::Success);
210+
}
211+
212+
fn on_detach(
213+
&mut self,
214+
_render_context: &mut lambda::render::RenderContext,
215+
) -> Result<ComponentResult, String> {
216+
logging::info!("Detaching component");
217+
return Ok(ComponentResult::Success);
218+
}
219+
220+
fn event_mask(&self) -> EventMask {
221+
return EventMask::WINDOW;
222+
}
223+
224+
fn on_window_event(&mut self, event: &WindowEvent) -> Result<(), String> {
225+
match event {
226+
WindowEvent::Resize { width, height } => {
227+
logging::info!("Window resized to {}x{}", width, height);
228+
self.width = *width;
229+
self.height = *height;
230+
}
231+
WindowEvent::Close => {
232+
logging::info!("Window closed");
233+
}
234+
}
235+
return Ok(());
236+
}
237+
238+
fn on_update(
239+
&mut self,
240+
last_frame: &std::time::Duration,
241+
) -> Result<ComponentResult, String> {
242+
self.elapsed_seconds += last_frame.as_secs_f32();
243+
return Ok(ComponentResult::Success);
244+
}
245+
246+
fn on_render(
247+
&mut self,
248+
_render_context: &mut lambda::render::RenderContext,
249+
) -> Vec<RenderCommand> {
250+
let viewport =
251+
viewport::ViewportBuilder::new().build(self.width, self.height);
252+
253+
let render_pass = self
254+
.render_pass
255+
.expect("Cannot begin the render pass when it doesn't exist.");
256+
let render_pipeline = self
257+
.render_pipeline
258+
.expect("No render pipeline actively set for rendering.");
259+
260+
let camera = SimpleCamera {
261+
position: [0.0, 0.0, 3.0],
262+
field_of_view_in_turns: 0.25,
263+
near_clipping_plane: 0.1,
264+
far_clipping_plane: 100.0,
265+
};
266+
267+
let turns = (self.elapsed_seconds * ROTATION_TURNS_PER_SECOND) % 1.0_f32;
268+
let mesh_matrix = compute_model_view_projection_matrix_about_pivot(
269+
&camera,
270+
self.width.max(1),
271+
self.height.max(1),
272+
[0.0, -1.0 / 3.0, 0.0],
273+
[0.0, 1.0, 0.0],
274+
turns,
275+
0.5,
276+
[0.0, 1.0 / 3.0, 0.0],
277+
);
278+
279+
// All state setting must be inside the render pass.
280+
let mut commands = vec![RenderCommand::BeginRenderPass {
281+
render_pass,
282+
viewport: viewport.clone(),
283+
}];
284+
285+
commands.push(RenderCommand::SetPipeline {
286+
pipeline: render_pipeline,
287+
});
288+
commands.push(RenderCommand::SetViewports {
289+
start_at: 0,
290+
viewports: vec![viewport.clone()],
291+
});
292+
commands.push(RenderCommand::SetScissors {
293+
start_at: 0,
294+
viewports: vec![viewport.clone()],
295+
});
296+
297+
commands.push(RenderCommand::BindVertexBuffer {
298+
pipeline: render_pipeline,
299+
buffer: 0,
300+
});
301+
302+
let immediate = ImmediateData {
303+
data: [0.0, 0.0, 0.0, 0.0],
304+
render_matrix: mesh_matrix.transpose(),
305+
};
306+
commands.push(RenderCommand::Immediates {
307+
pipeline: render_pipeline,
308+
offset: 0,
309+
bytes: Vec::from(immediate_data_to_bytes(&immediate)),
310+
});
311+
312+
commands.push(RenderCommand::Draw {
313+
vertices: 0..self.mesh.as_ref().unwrap().vertices().len() as u32,
314+
instances: 0..1,
315+
});
316+
commands.push(RenderCommand::EndRenderPass);
317+
318+
return commands;
319+
}
320+
}
321+
322+
impl Default for ImmediatesExample {
323+
fn default() -> Self {
324+
let triangle_vertex = VirtualShader::Source {
325+
source: VERTEX_SHADER_SOURCE.to_string(),
326+
kind: ShaderKind::Vertex,
327+
name: String::from("immediates"),
328+
entry_point: String::from("main"),
329+
};
330+
331+
let triangle_fragment = VirtualShader::Source {
332+
source: FRAGMENT_SHADER_SOURCE.to_string(),
333+
kind: ShaderKind::Fragment,
334+
name: String::from("immediates"),
335+
entry_point: String::from("main"),
336+
};
337+
338+
// Create a shader builder to compile the shaders.
339+
let mut builder = ShaderBuilder::new();
340+
let vs = builder.build(triangle_vertex);
341+
let fs = builder.build(triangle_fragment);
342+
343+
return ImmediatesExample {
344+
elapsed_seconds: 0.0,
345+
shader: vs,
346+
fs,
347+
mesh: None,
348+
render_pipeline: None,
349+
render_pass: None,
350+
width: 800,
351+
height: 600,
352+
};
353+
}
354+
}
355+
356+
fn main() {
357+
let runtime = ApplicationRuntimeBuilder::new("Immediates Demo")
358+
.with_renderer_configured_as(move |render_context_builder| {
359+
return render_context_builder.with_render_timeout(1_000_000_000);
360+
})
361+
.with_window_configured_as(move |window_builder| {
362+
return window_builder
363+
.with_dimensions(1200, 600)
364+
.with_name("Immediates Window");
365+
})
366+
.with_component(move |runtime, demo: ImmediatesExample| {
367+
return (runtime, demo);
368+
})
369+
.build();
370+
371+
start_runtime(runtime);
372+
}

0 commit comments

Comments
 (0)