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