use crate::{RenderError, RenderSize, RenderedTexture, Renderer, pipeline::CachedPipeline};
use alpha2_shaders::FULLSCREEN_TEXTURE_QUAD_WGSL;
impl Renderer {
#[allow(clippy::too_many_lines)]
pub fn render_quad(
&self,
size: RenderSize,
source: [u8; 4],
) -> Result<RenderedTexture, RenderError> {
let format = self.intermediate_format();
let mut encoder = self.command_encoder("alpha2 quad encoder");
let target = self
.textures
.acquire(self.gpu.device(), size, format, "alpha2 quad target");
let input = self.gpu.device().create_texture(&wgpu::TextureDescriptor {
label: None,
size: wgpu::Extent3d {
width: 1,
height: 1,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8Unorm,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
view_formats: &[],
});
self.gpu.queue().write_texture(
wgpu::TexelCopyTextureInfo {
texture: &input,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All,
},
&source,
wgpu::TexelCopyBufferLayout {
offset: 0,
bytes_per_row: Some(4),
rows_per_image: Some(1),
},
wgpu::Extent3d {
width: 1,
height: 1,
depth_or_array_layers: 1,
},
);
let cached = self.quad_pipeline();
let input_view = crate::pool::default_view(&input);
let group = self
.gpu
.device()
.create_bind_group(&wgpu::BindGroupDescriptor {
label: None,
layout: &cached.bind_group_layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&input_view),
}],
});
{
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: target.view(),
depth_slice: None,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
store: wgpu::StoreOp::Store,
},
})],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
multiview_mask: None,
});
pass.set_pipeline(&cached.pipeline);
pass.set_bind_group(0, &group, &[]);
pass.draw(0..3, 0..1);
}
self.submit([encoder.finish()])?;
Ok(RenderedTexture::pooled(size, format, target))
}
pub(crate) fn quad_pipeline(&self) -> &CachedPipeline {
self.pipelines.quad.get_or_init(|| {
let bind_group_layout =
self.gpu
.device()
.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("alpha2 quad layout"),
entries: &[wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: false },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
}],
});
let shader = self
.gpu
.device()
.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("alpha2 quad shader"),
source: wgpu::ShaderSource::Wgsl(FULLSCREEN_TEXTURE_QUAD_WGSL.into()),
});
let pipeline_layout =
self.gpu
.device()
.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("alpha2 quad pipeline layout"),
bind_group_layouts: &[Some(&bind_group_layout)],
immediate_size: 0,
});
let pipeline =
self.gpu
.device()
.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("alpha2 quad pipeline"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs"),
buffers: &[],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some("fs"),
targets: &[Some(wgpu::ColorTargetState {
format: self.intermediate_format(),
blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING),
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: wgpu::PrimitiveState::default(),
depth_stencil: None,
multisample: wgpu::MultisampleState::default(),
multiview_mask: None,
cache: None,
});
CachedPipeline {
bind_group_layout,
pipeline,
}
})
}
}