use core::num::NonZeroU32;
use std::borrow::Cow;
use wgpu::util::{DeviceExt, RenderEncoder};
#[repr(C)]
#[derive(Copy, Clone, Debug, bytemuck_derive::Pod, bytemuck_derive::Zeroable)]
pub struct FullscreenVertex {
pub position: [f32; 4],
pub uv: [f32; 2],
}
pub struct FragmentOnlyRenderPipelineDescriptor<'a> {
pub label: wgpu::Label<'a>,
pub layout: Option<&'a wgpu::PipelineLayout>,
pub multisample: wgpu::MultisampleState,
pub fragment: wgpu::FragmentState<'a>,
pub multiview: Option<NonZeroU32>,
}
pub struct FragmentOnlyRenderPipeline {
pipeline: wgpu::RenderPipeline,
vertex_buffer: wgpu::Buffer,
}
impl AsRef<wgpu::RenderPipeline> for FragmentOnlyRenderPipeline {
fn as_ref(&self) -> &wgpu::RenderPipeline {
&self.pipeline
}
}
impl FragmentOnlyRenderPipeline {
pub(crate) fn new(device: &wgpu::Device, desc: &FragmentOnlyRenderPipelineDescriptor) -> Self {
let fullscreen_vertex_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("fullscreen triangle vertex shader"),
source: wgpu::ShaderSource::Wgsl(Cow::from(include_str!("shaders/fullscreen.wgsl"))),
});
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: desc.label.as_deref(),
layout: desc.layout.clone(),
vertex: wgpu::VertexState {
module: &fullscreen_vertex_shader,
entry_point: "main",
buffers: &[wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<FullscreenVertex>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &[
wgpu::VertexAttribute {
offset: 0,
shader_location: 0,
format: wgpu::VertexFormat::Float32x4,
},
wgpu::VertexAttribute {
offset: std::mem::size_of::<[f32; 4]>() as wgpu::BufferAddress,
shader_location: 1,
format: wgpu::VertexFormat::Float32x2,
},
],
}],
},
primitive: wgpu::PrimitiveState::default(),
depth_stencil: None,
multisample: desc.multisample.clone(),
fragment: Some(desc.fragment.clone()),
multiview: desc.multiview.clone(),
});
let fullscreen_vertices = [
FullscreenVertex {
position: [-2.0, -1.0, 0.5, 1.0],
uv: [-2.0, -1.0],
},
FullscreenVertex {
position: [2.0, -1.0, 0.5, 1.0],
uv: [2.0, -1.0],
},
FullscreenVertex {
position: [0.0, 3.0, 0.5, 1.0],
uv: [0.0, 3.0],
},
];
let fullscreen_vertices_bytes: &[u8] = bytemuck::cast_slice(&fullscreen_vertices);
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("fullscreen triangle"),
contents: fullscreen_vertices_bytes,
usage: wgpu::BufferUsages::VERTEX,
});
Self {
pipeline,
vertex_buffer,
}
}
pub fn get_bind_group_layout(&self, index: u32) -> wgpu::BindGroupLayout {
self.pipeline.get_bind_group_layout(index)
}
}
fn set_pipeline<'a>(
encoder: &mut impl RenderEncoder<'a>,
pipeline: &'a FragmentOnlyRenderPipeline,
) {
encoder.set_pipeline(&pipeline.pipeline);
encoder.set_vertex_buffer(0, pipeline.vertex_buffer.slice(..));
}
fn draw<'a>(encoder: &mut impl RenderEncoder<'a>) {
encoder.draw(0..3, 0..1)
}
fn set_push_constants<'a>(encoder: &mut impl RenderEncoder<'a>, offset: u32, data: &[u8]) {
encoder.set_push_constants(wgpu::ShaderStages::FRAGMENT, offset, data)
}
pub struct FragmentOnlyRenderBundleEncoderDescriptor<'a> {
pub label: wgpu::Label<'a>,
pub color_formats: &'a [Option<wgpu::TextureFormat>],
pub sample_count: u32,
pub multiview: Option<NonZeroU32>,
}
pub struct FragmentOnlyRenderBundleEncoder<'a> {
encoder: wgpu::RenderBundleEncoder<'a>,
}
impl<'a> FragmentOnlyRenderBundleEncoder<'a> {
pub(crate) fn new(
device: &'a wgpu::Device,
desc: &FragmentOnlyRenderBundleEncoderDescriptor,
) -> Self {
let encoder = device.create_render_bundle_encoder(&wgpu::RenderBundleEncoderDescriptor {
label: desc.label.as_deref(),
color_formats: desc.color_formats,
depth_stencil: None,
sample_count: desc.sample_count,
multiview: desc.multiview,
});
Self { encoder }
}
pub fn finish(self, desc: &wgpu::RenderBundleDescriptor<'_>) -> FragmentOnlyRenderBundle {
let render_bundle = self.encoder.finish(desc);
FragmentOnlyRenderBundle { render_bundle }
}
pub fn set_pipeline(&mut self, pipeline: &'a FragmentOnlyRenderPipeline) {
set_pipeline(&mut self.encoder, pipeline)
}
pub fn draw(&mut self) {
draw(&mut self.encoder)
}
pub fn set_push_constants(&mut self, offset: u32, data: &[u8]) {
set_push_constants(&mut self.encoder, offset, data)
}
}
pub struct FragmentOnlyRenderBundle {
render_bundle: wgpu::RenderBundle,
}
pub struct FragmentOnlyRenderPassStencilAttachment<'tex> {
pub view: &'tex wgpu::TextureView,
pub stencil_ops: Option<wgpu::Operations<u32>>,
}
pub struct FragmentOnlyRenderPassDescriptor<'tex, 'desc> {
pub label: wgpu::Label<'desc>,
pub color_attachments: &'desc [Option<wgpu::RenderPassColorAttachment<'tex>>],
pub stencil_attachment: Option<FragmentOnlyRenderPassStencilAttachment<'tex>>,
}
#[derive(Debug)]
pub struct FragmentOnlyRenderPass<'a> {
renderpass: wgpu::RenderPass<'a>,
}
impl<'a> FragmentOnlyRenderPass<'a> {
pub(crate) fn new(
command_encoder: &'a mut wgpu::CommandEncoder,
desc: &FragmentOnlyRenderPassDescriptor<'a, '_>,
) -> Self {
let desc = wgpu::RenderPassDescriptor {
label: desc.label,
color_attachments: desc.color_attachments,
depth_stencil_attachment: desc.stencil_attachment.as_ref().map(|attachment| {
wgpu::RenderPassDepthStencilAttachment {
view: attachment.view,
depth_ops: None,
stencil_ops: attachment.stencil_ops,
}
}),
};
let renderpass = command_encoder.begin_render_pass(&desc);
Self { renderpass }
}
pub fn set_pipeline(&mut self, pipeline: &'a FragmentOnlyRenderPipeline) {
set_pipeline(&mut self.renderpass, pipeline)
}
pub fn draw(&mut self) {
draw(&mut self.renderpass)
}
pub fn set_push_constants(&mut self, offset: u32, data: &[u8]) {
set_push_constants(&mut self.renderpass, offset, data)
}
pub fn execute_bundles<I: IntoIterator<Item = &'a FragmentOnlyRenderBundle>>(
&mut self,
render_bundles: I,
) {
let render_bundles: Vec<&wgpu::RenderBundle> = render_bundles
.into_iter()
.map(|bundle| &bundle.render_bundle)
.collect();
self.renderpass.execute_bundles(render_bundles)
}
pub fn set_bind_group(
&mut self,
index: u32,
bind_group: &'a wgpu::BindGroup,
offsets: &[wgpu::DynamicOffset],
) {
self.renderpass.set_bind_group(index, bind_group, offsets)
}
pub fn set_blend_constant(&mut self, color: wgpu::Color) {
self.renderpass.set_blend_constant(color)
}
pub fn set_scissor_rect(&mut self, x: u32, y: u32, width: u32, height: u32) {
self.renderpass.set_scissor_rect(x, y, width, height)
}
pub fn set_stencil_reference(&mut self, reference: u32) {
self.renderpass.set_stencil_reference(reference)
}
pub fn insert_debug_marker(&mut self, label: &str) {
self.renderpass.insert_debug_marker(label)
}
pub fn push_debug_group(&mut self, label: &str) {
self.renderpass.push_debug_group(label)
}
pub fn pop_debug_group(&mut self) {
self.renderpass.pop_debug_group()
}
pub fn write_timestamp(&mut self, query_set: &wgpu::QuerySet, query_index: u32) {
self.renderpass.write_timestamp(query_set, query_index)
}
pub fn begin_pipeline_statistics_query(
&mut self,
query_set: &wgpu::QuerySet,
query_index: u32,
) {
self.renderpass
.begin_pipeline_statistics_query(query_set, query_index)
}
pub fn end_pipeline_statistics_query(&mut self) {
self.renderpass.end_pipeline_statistics_query()
}
}