Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions wgpu-core/src/command/clear.rs
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ fn clear_texture_via_render_passes(
},
depth_slice: None,
resolve_target: None,
ops: hal::AttachmentOps::STORE,
ops: hal::AttachmentOps::STORE | hal::AttachmentOps::LOAD_CLEAR,
clear_value: wgt::Color::TRANSPARENT,
})];
(&color_attachments_tmp[..], None)
Expand All @@ -515,8 +515,8 @@ fn clear_texture_via_render_passes(
),
usage: wgt::TextureUses::DEPTH_STENCIL_WRITE,
},
depth_ops: hal::AttachmentOps::STORE,
stencil_ops: hal::AttachmentOps::STORE,
depth_ops: hal::AttachmentOps::STORE | hal::AttachmentOps::LOAD_CLEAR,
stencil_ops: hal::AttachmentOps::STORE | hal::AttachmentOps::LOAD_CLEAR,
clear_value: (0.0, 0),
}),
)
Expand Down
14 changes: 8 additions & 6 deletions wgpu-core/src/command/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,15 @@ pub use wgt::{LoadOp, StoreOp};
fn load_hal_ops<V>(load: LoadOp<V>) -> hal::AttachmentOps {
match load {
LoadOp::Load => hal::AttachmentOps::LOAD,
LoadOp::Clear(_) => hal::AttachmentOps::empty(),
LoadOp::Clear(_) => hal::AttachmentOps::LOAD_CLEAR,
LoadOp::DontCare(_) => hal::AttachmentOps::LOAD_DONT_CARE,
}
}

fn store_hal_ops(store: StoreOp) -> hal::AttachmentOps {
match store {
StoreOp::Store => hal::AttachmentOps::STORE,
StoreOp::Discard => hal::AttachmentOps::empty(),
StoreOp::Discard => hal::AttachmentOps::STORE_DISCARD,
}
}

Expand Down Expand Up @@ -115,6 +116,7 @@ impl<V: Copy + Default> PassChannel<Option<V>> {
Ok(ResolvedPassChannel::Operational(wgt::Operations {
load: match self.load_op.ok_or(AttachmentError::NoLoad)? {
LoadOp::Clear(clear_value) => LoadOp::Clear(handle_clear(clear_value)?),
LoadOp::DontCare(token) => LoadOp::DontCare(token),
LoadOp::Load => LoadOp::Load,
},
store: self.store_op.ok_or(AttachmentError::NoStore)?,
Expand Down Expand Up @@ -204,7 +206,7 @@ impl ArcRenderPassColorAttachment {
fn clear_value(&self) -> Color {
match self.load_op {
LoadOp::Clear(clear_value) => clear_value,
LoadOp::Load => Color::default(),
LoadOp::DontCare(_) | LoadOp::Load => Color::default(),
}
}
}
Expand Down Expand Up @@ -1555,13 +1557,13 @@ impl RenderPassInfo {
if let Some((aspect, view)) = self.divergent_discarded_depth_stencil_aspect {
let (depth_ops, stencil_ops) = if aspect == wgt::TextureAspect::DepthOnly {
(
hal::AttachmentOps::STORE, // clear depth
hal::AttachmentOps::LOAD | hal::AttachmentOps::STORE, // unchanged stencil
hal::AttachmentOps::LOAD_CLEAR | hal::AttachmentOps::STORE, // clear depth
hal::AttachmentOps::LOAD | hal::AttachmentOps::STORE, // unchanged stencil
)
} else {
(
hal::AttachmentOps::LOAD | hal::AttachmentOps::STORE, // unchanged stencil
hal::AttachmentOps::STORE, // clear depth
hal::AttachmentOps::LOAD_CLEAR | hal::AttachmentOps::STORE, // clear depth
)
};
let desc = hal::RenderPassDescriptor::<'_, _, dyn hal::DynTextureView> {
Expand Down
2 changes: 1 addition & 1 deletion wgpu-hal/examples/halmark/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,7 @@ impl<A: hal::Api> Example<A> {
},
depth_slice: None,
resolve_target: None,
ops: hal::AttachmentOps::STORE,
ops: hal::AttachmentOps::STORE | hal::AttachmentOps::LOAD_CLEAR,
clear_value: wgpu_types::Color {
r: 0.1,
g: 0.2,
Expand Down
2 changes: 1 addition & 1 deletion wgpu-hal/examples/raw-gles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ fn fill_screen(exposed: &hal::ExposedAdapter<hal::api::Gles>, width: u32, height
},
depth_slice: None,
resolve_target: None,
ops: hal::AttachmentOps::STORE,
ops: hal::AttachmentOps::STORE | hal::AttachmentOps::LOAD_CLEAR,
clear_value: wgpu_types::Color::BLUE,
})],
depth_stencil_attachment: None,
Expand Down
6 changes: 3 additions & 3 deletions wgpu-hal/src/dx12/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -964,7 +964,7 @@ impl crate::CommandEncoder for super::CommandEncoder {
self.pass.resolves.clear();
for (rtv, cat) in color_views.iter().zip(desc.color_attachments.iter()) {
if let Some(cat) = cat.as_ref() {
if !cat.ops.contains(crate::AttachmentOps::LOAD) {
if cat.ops.contains(crate::AttachmentOps::LOAD_CLEAR) {
let value = [
cat.clear_value.r as f32,
cat.clear_value.g as f32,
Expand All @@ -989,12 +989,12 @@ impl crate::CommandEncoder for super::CommandEncoder {
if let Some(ref ds) = desc.depth_stencil_attachment {
let mut flags = Direct3D12::D3D12_CLEAR_FLAGS::default();
let aspects = ds.target.view.aspects;
if !ds.depth_ops.contains(crate::AttachmentOps::LOAD)
if ds.depth_ops.contains(crate::AttachmentOps::LOAD_CLEAR)
&& aspects.contains(crate::FormatAspects::DEPTH)
{
flags |= Direct3D12::D3D12_CLEAR_FLAG_DEPTH;
}
if !ds.stencil_ops.contains(crate::AttachmentOps::LOAD)
if ds.stencil_ops.contains(crate::AttachmentOps::LOAD_CLEAR)
&& aspects.contains(crate::FormatAspects::STENCIL)
{
flags |= Direct3D12::D3D12_CLEAR_FLAG_STENCIL;
Expand Down
14 changes: 8 additions & 6 deletions wgpu-hal/src/gles/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ impl crate::CommandEncoder for super::CommandEncoder {
.resolve_attachments
.push((attachment, rat.view.clone()));
}
if !cat.ops.contains(crate::AttachmentOps::STORE) {
if cat.ops.contains(crate::AttachmentOps::STORE_DISCARD) {
self.state.invalidate_attachments.push(attachment);
}
}
Expand All @@ -585,14 +585,16 @@ impl crate::CommandEncoder for super::CommandEncoder {
depth_slice: None,
});
if aspects.contains(crate::FormatAspects::DEPTH)
&& !dsat.depth_ops.contains(crate::AttachmentOps::STORE)
&& dsat.depth_ops.contains(crate::AttachmentOps::STORE_DISCARD)
{
self.state
.invalidate_attachments
.push(glow::DEPTH_ATTACHMENT);
}
if aspects.contains(crate::FormatAspects::STENCIL)
&& !dsat.stencil_ops.contains(crate::AttachmentOps::STORE)
&& dsat
.stencil_ops
.contains(crate::AttachmentOps::STORE_DISCARD)
{
self.state
.invalidate_attachments
Expand Down Expand Up @@ -628,7 +630,7 @@ impl crate::CommandEncoder for super::CommandEncoder {
.filter_map(|at| at.as_ref())
.enumerate()
{
if !cat.ops.contains(crate::AttachmentOps::LOAD) {
if cat.ops.contains(crate::AttachmentOps::LOAD_CLEAR) {
let c = &cat.clear_value;
self.cmd_buffer.commands.push(
match cat.target.view.format.sample_type(None, None).unwrap() {
Expand All @@ -652,8 +654,8 @@ impl crate::CommandEncoder for super::CommandEncoder {
}

if let Some(ref dsat) = desc.depth_stencil_attachment {
let clear_depth = !dsat.depth_ops.contains(crate::AttachmentOps::LOAD);
let clear_stencil = !dsat.stencil_ops.contains(crate::AttachmentOps::LOAD);
let clear_depth = dsat.depth_ops.contains(crate::AttachmentOps::LOAD_CLEAR);
let clear_stencil = dsat.stencil_ops.contains(crate::AttachmentOps::LOAD_CLEAR);

if clear_depth && clear_stencil {
self.cmd_buffer.commands.push(C::ClearDepthAndStencil(
Expand Down
5 changes: 4 additions & 1 deletion wgpu-hal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1757,7 +1757,10 @@ bitflags!(
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct AttachmentOps: u8 {
const LOAD = 1 << 0;
const STORE = 1 << 1;
const LOAD_CLEAR = 1 << 1;
const LOAD_DONT_CARE = 1 << 2;
const STORE = 1 << 3;
const STORE_DISCARD = 1 << 4;
}
);

Expand Down
21 changes: 18 additions & 3 deletions wgpu-hal/src/metal/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -670,9 +670,13 @@ impl crate::CommandEncoder for super::CommandEncoder {
}
let load_action = if at.ops.contains(crate::AttachmentOps::LOAD) {
MTLLoadAction::Load
} else {
} else if at.ops.contains(crate::AttachmentOps::LOAD_DONT_CARE) {
MTLLoadAction::DontCare
} else if at.ops.contains(crate::AttachmentOps::LOAD_CLEAR) {
at_descriptor.set_clear_color(conv::map_clear_color(&at.clear_value));
MTLLoadAction::Clear
} else {
unreachable!()
};
let store_action = conv::map_store_action(
at.ops.contains(crate::AttachmentOps::STORE),
Expand All @@ -690,9 +694,13 @@ impl crate::CommandEncoder for super::CommandEncoder {

let load_action = if at.depth_ops.contains(crate::AttachmentOps::LOAD) {
MTLLoadAction::Load
} else {
} else if at.depth_ops.contains(crate::AttachmentOps::LOAD_DONT_CARE) {
MTLLoadAction::DontCare
} else if at.depth_ops.contains(crate::AttachmentOps::LOAD_CLEAR) {
at_descriptor.set_clear_depth(at.clear_value.0 as f64);
MTLLoadAction::Clear
} else {
unreachable!();
};
let store_action = if at.depth_ops.contains(crate::AttachmentOps::STORE) {
MTLStoreAction::Store
Expand All @@ -713,9 +721,16 @@ impl crate::CommandEncoder for super::CommandEncoder {

let load_action = if at.stencil_ops.contains(crate::AttachmentOps::LOAD) {
MTLLoadAction::Load
} else {
} else if at
.stencil_ops
.contains(crate::AttachmentOps::LOAD_DONT_CARE)
{
MTLLoadAction::DontCare
} else if at.stencil_ops.contains(crate::AttachmentOps::LOAD_CLEAR) {
at_descriptor.set_clear_stencil(at.clear_value.1);
MTLLoadAction::Clear
} else {
unreachable!()
};
let store_action = if at.stencil_ops.contains(crate::AttachmentOps::STORE) {
MTLStoreAction::Store
Expand Down
9 changes: 5 additions & 4 deletions wgpu-hal/src/vulkan/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -813,10 +813,11 @@ impl crate::CommandEncoder for super::CommandEncoder {
});
let color = super::ColorAttachmentKey {
base: cat.target.make_attachment_key(cat.ops),
resolve: cat
.resolve_target
.as_ref()
.map(|target| target.make_attachment_key(crate::AttachmentOps::STORE)),
resolve: cat.resolve_target.as_ref().map(|target| {
target.make_attachment_key(
crate::AttachmentOps::LOAD_CLEAR | crate::AttachmentOps::STORE,
)
}),
};

rp_key.colors.push(Some(color));
Expand Down
10 changes: 8 additions & 2 deletions wgpu-hal/src/vulkan/conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,13 +452,19 @@ pub fn map_attachment_ops(
) -> (vk::AttachmentLoadOp, vk::AttachmentStoreOp) {
let load_op = if op.contains(crate::AttachmentOps::LOAD) {
vk::AttachmentLoadOp::LOAD
} else {
} else if op.contains(crate::AttachmentOps::LOAD_DONT_CARE) {
vk::AttachmentLoadOp::DONT_CARE
} else if op.contains(crate::AttachmentOps::LOAD_CLEAR) {
vk::AttachmentLoadOp::CLEAR
} else {
unreachable!()
};
let store_op = if op.contains(crate::AttachmentOps::STORE) {
vk::AttachmentStoreOp::STORE
} else {
} else if op.contains(crate::AttachmentOps::STORE_DISCARD) {
vk::AttachmentStoreOp::DONT_CARE
} else {
unreachable!()
};
(load_op, store_op)
}
Expand Down
19 changes: 18 additions & 1 deletion wgpu-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4790,14 +4790,31 @@ pub enum LoadOp<V> {
Clear(V) = 0,
/// Loads the existing value for this attachment into the render pass.
Load = 1,
/// The render target has undefined contents at the start of the render pass.
/// This may lead to undefined behavior if you read from the any of the
/// render target pixels without first writing to them.
///
/// Blending also becomes undefined behavior if the source
/// pixels are undefined.
///
/// This is the fastest option of all gpus if you will always overwrite all pixels
/// in the render target.
///
/// # Safety
///
/// - All pixels in the render target must be written to before
/// any read or a [`StoreOp::Store`] occurs.
DontCare(#[cfg_attr(feature = "serde", serde(skip))] LoadOpDontCare) = 2,
}

impl<V> LoadOp<V> {
/// Returns true if variants are same (ignoring clear value)
pub fn eq_variant<T>(&self, other: LoadOp<T>) -> bool {
matches!(
(self, other),
(LoadOp::Clear(_), LoadOp::Clear(_)) | (LoadOp::Load, LoadOp::Load)
(LoadOp::Clear(_), LoadOp::Clear(_))
| (LoadOp::Load, LoadOp::Load)
| (LoadOp::DontCare(_), LoadOp::DontCare(_))
)
}
}
Expand Down
29 changes: 29 additions & 0 deletions wgpu-types/src/tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,32 @@ impl ExperimentalFeatures {
self.enabled
}
}

/// Token of the user agreeing to use [`LoadOp::DontCare`](crate::LoadOp::DontCare).
#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)]
pub struct LoadOpDontCare {
// Private to prevent construction outside of the unsafe
// enabled() function.
_private: (),
}

impl LoadOpDontCare {
/// Using [`LoadOp::DontCare`](crate::LoadOp::DontCare) will result
/// in the render target having undefined contents at the start of the render pass.
/// This may lead to undefined behavior if you read from the any of the
/// render target pixels without first writing to them.
///
/// Blending also becomes undefined behavior if the source
/// pixels are undefined.
///
/// All pixels in the render target must be written to before
/// any read or a [`StoreOp::Store`](crate::StoreOp::Store) occurs.
///
/// # Safety
///
/// - You acknowledge that using `LoadOp::DontCare` may lead to undefined behavior
/// if the above conditions are not met.
pub const unsafe fn enabled() -> Self {
Self { _private: () }
}
}
17 changes: 17 additions & 0 deletions wgpu/src/backend/webgpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3050,6 +3050,13 @@ impl dispatch::CommandEncoderInterface for WebCommandEncoder {
clear_value = Some(wasm_bindgen::JsValue::from(map_color(color)));
webgpu_sys::GpuLoadOp::Clear
}
crate::LoadOp::DontCare(_token) => {
// WebGPU can't safely have a ClearOp::DontCare, so we clear to black
// which is ideal for most GPUs.
clear_value =
Some(wasm_bindgen::JsValue::from(map_color(crate::Color::BLACK)));
webgpu_sys::GpuLoadOp::Clear
}
crate::LoadOp::Load => webgpu_sys::GpuLoadOp::Load,
};

Expand Down Expand Up @@ -3091,6 +3098,11 @@ impl dispatch::CommandEncoderInterface for WebCommandEncoder {
mapped_depth_stencil_attachment.set_depth_clear_value(v);
webgpu_sys::GpuLoadOp::Clear
}
crate::LoadOp::DontCare(_token) => {
// WebGPU can't safely have a ClearOp::DontCare, so we clear to 1.0
mapped_depth_stencil_attachment.set_depth_clear_value(1.0);
webgpu_sys::GpuLoadOp::Clear
}
crate::LoadOp::Load => webgpu_sys::GpuLoadOp::Load,
};
mapped_depth_stencil_attachment.set_depth_load_op(load_op);
Expand All @@ -3103,6 +3115,11 @@ impl dispatch::CommandEncoderInterface for WebCommandEncoder {
mapped_depth_stencil_attachment.set_stencil_clear_value(v);
webgpu_sys::GpuLoadOp::Clear
}
crate::LoadOp::DontCare(_token) => {
// WebGPU can't safely have a ClearOp::DontCare, so we clear to 0
mapped_depth_stencil_attachment.set_stencil_clear_value(0);
webgpu_sys::GpuLoadOp::Clear
}
crate::LoadOp::Load => webgpu_sys::GpuLoadOp::Load,
};
mapped_depth_stencil_attachment.set_stencil_load_op(load_op);
Expand Down
5 changes: 3 additions & 2 deletions wgpu/src/backend/wgpu_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,8 +421,9 @@ fn map_texture_tagged_copy_view(
}

fn map_load_op<V: Copy>(load: &LoadOp<V>) -> LoadOp<Option<V>> {
match load {
LoadOp::Clear(clear_value) => LoadOp::Clear(Some(*clear_value)),
match *load {
LoadOp::Clear(clear_value) => LoadOp::Clear(Some(clear_value)),
LoadOp::DontCare(token) => LoadOp::DontCare(token),
LoadOp::Load => LoadOp::Load,
}
}
Expand Down
Loading