1mod binding;
9mod geometry;
10mod id;
11mod pass;
12mod plan;
13mod program;
14mod renderer;
15mod resource;
16mod update;
17#[cfg(all(target_os = "linux", feature = "vulkan"))]
18mod vulkan_export;
19
20pub use binding::*;
21pub use geometry::*;
22pub use id::*;
23pub use pass::*;
24pub use plan::*;
25pub use program::*;
26pub use renderer::*;
27pub use resource::*;
28pub use update::*;
29#[cfg(all(target_os = "linux", feature = "vulkan"))]
30pub use vulkan_export::*;
31pub use wgpu;
32
33#[cfg(test)]
34mod tests {
35 use super::*;
36
37 const COPY_SHADER: &str = r#"
38@group(0) @binding(0) var input_tex: texture_2d<f32>;
39@group(0) @binding(1) var input_sampler: sampler;
40
41struct VsOut {
42 @builtin(position) position: vec4<f32>,
43 @location(0) uv: vec2<f32>,
44}
45
46@vertex
47fn vs_main(@builtin(vertex_index) vertex: u32) -> VsOut {
48 let positions = array<vec2<f32>, 3>(
49 vec2<f32>(-1.0, -1.0),
50 vec2<f32>(3.0, -1.0),
51 vec2<f32>(-1.0, 3.0)
52 );
53 let uvs = array<vec2<f32>, 3>(
54 vec2<f32>(0.0, 1.0),
55 vec2<f32>(2.0, 1.0),
56 vec2<f32>(0.0, -1.0)
57 );
58 var out: VsOut;
59 out.position = vec4<f32>(positions[vertex], 0.0, 1.0);
60 out.uv = uvs[vertex];
61 return out;
62}
63
64@fragment
65fn fs_main(in: VsOut) -> @location(0) vec4<f32> {
66 return textureSample(input_tex, input_sampler, in.uv);
67}
68"#;
69
70 #[test]
71 fn render_plan_records_generic_shader_passes() {
72 let size = Size::new(64, 64);
73 let mut plan = RenderPlan::builder();
74 let source = plan.texture(
75 Some("source".to_string()),
76 TextureDesc::sampled(size, wgpu::TextureFormat::Rgba8Unorm),
77 );
78 let target = plan.texture(
79 Some("target".to_string()),
80 TextureDesc::render_target(size, wgpu::TextureFormat::Rgba8Unorm),
81 );
82 let sampler = plan.sampler(
83 Some("linear".to_string()),
84 wgpu::SamplerDescriptor::default(),
85 );
86 let program = plan.program(ProgramDesc::Render(RenderProgramDesc {
87 label: Some("copy".to_string()),
88 shader: COPY_SHADER.to_string(),
89 vertex_entry: "vs_main".to_string(),
90 fragment_entry: "fs_main".to_string(),
91 bind_groups: BindGroupLayoutSpec::single(vec![
92 BindingLayoutEntry::texture(0, wgpu::ShaderStages::FRAGMENT),
93 BindingLayoutEntry::sampler(1, wgpu::ShaderStages::FRAGMENT),
94 ]),
95 targets: vec![Some(wgpu::ColorTargetState {
96 format: wgpu::TextureFormat::Rgba8Unorm,
97 blend: Some(wgpu::BlendState::ALPHA_BLENDING),
98 write_mask: wgpu::ColorWrites::ALL,
99 })],
100 vertex_buffers: Vec::new(),
101 primitive: wgpu::PrimitiveState::default(),
102 }));
103 plan.render_pass(RenderPassDesc {
104 label: Some("copy pass".to_string()),
105 owner: Some(NodeKey(42)),
106 program,
107 targets: vec![RenderTargetRef {
108 texture: target,
109 load: LoadOp::Clear(wgpu::Color::TRANSPARENT),
110 store: wgpu::StoreOp::Store,
111 }],
112 bindings: vec![
113 Binding::sampled_texture(0, 0, source),
114 Binding::sampler(0, 1, sampler),
115 ],
116 vertex_buffers: Vec::new(),
117 index_buffer: None,
118 draw: DrawCommand::Draw(Draw {
119 vertices: 0..3,
120 instances: 0..1,
121 }),
122 scissor: None,
123 });
124 let plan = plan.build();
125
126 assert_eq!(plan.textures().len(), 2);
127 assert_eq!(plan.programs().len(), 1);
128 assert_eq!(plan.passes().len(), 1);
129 }
130
131 #[test]
132 fn frame_update_records_dynamic_uniform_uploads() {
133 let uniforms = BufferId(7);
134 let bytes = [1, 2, 3, 4];
135 let mut update = FrameUpdate::new();
136 update.write_buffer(uniforms, 0, &bytes);
137
138 assert_eq!(update.uploads().len(), 1);
139 }
140}