1use crate::{RenderError, RenderSize, RenderedTexture, Renderer, pipeline::CachedPipeline};
2use alpha2_shaders::FULLSCREEN_TEXTURE_QUAD_WGSL;
3
4impl Renderer {
5 #[allow(clippy::too_many_lines)]
10 pub fn render_quad(
11 &self,
12 size: RenderSize,
13 source: [u8; 4],
14 ) -> Result<RenderedTexture, RenderError> {
15 let format = self.intermediate_format();
16 let mut encoder = self.command_encoder("alpha2 quad encoder");
17 let target = self
18 .textures
19 .acquire(self.gpu.device(), size, format, "alpha2 quad target");
20 let input = self.gpu.device().create_texture(&wgpu::TextureDescriptor {
21 label: None,
22 size: wgpu::Extent3d {
23 width: 1,
24 height: 1,
25 depth_or_array_layers: 1,
26 },
27 mip_level_count: 1,
28 sample_count: 1,
29 dimension: wgpu::TextureDimension::D2,
30 format: wgpu::TextureFormat::Rgba8Unorm,
31 usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
32 view_formats: &[],
33 });
34 self.gpu.queue().write_texture(
35 wgpu::TexelCopyTextureInfo {
36 texture: &input,
37 mip_level: 0,
38 origin: wgpu::Origin3d::ZERO,
39 aspect: wgpu::TextureAspect::All,
40 },
41 &source,
42 wgpu::TexelCopyBufferLayout {
43 offset: 0,
44 bytes_per_row: Some(4),
45 rows_per_image: Some(1),
46 },
47 wgpu::Extent3d {
48 width: 1,
49 height: 1,
50 depth_or_array_layers: 1,
51 },
52 );
53 let cached = self.quad_pipeline();
54 let input_view = crate::pool::default_view(&input);
55 let group = self
56 .gpu
57 .device()
58 .create_bind_group(&wgpu::BindGroupDescriptor {
59 label: None,
60 layout: &cached.bind_group_layout,
61 entries: &[wgpu::BindGroupEntry {
62 binding: 0,
63 resource: wgpu::BindingResource::TextureView(&input_view),
64 }],
65 });
66 {
67 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
68 label: None,
69 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
70 view: target.view(),
71 depth_slice: None,
72 resolve_target: None,
73 ops: wgpu::Operations {
74 load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
75 store: wgpu::StoreOp::Store,
76 },
77 })],
78 depth_stencil_attachment: None,
79 timestamp_writes: None,
80 occlusion_query_set: None,
81 multiview_mask: None,
82 });
83 pass.set_pipeline(&cached.pipeline);
84 pass.set_bind_group(0, &group, &[]);
85 pass.draw(0..3, 0..1);
86 }
87 self.submit([encoder.finish()])?;
88 Ok(RenderedTexture::pooled(size, format, target))
89 }
90
91 pub(crate) fn quad_pipeline(&self) -> &CachedPipeline {
92 self.pipelines.quad.get_or_init(|| {
93 let bind_group_layout =
94 self.gpu
95 .device()
96 .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
97 label: Some("alpha2 quad layout"),
98 entries: &[wgpu::BindGroupLayoutEntry {
99 binding: 0,
100 visibility: wgpu::ShaderStages::FRAGMENT,
101 ty: wgpu::BindingType::Texture {
102 sample_type: wgpu::TextureSampleType::Float { filterable: false },
103 view_dimension: wgpu::TextureViewDimension::D2,
104 multisampled: false,
105 },
106 count: None,
107 }],
108 });
109 let shader = self
110 .gpu
111 .device()
112 .create_shader_module(wgpu::ShaderModuleDescriptor {
113 label: Some("alpha2 quad shader"),
114 source: wgpu::ShaderSource::Wgsl(FULLSCREEN_TEXTURE_QUAD_WGSL.into()),
115 });
116 let pipeline_layout =
117 self.gpu
118 .device()
119 .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
120 label: Some("alpha2 quad pipeline layout"),
121 bind_group_layouts: &[Some(&bind_group_layout)],
122 immediate_size: 0,
123 });
124 let pipeline =
125 self.gpu
126 .device()
127 .create_render_pipeline(&wgpu::RenderPipelineDescriptor {
128 label: Some("alpha2 quad pipeline"),
129 layout: Some(&pipeline_layout),
130 vertex: wgpu::VertexState {
131 module: &shader,
132 entry_point: Some("vs"),
133 buffers: &[],
134 compilation_options: wgpu::PipelineCompilationOptions::default(),
135 },
136 fragment: Some(wgpu::FragmentState {
137 module: &shader,
138 entry_point: Some("fs"),
139 targets: &[Some(wgpu::ColorTargetState {
140 format: self.intermediate_format(),
141 blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING),
142 write_mask: wgpu::ColorWrites::ALL,
143 })],
144 compilation_options: wgpu::PipelineCompilationOptions::default(),
145 }),
146 primitive: wgpu::PrimitiveState::default(),
147 depth_stencil: None,
148 multisample: wgpu::MultisampleState::default(),
149 multiview_mask: None,
150 cache: None,
151 });
152 CachedPipeline {
153 bind_group_layout,
154 pipeline,
155 }
156 })
157 }
158}