wgpu: Don't create depth buffers, or use any depth testing, if we aren't expecting masks
This commit is contained in:
parent
05f49dd487
commit
cb2b27ba03
|
@ -17,7 +17,7 @@ pub struct CommandTarget<'pass> {
|
||||||
frame_buffer: FrameBuffer,
|
frame_buffer: FrameBuffer,
|
||||||
blend_buffer: OnceCell<BlendBuffer>,
|
blend_buffer: OnceCell<BlendBuffer>,
|
||||||
resolve_buffer: Option<ResolveBuffer>,
|
resolve_buffer: Option<ResolveBuffer>,
|
||||||
depth: DepthBuffer,
|
depth: OnceCell<DepthBuffer>,
|
||||||
globals: &'pass Globals,
|
globals: &'pass Globals,
|
||||||
size: wgpu::Extent3d,
|
size: wgpu::Extent3d,
|
||||||
format: wgpu::TextureFormat,
|
format: wgpu::TextureFormat,
|
||||||
|
@ -97,18 +97,11 @@ impl<'pass> CommandTarget<'pass> {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let depth = DepthBuffer::new(
|
|
||||||
&descriptors.device,
|
|
||||||
create_debug_label!("Depth buffer"),
|
|
||||||
sample_count,
|
|
||||||
size,
|
|
||||||
);
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
frame_buffer,
|
frame_buffer,
|
||||||
blend_buffer: OnceCell::new(),
|
blend_buffer: OnceCell::new(),
|
||||||
resolve_buffer,
|
resolve_buffer,
|
||||||
depth,
|
depth: OnceCell::new(),
|
||||||
globals,
|
globals,
|
||||||
size,
|
size,
|
||||||
format,
|
format,
|
||||||
|
@ -160,9 +153,21 @@ impl<'pass> CommandTarget<'pass> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn depth_attachment(&self, clear: bool) -> Option<wgpu::RenderPassDepthStencilAttachment> {
|
pub fn depth_attachment(
|
||||||
|
&self,
|
||||||
|
descriptors: &Descriptors,
|
||||||
|
clear: bool,
|
||||||
|
) -> Option<wgpu::RenderPassDepthStencilAttachment> {
|
||||||
|
let depth = self.depth.get_or_init(|| {
|
||||||
|
DepthBuffer::new(
|
||||||
|
&descriptors.device,
|
||||||
|
create_debug_label!("Depth buffer"),
|
||||||
|
self.sample_count,
|
||||||
|
self.size,
|
||||||
|
)
|
||||||
|
});
|
||||||
Some(wgpu::RenderPassDepthStencilAttachment {
|
Some(wgpu::RenderPassDepthStencilAttachment {
|
||||||
view: self.depth.view(),
|
view: depth.view(),
|
||||||
depth_ops: Some(wgpu::Operations {
|
depth_ops: Some(wgpu::Operations {
|
||||||
load: if clear {
|
load: if clear {
|
||||||
wgpu::LoadOp::Clear(0.0)
|
wgpu::LoadOp::Clear(0.0)
|
||||||
|
@ -231,6 +236,7 @@ pub struct CommandRenderer<'pass, 'frame: 'pass, 'global: 'frame> {
|
||||||
render_pass: wgpu::RenderPass<'pass>,
|
render_pass: wgpu::RenderPass<'pass>,
|
||||||
uniform_buffers: &'frame mut UniformBuffer<'global, Transforms>,
|
uniform_buffers: &'frame mut UniformBuffer<'global, Transforms>,
|
||||||
uniform_encoder: &'frame mut wgpu::CommandEncoder,
|
uniform_encoder: &'frame mut wgpu::CommandEncoder,
|
||||||
|
needs_depth: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'pass, 'frame: 'pass, 'global: 'frame> CommandRenderer<'pass, 'frame, 'global> {
|
impl<'pass, 'frame: 'pass, 'global: 'frame> CommandRenderer<'pass, 'frame, 'global> {
|
||||||
|
@ -244,6 +250,7 @@ impl<'pass, 'frame: 'pass, 'global: 'frame> CommandRenderer<'pass, 'frame, 'glob
|
||||||
render_pass: wgpu::RenderPass<'pass>,
|
render_pass: wgpu::RenderPass<'pass>,
|
||||||
num_masks: u32,
|
num_masks: u32,
|
||||||
mask_state: MaskState,
|
mask_state: MaskState,
|
||||||
|
needs_depth: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
pipelines,
|
pipelines,
|
||||||
|
@ -254,6 +261,7 @@ impl<'pass, 'frame: 'pass, 'global: 'frame> CommandRenderer<'pass, 'frame, 'glob
|
||||||
descriptors,
|
descriptors,
|
||||||
uniform_buffers,
|
uniform_buffers,
|
||||||
uniform_encoder,
|
uniform_encoder,
|
||||||
|
needs_depth,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,12 +292,16 @@ impl<'pass, 'frame: 'pass, 'global: 'frame> CommandRenderer<'pass, 'frame, 'glob
|
||||||
|
|
||||||
for chunk in chunk_blends(commands.0) {
|
for chunk in chunk_blends(commands.0) {
|
||||||
match chunk {
|
match chunk {
|
||||||
Chunk::Draw(chunk) => {
|
Chunk::Draw(chunk, needs_depth) => {
|
||||||
let mut render_pass =
|
let mut render_pass =
|
||||||
draw_encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
draw_encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
color_attachments: &[target.color_attachments(clear_color.take())],
|
color_attachments: &[target.color_attachments(clear_color.take())],
|
||||||
depth_stencil_attachment: target.depth_attachment(first && clear_depth),
|
depth_stencil_attachment: if needs_depth {
|
||||||
|
target.depth_attachment(&descriptors, first && clear_depth)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
});
|
});
|
||||||
render_pass.set_bind_group(0, target.globals.bind_group(), &[]);
|
render_pass.set_bind_group(0, target.globals.bind_group(), &[]);
|
||||||
let mut renderer = CommandRenderer::new(
|
let mut renderer = CommandRenderer::new(
|
||||||
|
@ -301,6 +313,7 @@ impl<'pass, 'frame: 'pass, 'global: 'frame> CommandRenderer<'pass, 'frame, 'glob
|
||||||
render_pass,
|
render_pass,
|
||||||
num_masks,
|
num_masks,
|
||||||
mask_state,
|
mask_state,
|
||||||
|
needs_depth,
|
||||||
);
|
);
|
||||||
|
|
||||||
for command in &chunk {
|
for command in &chunk {
|
||||||
|
@ -348,7 +361,7 @@ impl<'pass, 'frame: 'pass, 'global: 'frame> CommandRenderer<'pass, 'frame, 'glob
|
||||||
num_masks = renderer.num_masks;
|
num_masks = renderer.num_masks;
|
||||||
mask_state = renderer.mask_state;
|
mask_state = renderer.mask_state;
|
||||||
}
|
}
|
||||||
Chunk::Blend(commands, blend_mode) => {
|
Chunk::Blend(commands, blend_mode, needs_depth) => {
|
||||||
let parent = match blend_mode {
|
let parent = match blend_mode {
|
||||||
BlendMode::Alpha | BlendMode::Erase => nearest_layer,
|
BlendMode::Alpha | BlendMode::Erase => nearest_layer,
|
||||||
_ => target,
|
_ => target,
|
||||||
|
@ -434,7 +447,11 @@ impl<'pass, 'frame: 'pass, 'global: 'frame> CommandRenderer<'pass, 'frame, 'glob
|
||||||
color_attachments: &[
|
color_attachments: &[
|
||||||
target.color_attachments(clear_color.take())
|
target.color_attachments(clear_color.take())
|
||||||
],
|
],
|
||||||
depth_stencil_attachment: target.depth_attachment(false),
|
depth_stencil_attachment: if needs_depth {
|
||||||
|
target.depth_attachment(descriptors, false)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
});
|
});
|
||||||
render_pass.set_bind_group(0, target.globals.bind_group(), &[]);
|
render_pass.set_bind_group(0, target.globals.bind_group(), &[]);
|
||||||
|
|
||||||
|
@ -451,8 +468,13 @@ impl<'pass, 'frame: 'pass, 'global: 'frame> CommandRenderer<'pass, 'frame, 'glob
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render_pass
|
if needs_depth {
|
||||||
.set_pipeline(pipelines.bitmap[blend].pipeline_for(mask_state));
|
render_pass
|
||||||
|
.set_pipeline(pipelines.bitmap[blend].pipeline_for(mask_state));
|
||||||
|
} else {
|
||||||
|
render_pass
|
||||||
|
.set_pipeline(pipelines.bitmap[blend].depthless_pipeline());
|
||||||
|
}
|
||||||
|
|
||||||
render_pass.set_bind_group(1, target.whole_frame_bind_group(), &[0]);
|
render_pass.set_bind_group(1, target.whole_frame_bind_group(), &[0]);
|
||||||
render_pass.set_bind_group(2, &bitmap_bind_group, &[]);
|
render_pass.set_bind_group(2, &bitmap_bind_group, &[]);
|
||||||
|
@ -512,7 +534,11 @@ impl<'pass, 'frame: 'pass, 'global: 'frame> CommandRenderer<'pass, 'frame, 'glob
|
||||||
color_attachments: &[
|
color_attachments: &[
|
||||||
target.color_attachments(clear_color.take())
|
target.color_attachments(clear_color.take())
|
||||||
],
|
],
|
||||||
depth_stencil_attachment: target.depth_attachment(false),
|
depth_stencil_attachment: if needs_depth {
|
||||||
|
target.depth_attachment(descriptors, false)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
});
|
});
|
||||||
render_pass.set_bind_group(0, target.globals.bind_group(), &[]);
|
render_pass.set_bind_group(0, target.globals.bind_group(), &[]);
|
||||||
|
|
||||||
|
@ -529,8 +555,13 @@ impl<'pass, 'frame: 'pass, 'global: 'frame> CommandRenderer<'pass, 'frame, 'glob
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render_pass
|
if needs_depth {
|
||||||
.set_pipeline(pipelines.complex_blend.pipeline_for(mask_state));
|
render_pass
|
||||||
|
.set_pipeline(pipelines.complex_blend.pipeline_for(mask_state));
|
||||||
|
} else {
|
||||||
|
render_pass
|
||||||
|
.set_pipeline(pipelines.complex_blend.depthless_pipeline());
|
||||||
|
}
|
||||||
|
|
||||||
render_pass.set_bind_group(1, target.whole_frame_bind_group(), &[0]);
|
render_pass.set_bind_group(1, target.whole_frame_bind_group(), &[0]);
|
||||||
render_pass.set_bind_group(2, &blend_bind_group, &[]);
|
render_pass.set_bind_group(2, &blend_bind_group, &[]);
|
||||||
|
@ -554,21 +585,36 @@ impl<'pass, 'frame: 'pass, 'global: 'frame> CommandRenderer<'pass, 'frame, 'glob
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prep_color(&mut self) {
|
pub fn prep_color(&mut self) {
|
||||||
self.render_pass
|
if self.needs_depth {
|
||||||
.set_pipeline(self.pipelines.color.pipeline_for(self.mask_state));
|
self.render_pass
|
||||||
|
.set_pipeline(self.pipelines.color.pipeline_for(self.mask_state));
|
||||||
|
} else {
|
||||||
|
self.render_pass
|
||||||
|
.set_pipeline(self.pipelines.color.depthless_pipeline());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prep_gradient(&mut self, bind_group: &'pass wgpu::BindGroup) {
|
pub fn prep_gradient(&mut self, bind_group: &'pass wgpu::BindGroup) {
|
||||||
self.render_pass
|
if self.needs_depth {
|
||||||
.set_pipeline(self.pipelines.gradient.pipeline_for(self.mask_state));
|
self.render_pass
|
||||||
|
.set_pipeline(self.pipelines.gradient.pipeline_for(self.mask_state));
|
||||||
|
} else {
|
||||||
|
self.render_pass
|
||||||
|
.set_pipeline(self.pipelines.gradient.depthless_pipeline());
|
||||||
|
}
|
||||||
|
|
||||||
self.render_pass.set_bind_group(2, bind_group, &[]);
|
self.render_pass.set_bind_group(2, bind_group, &[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prep_bitmap(&mut self, bind_group: &'pass wgpu::BindGroup) {
|
pub fn prep_bitmap(&mut self, bind_group: &'pass wgpu::BindGroup) {
|
||||||
self.render_pass.set_pipeline(
|
if self.needs_depth {
|
||||||
self.pipelines.bitmap[TrivialBlend::Normal].pipeline_for(self.mask_state),
|
self.render_pass.set_pipeline(
|
||||||
);
|
self.pipelines.bitmap[TrivialBlend::Normal].pipeline_for(self.mask_state),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
self.render_pass
|
||||||
|
.set_pipeline(self.pipelines.bitmap[TrivialBlend::Normal].depthless_pipeline());
|
||||||
|
}
|
||||||
|
|
||||||
self.render_pass.set_bind_group(2, bind_group, &[]);
|
self.render_pass.set_bind_group(2, bind_group, &[]);
|
||||||
}
|
}
|
||||||
|
@ -749,22 +795,30 @@ impl<'pass, 'frame: 'pass, 'global: 'frame> CommandRenderer<'pass, 'frame, 'glob
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Chunk {
|
pub enum Chunk {
|
||||||
Draw(Vec<Command>),
|
Draw(Vec<Command>, bool),
|
||||||
Blend(CommandList, BlendMode),
|
Blend(CommandList, BlendMode, bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Chunk the commands such that every Blend is separated out
|
/// Chunk the commands such that every Blend is separated out
|
||||||
fn chunk_blends(commands: Vec<Command>) -> Vec<Chunk> {
|
fn chunk_blends(commands: Vec<Command>) -> Vec<Chunk> {
|
||||||
let mut result = vec![];
|
let mut result = vec![];
|
||||||
let mut current = vec![];
|
let mut current = vec![];
|
||||||
|
let mut needs_depth = false;
|
||||||
|
|
||||||
for command in commands {
|
for command in commands {
|
||||||
match command {
|
match command {
|
||||||
Command::Blend(commands, blend_mode) => {
|
Command::Blend(commands, blend_mode) => {
|
||||||
if !current.is_empty() {
|
if !current.is_empty() {
|
||||||
result.push(Chunk::Draw(std::mem::take(&mut current)));
|
result.push(Chunk::Draw(std::mem::take(&mut current), needs_depth));
|
||||||
}
|
}
|
||||||
result.push(Chunk::Blend(commands, blend_mode));
|
result.push(Chunk::Blend(commands, blend_mode, needs_depth));
|
||||||
|
}
|
||||||
|
Command::PushMask
|
||||||
|
| Command::ActivateMask
|
||||||
|
| Command::PopMask
|
||||||
|
| Command::DeactivateMask => {
|
||||||
|
needs_depth = true;
|
||||||
|
current.push(command);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
current.push(command);
|
current.push(command);
|
||||||
|
@ -773,7 +827,7 @@ fn chunk_blends(commands: Vec<Command>) -> Vec<Chunk> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !current.is_empty() {
|
if !current.is_empty() {
|
||||||
result.push(Chunk::Draw(current));
|
result.push(Chunk::Draw(current, needs_depth));
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
|
|
|
@ -17,6 +17,7 @@ pub const VERTEX_BUFFERS_DESCRIPTION: [wgpu::VertexBufferLayout; 1] = [wgpu::Ver
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ShapePipeline {
|
pub struct ShapePipeline {
|
||||||
pub pipelines: EnumMap<MaskState, wgpu::RenderPipeline>,
|
pub pipelines: EnumMap<MaskState, wgpu::RenderPipeline>,
|
||||||
|
depthless: wgpu::RenderPipeline,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Enum, Debug)]
|
#[derive(Enum, Debug)]
|
||||||
|
@ -99,10 +100,17 @@ impl ShapePipeline {
|
||||||
&self.pipelines[mask_state]
|
&self.pipelines[mask_state]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn depthless_pipeline(&self) -> &wgpu::RenderPipeline {
|
||||||
|
&self.depthless
|
||||||
|
}
|
||||||
|
|
||||||
/// Builds of a nested `EnumMap` that maps a `MaskState` to
|
/// Builds of a nested `EnumMap` that maps a `MaskState` to
|
||||||
/// a `RenderPipeline`. The provided callback is used to construct the `RenderPipeline`
|
/// a `RenderPipeline`. The provided callback is used to construct the `RenderPipeline`
|
||||||
/// for each possible `MaskState`.
|
/// for each possible `MaskState`.
|
||||||
fn build(mut f: impl FnMut(MaskState) -> wgpu::RenderPipeline) -> Self {
|
fn build(
|
||||||
|
depthless: wgpu::RenderPipeline,
|
||||||
|
mut f: impl FnMut(MaskState) -> wgpu::RenderPipeline,
|
||||||
|
) -> Self {
|
||||||
let mask_array: [wgpu::RenderPipeline; MaskState::LENGTH] = (0..MaskState::LENGTH)
|
let mask_array: [wgpu::RenderPipeline; MaskState::LENGTH] = (0..MaskState::LENGTH)
|
||||||
.map(|mask_enum| {
|
.map(|mask_enum| {
|
||||||
let mask_state = MaskState::from_usize(mask_enum);
|
let mask_state = MaskState::from_usize(mask_enum);
|
||||||
|
@ -113,6 +121,7 @@ impl ShapePipeline {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
ShapePipeline {
|
ShapePipeline {
|
||||||
pipelines: EnumMap::from_array(mask_array),
|
pipelines: EnumMap::from_array(mask_array),
|
||||||
|
depthless,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -289,46 +298,62 @@ fn create_shape_pipeline(
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
ShapePipeline::build(|mask_state| match mask_state {
|
ShapePipeline::build(
|
||||||
MaskState::NoMask => mask_render_state(
|
device.create_render_pipeline(&create_pipeline_descriptor(
|
||||||
"no mask",
|
create_debug_label!("{} depthless pipeline", name).as_deref(),
|
||||||
wgpu::StencilFaceState {
|
shader,
|
||||||
compare: wgpu::CompareFunction::Always,
|
shader,
|
||||||
fail_op: wgpu::StencilOperation::Keep,
|
&pipeline_layout,
|
||||||
depth_fail_op: wgpu::StencilOperation::Keep,
|
None,
|
||||||
pass_op: wgpu::StencilOperation::Keep,
|
&[Some(wgpu::ColorTargetState {
|
||||||
},
|
format,
|
||||||
wgpu::ColorWrites::ALL,
|
blend: Some(blend),
|
||||||
),
|
write_mask: wgpu::ColorWrites::ALL,
|
||||||
MaskState::DrawMaskStencil => mask_render_state(
|
})],
|
||||||
"draw mask stencil",
|
vertex_buffers_layout,
|
||||||
wgpu::StencilFaceState {
|
msaa_sample_count,
|
||||||
compare: wgpu::CompareFunction::Equal,
|
)),
|
||||||
fail_op: wgpu::StencilOperation::Keep,
|
|mask_state| match mask_state {
|
||||||
depth_fail_op: wgpu::StencilOperation::Keep,
|
MaskState::NoMask => mask_render_state(
|
||||||
pass_op: wgpu::StencilOperation::IncrementClamp,
|
"no mask",
|
||||||
},
|
wgpu::StencilFaceState {
|
||||||
wgpu::ColorWrites::empty(),
|
compare: wgpu::CompareFunction::Always,
|
||||||
),
|
fail_op: wgpu::StencilOperation::Keep,
|
||||||
MaskState::DrawMaskedContent => mask_render_state(
|
depth_fail_op: wgpu::StencilOperation::Keep,
|
||||||
"draw masked content",
|
pass_op: wgpu::StencilOperation::Keep,
|
||||||
wgpu::StencilFaceState {
|
},
|
||||||
compare: wgpu::CompareFunction::Equal,
|
wgpu::ColorWrites::ALL,
|
||||||
fail_op: wgpu::StencilOperation::Keep,
|
),
|
||||||
depth_fail_op: wgpu::StencilOperation::Keep,
|
MaskState::DrawMaskStencil => mask_render_state(
|
||||||
pass_op: wgpu::StencilOperation::Keep,
|
"draw mask stencil",
|
||||||
},
|
wgpu::StencilFaceState {
|
||||||
wgpu::ColorWrites::ALL,
|
compare: wgpu::CompareFunction::Equal,
|
||||||
),
|
fail_op: wgpu::StencilOperation::Keep,
|
||||||
MaskState::ClearMaskStencil => mask_render_state(
|
depth_fail_op: wgpu::StencilOperation::Keep,
|
||||||
"clear mask stencil",
|
pass_op: wgpu::StencilOperation::IncrementClamp,
|
||||||
wgpu::StencilFaceState {
|
},
|
||||||
compare: wgpu::CompareFunction::Equal,
|
wgpu::ColorWrites::empty(),
|
||||||
fail_op: wgpu::StencilOperation::Keep,
|
),
|
||||||
depth_fail_op: wgpu::StencilOperation::Keep,
|
MaskState::DrawMaskedContent => mask_render_state(
|
||||||
pass_op: wgpu::StencilOperation::DecrementClamp,
|
"draw masked content",
|
||||||
},
|
wgpu::StencilFaceState {
|
||||||
wgpu::ColorWrites::empty(),
|
compare: wgpu::CompareFunction::Equal,
|
||||||
),
|
fail_op: wgpu::StencilOperation::Keep,
|
||||||
})
|
depth_fail_op: wgpu::StencilOperation::Keep,
|
||||||
|
pass_op: wgpu::StencilOperation::Keep,
|
||||||
|
},
|
||||||
|
wgpu::ColorWrites::ALL,
|
||||||
|
),
|
||||||
|
MaskState::ClearMaskStencil => mask_render_state(
|
||||||
|
"clear mask stencil",
|
||||||
|
wgpu::StencilFaceState {
|
||||||
|
compare: wgpu::CompareFunction::Equal,
|
||||||
|
fail_op: wgpu::StencilOperation::Keep,
|
||||||
|
depth_fail_op: wgpu::StencilOperation::Keep,
|
||||||
|
pass_op: wgpu::StencilOperation::DecrementClamp,
|
||||||
|
},
|
||||||
|
wgpu::ColorWrites::empty(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue