Relax render pass color_attachments validation (#2778)

* Make the color attachments `Option`-al in render pipelines, render passes, and render bundles

* vk:  `Option`-al color attachments support

* dx12: sparse color_attachments support

* Only non-hole attachments is supported on wasm target and gl backend

* deno_webgpu: `Option`-al color attachments support

* Follow all suggestions
This commit is contained in:
Jinlei Li 2022-06-28 07:10:18 +08:00 committed by GitHub
parent 892c272d18
commit 61796b1d59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 483 additions and 373 deletions

View File

@ -32,7 +32,7 @@ impl Resource for WebGpuRenderBundle {
pub struct CreateRenderBundleEncoderArgs {
device_rid: ResourceId,
label: Option<String>,
color_formats: Vec<wgpu_types::TextureFormat>,
color_formats: Vec<Option<wgpu_types::TextureFormat>>,
depth_stencil_format: Option<wgpu_types::TextureFormat>,
sample_count: u32,
depth_read_only: bool,

View File

@ -78,7 +78,7 @@ pub fn op_webgpu_command_encoder_begin_render_pass(
state: &mut OpState,
command_encoder_rid: ResourceId,
label: Option<String>,
color_attachments: Vec<GpuRenderPassColorAttachment>,
color_attachments: Vec<Option<GpuRenderPassColorAttachment>>,
depth_stencil_attachment: Option<GpuRenderPassDepthStencilAttachment>,
_occlusion_query_set: Option<u32>, // not yet implemented
) -> Result<WebGpuResult, AnyError> {
@ -89,30 +89,35 @@ pub fn op_webgpu_command_encoder_begin_render_pass(
let color_attachments = color_attachments
.into_iter()
.map(|color_attachment| {
let texture_view_resource = state
.resource_table
.get::<super::texture::WebGpuTextureView>(color_attachment.view)?;
let rp_at = if let Some(at) = color_attachment.as_ref() {
let texture_view_resource = state
.resource_table
.get::<super::texture::WebGpuTextureView>(at.view)?;
let resolve_target = color_attachment
.resolve_target
.map(|rid| {
state
.resource_table
.get::<super::texture::WebGpuTextureView>(rid)
let resolve_target = at
.resolve_target
.map(|rid| {
state
.resource_table
.get::<super::texture::WebGpuTextureView>(rid)
})
.transpose()?
.map(|texture| texture.0);
Some(wgpu_core::command::RenderPassColorAttachment {
view: texture_view_resource.0,
resolve_target,
channel: wgpu_core::command::PassChannel {
load_op: at.load_op,
store_op: at.store_op,
clear_value: at.clear_value.unwrap_or_default(),
read_only: false,
},
})
.transpose()?
.map(|texture| texture.0);
Ok(wgpu_core::command::RenderPassColorAttachment {
view: texture_view_resource.0,
resolve_target,
channel: wgpu_core::command::PassChannel {
load_op: color_attachment.load_op,
store_op: color_attachment.store_op,
clear_value: color_attachment.clear_value.unwrap_or_default(),
read_only: false,
},
})
} else {
None
};
Ok(rp_at)
})
.collect::<Result<Vec<_>, AnyError>>()?;

View File

@ -260,7 +260,7 @@ impl From<GpuMultisampleState> for wgpu_types::MultisampleState {
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct GpuFragmentState {
targets: Vec<wgpu_types::ColorTargetState>,
targets: Vec<Option<wgpu_types::ColorTargetState>>,
module: u32,
entry_point: String,
// TODO(lucacasonato): constants

View File

@ -613,7 +613,7 @@ dictionary GPUMultisampleState {
};
dictionary GPUFragmentState : GPUProgrammableStage {
required sequence<GPUColorTargetState> targets;
required sequence<GPUColorTargetState?> targets;
};
dictionary GPUColorTargetState {
@ -908,7 +908,7 @@ GPURenderPassEncoder includes GPUBindingCommandsMixin;
GPURenderPassEncoder includes GPURenderCommandsMixin;
dictionary GPURenderPassDescriptor : GPUObjectDescriptorBase {
required sequence<GPURenderPassColorAttachment> colorAttachments;
required sequence<GPURenderPassColorAttachment?> colorAttachments;
GPURenderPassDepthStencilAttachment depthStencilAttachment;
GPUQuerySet occlusionQuerySet;
};
@ -947,7 +947,7 @@ enum GPUStoreOp {
};
dictionary GPURenderPassLayout: GPUObjectDescriptorBase {
required sequence<GPUTextureFormat> colorFormats;
required sequence<GPUTextureFormat?> colorFormats;
GPUTextureFormat depthStencilFormat;
GPUSize32 sampleCount = 1;
};

View File

@ -66,9 +66,9 @@
entry_point: "fs_main",
),
targets: [
(
Some((
format: rgba8unorm,
),
)),
],
)),
),
@ -90,7 +90,7 @@
push_constant_data: [],
),
target_colors: [
(
Some((
view: Id(0, 1, Empty),
resolve_target: None,
channel: (
@ -104,7 +104,7 @@
),
read_only: false,
),
),
)),
],
target_depth_stencil: None,
),

View File

@ -46,7 +46,7 @@
push_constant_data: [],
),
target_colors: [
(
Some((
view: Id(0, 1, Empty),
resolve_target: None,
channel: (
@ -57,7 +57,7 @@
),
read_only: false,
),
),
)),
],
target_depth_stencil: None,
),

View File

@ -114,7 +114,7 @@ pub struct RenderBundleEncoderDescriptor<'a> {
pub label: Label<'a>,
/// The formats of the color attachments that this render bundle is capable to rendering to. This
/// must match the formats of the color attachments in the renderpass this render bundle is executed in.
pub color_formats: Cow<'a, [wgt::TextureFormat]>,
pub color_formats: Cow<'a, [Option<wgt::TextureFormat>]>,
/// Information about the depth attachment that this render bundle is capable to rendering to. The format
/// must match the format of the depth attachments in the renderpass this render bundle is executed in.
pub depth_stencil: Option<wgt::RenderBundleDepthStencil>,

View File

@ -408,7 +408,7 @@ fn clear_texture_via_render_passes<A: hal::Api>(
for depth_or_layer in layer_or_depth_range {
let color_attachments_tmp;
let (color_attachments, depth_stencil_attachment) = if is_color {
color_attachments_tmp = [hal::ColorAttachment {
color_attachments_tmp = [Some(hal::ColorAttachment {
target: hal::Attachment {
view: dst_texture.get_clear_view(mip_level, depth_or_layer),
usage: hal::TextureUses::COLOR_TARGET,
@ -416,7 +416,7 @@ fn clear_texture_via_render_passes<A: hal::Api>(
resolve_target: None,
ops: hal::AttachmentOps::STORE,
clear_value: wgt::Color::TRANSPARENT,
}];
})];
(&color_attachments_tmp[..], None)
} else {
(

View File

@ -173,7 +173,7 @@ impl RenderPassDepthStencilAttachment {
pub struct RenderPassDescriptor<'a> {
pub label: Label<'a>,
/// The color attachments of the render pass.
pub color_attachments: Cow<'a, [RenderPassColorAttachment]>,
pub color_attachments: Cow<'a, [Option<RenderPassColorAttachment>]>,
/// The depth and stencil attachment of the render pass, if any.
pub depth_stencil_attachment: Option<&'a RenderPassDepthStencilAttachment>,
}
@ -182,7 +182,7 @@ pub struct RenderPassDescriptor<'a> {
pub struct RenderPass {
base: BasePass<RenderCommand>,
parent_id: id::CommandEncoderId,
color_targets: ArrayVec<RenderPassColorAttachment, { hal::MAX_COLOR_ATTACHMENTS }>,
color_targets: ArrayVec<Option<RenderPassColorAttachment>, { hal::MAX_COLOR_ATTACHMENTS }>,
depth_stencil_target: Option<RenderPassDepthStencilAttachment>,
// Resource binding dedupe state.
@ -441,7 +441,7 @@ pub enum RenderPassErrorInner {
InvalidDepthStencilAttachmentFormat(wgt::TextureFormat),
#[error("attachment format {0:?} can not be resolved")]
UnsupportedResolveTargetFormat(wgt::TextureFormat),
#[error("necessary attachments are missing")]
#[error("missing color or depth_stencil attachments, at least one is required.")]
MissingAttachments,
#[error("attachments have differing sizes: {previous:?} is followed by {mismatch:?}")]
AttachmentsDimensionMismatch {
@ -646,7 +646,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
fn start(
device: &Device<A>,
label: Option<&str>,
color_attachments: &[RenderPassColorAttachment],
color_attachments: &[Option<RenderPassColorAttachment>],
depth_stencil_attachment: Option<&RenderPassDepthStencilAttachment>,
cmd_buf: &mut CommandBuffer<A>,
view_guard: &'a Storage<TextureView<A>, id::TextureViewId>,
@ -722,11 +722,15 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
expected: sample_count,
});
}
if sample_count != 1 && sample_count != 4 {
return Err(RenderPassErrorInner::InvalidSampleCount(sample_count));
}
attachment_type_name = type_name;
Ok(())
};
let mut colors = ArrayVec::<hal::ColorAttachment<A>, { hal::MAX_COLOR_ATTACHMENTS }>::new();
let mut colors =
ArrayVec::<Option<hal::ColorAttachment<A>>, { hal::MAX_COLOR_ATTACHMENTS }>::new();
let mut depth_stencil = None;
if let Some(at) = depth_stencil_attachment {
@ -840,6 +844,12 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
}
for at in color_attachments {
let at = if let Some(attachment) = at.as_ref() {
attachment
} else {
colors.push(None);
continue;
};
let color_view: &TextureView<A> = cmd_buf
.trackers
.views
@ -919,7 +929,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
});
}
colors.push(hal::ColorAttachment {
colors.push(Some(hal::ColorAttachment {
target: hal::Attachment {
view: &color_view.raw,
usage: hal::TextureUses::COLOR_TARGET,
@ -927,28 +937,30 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
resolve_target: hal_resolve_target,
ops: at.channel.hal_ops(),
clear_value: at.channel.clear_value,
});
}));
}
if sample_count != 1 && sample_count != 4 {
return Err(RenderPassErrorInner::InvalidSampleCount(sample_count));
}
let extent = extent.ok_or(RenderPassErrorInner::MissingAttachments)?;
let multiview = detected_multiview.expect("Multiview was not detected, no attachments");
let view_data = AttachmentData {
colors: color_attachments
.iter()
.map(|at| view_guard.get(at.view).unwrap())
.map(|at| at.as_ref().map(|at| view_guard.get(at.view).unwrap()))
.collect(),
resolves: color_attachments
.iter()
.filter_map(|at| at.resolve_target)
.map(|attachment| view_guard.get(attachment).unwrap())
.filter_map(|at| match *at {
Some(RenderPassColorAttachment {
resolve_target: Some(resolve),
..
}) => Some(view_guard.get(resolve).unwrap()),
_ => None,
})
.collect(),
depth_stencil: depth_stencil_attachment.map(|at| view_guard.get(at.view).unwrap()),
};
let extent = extent.ok_or(RenderPassErrorInner::MissingAttachments)?;
let multiview = detected_multiview.expect("Multiview was not detected, no attachments");
let context = RenderPassContext {
attachments: view_data.map(|view| view.desc.format),
sample_count,
@ -1076,7 +1088,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
&self,
encoder_id: id::CommandEncoderId,
base: BasePassRef<RenderCommand>,
color_attachments: &[RenderPassColorAttachment],
color_attachments: &[Option<RenderPassColorAttachment>],
depth_stencil_attachment: Option<&RenderPassDepthStencilAttachment>,
) -> Result<(), RenderPassError> {
profiling::scope!("run_render_pass", "CommandEncoder");

View File

@ -52,7 +52,7 @@ pub enum HostMap {
#[derive(Clone, Debug, Hash, PartialEq)]
#[cfg_attr(feature = "serial-pass", derive(serde::Deserialize, serde::Serialize))]
pub(crate) struct AttachmentData<T> {
pub colors: ArrayVec<T, { hal::MAX_COLOR_ATTACHMENTS }>,
pub colors: ArrayVec<Option<T>, { hal::MAX_COLOR_ATTACHMENTS }>,
pub resolves: ArrayVec<T, { hal::MAX_COLOR_ATTACHMENTS }>,
pub depth_stencil: Option<T>,
}
@ -60,7 +60,7 @@ impl<T: PartialEq> Eq for AttachmentData<T> {}
impl<T> AttachmentData<T> {
pub(crate) fn map<U, F: Fn(&T) -> U>(&self, fun: F) -> AttachmentData<U> {
AttachmentData {
colors: self.colors.iter().map(&fun).collect(),
colors: self.colors.iter().map(|c| c.as_ref().map(&fun)).collect(),
resolves: self.resolves.iter().map(&fun).collect(),
depth_stencil: self.depth_stencil.as_ref().map(&fun),
}
@ -78,8 +78,8 @@ pub(crate) struct RenderPassContext {
pub enum RenderPassCompatibilityError {
#[error("Incompatible color attachment: the renderpass expected {0:?} but was given {1:?}")]
IncompatibleColorAttachment(
ArrayVec<TextureFormat, { hal::MAX_COLOR_ATTACHMENTS }>,
ArrayVec<TextureFormat, { hal::MAX_COLOR_ATTACHMENTS }>,
ArrayVec<Option<TextureFormat>, { hal::MAX_COLOR_ATTACHMENTS }>,
ArrayVec<Option<TextureFormat>, { hal::MAX_COLOR_ATTACHMENTS }>,
),
#[error(
"Incompatible depth-stencil attachment: the renderpass expected {0:?} but was given {1:?}"
@ -2465,9 +2465,11 @@ impl<A: HalApi> Device<A> {
.map_or(&[][..], |fragment| &fragment.targets);
let depth_stencil_state = desc.depth_stencil.as_ref();
if !color_targets.is_empty() && {
let first = &color_targets[0];
color_targets[1..]
let cts: ArrayVec<_, { hal::MAX_COLOR_ATTACHMENTS }> =
color_targets.iter().filter_map(|x| x.as_ref()).collect();
if !cts.is_empty() && {
let first = &cts[0];
cts[1..]
.iter()
.any(|ct| ct.write_mask != first.write_mask || ct.blend != first.blend)
} {
@ -2580,29 +2582,32 @@ impl<A: HalApi> Device<A> {
}
for (i, cs) in color_targets.iter().enumerate() {
let error = loop {
let format_features = self.describe_format_features(adapter, cs.format)?;
if !format_features
.allowed_usages
.contains(wgt::TextureUsages::RENDER_ATTACHMENT)
{
break Some(pipeline::ColorStateError::FormatNotRenderable(cs.format));
}
if cs.blend.is_some() && !format_features.flags.contains(Tfff::FILTERABLE) {
break Some(pipeline::ColorStateError::FormatNotBlendable(cs.format));
}
if !hal::FormatAspects::from(cs.format).contains(hal::FormatAspects::COLOR) {
break Some(pipeline::ColorStateError::FormatNotColor(cs.format));
}
if desc.multisample.count > 1 && !format_features.flags.contains(Tfff::MULTISAMPLE)
{
break Some(pipeline::ColorStateError::FormatNotMultisampled(cs.format));
}
if let Some(cs) = cs.as_ref() {
let error = loop {
let format_features = self.describe_format_features(adapter, cs.format)?;
if !format_features
.allowed_usages
.contains(wgt::TextureUsages::RENDER_ATTACHMENT)
{
break Some(pipeline::ColorStateError::FormatNotRenderable(cs.format));
}
if cs.blend.is_some() && !format_features.flags.contains(Tfff::FILTERABLE) {
break Some(pipeline::ColorStateError::FormatNotBlendable(cs.format));
}
if !hal::FormatAspects::from(cs.format).contains(hal::FormatAspects::COLOR) {
break Some(pipeline::ColorStateError::FormatNotColor(cs.format));
}
if desc.multisample.count > 1
&& !format_features.flags.contains(Tfff::MULTISAMPLE)
{
break Some(pipeline::ColorStateError::FormatNotMultisampled(cs.format));
}
break None;
};
if let Some(e) = error {
return Err(pipeline::CreateRenderPipelineError::ColorState(i as u8, e));
break None;
};
if let Some(e) = error {
return Err(pipeline::CreateRenderPipelineError::ColorState(i as u8, e));
}
}
}
@ -2754,13 +2759,13 @@ impl<A: HalApi> Device<A> {
};
if validated_stages.contains(wgt::ShaderStages::FRAGMENT) {
for (i, state) in color_targets.iter().enumerate() {
match io.get(&(i as wgt::ShaderLocation)) {
Some(output) => {
for (i, output) in io.iter() {
match color_targets.get(*i as usize) {
Some(&Some(ref state)) => {
validation::check_texture_format(state.format, &output.ty).map_err(
|pipeline| {
pipeline::CreateRenderPipelineError::ColorState(
i as u8,
*i as u8,
pipeline::ColorStateError::IncompatibleFormat {
pipeline,
shader: output.ty,
@ -2769,11 +2774,14 @@ impl<A: HalApi> Device<A> {
},
)?;
}
None if state.write_mask.is_empty() => {}
None => {
log::warn!("Missing fragment output[{}], expected {:?}", i, state,);
Some(&None) => {
return Err(
pipeline::CreateRenderPipelineError::InvalidFragmentOutputLocation(*i),
);
}
_ => {
return Err(pipeline::CreateRenderPipelineError::ColorState(
i as u8,
*i as u8,
pipeline::ColorStateError::Missing,
));
}
@ -2850,7 +2858,10 @@ impl<A: HalApi> Device<A> {
let pass_context = RenderPassContext {
attachments: AttachmentData {
colors: color_targets.iter().map(|state| state.format).collect(),
colors: color_targets
.iter()
.map(|state| state.as_ref().map(|s| s.format))
.collect(),
resolves: ArrayVec::new(),
depth_stencil: depth_stencil_state.as_ref().map(|state| state.format),
},
@ -2859,7 +2870,7 @@ impl<A: HalApi> Device<A> {
};
let mut flags = pipeline::PipelineFlags::empty();
for state in color_targets.iter() {
for state in color_targets.iter().filter_map(|s| s.as_ref()) {
if let Some(ref bs) = state.blend {
if bs.color.uses_constant() | bs.alpha.uses_constant() {
flags |= pipeline::PipelineFlags::BLEND_CONSTANT;

View File

@ -176,7 +176,7 @@ pub enum Command {
},
RunRenderPass {
base: crate::command::BasePass<crate::command::RenderCommand>,
target_colors: Vec<crate::command::RenderPassColorAttachment>,
target_colors: Vec<Option<crate::command::RenderPassColorAttachment>>,
target_depth_stencil: Option<crate::command::RenderPassDepthStencilAttachment>,
},
}

View File

@ -249,7 +249,7 @@ pub struct FragmentState<'a> {
/// The compiled fragment stage and its entry point.
pub stage: ProgrammableStageDescriptor<'a>,
/// The effect of draw calls on the color aspect of the output target.
pub targets: Cow<'a, [wgt::ColorTargetState]>,
pub targets: Cow<'a, [Option<wgt::ColorTargetState>]>,
}
/// Describes a render (graphics) pipeline.
@ -317,6 +317,8 @@ pub enum CreateRenderPipelineError {
Device(#[from] DeviceError),
#[error("pipeline layout is invalid")]
InvalidLayout,
#[error("fragment output @location({0}) is invalid")]
InvalidFragmentOutputLocation(u32),
#[error("unable to derive an implicit layout")]
Implicit(#[from] ImplicitLayoutError),
#[error("color state [{0}] is invalid")]

View File

@ -238,11 +238,11 @@ impl<A: hal::Api> Example<A> {
},
depth_stencil: None,
multisample: wgt::MultisampleState::default(),
color_targets: &[wgt::ColorTargetState {
color_targets: &[Some(wgt::ColorTargetState {
format: surface_config.format,
blend: Some(wgt::BlendState::ALPHA_BLENDING),
write_mask: wgt::ColorWrites::default(),
}],
})],
multiview: None,
};
let pipeline = unsafe { device.create_render_pipeline(&pipeline_desc).unwrap() };
@ -646,7 +646,7 @@ impl<A: hal::Api> Example<A> {
depth_or_array_layers: 1,
},
sample_count: 1,
color_attachments: &[hal::ColorAttachment {
color_attachments: &[Some(hal::ColorAttachment {
target: hal::Attachment {
view: &surface_tex_view,
usage: hal::TextureUses::COLOR_TARGET,
@ -659,7 +659,7 @@ impl<A: hal::Api> Example<A> {
b: 0.3,
a: 1.0,
},
}],
})],
depth_stencil_attachment: None,
multiview: None,
};

View File

@ -163,7 +163,7 @@ fn fill_screen(exposed: &hal::ExposedAdapter<hal::api::Gles>, width: u32, height
depth_or_array_layers: 1,
},
sample_count: 1,
color_attachments: &[hal::ColorAttachment {
color_attachments: &[Some(hal::ColorAttachment {
target: hal::Attachment {
view: &view,
usage: hal::TextureUses::COLOR_TARGET,
@ -171,7 +171,7 @@ fn fill_screen(exposed: &hal::ExposedAdapter<hal::api::Gles>, width: u32, height
resolve_target: None,
ops: hal::AttachmentOps::STORE,
clear_value: wgt::Color::BLUE,
}],
})],
depth_stencil_attachment: None,
multiview: None,
};

View File

@ -579,11 +579,15 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
unsafe fn begin_render_pass(&mut self, desc: &crate::RenderPassDescriptor<super::Api>) {
self.begin_pass(super::PassKind::Render, desc.label);
let mut color_views = [native::CpuDescriptor { ptr: 0 }; crate::MAX_COLOR_ATTACHMENTS];
for (rtv, cat) in color_views.iter_mut().zip(desc.color_attachments.iter()) {
*rtv = cat.target.view.handle_rtv.unwrap().raw;
if let Some(cat) = cat.as_ref() {
*rtv = cat.target.view.handle_rtv.unwrap().raw;
} else {
*rtv = self.null_rtv_handle.raw;
}
}
let ds_view = match desc.depth_stencil_attachment {
None => ptr::null(),
Some(ref ds) => {
@ -605,23 +609,26 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
self.pass.resolves.clear();
for (rtv, cat) in color_views.iter().zip(desc.color_attachments.iter()) {
if !cat.ops.contains(crate::AttachmentOps::LOAD) {
let value = [
cat.clear_value.r as f32,
cat.clear_value.g as f32,
cat.clear_value.b as f32,
cat.clear_value.a as f32,
];
list.clear_render_target_view(*rtv, value, &[]);
}
if let Some(ref target) = cat.resolve_target {
self.pass.resolves.push(super::PassResolve {
src: cat.target.view.target_base,
dst: target.view.target_base,
format: target.view.raw_format,
});
if let Some(cat) = cat.as_ref() {
if !cat.ops.contains(crate::AttachmentOps::LOAD) {
let value = [
cat.clear_value.r as f32,
cat.clear_value.g as f32,
cat.clear_value.b as f32,
cat.clear_value.a as f32,
];
list.clear_render_target_view(*rtv, value, &[]);
}
if let Some(ref target) = cat.resolve_target {
self.pass.resolves.push(super::PassResolve {
src: cat.target.view.target_base,
dst: target.view.target_base,
format: target.view.raw_format,
});
}
}
}
if let Some(ref ds) = desc.depth_stencil_attachment {
let mut flags = native::ClearFlags::empty();
let aspects = ds.target.view.format_aspects;

View File

@ -267,7 +267,7 @@ fn map_blend_component(
}
pub fn map_render_targets(
color_targets: &[wgt::ColorTargetState],
color_targets: &[Option<wgt::ColorTargetState>],
) -> [d3d12::D3D12_RENDER_TARGET_BLEND_DESC; d3d12::D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize]
{
let dummy_target = d3d12::D3D12_RENDER_TARGET_BLEND_DESC {
@ -285,17 +285,19 @@ pub fn map_render_targets(
let mut raw_targets = [dummy_target; d3d12::D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize];
for (raw, ct) in raw_targets.iter_mut().zip(color_targets.iter()) {
raw.RenderTargetWriteMask = ct.write_mask.bits() as u8;
if let Some(ref blend) = ct.blend {
let (color_op, color_src, color_dst) = map_blend_component(&blend.color, false);
let (alpha_op, alpha_src, alpha_dst) = map_blend_component(&blend.alpha, true);
raw.BlendEnable = 1;
raw.BlendOp = color_op;
raw.SrcBlend = color_src;
raw.DestBlend = color_dst;
raw.BlendOpAlpha = alpha_op;
raw.SrcBlendAlpha = alpha_src;
raw.DestBlendAlpha = alpha_dst;
if let Some(ct) = ct.as_ref() {
raw.RenderTargetWriteMask = ct.write_mask.bits() as u8;
if let Some(ref blend) = ct.blend {
let (color_op, color_src, color_dst) = map_blend_component(&blend.color, false);
let (alpha_op, alpha_src, alpha_dst) = map_blend_component(&blend.alpha, true);
raw.BlendEnable = 1;
raw.BlendOp = color_op;
raw.SrcBlend = color_src;
raw.DestBlend = color_dst;
raw.BlendOpAlpha = alpha_op;
raw.SrcBlendAlpha = alpha_src;
raw.DestBlendAlpha = alpha_dst;
}
}
}

View File

@ -125,6 +125,20 @@ impl super::Device {
)?,
};
let mut rtv_pool = descriptor::CpuPool::new(raw, native::DescriptorHeapType::Rtv);
let null_rtv_handle = rtv_pool.alloc_handle();
// A null pResource is used to initialize a null descriptor,
// which guarantees D3D11-like null binding behavior (reading 0s, writes are discarded)
raw.create_render_target_view(
native::WeakPtr::null(),
&native::RenderTargetViewDesc::texture_2d(
winapi::shared::dxgiformat::DXGI_FORMAT_R8G8B8A8_UNORM,
0,
0,
),
null_rtv_handle.raw,
);
Ok(super::Device {
raw,
present_queue,
@ -134,10 +148,7 @@ impl super::Device {
},
private_caps,
shared: Arc::new(shared),
rtv_pool: Mutex::new(descriptor::CpuPool::new(
raw,
native::DescriptorHeapType::Rtv,
)),
rtv_pool: Mutex::new(rtv_pool),
dsv_pool: Mutex::new(descriptor::CpuPool::new(
raw,
native::DescriptorHeapType::Dsv,
@ -153,6 +164,7 @@ impl super::Device {
library: Arc::clone(library),
#[cfg(feature = "renderdoc")]
render_doc: Default::default(),
null_rtv_handle,
})
}
@ -306,6 +318,7 @@ impl super::Device {
impl crate::Device<super::Api> for super::Device {
unsafe fn exit(self, queue: super::Queue) {
self.rtv_pool.lock().free_handle(self.null_rtv_handle);
self.rtv_pool.into_inner().destroy();
self.dsv_pool.into_inner().destroy();
self.srv_uav_pool.into_inner().destroy();
@ -658,6 +671,7 @@ impl crate::Device<super::Api> for super::Device {
allocator,
device: self.raw,
shared: Arc::clone(&self.shared),
null_rtv_handle: self.null_rtv_handle.clone(),
list: None,
free_lists: Vec::new(),
pass: super::PassState::new(),
@ -1283,7 +1297,9 @@ impl crate::Device<super::Api> for super::Device {
let mut rtv_formats = [dxgiformat::DXGI_FORMAT_UNKNOWN;
d3d12::D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize];
for (rtv_format, ct) in rtv_formats.iter_mut().zip(desc.color_targets) {
*rtv_format = auxil::dxgi::conv::map_texture_format(ct.format);
if let Some(ct) = ct.as_ref() {
*rtv_format = auxil::dxgi::conv::map_texture_format(ct.format);
}
}
let bias = desc

View File

@ -229,6 +229,7 @@ pub struct Device {
library: Arc<native::D3D12Lib>,
#[cfg(feature = "renderdoc")]
render_doc: crate::auxil::renderdoc::RenderDoc,
null_rtv_handle: descriptor::Handle,
}
unsafe impl Send for Device {}
@ -329,6 +330,7 @@ pub struct CommandEncoder {
allocator: native::CommandAllocator,
device: native::Device,
shared: Arc<DeviceShared>,
null_rtv_handle: descriptor::Handle,
list: Option<native::GraphicsCommandList>,
free_lists: Vec<native::GraphicsCommandList>,
pass: PassState,

View File

@ -429,7 +429,8 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
match desc
.color_attachments
.first()
.map(|at| &at.target.view.inner)
.filter(|at| at.is_some())
.and_then(|at| at.as_ref().map(|at| &at.target.view.inner))
{
// default framebuffer (provided externally)
Some(&super::TextureInner::DefaultRenderbuffer) => {
@ -444,18 +445,20 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
.push(C::ResetFramebuffer { is_default: false });
for (i, cat) in desc.color_attachments.iter().enumerate() {
let attachment = glow::COLOR_ATTACHMENT0 + i as u32;
self.cmd_buffer.commands.push(C::BindAttachment {
attachment,
view: cat.target.view.clone(),
});
if let Some(ref rat) = cat.resolve_target {
self.state
.resolve_attachments
.push((attachment, rat.view.clone()));
}
if !cat.ops.contains(crate::AttachmentOps::STORE) {
self.state.invalidate_attachments.push(attachment);
if let Some(cat) = cat.as_ref() {
let attachment = glow::COLOR_ATTACHMENT0 + i as u32;
self.cmd_buffer.commands.push(C::BindAttachment {
attachment,
view: cat.target.view.clone(),
});
if let Some(ref rat) = cat.resolve_target {
self.state
.resolve_attachments
.push((attachment, rat.view.clone()));
}
if !cat.ops.contains(crate::AttachmentOps::STORE) {
self.state.invalidate_attachments.push(attachment);
}
}
}
if let Some(ref dsat) = desc.depth_stencil_attachment {
@ -505,7 +508,12 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
});
// issue the clears
for (i, cat) in desc.color_attachments.iter().enumerate() {
for (i, cat) in desc
.color_attachments
.iter()
.filter_map(|at| at.as_ref())
.enumerate()
{
if !cat.ops.contains(crate::AttachmentOps::LOAD) {
let c = &cat.clear_value;
self.cmd_buffer

View File

@ -1002,7 +1002,7 @@ impl crate::Device<super::Api> for super::Device {
let color_targets = {
let mut targets = Vec::new();
for ct in desc.color_targets.iter() {
for ct in desc.color_targets.iter().filter_map(|at| at.as_ref()) {
targets.push(super::ColorTargetDesc {
mask: ct.write_mask,
blend: ct.blend.as_ref().map(conv::map_blend),

View File

@ -1024,7 +1024,7 @@ pub struct RenderPipelineDescriptor<'a, A: Api> {
/// The fragment stage for this pipeline.
pub fragment_stage: Option<ProgrammableStage<'a, A>>,
/// The effect of draw calls on the color aspect of the output target.
pub color_targets: &'a [wgt::ColorTargetState],
pub color_targets: &'a [Option<wgt::ColorTargetState>],
/// If the pipeline will be used with a multiview render pass, this indicates how many array
/// layers the attachments will have.
pub multiview: Option<NonZeroU32>,
@ -1179,7 +1179,7 @@ pub struct RenderPassDescriptor<'a, A: Api> {
pub label: Label<'a>,
pub extent: wgt::Extent3d,
pub sample_count: u32,
pub color_attachments: &'a [ColorAttachment<'a, A>],
pub color_attachments: &'a [Option<ColorAttachment<'a, A>>],
pub depth_stencil_attachment: Option<DepthStencilAttachment<'a, A>>,
pub multiview: Option<NonZeroU32>,
}

View File

@ -353,24 +353,26 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
//TODO: set visibility results buffer
for (i, at) in desc.color_attachments.iter().enumerate() {
let at_descriptor = descriptor.color_attachments().object_at(i as u64).unwrap();
at_descriptor.set_texture(Some(&at.target.view.raw));
if let Some(ref resolve) = at.resolve_target {
//Note: the selection of levels and slices is already handled by `TextureView`
at_descriptor.set_resolve_texture(Some(&resolve.view.raw));
if let Some(at) = at.as_ref() {
let at_descriptor = descriptor.color_attachments().object_at(i as u64).unwrap();
at_descriptor.set_texture(Some(&at.target.view.raw));
if let Some(ref resolve) = at.resolve_target {
//Note: the selection of levels and slices is already handled by `TextureView`
at_descriptor.set_resolve_texture(Some(&resolve.view.raw));
}
let load_action = if at.ops.contains(crate::AttachmentOps::LOAD) {
mtl::MTLLoadAction::Load
} else {
at_descriptor.set_clear_color(conv::map_clear_color(&at.clear_value));
mtl::MTLLoadAction::Clear
};
let store_action = conv::map_store_action(
at.ops.contains(crate::AttachmentOps::STORE),
at.resolve_target.is_some(),
);
at_descriptor.set_load_action(load_action);
at_descriptor.set_store_action(store_action);
}
let load_action = if at.ops.contains(crate::AttachmentOps::LOAD) {
mtl::MTLLoadAction::Load
} else {
at_descriptor.set_clear_color(conv::map_clear_color(&at.clear_value));
mtl::MTLLoadAction::Clear
};
let store_action = conv::map_store_action(
at.ops.contains(crate::AttachmentOps::STORE),
at.resolve_target.is_some(),
);
at_descriptor.set_load_action(load_action);
at_descriptor.set_store_action(store_action);
}
if let Some(ref at) = desc.depth_stencil_attachment {

View File

@ -841,6 +841,12 @@ impl crate::Device<super::Api> for super::Device {
for (i, ct) in desc.color_targets.iter().enumerate() {
let at_descriptor = descriptor.color_attachments().object_at(i as u64).unwrap();
let ct = if let Some(color_target) = ct.as_ref() {
color_target
} else {
at_descriptor.set_pixel_format(mtl::MTLPixelFormat::Invalid);
continue;
};
let raw_format = self.shared.private_caps.map_format(ct.format);
at_descriptor.set_pixel_format(raw_format);

View File

@ -1059,19 +1059,17 @@ impl super::Instance {
|| phd_capabilities.supports_extension(vk::KhrMaintenance1Fn::name()),
imageless_framebuffers: match phd_features.vulkan_1_2 {
Some(features) => features.imageless_framebuffer == vk::TRUE,
None => match phd_features.imageless_framebuffer {
Some(ref ext) => ext.imageless_framebuffer != 0,
None => false,
},
None => phd_features
.imageless_framebuffer
.map_or(false, |ext| ext.imageless_framebuffer != 0),
},
image_view_usage: phd_capabilities.properties.api_version >= vk::API_VERSION_1_1
|| phd_capabilities.supports_extension(vk::KhrMaintenance2Fn::name()),
timeline_semaphores: match phd_features.vulkan_1_2 {
Some(features) => features.timeline_semaphore == vk::TRUE,
None => match phd_features.timeline_semaphore {
Some(ref ext) => ext.timeline_semaphore != 0,
None => false,
},
None => phd_features
.timeline_semaphore
.map_or(false, |ext| ext.timeline_semaphore != 0),
},
texture_d24: unsafe {
self.shared
@ -1093,13 +1091,11 @@ impl super::Instance {
robust_buffer_access: phd_features.core.robust_buffer_access != 0,
robust_image_access: match phd_features.robustness2 {
Some(ref f) => f.robust_image_access2 != 0,
None => match phd_features.image_robustness {
Some(ref f) => f.robust_image_access != 0,
None => false,
},
None => phd_features
.image_robustness
.map_or(false, |ext| ext.robust_image_access != 0),
},
};
let capabilities = crate::Capabilities {
limits: phd_capabilities.to_wgpu_limits(&phd_features),
alignments: phd_capabilities.to_hal_alignments(),

View File

@ -362,31 +362,36 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
let caps = &self.device.private_caps;
for cat in desc.color_attachments {
vk_clear_values.push(vk::ClearValue {
color: cat.make_vk_clear_color(),
});
vk_image_views.push(cat.target.view.raw);
rp_key.colors.push(super::ColorAttachmentKey {
base: cat.target.make_attachment_key(cat.ops, caps),
resolve: cat
.resolve_target
.as_ref()
.map(|target| target.make_attachment_key(crate::AttachmentOps::STORE, caps)),
});
fb_key.attachments.push(cat.target.view.attachment.clone());
if let Some(ref at) = cat.resolve_target {
vk_clear_values.push(mem::zeroed());
vk_image_views.push(at.view.raw);
fb_key.attachments.push(at.view.attachment.clone());
}
if let Some(cat) = cat.as_ref() {
vk_clear_values.push(vk::ClearValue {
color: cat.make_vk_clear_color(),
});
vk_image_views.push(cat.target.view.raw);
let color = super::ColorAttachmentKey {
base: cat.target.make_attachment_key(cat.ops, caps),
resolve: cat.resolve_target.as_ref().map(|target| {
target.make_attachment_key(crate::AttachmentOps::STORE, caps)
}),
};
// Assert this attachment is valid for the detected multiview, as a sanity check
// The driver crash for this is really bad on AMD, so the check is worth it
if let Some(multiview) = desc.multiview {
assert_eq!(cat.target.view.layers, multiview);
if let Some(ref resolve_target) = cat.resolve_target {
assert_eq!(resolve_target.view.layers, multiview);
rp_key.colors.push(Some(color));
fb_key.attachments.push(cat.target.view.attachment.clone());
if let Some(ref at) = cat.resolve_target {
vk_clear_values.push(mem::zeroed());
vk_image_views.push(at.view.raw);
fb_key.attachments.push(at.view.attachment.clone());
}
// Assert this attachment is valid for the detected multiview, as a sanity check
// The driver crash for this is really bad on AMD, so the check is worth it
if let Some(multiview) = desc.multiview {
assert_eq!(cat.target.view.layers, multiview);
if let Some(ref resolve_target) = cat.resolve_target {
assert_eq!(resolve_target.view.layers, multiview);
}
}
} else {
rp_key.colors.push(None);
}
}
if let Some(ref ds) = desc.depth_stencil_attachment {
@ -431,25 +436,29 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
min_depth: 0.0,
max_depth: 1.0,
}];
let vk_scissors = [render_area];
let raw_pass = self.device.make_render_pass(rp_key).unwrap();
let raw_framebuffer = self
.device
.make_framebuffer(fb_key, raw_pass, desc.label)
.unwrap();
let mut vk_attachment_info = vk::RenderPassAttachmentBeginInfo::builder()
.attachments(&vk_image_views)
.build();
let mut vk_info = vk::RenderPassBeginInfo::builder()
.render_pass(raw_pass)
.render_area(render_area)
.clear_values(&vk_clear_values)
.framebuffer(raw_framebuffer);
if caps.imageless_framebuffers {
vk_info = vk_info.push_next(&mut vk_attachment_info);
let mut vk_attachment_info = if caps.imageless_framebuffers {
Some(
vk::RenderPassAttachmentBeginInfo::builder()
.attachments(&vk_image_views)
.build(),
)
} else {
None
};
if let Some(attachment_info) = vk_attachment_info.as_mut() {
vk_info = vk_info.push_next(attachment_info);
}
if let Some(label) = desc.label {
@ -462,7 +471,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
.cmd_set_viewport(self.active, 0, &vk_viewports);
self.device
.raw
.cmd_set_scissor(self.active, 0, &vk_scissors);
.cmd_set_scissor(self.active, 0, &[render_area]);
self.device
.raw
.cmd_begin_render_pass(self.active, &vk_info, vk::SubpassContents::INLINE);

View File

@ -71,46 +71,54 @@ impl super::DeviceShared {
let mut resolve_refs = Vec::with_capacity(color_refs.capacity());
let mut ds_ref = None;
let samples = vk::SampleCountFlags::from_raw(e.key().sample_count);
let unused = vk::AttachmentReference {
attachment: vk::ATTACHMENT_UNUSED,
layout: vk::ImageLayout::UNDEFINED,
};
for cat in e.key().colors.iter() {
color_refs.push(vk::AttachmentReference {
attachment: vk_attachments.len() as u32,
layout: cat.base.layout,
});
vk_attachments.push({
let (load_op, store_op) = conv::map_attachment_ops(cat.base.ops);
vk::AttachmentDescription::builder()
.format(cat.base.format)
.samples(samples)
.load_op(load_op)
.store_op(store_op)
.initial_layout(cat.base.layout)
.final_layout(cat.base.layout)
.build()
});
let at_ref = if let Some(ref rat) = cat.resolve {
let at_ref = vk::AttachmentReference {
let (color_ref, resolve_ref) = if let Some(cat) = cat.as_ref() {
let color_ref = vk::AttachmentReference {
attachment: vk_attachments.len() as u32,
layout: rat.layout,
layout: cat.base.layout,
};
let (load_op, store_op) = conv::map_attachment_ops(rat.ops);
let vk_attachment = vk::AttachmentDescription::builder()
.format(rat.format)
.samples(vk::SampleCountFlags::TYPE_1)
.load_op(load_op)
.store_op(store_op)
.initial_layout(rat.layout)
.final_layout(rat.layout)
.build();
vk_attachments.push(vk_attachment);
at_ref
vk_attachments.push({
let (load_op, store_op) = conv::map_attachment_ops(cat.base.ops);
vk::AttachmentDescription::builder()
.format(cat.base.format)
.samples(samples)
.load_op(load_op)
.store_op(store_op)
.initial_layout(cat.base.layout)
.final_layout(cat.base.layout)
.build()
});
let resolve_ref = if let Some(ref rat) = cat.resolve {
let (load_op, store_op) = conv::map_attachment_ops(rat.ops);
let vk_attachment = vk::AttachmentDescription::builder()
.format(rat.format)
.samples(vk::SampleCountFlags::TYPE_1)
.load_op(load_op)
.store_op(store_op)
.initial_layout(rat.layout)
.final_layout(rat.layout)
.build();
vk_attachments.push(vk_attachment);
vk::AttachmentReference {
attachment: vk_attachments.len() as u32 - 1,
layout: rat.layout,
}
} else {
unused
};
(color_ref, resolve_ref)
} else {
vk::AttachmentReference {
attachment: vk::ATTACHMENT_UNUSED,
layout: vk::ImageLayout::UNDEFINED,
}
(unused, unused)
};
resolve_refs.push(at_ref);
color_refs.push(color_ref);
resolve_refs.push(resolve_ref);
}
if let Some(ref ds) = e.key().depth_stencil {
@ -1574,30 +1582,39 @@ impl crate::Device<super::Api> for super::Device {
let mut vk_attachments = Vec::with_capacity(desc.color_targets.len());
for cat in desc.color_targets {
let vk_format = self.shared.private_caps.map_texture_format(cat.format);
compatible_rp_key.colors.push(super::ColorAttachmentKey {
base: super::AttachmentKey::compatible(
vk_format,
vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
),
resolve: None,
});
let (key, attarchment) = if let Some(cat) = cat.as_ref() {
let mut vk_attachment = vk::PipelineColorBlendAttachmentState::builder()
.color_write_mask(vk::ColorComponentFlags::from_raw(cat.write_mask.bits()));
if let Some(ref blend) = cat.blend {
let (color_op, color_src, color_dst) = conv::map_blend_component(&blend.color);
let (alpha_op, alpha_src, alpha_dst) = conv::map_blend_component(&blend.alpha);
vk_attachment = vk_attachment
.blend_enable(true)
.color_blend_op(color_op)
.src_color_blend_factor(color_src)
.dst_color_blend_factor(color_dst)
.alpha_blend_op(alpha_op)
.src_alpha_blend_factor(alpha_src)
.dst_alpha_blend_factor(alpha_dst);
}
let mut vk_attachment = vk::PipelineColorBlendAttachmentState::builder()
.color_write_mask(vk::ColorComponentFlags::from_raw(cat.write_mask.bits()));
if let Some(ref blend) = cat.blend {
let (color_op, color_src, color_dst) = conv::map_blend_component(&blend.color);
let (alpha_op, alpha_src, alpha_dst) = conv::map_blend_component(&blend.alpha);
vk_attachment = vk_attachment
.blend_enable(true)
.color_blend_op(color_op)
.src_color_blend_factor(color_src)
.dst_color_blend_factor(color_dst)
.alpha_blend_op(alpha_op)
.src_alpha_blend_factor(alpha_src)
.dst_alpha_blend_factor(alpha_dst);
}
vk_attachments.push(vk_attachment.build());
let vk_format = self.shared.private_caps.map_texture_format(cat.format);
(
Some(super::ColorAttachmentKey {
base: super::AttachmentKey::compatible(
vk_format,
vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
),
resolve: None,
}),
vk_attachment.build(),
)
} else {
(None, vk::PipelineColorBlendAttachmentState::default())
};
compatible_rp_key.colors.push(key);
vk_attachments.push(attarchment);
}
let vk_color_blend = vk::PipelineColorBlendStateCreateInfo::builder()

View File

@ -212,7 +212,7 @@ struct DepthStencilAttachmentKey {
#[derive(Clone, Eq, Default, Hash, PartialEq)]
struct RenderPassKey {
colors: ArrayVec<ColorAttachmentKey, { crate::MAX_COLOR_ATTACHMENTS }>,
colors: ArrayVec<Option<ColorAttachmentKey>, { crate::MAX_COLOR_ATTACHMENTS }>,
depth_stencil: Option<DepthStencilAttachmentKey>,
sample_count: u32,
multiview: Option<NonZeroU32>,

View File

@ -151,7 +151,7 @@ impl framework::Example for Example {
fragment: Some(wgpu::FragmentState {
module: &draw_shader,
entry_point: "main_fs",
targets: &[config.format.into()],
targets: &[Some(config.format.into())],
}),
primitive: wgpu::PrimitiveState::default(),
depth_stencil: None,
@ -272,7 +272,7 @@ impl framework::Example for Example {
_spawner: &framework::Spawner,
) {
// create render pass descriptor and its color attachments
let color_attachments = [wgpu::RenderPassColorAttachment {
let color_attachments = [Some(wgpu::RenderPassColorAttachment {
view,
resolve_target: None,
ops: wgpu::Operations {
@ -281,7 +281,7 @@ impl framework::Example for Example {
load: wgpu::LoadOp::Load,
store: true,
},
}];
})];
let render_pass_descriptor = wgpu::RenderPassDescriptor {
label: None,
color_attachments: &color_attachments,

View File

@ -116,11 +116,11 @@ impl framework::Example for Example {
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "fs_main",
targets: &[wgpu::ColorTargetState {
targets: &[Some(wgpu::ColorTargetState {
format: config.format,
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
write_mask: wgpu::ColorWrites::default(),
}],
})],
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleStrip,
@ -329,14 +329,14 @@ impl framework::Example for Example {
};
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[wgpu::RenderPassColorAttachment {
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(clear_color),
store: true,
},
}],
})],
depth_stencil_attachment: None,
});
rpass.set_pipeline(&self.pipeline);

View File

@ -91,14 +91,14 @@ async fn create_red_image_with_dimensions(
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[wgpu::RenderPassColorAttachment {
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &texture.create_view(&wgpu::TextureViewDescriptor::default()),
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::RED),
store: true,
},
}],
})],
depth_stencil_attachment: None,
});

View File

@ -104,7 +104,7 @@ impl framework::Example for Example {
fragment: Some(wgpu::FragmentState {
module: &shader_triangle_and_lines,
entry_point: "fs_main_red",
targets: &[RENDER_TARGET_FORMAT.into()],
targets: &[Some(RENDER_TARGET_FORMAT.into())],
}),
primitive: wgpu::PrimitiveState {
conservative: true,
@ -127,7 +127,7 @@ impl framework::Example for Example {
fragment: Some(wgpu::FragmentState {
module: &shader_triangle_and_lines,
entry_point: "fs_main_blue",
targets: &[RENDER_TARGET_FORMAT.into()],
targets: &[Some(RENDER_TARGET_FORMAT.into())],
}),
primitive: wgpu::PrimitiveState::default(),
depth_stencil: None,
@ -151,7 +151,7 @@ impl framework::Example for Example {
fragment: Some(wgpu::FragmentState {
module: &shader_triangle_and_lines,
entry_point: "fs_main_white",
targets: &[config.format.into()],
targets: &[Some(config.format.into())],
}),
primitive: wgpu::PrimitiveState {
polygon_mode: wgpu::PolygonMode::Line,
@ -212,7 +212,7 @@ impl framework::Example for Example {
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "fs_main",
targets: &[config.format.into()],
targets: &[Some(config.format.into())],
}),
primitive: wgpu::PrimitiveState::default(),
depth_stencil: None,
@ -266,14 +266,14 @@ impl framework::Example for Example {
{
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("low resolution"),
color_attachments: &[wgpu::RenderPassColorAttachment {
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &self.low_res_target,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
store: true,
},
}],
})],
depth_stencil_attachment: None,
});
@ -285,14 +285,14 @@ impl framework::Example for Example {
{
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("full resolution"),
color_attachments: &[wgpu::RenderPassColorAttachment {
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
store: true,
},
}],
})],
depth_stencil_attachment: None,
});

View File

@ -273,7 +273,7 @@ impl framework::Example for Example {
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "fs_main",
targets: &[config.format.into()],
targets: &[Some(config.format.into())],
}),
primitive: wgpu::PrimitiveState {
cull_mode: Some(wgpu::Face::Back),
@ -296,7 +296,7 @@ impl framework::Example for Example {
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "fs_wire",
targets: &[wgpu::ColorTargetState {
targets: &[Some(wgpu::ColorTargetState {
format: config.format,
blend: Some(wgpu::BlendState {
color: wgpu::BlendComponent {
@ -307,7 +307,7 @@ impl framework::Example for Example {
alpha: wgpu::BlendComponent::REPLACE,
}),
write_mask: wgpu::ColorWrites::ALL,
}],
})],
}),
primitive: wgpu::PrimitiveState {
front_face: wgpu::FrontFace::Ccw,
@ -364,7 +364,7 @@ impl framework::Example for Example {
{
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[wgpu::RenderPassColorAttachment {
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view,
resolve_target: None,
ops: wgpu::Operations {
@ -376,7 +376,7 @@ impl framework::Example for Example {
}),
store: true,
},
}],
})],
depth_stencil_attachment: None,
});
rpass.push_debug_group("Prepare data for draw.");

View File

@ -59,7 +59,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "fs_main",
targets: &[swapchain_format.into()],
targets: &[Some(swapchain_format.into())],
}),
primitive: wgpu::PrimitiveState::default(),
depth_stencil: None,
@ -108,14 +108,14 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
{
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[wgpu::RenderPassColorAttachment {
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::GREEN),
store: true,
},
}],
})],
depth_stencil_attachment: None,
});
rpass.set_pipeline(&render_pipeline);

View File

@ -123,14 +123,14 @@ async fn run(event_loop: EventLoop<()>, viewports: Vec<(Window, wgpu::Color)>) {
{
let _rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[wgpu::RenderPassColorAttachment {
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(viewport.desc.background),
store: true,
},
}],
})],
depth_stencil_attachment: None,
});
}

View File

@ -94,7 +94,7 @@ impl Example {
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "fs_main",
targets: &[TEXTURE_FORMAT.into()],
targets: &[Some(TEXTURE_FORMAT.into())],
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
@ -154,14 +154,14 @@ impl Example {
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[wgpu::RenderPassColorAttachment {
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &views[target_mip],
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::WHITE),
store: true,
},
}],
})],
depth_stencil_attachment: None,
});
if let Some(ref query_sets) = query_sets {
@ -288,7 +288,7 @@ impl framework::Example for Example {
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "fs_main",
targets: &[config.format.into()],
targets: &[Some(config.format.into())],
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleStrip,
@ -461,14 +461,14 @@ impl framework::Example for Example {
};
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[wgpu::RenderPassColorAttachment {
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(clear_color),
store: true,
},
}],
})],
depth_stencil_attachment: None,
});
rpass.set_pipeline(&self.draw_pipeline);

View File

@ -60,7 +60,7 @@ impl Example {
fragment: Some(wgpu::FragmentState {
module: shader,
entry_point: "fs_main",
targets: &[config.format.into()],
targets: &[Some(config.format.into())],
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::LineList,
@ -77,7 +77,7 @@ impl Example {
let mut encoder =
device.create_render_bundle_encoder(&wgpu::RenderBundleEncoderDescriptor {
label: None,
color_formats: &[config.format],
color_formats: &[Some(config.format)],
depth_stencil: None,
sample_count,
multiview: None,
@ -275,7 +275,7 @@ impl framework::Example for Example {
encoder
.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[rpass_color_attachment],
color_attachments: &[Some(rpass_color_attachment)],
depth_stencil_attachment: None,
})
.execute_bundles(iter::once(&self.bundle));

View File

@ -642,7 +642,7 @@ impl framework::Example for Example {
} else {
"fs_main_without_storage"
},
targets: &[sc_desc.format.into()],
targets: &[Some(sc_desc.format.into())],
}),
primitive: wgpu::PrimitiveState {
front_face: wgpu::FrontFace::Ccw,
@ -799,7 +799,7 @@ impl framework::Example for Example {
{
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[wgpu::RenderPassColorAttachment {
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view,
resolve_target: None,
ops: wgpu::Operations {
@ -811,7 +811,7 @@ impl framework::Example for Example {
}),
store: true,
},
}],
})],
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
view: &self.forward_depth,
depth_ops: Some(wgpu::Operations {

View File

@ -206,7 +206,7 @@ impl framework::Example for Skybox {
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "fs_sky",
targets: &[config.format.into()],
targets: &[Some(config.format.into())],
}),
primitive: wgpu::PrimitiveState {
front_face: wgpu::FrontFace::Cw,
@ -237,7 +237,7 @@ impl framework::Example for Skybox {
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "fs_entity",
targets: &[config.format.into()],
targets: &[Some(config.format.into())],
}),
primitive: wgpu::PrimitiveState {
front_face: wgpu::FrontFace::Cw,
@ -420,7 +420,7 @@ impl framework::Example for Skybox {
{
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[wgpu::RenderPassColorAttachment {
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view,
resolve_target: None,
ops: wgpu::Operations {
@ -432,7 +432,7 @@ impl framework::Example for Skybox {
}),
store: true,
},
}],
})],
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
view: &self.depth_view,
depth_ops: Some(wgpu::Operations {

View File

@ -328,7 +328,7 @@ impl framework::Example for Example {
fragment: Some(wgpu::FragmentState {
module: fragment_shader_module,
entry_point: fragment_entry_point,
targets: &[config.format.into()],
targets: &[Some(config.format.into())],
}),
primitive: wgpu::PrimitiveState {
front_face: wgpu::FrontFace::Ccw,
@ -372,14 +372,14 @@ impl framework::Example for Example {
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[wgpu::RenderPassColorAttachment {
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
store: true,
},
}],
})],
depth_stencil_attachment: None,
});

View File

@ -530,7 +530,7 @@ impl framework::Example for Example {
entry_point: "fs_main",
// Describes how the colour will be interpolated
// and assigned to the output attachment.
targets: &[wgpu::ColorTargetState {
targets: &[Some(wgpu::ColorTargetState {
format: config.format,
blend: Some(wgpu::BlendState {
color: wgpu::BlendComponent {
@ -545,7 +545,7 @@ impl framework::Example for Example {
},
}),
write_mask: wgpu::ColorWrites::ALL,
}],
})],
}),
// How the triangles will be rasterized. This is more important
// for the terrain because of the beneath-the water shot.
@ -591,7 +591,7 @@ impl framework::Example for Example {
fragment: Some(wgpu::FragmentState {
module: &terrain_module,
entry_point: "fs_main",
targets: &[config.format.into()],
targets: &[Some(config.format.into())],
}),
primitive: wgpu::PrimitiveState {
front_face: wgpu::FrontFace::Ccw,
@ -614,7 +614,7 @@ impl framework::Example for Example {
let mut encoder =
device.create_render_bundle_encoder(&wgpu::RenderBundleEncoderDescriptor {
label: None,
color_formats: &[config.format],
color_formats: &[Some(config.format)],
depth_stencil: Some(wgpu::RenderBundleDepthStencil {
format: wgpu::TextureFormat::Depth32Float,
depth_read_only: false,
@ -735,14 +735,14 @@ impl framework::Example for Example {
{
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[wgpu::RenderPassColorAttachment {
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &self.reflect_view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(back_color),
store: true,
},
}],
})],
// We still need to use the depth buffer here
// since the pipeline requires it.
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
@ -762,14 +762,14 @@ impl framework::Example for Example {
{
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[wgpu::RenderPassColorAttachment {
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(back_color),
store: true,
},
}],
})],
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
view: &self.depth_buffer,
depth_ops: Some(wgpu::Operations {
@ -789,14 +789,14 @@ impl framework::Example for Example {
{
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[wgpu::RenderPassColorAttachment {
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: true,
},
}],
})],
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
view: &self.depth_buffer,
depth_ops: None,

View File

@ -2031,10 +2031,13 @@ impl crate::Context for Context {
let colors = desc
.color_attachments
.iter()
.map(|ca| wgc::command::RenderPassColorAttachment {
view: ca.view.id,
resolve_target: ca.resolve_target.map(|rt| rt.id),
channel: map_pass_channel(Some(&ca.ops)),
.map(|ca| {
ca.as_ref()
.map(|at| wgc::command::RenderPassColorAttachment {
view: at.view.id,
resolve_target: at.resolve_target.map(|rt| rt.id),
channel: map_pass_channel(Some(&at.ops)),
})
})
.collect::<ArrayVec<_, { wgc::MAX_COLOR_ATTACHMENTS }>>();

View File

@ -1556,17 +1556,20 @@ impl crate::Context for Context {
let targets = frag
.targets
.iter()
.map(|target| {
let mapped_format = map_texture_format(target.format);
let mut mapped_color_state = web_sys::GpuColorTargetState::new(mapped_format);
if let Some(ref bs) = target.blend {
let alpha = map_blend_component(&bs.alpha);
let color = map_blend_component(&bs.color);
let mapped_blend_state = web_sys::GpuBlendState::new(&alpha, &color);
mapped_color_state.blend(&mapped_blend_state);
}
mapped_color_state.write_mask(target.write_mask.bits());
mapped_color_state
.filter_map(|t| {
t.as_ref().map(|target| {
let mapped_format = map_texture_format(target.format);
let mut mapped_color_state =
web_sys::GpuColorTargetState::new(mapped_format);
if let Some(ref bs) = target.blend {
let alpha = map_blend_component(&bs.alpha);
let color = map_blend_component(&bs.color);
let mapped_blend_state = web_sys::GpuBlendState::new(&alpha, &color);
mapped_color_state.blend(&mapped_blend_state);
}
mapped_color_state.write_mask(target.write_mask.bits());
mapped_color_state
})
})
.collect::<js_sys::Array>();
let mapped_fragment_desc =
@ -1690,7 +1693,10 @@ impl crate::Context for Context {
let mapped_color_formats = desc
.color_formats
.iter()
.map(|cf| wasm_bindgen::JsValue::from(map_texture_format(*cf)))
.filter_map(|cf| {
cf.as_ref()
.map(|format| wasm_bindgen::JsValue::from(map_texture_format(*format)))
})
.collect::<js_sys::Array>();
let mut mapped_desc = web_sys::GpuRenderBundleEncoderDescriptor::new(&mapped_color_formats);
if let Some(label) = desc.label {
@ -1985,25 +1991,31 @@ impl crate::Context for Context {
let mapped_color_attachments = desc
.color_attachments
.iter()
.map(|ca| {
let load_value = match ca.ops.load {
crate::LoadOp::Clear(color) => wasm_bindgen::JsValue::from(map_color(color)),
crate::LoadOp::Load => wasm_bindgen::JsValue::from(web_sys::GpuLoadOp::Load),
};
.filter_map(|attachment| {
attachment.as_ref().map(|ca| {
let load_value = match ca.ops.load {
crate::LoadOp::Clear(color) => {
wasm_bindgen::JsValue::from(map_color(color))
}
crate::LoadOp::Load => {
wasm_bindgen::JsValue::from(web_sys::GpuLoadOp::Load)
}
};
let mut mapped_color_attachment = web_sys::GpuRenderPassColorAttachment::new(
&load_value,
map_store_op(ca.ops.store),
&ca.view.id.0,
);
let mut mapped_color_attachment = web_sys::GpuRenderPassColorAttachment::new(
&load_value,
map_store_op(ca.ops.store),
&ca.view.id.0,
);
if let Some(rt) = ca.resolve_target {
mapped_color_attachment.resolve_target(&rt.id.0);
}
if let Some(rt) = ca.resolve_target {
mapped_color_attachment.resolve_target(&rt.id.0);
}
mapped_color_attachment.store_op(map_store_op(ca.ops.store));
mapped_color_attachment.store_op(map_store_op(ca.ops.store));
mapped_color_attachment
mapped_color_attachment
})
})
.collect::<js_sys::Array>();

View File

@ -1413,7 +1413,7 @@ pub struct RenderPassDescriptor<'tex, 'desc> {
/// Debug label of the render pass. This will show up in graphics debuggers for easy identification.
pub label: Label<'desc>,
/// The color attachments of the render pass.
pub color_attachments: &'desc [RenderPassColorAttachment<'tex>],
pub color_attachments: &'desc [Option<RenderPassColorAttachment<'tex>>],
/// The depth and stencil attachment of the render pass, if any.
pub depth_stencil_attachment: Option<RenderPassDepthStencilAttachment<'tex>>,
}
@ -1465,7 +1465,7 @@ pub struct FragmentState<'a> {
/// void with this name in the shader.
pub entry_point: &'a str,
/// The color state of the render targets.
pub targets: &'a [ColorTargetState],
pub targets: &'a [Option<ColorTargetState>],
}
/// Describes a render (graphics) pipeline.
@ -1567,7 +1567,7 @@ pub struct RenderBundleEncoderDescriptor<'a> {
pub label: Label<'a>,
/// The formats of the color attachments that this render bundle is capable to rendering to. This
/// must match the formats of the color attachments in the renderpass this render bundle is executed in.
pub color_formats: &'a [TextureFormat],
pub color_formats: &'a [Option<TextureFormat>],
/// Information about the depth attachment that this render bundle is capable to rendering to. This
/// must match the format of the depth attachments in the renderpass this render bundle is executed in.
pub depth_stencil: Option<RenderBundleDepthStencil>,

View File

@ -152,11 +152,11 @@ fn pulling_common(
fragment: Some(wgpu::FragmentState {
entry_point: "fs_main",
module: &shader,
targets: &[wgpu::ColorTargetState {
targets: &[Some(wgpu::ColorTargetState {
format: wgpu::TextureFormat::Rgba8Unorm,
blend: None,
write_mask: wgpu::ColorWrites::ALL,
}],
})],
}),
multiview: None,
});
@ -184,14 +184,14 @@ fn pulling_common(
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
color_attachments: &[wgpu::RenderPassColorAttachment {
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::WHITE),
store: true,
},
resolve_target: None,
view: &color_view,
}],
})],
depth_stencil_attachment: None,
label: None,
});

View File

@ -71,11 +71,11 @@ fn pulling_common(
fragment: Some(wgpu::FragmentState {
entry_point: "fs_main",
module: &shader,
targets: &[wgpu::ColorTargetState {
targets: &[Some(wgpu::ColorTargetState {
format: wgpu::TextureFormat::Rgba8Unorm,
blend: None,
write_mask: wgpu::ColorWrites::ALL,
}],
})],
}),
multiview: None,
});
@ -106,11 +106,11 @@ fn pulling_common(
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
color_attachments: &[wgpu::RenderPassColorAttachment {
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
ops: wgpu::Operations::default(),
resolve_target: None,
view: &dummy,
}],
})],
depth_stencil_attachment: None,
label: None,
});

View File

@ -14,14 +14,14 @@ fn discarding_color_target_resets_texture_init_state_check_visible_on_copy_after
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Color Discard"),
color_attachments: &[wgpu::RenderPassColorAttachment {
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &texture.create_view(&wgpu::TextureViewDescriptor::default()),
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: false, // discard!
},
}],
})],
depth_stencil_attachment: None,
});
ctx.queue.submit([encoder.finish()]);
@ -49,14 +49,14 @@ fn discarding_color_target_resets_texture_init_state_check_visible_on_copy_in_sa
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Color Discard"),
color_attachments: &[wgpu::RenderPassColorAttachment {
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &texture.create_view(&wgpu::TextureViewDescriptor::default()),
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: false, // discard!
},
}],
})],
depth_stencil_attachment: None,
});
copy_texture_to_buffer(&mut encoder, &texture, &readback_buffer);