1use core::num::NonZeroU32;
2use std::{borrow::Cow, collections::HashMap};
3
4use wgpu::{
5 util::{DeviceExt, RenderEncoder},
6 PipelineCompilationOptions,
7};
8
9#[repr(C)]
10#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
11pub struct FullscreenVertex {
12 pub position: [f32; 4],
13 pub uv: [f32; 2],
14}
15
16pub struct FragmentOnlyRenderPipelineDescriptor<'a> {
17 pub label: wgpu::Label<'a>,
18 pub layout: Option<&'a wgpu::PipelineLayout>,
19 pub multisample: wgpu::MultisampleState,
20 pub fragment: wgpu::FragmentState<'a>,
21 pub multiview: Option<NonZeroU32>,
22 pub cache: Option<&'a wgpu::PipelineCache>,
23}
24
25pub struct FragmentOnlyRenderPipeline {
26 pipeline: wgpu::RenderPipeline,
27 vertex_buffer: wgpu::Buffer,
28}
29
30impl AsRef<wgpu::RenderPipeline> for FragmentOnlyRenderPipeline {
31 fn as_ref(&self) -> &wgpu::RenderPipeline {
32 &self.pipeline
33 }
34}
35
36impl FragmentOnlyRenderPipeline {
37 pub(crate) fn new(device: &wgpu::Device, desc: &FragmentOnlyRenderPipelineDescriptor) -> Self {
38 let fullscreen_vertex_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
39 label: Some("fullscreen triangle vertex shader"),
40 source: wgpu::ShaderSource::Wgsl(Cow::from(include_str!("shaders/fullscreen.wgsl"))),
41 });
42
43 let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
44 label: desc.label.as_deref(),
45 layout: desc.layout.clone(),
46 vertex: wgpu::VertexState {
47 module: &fullscreen_vertex_shader,
48 entry_point: Some("main"),
49 buffers: &[wgpu::VertexBufferLayout {
50 array_stride: std::mem::size_of::<FullscreenVertex>() as wgpu::BufferAddress,
51 step_mode: wgpu::VertexStepMode::Vertex,
52 attributes: &[
53 wgpu::VertexAttribute {
54 offset: 0,
55 shader_location: 0,
56 format: wgpu::VertexFormat::Float32x4,
57 },
58 wgpu::VertexAttribute {
59 offset: std::mem::size_of::<[f32; 4]>() as wgpu::BufferAddress,
60 shader_location: 1,
61 format: wgpu::VertexFormat::Float32x2,
62 },
63 ],
64 }],
65 compilation_options: PipelineCompilationOptions {
66 constants: &HashMap::new(),
67 zero_initialize_workgroup_memory: false,
68 },
69 },
70 primitive: wgpu::PrimitiveState::default(),
71 depth_stencil: None,
72 multisample: desc.multisample.clone(),
73 fragment: Some(desc.fragment.clone()),
74 multiview: desc.multiview.clone(),
75 cache: desc.cache.clone(),
76 });
77
78 let fullscreen_vertices = [
79 FullscreenVertex {
80 position: [-2.0, -1.0, 0.5, 1.0],
81 uv: [-2.0, -1.0],
82 },
83 FullscreenVertex {
84 position: [2.0, -1.0, 0.5, 1.0],
85 uv: [2.0, -1.0],
86 },
87 FullscreenVertex {
88 position: [0.0, 3.0, 0.5, 1.0],
89 uv: [0.0, 3.0],
90 },
91 ];
92 let fullscreen_vertices_bytes: &[u8] = bytemuck::cast_slice(&fullscreen_vertices);
93 let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
94 label: Some("fullscreen triangle"),
95 contents: fullscreen_vertices_bytes,
96 usage: wgpu::BufferUsages::VERTEX,
97 });
98
99 Self {
100 pipeline,
101 vertex_buffer,
102 }
103 }
104
105 pub fn get_bind_group_layout(&self, index: u32) -> wgpu::BindGroupLayout {
106 self.pipeline.get_bind_group_layout(index)
107 }
108}
109
110fn set_pipeline<'a>(
111 encoder: &mut impl RenderEncoder<'a>,
112 pipeline: &'a FragmentOnlyRenderPipeline,
113) {
114 encoder.set_pipeline(&pipeline.pipeline);
115 encoder.set_vertex_buffer(0, pipeline.vertex_buffer.slice(..));
116}
117
118fn draw<'a>(encoder: &mut impl RenderEncoder<'a>) {
119 encoder.draw(0..3, 0..1)
120}
121
122fn set_push_constants<'a>(encoder: &mut impl RenderEncoder<'a>, offset: u32, data: &[u8]) {
123 encoder.set_push_constants(wgpu::ShaderStages::FRAGMENT, offset, data)
124}
125
126pub struct FragmentOnlyRenderBundleEncoderDescriptor<'a> {
127 pub label: wgpu::Label<'a>,
128 pub color_formats: &'a [Option<wgpu::TextureFormat>],
129 pub sample_count: u32,
130 pub multiview: Option<NonZeroU32>,
131}
132
133pub struct FragmentOnlyRenderBundleEncoder<'a> {
134 encoder: wgpu::RenderBundleEncoder<'a>,
135}
136
137impl<'a> FragmentOnlyRenderBundleEncoder<'a> {
138 pub(crate) fn new(
139 device: &'a wgpu::Device,
140 desc: &FragmentOnlyRenderBundleEncoderDescriptor,
141 ) -> Self {
142 let encoder = device.create_render_bundle_encoder(&wgpu::RenderBundleEncoderDescriptor {
143 label: desc.label.as_deref(),
144 color_formats: desc.color_formats,
145 depth_stencil: None,
146 sample_count: desc.sample_count,
147 multiview: desc.multiview,
148 });
149
150 Self { encoder }
151 }
152
153 pub fn finish(self, desc: &wgpu::RenderBundleDescriptor<'_>) -> FragmentOnlyRenderBundle {
155 let render_bundle = self.encoder.finish(desc);
156
157 FragmentOnlyRenderBundle { render_bundle }
158 }
159 pub fn set_pipeline(&mut self, pipeline: &'a FragmentOnlyRenderPipeline) {
160 set_pipeline(&mut self.encoder, pipeline)
161 }
162 pub fn draw(&mut self) {
163 draw(&mut self.encoder)
164 }
165 pub fn set_push_constants(&mut self, offset: u32, data: &[u8]) {
166 set_push_constants(&mut self.encoder, offset, data)
167 }
168}
169
170pub struct FragmentOnlyRenderBundle {
171 render_bundle: wgpu::RenderBundle,
172}
173
174pub struct FragmentOnlyRenderPassStencilAttachment<'tex> {
175 pub view: &'tex wgpu::TextureView,
176 pub stencil_ops: Option<wgpu::Operations<u32>>,
177}
178
179pub struct FragmentOnlyRenderPassDescriptor<'tex, 'desc> {
180 pub label: wgpu::Label<'desc>,
181 pub color_attachments: &'desc [Option<wgpu::RenderPassColorAttachment<'tex>>],
182 pub stencil_attachment: Option<FragmentOnlyRenderPassStencilAttachment<'tex>>,
183 pub timestamp_writes: Option<wgpu::RenderPassTimestampWrites<'desc>>,
184}
185
186#[derive(Debug)]
187pub struct FragmentOnlyRenderPass<'a> {
188 renderpass: wgpu::RenderPass<'a>,
189}
190
191impl<'a> FragmentOnlyRenderPass<'a> {
192 pub(crate) fn new(
193 command_encoder: &'a mut wgpu::CommandEncoder,
194 desc: &FragmentOnlyRenderPassDescriptor<'a, '_>,
195 ) -> Self {
196 let desc = wgpu::RenderPassDescriptor {
197 label: desc.label,
198 color_attachments: desc.color_attachments,
199 depth_stencil_attachment: desc.stencil_attachment.as_ref().map(|attachment| {
200 wgpu::RenderPassDepthStencilAttachment {
201 view: attachment.view,
202 depth_ops: None,
203 stencil_ops: attachment.stencil_ops,
204 }
205 }),
206 timestamp_writes: desc.timestamp_writes.clone(),
207 occlusion_query_set: None, };
209
210 let renderpass = command_encoder.begin_render_pass(&desc);
211
212 Self { renderpass }
213 }
214
215 pub fn set_pipeline(&mut self, pipeline: &'a FragmentOnlyRenderPipeline) {
218 set_pipeline(&mut self.renderpass, pipeline)
219 }
220 pub fn draw(&mut self) {
221 draw(&mut self.renderpass)
222 }
223 pub fn set_push_constants(&mut self, offset: u32, data: &[u8]) {
224 set_push_constants(&mut self.renderpass, offset, data)
225 }
226 pub fn execute_bundles<I: IntoIterator<Item = &'a FragmentOnlyRenderBundle>>(
227 &mut self,
228 render_bundles: I,
229 ) {
230 let render_bundles: Vec<&wgpu::RenderBundle> = render_bundles
231 .into_iter()
232 .map(|bundle| &bundle.render_bundle)
233 .collect();
234
235 self.renderpass.execute_bundles(render_bundles)
236 }
237
238 pub fn set_bind_group(
242 &mut self,
243 index: u32,
244 bind_group: &'a wgpu::BindGroup,
245 offsets: &[wgpu::DynamicOffset],
246 ) {
247 self.renderpass.set_bind_group(index, bind_group, offsets)
248 }
249 pub fn set_blend_constant(&mut self, color: wgpu::Color) {
250 self.renderpass.set_blend_constant(color)
251 }
252 pub fn set_scissor_rect(&mut self, x: u32, y: u32, width: u32, height: u32) {
253 self.renderpass.set_scissor_rect(x, y, width, height)
254 }
255 pub fn set_stencil_reference(&mut self, reference: u32) {
256 self.renderpass.set_stencil_reference(reference)
257 }
258 pub fn insert_debug_marker(&mut self, label: &str) {
259 self.renderpass.insert_debug_marker(label)
260 }
261 pub fn push_debug_group(&mut self, label: &str) {
262 self.renderpass.push_debug_group(label)
263 }
264 pub fn pop_debug_group(&mut self) {
265 self.renderpass.pop_debug_group()
266 }
267 pub fn write_timestamp(&mut self, query_set: &wgpu::QuerySet, query_index: u32) {
268 self.renderpass.write_timestamp(query_set, query_index)
269 }
270 pub fn begin_pipeline_statistics_query(
271 &mut self,
272 query_set: &wgpu::QuerySet,
273 query_index: u32,
274 ) {
275 self.renderpass
276 .begin_pipeline_statistics_query(query_set, query_index)
277 }
278 pub fn end_pipeline_statistics_query(&mut self) {
279 self.renderpass.end_pipeline_statistics_query()
280 }
281}