use std::ops::{Deref, DerefMut};
use crate::{CommandEncoder, Frame, Gpu, RenderPipeline, Texture};
pub struct RenderPassBuilder<'a, 'b> {
pub(crate) encoder: &'a mut CommandEncoder,
pub(crate) desc: wgpu::RenderPassDescriptor<'a, 'b>,
pub(crate) init_color_attachments: Option<Vec<wgpu::RenderPassColorAttachment<'a>>>,
pub(crate) init_pipeline: Option<&'a wgpu::RenderPipeline>,
}
pub trait RenderAttachmentBuild {
fn clear_impl(self, r: f64, g: f64, b: f64, a: f64) -> Self;
fn clear(self) -> Self;
fn clear_black(self) -> Self;
fn clear_white(self) -> Self;
fn clear_color(self, color: u32) -> Self;
fn readonly(self) -> Self;
}
impl<'a> RenderAttachmentBuild for wgpu::RenderPassColorAttachment<'a> {
fn clear_impl(mut self, r: f64, g: f64, b: f64, a: f64) -> Self {
self.ops = wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color { r, g, b, a }),
..self.ops
};
self
}
fn clear(self) -> Self {
self.clear_impl(0.0, 0.0, 0.0, 0.0)
}
fn clear_black(self) -> Self {
self.clear_impl(0.0, 0.0, 0.0, 1.0)
}
fn clear_white(self) -> Self {
self.clear_impl(1.0, 1.0, 1.0, 1.0)
}
fn clear_color(self, color: u32) -> Self {
let [r, g, b, a] = color.to_be_bytes();
self.clear_impl(
r as f64 / 255.0,
g as f64 / 255.0,
b as f64 / 255.0,
a as f64 / 255.0,
)
}
fn readonly(mut self) -> Self {
self.ops = wgpu::Operations {
store: false,
..self.ops
};
self
}
}
pub trait DepthAttachmentBuild {
fn clear_depth_val(self, val: f32) -> Self;
fn clear_stencil_val(self, val: u32) -> Self;
fn clear_depth(self) -> Self;
fn clear_stencil(self) -> Self;
fn clear(self) -> Self;
}
impl<'a> DepthAttachmentBuild for wgpu::RenderPassDepthStencilAttachment<'a> {
fn clear_depth_val(mut self, val: f32) -> Self {
if let Some(mut ops) = self.depth_ops.as_mut() {
ops.load = wgpu::LoadOp::Clear(val);
}
self
}
fn clear_stencil_val(mut self, val: u32) -> Self {
if let Some(mut ops) = self.stencil_ops.as_mut() {
ops.load = wgpu::LoadOp::Clear(val);
}
self
}
fn clear_depth(self) -> Self {
self.clear_depth_val(1.0)
}
fn clear_stencil(self) -> Self {
self.clear_stencil_val(0)
}
fn clear(self) -> Self {
self.clear_depth().clear_stencil()
}
}
impl<'a, 'b> RenderPassBuilder<'a, 'b> {
pub fn new(encoder: &'a mut CommandEncoder, _gpu: &'a mut Gpu) -> Self {
Self {
encoder,
desc: wgpu::RenderPassDescriptor {
label: Some("Render pass"),
color_attachments: &[],
depth_stencil_attachment: None,
},
init_pipeline: None,
init_color_attachments: None,
}
}
pub fn with_depth(mut self, depth: wgpu::RenderPassDepthStencilAttachment<'a>) -> Self {
self.desc.depth_stencil_attachment = Some(depth);
self
}
#[inline]
pub fn with_pipeline(mut self, pipeline: &'a RenderPipeline) -> Self {
self.init_pipeline = Some(pipeline);
if pipeline.depth_stencil.is_none() {
self.desc.depth_stencil_attachment = None;
}
self
}
pub fn begin(self) -> RenderPass<'a> {
let desc = self.desc.clone();
self.begin_impl(&desc)
}
fn begin_impl(self, desc: &'b wgpu::RenderPassDescriptor<'a, 'b>) -> RenderPass<'a> {
let gpu = self.encoder.gpu.clone();
if self.encoder.gpu.profiler.timestamp.is_some() {
gpu.begin_profiler_section(self.desc.label.unwrap_or("Render pass"), self.encoder);
}
let mut inner = if let Some(init_attachment) = self.init_color_attachments {
let color_attachments = &init_attachment;
let desc = wgpu::RenderPassDescriptor {
color_attachments,
..desc.clone()
};
self.encoder.begin_render_pass(&desc)
} else {
self.encoder.begin_render_pass(desc)
};
let pipeline_statistics = gpu.profiler.stats.is_some();
if pipeline_statistics {
gpu.begin_pipeline_statistics_query(&mut inner);
}
if let Some(pipeline) = self.init_pipeline {
inner.set_pipeline(pipeline);
}
RenderPass {
inner,
pipeline_statistics,
}
}
}
pub struct RenderPass<'a> {
inner: wgpu::RenderPass<'a>,
pipeline_statistics: bool,
}
impl RenderPass<'_> {
pub fn draw_triangles(&mut self, count: u32) {
self.inner.draw(0..3, 0..count);
}
#[inline]
pub fn draw_triangle(&mut self) {
self.inner.draw(0..3, 0..1);
}
pub fn draw_one(&mut self, vertices: u32) {
self.inner.draw(0..vertices, 0..1);
}
pub fn draw_one_indexed(&mut self, vertices: u32) {
self.inner.draw_indexed(0..vertices, 0, 0..1);
}
}
impl<'a> RenderPass<'a> {
pub fn set_bind_group(
&mut self,
index: u32,
bind_group: &'a wgpu::BindGroup,
offsets: &[wgpu::DynamicOffset],
) -> &mut Self {
self.inner.set_bind_group(index, bind_group, offsets);
self
}
pub fn set_pipeline(&mut self, pipeline: &'a wgpu::RenderPipeline) -> &mut Self {
self.inner.set_pipeline(pipeline);
self
}
pub fn set_index_buffer(&mut self, buffer_slice: wgpu::BufferSlice<'a>) -> &mut Self {
self.inner
.set_index_buffer(buffer_slice, wgpu::IndexFormat::Uint16);
self
}
pub fn set_index_buffer_u32(&mut self, buffer_slice: wgpu::BufferSlice<'a>) -> &mut Self {
self.inner
.set_index_buffer(buffer_slice, wgpu::IndexFormat::Uint32);
self
}
pub fn set_vertex_buffer(
&mut self,
slot: u32,
buffer_slice: wgpu::BufferSlice<'a>,
) -> &mut Self {
self.inner.set_vertex_buffer(slot, buffer_slice);
self
}
pub fn set_scissor_rect(&mut self, x: u32, y: u32, width: u32, height: u32) -> &mut Self {
self.inner.set_scissor_rect(x, y, width, height);
self
}
}
impl<'a> Deref for RenderPass<'a> {
type Target = wgpu::RenderPass<'a>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<'a> DerefMut for RenderPass<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl<'a> From<wgpu::RenderPass<'a>> for RenderPass<'a> {
fn from(render_pass: wgpu::RenderPass<'a>) -> Self {
Self {
inner: render_pass,
pipeline_statistics: false,
}
}
}
impl Drop for RenderPass<'_> {
fn drop(&mut self) {
if self.pipeline_statistics {
self.end_pipeline_statistics_query();
}
}
}
impl crate::CommandEncoder {
pub fn render_pass<'a, 'b>(
&'a mut self,
label: &'a str,
targets: &'b [wgpu::RenderPassColorAttachment<'a>],
) -> RenderPassBuilder<'a, 'b> {
RenderPassBuilder {
encoder: self,
desc: wgpu::RenderPassDescriptor {
color_attachments: targets,
label: Some(label),
depth_stencil_attachment: None,
},
init_pipeline: None,
init_color_attachments: None,
}
}
}
impl<D> Texture<D>
where
D: crate::TextureDimensions,
{
pub fn attach_render(&self) -> RenderAttachment<'_> {
wgpu::RenderPassColorAttachment {
view: &self.view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: true,
},
}
}
pub fn attach_depth(&self) -> DepthAttachment<'_> {
wgpu::RenderPassDepthStencilAttachment {
view: &self.view,
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Load,
store: true,
}),
stencil_ops: None,
}
}
pub fn attach_stencil(&self) -> DepthAttachment<'_> {
wgpu::RenderPassDepthStencilAttachment {
view: &self.view,
depth_ops: None,
stencil_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Load,
store: true,
}),
}
}
pub fn attach_depth_stencil(&self) -> DepthAttachment<'_> {
wgpu::RenderPassDepthStencilAttachment {
view: &self.view,
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Load,
store: true,
}),
stencil_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Load,
store: true,
}),
}
}
}
pub type RenderAttachment<'a> = wgpu::RenderPassColorAttachment<'a>;
pub type DepthAttachment<'a> = wgpu::RenderPassDepthStencilAttachment<'a>;
impl Frame<'_> {
pub const fn attach_render(&self) -> RenderAttachment<'_> {
wgpu::RenderPassColorAttachment {
view: self.view.deref_const(),
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: true,
},
}
}
pub const fn attach_depth(&self) -> DepthAttachment<'_> {
wgpu::RenderPassDepthStencilAttachment {
view: self.depth_texture.deref_const(),
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Load,
store: true,
}),
stencil_ops: None,
}
}
pub const fn attach_stencil(&self) -> DepthAttachment<'_> {
wgpu::RenderPassDepthStencilAttachment {
view: self.depth_texture.deref_const(),
depth_ops: None,
stencil_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Load,
store: true,
}),
}
}
pub const fn attach_depth_stencil(&self) -> DepthAttachment<'_> {
wgpu::RenderPassDepthStencilAttachment {
view: self.depth_texture.deref_const(),
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Load,
store: true,
}),
stencil_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Load,
store: true,
}),
}
}
}