From 0fe20342e0bb390e6813b1f9a6cfd9b7f1796c33 Mon Sep 17 00:00:00 2001 From: Valtteri Vallius <36015558+kaphula@users.noreply.github.com> Date: Wed, 18 Dec 2024 06:41:21 +0200 Subject: [PATCH] Add multiple render targets example (v2) (#5313) Co-authored-by: Connor Fitzgerald --- CHANGELOG.md | 5 + examples/README.md | 1 + examples/src/lib.rs | 1 + examples/src/main.rs | 6 + .../src/multiple_render_targets/README.md | 21 + examples/src/multiple_render_targets/mod.rs | 544 ++++++++++++++++++ .../multiple_render_targets/screenshot.png | Bin 0 -> 51569 bytes .../src/multiple_render_targets/shader.wgsl | 44 ++ 8 files changed, 622 insertions(+) create mode 100644 examples/src/multiple_render_targets/README.md create mode 100644 examples/src/multiple_render_targets/mod.rs create mode 100644 examples/src/multiple_render_targets/screenshot.png create mode 100644 examples/src/multiple_render_targets/shader.wgsl diff --git a/CHANGELOG.md b/CHANGELOG.md index b89aac4aa7..622deaab7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -197,6 +197,11 @@ By @ErichDonGubler in [#6456](https://github.com/gfx-rs/wgpu/pull/6456), [#6148] - Fix crash when a texture argument is missing. By @aedm in [#6486](https://github.com/gfx-rs/wgpu/pull/6486) - Emit an error in constant evaluation, rather than crash, in certain cases where `vecN` constructors have less than N arguments. By @ErichDonGubler in [#6508](https://github.com/gfx-rs/wgpu/pull/6508). + +### Examples + +- Add multiple render targets example. By @kaphula in [#5297](https://github.com/gfx-rs/wgpu/pull/5313) + ### Testing diff --git a/examples/README.md b/examples/README.md index c67941e067..799c8a8d5b 100644 --- a/examples/README.md +++ b/examples/README.md @@ -24,6 +24,7 @@ The rest of the examples are for demonstrating specific features that you can co - `bunnymark` - Demonstrates many things, but chief among them is performing numerous draw calls with different bind groups in one render pass. The example also uses textures for the icon and uniform buffers to transfer both global and per-particle states. - `skybox` - Shows off too many concepts to list here. The name comes from game development where a "skybox" acts as a background for rendering, usually to add a sky texture for immersion, although they can also be used for backdrops to give the idea of a world beyond the game scene. This example does so much more than this, though, as it uses a car model loaded from a file and uses the user's mouse to rotate the car model in 3d. `skybox` also makes use of depth textures and similar app patterns to `uniform_values`. - `shadow` - Likely by far the most complex example (certainly the largest in lines of code) of the official WGPU examples. `shadow` demonstrates basic scene rendering with the main attraction being lighting and shadows (as the name implies). It is recommended that any user looking into lighting be very familiar with the basic concepts of not only rendering with WGPU but also the primary mathematical ideas of computer graphics. +- `multiple-render-targets` - Demonstrates how to render to two texture targets simultaneously from fragment shader. - `render_to_texture` - Renders to an image texture offscreen, demonstrating both off-screen rendering as well as how to add a sort of resolution-agnostic screenshot feature to an engine. This example either outputs an image file of your naming (pass command line arguments after specifying a `--` like `cargo run --bin wgpu-examples -- render_to_texture "test.png"`) or adds an `img` element containing the image to the page in WASM. - `ray_cube_fragment` - Demonstrates using ray queries with a fragment shader. - `ray_scene` - Demonstrates using ray queries and model loading diff --git a/examples/src/lib.rs b/examples/src/lib.rs index 358993e1af..71b3799744 100644 --- a/examples/src/lib.rs +++ b/examples/src/lib.rs @@ -15,6 +15,7 @@ pub mod hello_windows; pub mod hello_workgroups; pub mod mipmap; pub mod msaa_line; +pub mod multiple_render_targets; pub mod ray_cube_compute; pub mod ray_cube_fragment; pub mod ray_scene; diff --git a/examples/src/main.rs b/examples/src/main.rs index 77e658a883..66f0fea4d8 100644 --- a/examples/src/main.rs +++ b/examples/src/main.rs @@ -80,6 +80,12 @@ const EXAMPLES: &[ExampleDesc] = &[ webgl: true, webgpu: true, }, + ExampleDesc { + name: "multiple_render_targets", + function: wgpu_examples::multiple_render_targets::main, + webgl: false, + webgpu: true, + }, ExampleDesc { name: "render_to_texture", function: wgpu_examples::render_to_texture::main, diff --git a/examples/src/multiple_render_targets/README.md b/examples/src/multiple_render_targets/README.md new file mode 100644 index 0000000000..677f32b266 --- /dev/null +++ b/examples/src/multiple_render_targets/README.md @@ -0,0 +1,21 @@ +# multiple_render_targets + +This example demonstrates how to use fragment shader to output to two color attachments of a renderpass simultaneously. + +The program generates a black and white ball-shaped texture from scratch and uses the fragment shader to draw it to two +separate texture targets. The first texture target receives a red version of the texture and the second target receives +a green version. + +Once the colored shapes have been drawn to two separate textures, they +will be displayed on the screen by rendering each one of them to their own viewports that split the screen in half. + + +## To Run + +``` +cargo run --bin wgpu-examples multiple_render_targets +``` + +## Screenshots + +![Multi render target](./screenshot.png) diff --git a/examples/src/multiple_render_targets/mod.rs b/examples/src/multiple_render_targets/mod.rs new file mode 100644 index 0000000000..7680ad4385 --- /dev/null +++ b/examples/src/multiple_render_targets/mod.rs @@ -0,0 +1,544 @@ +const EXAMPLE_NAME: &str = "multiple_render_targets"; + +/// Renderer that draws its outputs to two output texture targets at the same time. +struct MultiTargetRenderer { + pipeline: wgpu::RenderPipeline, + bindgroup: wgpu::BindGroup, +} + +fn create_ball_texture_data(width: usize, height: usize) -> Vec { + // Creates black and white pixel data for the texture to sample. + let mut img_data = Vec::with_capacity(width * height); + let center: glam::Vec2 = glam::Vec2::new(width as f32 * 0.5, height as f32 * 0.5); + let half_distance = width as f32 * 0.5; + for y in 0..width { + for x in 0..height { + let cur_pos = glam::Vec2::new(x as f32, y as f32); + let distance_to_center_normalized = 1.0 - (cur_pos - center).length() / half_distance; + let val: u8 = (u8::MAX as f32 * distance_to_center_normalized) as u8; + img_data.push(val) + } + } + img_data +} + +impl MultiTargetRenderer { + fn create_image_texture( + device: &wgpu::Device, + queue: &wgpu::Queue, + ) -> (wgpu::Texture, wgpu::TextureView) { + const WIDTH: usize = 256; + const HEIGHT: usize = 256; + + let size = wgpu::Extent3d { + width: WIDTH as u32, + height: HEIGHT as u32, + depth_or_array_layers: 1, + }; + + let texture = device.create_texture(&wgpu::TextureDescriptor { + label: Some("data texture"), + size, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::R8Unorm, // we need only the red channel for black/white image, + usage: wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::TEXTURE_BINDING, + view_formats: &[], + }); + + let ball_texture_data = &create_ball_texture_data(WIDTH, HEIGHT); + + queue.write_texture( + wgpu::TexelCopyTextureInfo { + aspect: wgpu::TextureAspect::All, + texture: &texture, + mip_level: 0, + origin: wgpu::Origin3d::ZERO, + }, + ball_texture_data, + wgpu::TexelCopyBufferLayout { + offset: 0, + bytes_per_row: Some(WIDTH as u32), + rows_per_image: Some(HEIGHT as u32), + }, + size, + ); + + let view = texture.create_view(&wgpu::TextureViewDescriptor { + label: Some("view"), + format: None, + dimension: Some(wgpu::TextureViewDimension::D2), + aspect: wgpu::TextureAspect::All, + base_mip_level: 0, + mip_level_count: None, + base_array_layer: 0, + array_layer_count: None, + }); + + (texture, view) + } + + fn init( + device: &wgpu::Device, + queue: &wgpu::Queue, + shader: &wgpu::ShaderModule, + target_states: &[Option], + ) -> MultiTargetRenderer { + let texture_bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + multisampled: false, + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::D2, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), + count: None, + }, + ], + label: None, + }); + + let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: None, + bind_group_layouts: &[&texture_bind_group_layout], + push_constant_ranges: &[], + }); + + let sampler = device.create_sampler(&wgpu::SamplerDescriptor { + address_mode_u: wgpu::AddressMode::Repeat, + address_mode_v: wgpu::AddressMode::Repeat, + address_mode_w: wgpu::AddressMode::Repeat, + mag_filter: wgpu::FilterMode::Nearest, + min_filter: wgpu::FilterMode::Nearest, + mipmap_filter: wgpu::FilterMode::Nearest, + ..Default::default() + }); + + let (_, texture_view) = Self::create_image_texture(device, queue); + + let bindgroup = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &texture_bind_group_layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&texture_view), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::Sampler(&sampler), + }, + ], + label: None, + }); + + let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: None, + layout: Some(&pipeline_layout), + vertex: wgpu::VertexState { + module: shader, + entry_point: Some("vs_main"), + compilation_options: Default::default(), + buffers: &[], + }, + fragment: Some(wgpu::FragmentState { + module: shader, + entry_point: Some("fs_multi_main"), + // IMPORTANT: specify the color states for the outputs: + compilation_options: Default::default(), + targets: target_states, + }), + primitive: wgpu::PrimitiveState::default(), + depth_stencil: None, + multisample: wgpu::MultisampleState::default(), + multiview: None, + cache: None, + }); + + Self { + pipeline, + bindgroup, + } + } + + fn draw( + &self, + encoder: &mut wgpu::CommandEncoder, + targets: &[Option], + ) { + let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: None, + color_attachments: targets, + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + rpass.set_pipeline(&self.pipeline); + rpass.set_bind_group(0, &self.bindgroup, &[]); + rpass.draw(0..3, 0..1); + } +} + +/// Renderer that displays results on the screen. +struct TargetRenderer { + pipeline: wgpu::RenderPipeline, + bindgroup_layout: wgpu::BindGroupLayout, + bindgroup_left: wgpu::BindGroup, + bindgroup_right: wgpu::BindGroup, + sampler: wgpu::Sampler, +} + +impl TargetRenderer { + fn init( + device: &wgpu::Device, + shader: &wgpu::ShaderModule, + format: wgpu::TextureFormat, + targets: &TextureTargets, + ) -> TargetRenderer { + let texture_bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + multisampled: false, + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::D2, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), + count: None, + }, + ], + label: None, + }); + + let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: None, + bind_group_layouts: &[&texture_bind_group_layout], + push_constant_ranges: &[], + }); + + let sampler = device.create_sampler(&wgpu::SamplerDescriptor { + address_mode_u: wgpu::AddressMode::Repeat, + address_mode_v: wgpu::AddressMode::Repeat, + address_mode_w: wgpu::AddressMode::Repeat, + mag_filter: wgpu::FilterMode::Nearest, + min_filter: wgpu::FilterMode::Nearest, + mipmap_filter: wgpu::FilterMode::Nearest, + ..Default::default() + }); + + let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: None, + layout: Some(&pipeline_layout), + vertex: wgpu::VertexState { + module: shader, + entry_point: Some("vs_main"), + compilation_options: Default::default(), + buffers: &[], + }, + fragment: Some(wgpu::FragmentState { + module: shader, + entry_point: Some("fs_display_main"), + compilation_options: Default::default(), + targets: &[Some(wgpu::ColorTargetState { + format, + blend: None, + write_mask: Default::default(), + })], + }), + primitive: wgpu::PrimitiveState::default(), + depth_stencil: None, + multisample: wgpu::MultisampleState::default(), + multiview: None, + cache: None, + }); + + let (bg_left, bg_right) = + Self::create_bindgroups(device, &texture_bind_group_layout, targets, &sampler); + Self { + pipeline: render_pipeline, + bindgroup_layout: texture_bind_group_layout, + bindgroup_left: bg_left, + bindgroup_right: bg_right, + sampler, + } + } + fn create_bindgroups( + device: &wgpu::Device, + layout: &wgpu::BindGroupLayout, + texture_targets: &TextureTargets, + sampler: &wgpu::Sampler, + ) -> (wgpu::BindGroup, wgpu::BindGroup) { + let left = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&texture_targets.red_view), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::Sampler(sampler), + }, + ], + label: None, + }); + + let right = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&texture_targets.green_view), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::Sampler(sampler), + }, + ], + label: None, + }); + (left, right) + } + + fn draw( + &self, + encoder: &mut wgpu::CommandEncoder, + surface_view: &wgpu::TextureView, + width: u32, + height: u32, + ) { + let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: None, + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: surface_view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color::GREEN), + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + rpass.set_pipeline(&self.pipeline); + rpass.set_bind_group(0, &self.bindgroup_left, &[]); + + let height = height as f32; + let half_w = width as f32 * 0.5; + + // draw results in two separate viewports that split the screen: + + rpass.set_viewport(0.0, 0.0, half_w, height, 0.0, 1.0); + rpass.draw(0..3, 0..1); + + rpass.set_viewport(half_w, 0.0, half_w, height, 0.0, 1.0); + rpass.set_bind_group(0, &self.bindgroup_right, &[]); + rpass.draw(0..3, 0..1); + } + + fn rebuild_resources(&mut self, device: &wgpu::Device, texture_targets: &TextureTargets) { + (self.bindgroup_left, self.bindgroup_right) = Self::create_bindgroups( + device, + &self.bindgroup_layout, + texture_targets, + &self.sampler, + ) + } +} + +struct TextureTargets { + red_view: wgpu::TextureView, + green_view: wgpu::TextureView, +} + +impl TextureTargets { + fn new( + device: &wgpu::Device, + format: wgpu::TextureFormat, + width: u32, + height: u32, + ) -> TextureTargets { + let size = wgpu::Extent3d { + width, + height, + depth_or_array_layers: 1, + }; + + let red_texture = device.create_texture(&wgpu::TextureDescriptor { + label: None, + size, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format, + usage: wgpu::TextureUsages::COPY_DST + | wgpu::TextureUsages::TEXTURE_BINDING + | wgpu::TextureUsages::RENDER_ATTACHMENT, + view_formats: &[format], + }); + let green_texture = device.create_texture(&wgpu::TextureDescriptor { + label: None, + size, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format, + usage: wgpu::TextureUsages::COPY_DST + | wgpu::TextureUsages::TEXTURE_BINDING + | wgpu::TextureUsages::RENDER_ATTACHMENT, + view_formats: &[format], + }); + let red_view = red_texture.create_view(&wgpu::TextureViewDescriptor { + format: Some(format), + dimension: Some(wgpu::TextureViewDimension::D2), + ..wgpu::TextureViewDescriptor::default() + }); + let green_view = green_texture.create_view(&wgpu::TextureViewDescriptor { + format: Some(format), + dimension: Some(wgpu::TextureViewDimension::D2), + ..wgpu::TextureViewDescriptor::default() + }); + TextureTargets { + red_view, + green_view, + } + } +} + +struct Example { + drawer: TargetRenderer, + multi_target_renderer: MultiTargetRenderer, + texture_targets: TextureTargets, + screen_width: u32, + screen_height: u32, +} + +impl crate::framework::Example for Example { + fn init( + config: &wgpu::SurfaceConfiguration, + _adapter: &wgpu::Adapter, + device: &wgpu::Device, + queue: &wgpu::Queue, + ) -> Self { + let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { + label: None, + source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(include_str!( + "shader.wgsl" + ))), + }); + // Renderer that draws to 2 textures at the same time: + let multi_target_renderer = MultiTargetRenderer::init( + device, + queue, + &shader, + // ColorTargetStates specify how the data will be written to the + // output textures: + &[ + Some(wgpu::ColorTargetState { + format: config.format, + blend: None, + write_mask: Default::default(), + }), + Some(wgpu::ColorTargetState { + format: config.format, + blend: None, + write_mask: Default::default(), + }), + ], + ); + + // create our target textures that will receive the simultaneous rendering: + let texture_targets = + TextureTargets::new(device, config.format, config.width, config.height); + + // helper renderer that displays the results in 2 separate viewports: + let drawer = TargetRenderer::init(device, &shader, config.format, &texture_targets); + + Self { + texture_targets, + multi_target_renderer, + drawer, + screen_width: config.width, + screen_height: config.height, + } + } + + fn resize( + &mut self, + config: &wgpu::SurfaceConfiguration, + device: &wgpu::Device, + _queue: &wgpu::Queue, + ) { + self.screen_width = config.width; + self.screen_height = config.height; + self.texture_targets = + TextureTargets::new(device, config.format, config.width, config.height); + self.drawer.rebuild_resources(device, &self.texture_targets); + } + + fn update(&mut self, _event: winit::event::WindowEvent) {} + + fn render(&mut self, view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue) { + let mut encoder = + device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); + + // draw to 2 textures at the same time: + self.multi_target_renderer.draw( + &mut encoder, + &[ + Some(wgpu::RenderPassColorAttachment { + view: &self.texture_targets.red_view, + resolve_target: None, + ops: Default::default(), + }), + Some(wgpu::RenderPassColorAttachment { + view: &self.texture_targets.green_view, + resolve_target: None, + ops: Default::default(), + }), + ], + ); + + // display results of the both drawn textures on screen: + self.drawer + .draw(&mut encoder, view, self.screen_width, self.screen_height); + + queue.submit(Some(encoder.finish())); + } +} + +pub fn main() { + crate::framework::run::(EXAMPLE_NAME); +} + +#[cfg(test)] +#[wgpu_test::gpu_test] +static TEST: crate::framework::ExampleTestParams = crate::framework::ExampleTestParams { + name: EXAMPLE_NAME, + image_path: "/examples/src/multiple_render_targets/screenshot.png", + width: 1024, + height: 768, + optional_features: wgpu::Features::default(), + base_test_parameters: wgpu_test::TestParameters::default(), + // Bounded by lavapipe + comparisons: &[wgpu_test::ComparisonType::Mean(0.005)], + _phantom: std::marker::PhantomData::, +}; diff --git a/examples/src/multiple_render_targets/screenshot.png b/examples/src/multiple_render_targets/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..35ebf5a46a6e1eb4398af433785dd208b67051e6 GIT binary patch literal 51569 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, + @location(0) uv: vec2, +}; + +@vertex +fn vs_main( @builtin(vertex_index) vi: u32) -> VertexOutput { + var out: VertexOutput; + out.uv = vec2( + f32((vi << 1u) & 2u), + f32(vi & 2u), + ); + out.clip_position = vec4(out.uv * 2.0 - 1.0, 0.0, 1.0); + out.uv.y = 1.0 - out.uv.y; + return out; +} + +@group(0) +@binding(0) +var image_texture: texture_2d; +@group(0) +@binding(1) +var image_sampler: sampler; + +struct FragmentOutput { + @location(0) red_target : vec4, + @location(1) green_target : vec4, +} + +@fragment +fn fs_multi_main(vs: VertexOutput) -> FragmentOutput { + let smp = textureSample(image_texture, image_sampler, vs.uv).x; + + var output: FragmentOutput; + output.red_target = vec4(smp, 0.0, 0.0, 1.0); + output.green_target = vec4(0.0, smp, 0.0, 1.0); + return output; +} + +@fragment +fn fs_display_main(vs: VertexOutput) -> @location(0) vec4 { + let smp = textureSample(image_texture, image_sampler, vs.uv).xyz; + return vec4(smp, 1.0); +}