mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-25 08:13:27 +00:00
Add multiview support (#2187)
Co-authored-by: Layl Bongers <2385329-layl@users.noreply.gitlab.com>
This commit is contained in:
parent
fca82ddd7e
commit
2ef72b9313
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -984,18 +984,18 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "naga"
|
name = "naga"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
source = "git+https://github.com/gfx-rs/naga?rev=eda078d#eda078d736a906b4267e4803db6b32e3162aac30"
|
source = "git+https://github.com/gfx-rs/naga?rev=29571cc#29571cc4cfbb28558948b1b31ad764f55b69f37b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit-set",
|
"bit-set",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"codespan-reporting",
|
"codespan-reporting",
|
||||||
"fxhash",
|
|
||||||
"hexf-parse",
|
"hexf-parse",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"log",
|
"log",
|
||||||
"num-traits 0.2.14",
|
"num-traits 0.2.14",
|
||||||
"petgraph",
|
"petgraph",
|
||||||
"pp-rs",
|
"pp-rs",
|
||||||
|
"rustc-hash",
|
||||||
"serde",
|
"serde",
|
||||||
"spirv",
|
"spirv",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@ -1437,6 +1437,12 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rusttype"
|
name = "rusttype"
|
||||||
version = "0.9.2"
|
version = "0.9.2"
|
||||||
|
@ -68,6 +68,7 @@ pub fn op_webgpu_create_render_bundle_encoder(
|
|||||||
color_formats: Cow::from(color_formats),
|
color_formats: Cow::from(color_formats),
|
||||||
sample_count: args.sample_count,
|
sample_count: args.sample_count,
|
||||||
depth_stencil,
|
depth_stencil,
|
||||||
|
multiview: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let res = wgpu_core::command::RenderBundleEncoder::new(&descriptor, device, None);
|
let res = wgpu_core::command::RenderBundleEncoder::new(&descriptor, device, None);
|
||||||
|
@ -358,6 +358,7 @@ pub fn op_webgpu_create_render_pipeline(
|
|||||||
depth_stencil: args.depth_stencil.map(TryInto::try_into).transpose()?,
|
depth_stencil: args.depth_stencil.map(TryInto::try_into).transpose()?,
|
||||||
multisample: args.multisample.into(),
|
multisample: args.multisample.into(),
|
||||||
fragment,
|
fragment,
|
||||||
|
multiview: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let implicit_pipelines = match args.layout {
|
let implicit_pipelines = match args.layout {
|
||||||
|
@ -37,7 +37,7 @@ thiserror = "1"
|
|||||||
|
|
||||||
[dependencies.naga]
|
[dependencies.naga]
|
||||||
git = "https://github.com/gfx-rs/naga"
|
git = "https://github.com/gfx-rs/naga"
|
||||||
rev = "eda078d"
|
rev = "29571cc"
|
||||||
#version = "0.7"
|
#version = "0.7"
|
||||||
features = ["span", "validate", "wgsl-in"]
|
features = ["span", "validate", "wgsl-in"]
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ use crate::{
|
|||||||
Label, LabelHelpers, LifeGuard, Stored,
|
Label, LabelHelpers, LifeGuard, Stored,
|
||||||
};
|
};
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
use std::{borrow::Cow, mem, ops::Range};
|
use std::{borrow::Cow, mem, num::NonZeroU32, ops::Range};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use hal::CommandEncoder as _;
|
use hal::CommandEncoder as _;
|
||||||
@ -75,6 +75,8 @@ pub struct RenderBundleEncoderDescriptor<'a> {
|
|||||||
/// Sample count this render bundle is capable of rendering to. This must match the pipelines and
|
/// Sample count this render bundle is capable of rendering to. This must match the pipelines and
|
||||||
/// the renderpasses it is used in.
|
/// the renderpasses it is used in.
|
||||||
pub sample_count: u32,
|
pub sample_count: u32,
|
||||||
|
/// If this render bundle will rendering to multiple array layers in the attachments at the same time.
|
||||||
|
pub multiview: Option<NonZeroU32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -112,6 +114,7 @@ impl RenderBundleEncoder {
|
|||||||
}
|
}
|
||||||
sc
|
sc
|
||||||
},
|
},
|
||||||
|
multiview: desc.multiview,
|
||||||
},
|
},
|
||||||
is_ds_read_only: match desc.depth_stencil {
|
is_ds_read_only: match desc.depth_stencil {
|
||||||
Some(ds) => {
|
Some(ds) => {
|
||||||
@ -135,6 +138,7 @@ impl RenderBundleEncoder {
|
|||||||
depth_stencil: None,
|
depth_stencil: None,
|
||||||
},
|
},
|
||||||
sample_count: 0,
|
sample_count: 0,
|
||||||
|
multiview: None,
|
||||||
},
|
},
|
||||||
is_ds_read_only: false,
|
is_ds_read_only: false,
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,8 @@ use crate::{
|
|||||||
RenderCommandError, StateChange,
|
RenderCommandError, StateChange,
|
||||||
},
|
},
|
||||||
device::{
|
device::{
|
||||||
AttachmentData, MissingDownlevelFlags, MissingFeatures, RenderPassCompatibilityError,
|
AttachmentData, Device, MissingDownlevelFlags, MissingFeatures,
|
||||||
RenderPassContext,
|
RenderPassCompatibilityError, RenderPassContext,
|
||||||
},
|
},
|
||||||
error::{ErrorFormatter, PrettyError},
|
error::{ErrorFormatter, PrettyError},
|
||||||
hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token},
|
hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token},
|
||||||
@ -29,7 +29,8 @@ use arrayvec::ArrayVec;
|
|||||||
use hal::CommandEncoder as _;
|
use hal::CommandEncoder as _;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use wgt::{
|
use wgt::{
|
||||||
BufferAddress, BufferSize, BufferUsages, Color, IndexFormat, TextureUsages, VertexStepMode,
|
BufferAddress, BufferSize, BufferUsages, Color, IndexFormat, TextureUsages,
|
||||||
|
TextureViewDimension, VertexStepMode,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(any(feature = "serial-pass", feature = "replay"))]
|
#[cfg(any(feature = "serial-pass", feature = "replay"))]
|
||||||
@ -461,6 +462,12 @@ pub enum RenderPassErrorInner {
|
|||||||
Bind(#[from] BindError),
|
Bind(#[from] BindError),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
QueryUse(#[from] QueryUseError),
|
QueryUse(#[from] QueryUseError),
|
||||||
|
#[error("multiview layer count must match")]
|
||||||
|
MultiViewMismatch,
|
||||||
|
#[error(
|
||||||
|
"multiview pass texture views with more than one array layer must have D2Array dimension"
|
||||||
|
)]
|
||||||
|
MultiViewDimensionMismatch,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrettyError for RenderPassErrorInner {
|
impl PrettyError for RenderPassErrorInner {
|
||||||
@ -542,6 +549,7 @@ struct RenderPassInfo<'a, A: hal::Api> {
|
|||||||
|
|
||||||
pending_discard_init_fixups: SurfacesInDiscardState,
|
pending_discard_init_fixups: SurfacesInDiscardState,
|
||||||
divergent_discarded_depth_stencil_aspect: Option<(wgt::TextureAspect, &'a TextureView<A>)>,
|
divergent_discarded_depth_stencil_aspect: Option<(wgt::TextureAspect, &'a TextureView<A>)>,
|
||||||
|
multiview: Option<NonZeroU32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, A: HalApi> RenderPassInfo<'a, A> {
|
impl<'a, A: HalApi> RenderPassInfo<'a, A> {
|
||||||
@ -582,6 +590,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn start(
|
fn start(
|
||||||
|
device: &Device<A>,
|
||||||
label: Option<&str>,
|
label: Option<&str>,
|
||||||
color_attachments: &[RenderPassColorAttachment],
|
color_attachments: &[RenderPassColorAttachment],
|
||||||
depth_stencil_attachment: Option<&RenderPassDepthStencilAttachment>,
|
depth_stencil_attachment: Option<&RenderPassDepthStencilAttachment>,
|
||||||
@ -605,6 +614,39 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
|
|||||||
let mut extent = None;
|
let mut extent = None;
|
||||||
let mut sample_count = 0;
|
let mut sample_count = 0;
|
||||||
|
|
||||||
|
let mut detected_multiview: Option<Option<NonZeroU32>> = None;
|
||||||
|
|
||||||
|
let mut check_multiview = |view: &TextureView<A>| {
|
||||||
|
// Get the multiview configuration for this texture view
|
||||||
|
let layers = view.selector.layers.end - view.selector.layers.start;
|
||||||
|
let this_multiview = if layers >= 2 {
|
||||||
|
// Trivially proven by the if above
|
||||||
|
Some(unsafe { NonZeroU32::new_unchecked(layers) })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
// Make sure that if this view is a multiview, it is set to be an array
|
||||||
|
if this_multiview.is_some() && view.desc.dimension != TextureViewDimension::D2Array {
|
||||||
|
return Err(RenderPassErrorInner::MultiViewDimensionMismatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate matching first, or store the first one
|
||||||
|
if let Some(multiview) = detected_multiview {
|
||||||
|
if multiview != this_multiview {
|
||||||
|
return Err(RenderPassErrorInner::MultiViewMismatch);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Multiview is only supported if the feature is enabled
|
||||||
|
if this_multiview.is_some() {
|
||||||
|
device.require_features(wgt::Features::MULTIVIEW)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
detected_multiview = Some(this_multiview);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
let mut add_view = |view: &TextureView<A>, type_name| {
|
let mut add_view = |view: &TextureView<A>, type_name| {
|
||||||
if let Some(ex) = extent {
|
if let Some(ex) = extent {
|
||||||
if ex != view.extent {
|
if ex != view.extent {
|
||||||
@ -637,6 +679,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
|
|||||||
.views
|
.views
|
||||||
.use_extend(&*view_guard, at.view, (), ())
|
.use_extend(&*view_guard, at.view, (), ())
|
||||||
.map_err(|_| RenderPassErrorInner::InvalidAttachment(at.view))?;
|
.map_err(|_| RenderPassErrorInner::InvalidAttachment(at.view))?;
|
||||||
|
check_multiview(view)?;
|
||||||
add_view(view, "depth")?;
|
add_view(view, "depth")?;
|
||||||
|
|
||||||
let ds_aspects = view.desc.aspects();
|
let ds_aspects = view.desc.aspects();
|
||||||
@ -745,6 +788,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
|
|||||||
.views
|
.views
|
||||||
.use_extend(&*view_guard, at.view, (), ())
|
.use_extend(&*view_guard, at.view, (), ())
|
||||||
.map_err(|_| RenderPassErrorInner::InvalidAttachment(at.view))?;
|
.map_err(|_| RenderPassErrorInner::InvalidAttachment(at.view))?;
|
||||||
|
check_multiview(color_view)?;
|
||||||
add_view(color_view, "color")?;
|
add_view(color_view, "color")?;
|
||||||
|
|
||||||
if !color_view
|
if !color_view
|
||||||
@ -774,6 +818,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
|
|||||||
.views
|
.views
|
||||||
.use_extend(&*view_guard, resolve_target, (), ())
|
.use_extend(&*view_guard, resolve_target, (), ())
|
||||||
.map_err(|_| RenderPassErrorInner::InvalidAttachment(resolve_target))?;
|
.map_err(|_| RenderPassErrorInner::InvalidAttachment(resolve_target))?;
|
||||||
|
check_multiview(resolve_view)?;
|
||||||
if color_view.extent != resolve_view.extent {
|
if color_view.extent != resolve_view.extent {
|
||||||
return Err(RenderPassErrorInner::AttachmentsDimensionMismatch {
|
return Err(RenderPassErrorInner::AttachmentsDimensionMismatch {
|
||||||
previous: (attachment_type_name, extent.unwrap_or_default()),
|
previous: (attachment_type_name, extent.unwrap_or_default()),
|
||||||
@ -829,9 +874,12 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
|
|||||||
depth_stencil: depth_stencil_attachment.map(|at| view_guard.get(at.view).unwrap()),
|
depth_stencil: depth_stencil_attachment.map(|at| view_guard.get(at.view).unwrap()),
|
||||||
};
|
};
|
||||||
let extent = extent.ok_or(RenderPassErrorInner::MissingAttachments)?;
|
let extent = extent.ok_or(RenderPassErrorInner::MissingAttachments)?;
|
||||||
|
|
||||||
|
let multiview = detected_multiview.expect("Multiview was not detected, no attachments");
|
||||||
let context = RenderPassContext {
|
let context = RenderPassContext {
|
||||||
attachments: view_data.map(|view| view.desc.format),
|
attachments: view_data.map(|view| view.desc.format),
|
||||||
sample_count,
|
sample_count,
|
||||||
|
multiview,
|
||||||
};
|
};
|
||||||
|
|
||||||
let hal_desc = hal::RenderPassDescriptor {
|
let hal_desc = hal::RenderPassDescriptor {
|
||||||
@ -840,6 +888,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
|
|||||||
sample_count,
|
sample_count,
|
||||||
color_attachments: &colors,
|
color_attachments: &colors,
|
||||||
depth_stencil_attachment: depth_stencil,
|
depth_stencil_attachment: depth_stencil,
|
||||||
|
multiview,
|
||||||
};
|
};
|
||||||
unsafe {
|
unsafe {
|
||||||
cmd_buf.encoder.raw.begin_render_pass(&hal_desc);
|
cmd_buf.encoder.raw.begin_render_pass(&hal_desc);
|
||||||
@ -854,6 +903,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
|
|||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
pending_discard_init_fixups,
|
pending_discard_init_fixups,
|
||||||
divergent_discarded_depth_stencil_aspect,
|
divergent_discarded_depth_stencil_aspect,
|
||||||
|
multiview,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -916,6 +966,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
|
|||||||
stencil_ops,
|
stencil_ops,
|
||||||
clear_value: (0.0, 0),
|
clear_value: (0.0, 0),
|
||||||
}),
|
}),
|
||||||
|
multiview: self.multiview,
|
||||||
};
|
};
|
||||||
unsafe {
|
unsafe {
|
||||||
raw.begin_render_pass(&desc);
|
raw.begin_render_pass(&desc);
|
||||||
@ -997,6 +1048,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let mut info = RenderPassInfo::start(
|
let mut info = RenderPassInfo::start(
|
||||||
|
device,
|
||||||
base.label,
|
base.label,
|
||||||
color_attachments,
|
color_attachments,
|
||||||
depth_stencil_attachment,
|
depth_stencil_attachment,
|
||||||
|
@ -72,6 +72,7 @@ impl<T> AttachmentData<T> {
|
|||||||
pub(crate) struct RenderPassContext {
|
pub(crate) struct RenderPassContext {
|
||||||
pub attachments: AttachmentData<TextureFormat>,
|
pub attachments: AttachmentData<TextureFormat>,
|
||||||
pub sample_count: u32,
|
pub sample_count: u32,
|
||||||
|
pub multiview: Option<NonZeroU32>,
|
||||||
}
|
}
|
||||||
#[derive(Clone, Debug, Error)]
|
#[derive(Clone, Debug, Error)]
|
||||||
pub enum RenderPassCompatibilityError {
|
pub enum RenderPassCompatibilityError {
|
||||||
@ -84,6 +85,8 @@ pub enum RenderPassCompatibilityError {
|
|||||||
IncompatibleDepthStencilAttachment(Option<TextureFormat>, Option<TextureFormat>),
|
IncompatibleDepthStencilAttachment(Option<TextureFormat>, Option<TextureFormat>),
|
||||||
#[error("Incompatible sample count: {0:?} != {1:?}")]
|
#[error("Incompatible sample count: {0:?} != {1:?}")]
|
||||||
IncompatibleSampleCount(u32, u32),
|
IncompatibleSampleCount(u32, u32),
|
||||||
|
#[error("Incompatible multiview: {0:?} != {1:?}")]
|
||||||
|
IncompatibleMultiview(Option<NonZeroU32>, Option<NonZeroU32>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderPassContext {
|
impl RenderPassContext {
|
||||||
@ -112,6 +115,12 @@ impl RenderPassContext {
|
|||||||
other.sample_count,
|
other.sample_count,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
if self.multiview != other.multiview {
|
||||||
|
return Err(RenderPassCompatibilityError::IncompatibleMultiview(
|
||||||
|
self.multiview,
|
||||||
|
other.multiview,
|
||||||
|
));
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2454,6 +2463,11 @@ impl<A: HalApi> Device<A> {
|
|||||||
.get(pipeline_layout_id)
|
.get(pipeline_layout_id)
|
||||||
.map_err(|_| pipeline::CreateRenderPipelineError::InvalidLayout)?;
|
.map_err(|_| pipeline::CreateRenderPipelineError::InvalidLayout)?;
|
||||||
|
|
||||||
|
// Multiview is only supported if the feature is enabled
|
||||||
|
if desc.multiview.is_some() {
|
||||||
|
self.require_features(wgt::Features::MULTIVIEW)?;
|
||||||
|
}
|
||||||
|
|
||||||
let pipeline_desc = hal::RenderPipelineDescriptor {
|
let pipeline_desc = hal::RenderPipelineDescriptor {
|
||||||
label: desc.label.borrow_option(),
|
label: desc.label.borrow_option(),
|
||||||
layout: &layout.raw,
|
layout: &layout.raw,
|
||||||
@ -2464,6 +2478,7 @@ impl<A: HalApi> Device<A> {
|
|||||||
multisample: desc.multisample,
|
multisample: desc.multisample,
|
||||||
fragment_stage,
|
fragment_stage,
|
||||||
color_targets,
|
color_targets,
|
||||||
|
multiview: desc.multiview,
|
||||||
};
|
};
|
||||||
let raw =
|
let raw =
|
||||||
unsafe { self.raw.create_render_pipeline(&pipeline_desc) }.map_err(
|
unsafe { self.raw.create_render_pipeline(&pipeline_desc) }.map_err(
|
||||||
@ -2490,6 +2505,7 @@ impl<A: HalApi> Device<A> {
|
|||||||
depth_stencil: depth_stencil_state.as_ref().map(|state| state.format),
|
depth_stencil: depth_stencil_state.as_ref().map(|state| state.format),
|
||||||
},
|
},
|
||||||
sample_count: samples,
|
sample_count: samples,
|
||||||
|
multiview: desc.multiview,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut flags = pipeline::PipelineFlags::empty();
|
let mut flags = pipeline::PipelineFlags::empty();
|
||||||
|
@ -27,6 +27,7 @@ pub(crate) fn new_render_bundle_encoder_descriptor<'a>(
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
sample_count: context.sample_count,
|
sample_count: context.sample_count,
|
||||||
|
multiview: context.multiview,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ use crate::{
|
|||||||
id::{DeviceId, PipelineLayoutId, ShaderModuleId},
|
id::{DeviceId, PipelineLayoutId, ShaderModuleId},
|
||||||
validation, Label, LifeGuard, Stored,
|
validation, Label, LifeGuard, Stored,
|
||||||
};
|
};
|
||||||
use std::{borrow::Cow, error::Error, fmt};
|
use std::{borrow::Cow, error::Error, fmt, num::NonZeroU32};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
@ -243,6 +243,9 @@ pub struct RenderPipelineDescriptor<'a> {
|
|||||||
pub multisample: wgt::MultisampleState,
|
pub multisample: wgt::MultisampleState,
|
||||||
/// The fragment processing state for this pipeline.
|
/// The fragment processing state for this pipeline.
|
||||||
pub fragment: Option<FragmentState<'a>>,
|
pub fragment: Option<FragmentState<'a>>,
|
||||||
|
/// 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>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Error)]
|
#[derive(Clone, Debug, Error)]
|
||||||
|
@ -75,12 +75,12 @@ js-sys = { version = "0.3" }
|
|||||||
|
|
||||||
[dependencies.naga]
|
[dependencies.naga]
|
||||||
git = "https://github.com/gfx-rs/naga"
|
git = "https://github.com/gfx-rs/naga"
|
||||||
rev = "eda078d"
|
rev = "29571cc"
|
||||||
#version = "0.7"
|
#version = "0.7"
|
||||||
|
|
||||||
[dev-dependencies.naga]
|
[dev-dependencies.naga]
|
||||||
git = "https://github.com/gfx-rs/naga"
|
git = "https://github.com/gfx-rs/naga"
|
||||||
rev = "eda078d"
|
rev = "29571cc"
|
||||||
#version = "0.7"
|
#version = "0.7"
|
||||||
features = ["wgsl-in"]
|
features = ["wgsl-in"]
|
||||||
|
|
||||||
|
@ -238,6 +238,7 @@ impl<A: hal::Api> Example<A> {
|
|||||||
blend: Some(wgt::BlendState::ALPHA_BLENDING),
|
blend: Some(wgt::BlendState::ALPHA_BLENDING),
|
||||||
write_mask: wgt::ColorWrites::default(),
|
write_mask: wgt::ColorWrites::default(),
|
||||||
}],
|
}],
|
||||||
|
multiview: None,
|
||||||
};
|
};
|
||||||
let pipeline = unsafe { device.create_render_pipeline(&pipeline_desc).unwrap() };
|
let pipeline = unsafe { device.create_render_pipeline(&pipeline_desc).unwrap() };
|
||||||
|
|
||||||
@ -664,6 +665,7 @@ impl<A: hal::Api> Example<A> {
|
|||||||
},
|
},
|
||||||
}],
|
}],
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
|
multiview: None,
|
||||||
};
|
};
|
||||||
unsafe {
|
unsafe {
|
||||||
ctx.encoder.begin_render_pass(&pass_desc);
|
ctx.encoder.begin_render_pass(&pass_desc);
|
||||||
|
@ -93,7 +93,7 @@ pub use vulkan::UpdateAfterBindTypes;
|
|||||||
use std::{
|
use std::{
|
||||||
borrow::Borrow,
|
borrow::Borrow,
|
||||||
fmt,
|
fmt,
|
||||||
num::NonZeroU8,
|
num::{NonZeroU32, NonZeroU8},
|
||||||
ops::{Range, RangeInclusive},
|
ops::{Range, RangeInclusive},
|
||||||
ptr::NonNull,
|
ptr::NonNull,
|
||||||
};
|
};
|
||||||
@ -991,6 +991,9 @@ pub struct RenderPipelineDescriptor<'a, A: Api> {
|
|||||||
pub fragment_stage: Option<ProgrammableStage<'a, A>>,
|
pub fragment_stage: Option<ProgrammableStage<'a, A>>,
|
||||||
/// The effect of draw calls on the color aspect of the output target.
|
/// The effect of draw calls on the color aspect of the output target.
|
||||||
pub color_targets: &'a [wgt::ColorTargetState],
|
pub color_targets: &'a [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>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specifies how the alpha channel of the textures should be handled during (martin mouv i step)
|
/// Specifies how the alpha channel of the textures should be handled during (martin mouv i step)
|
||||||
@ -1144,6 +1147,7 @@ pub struct RenderPassDescriptor<'a, A: Api> {
|
|||||||
pub sample_count: u32,
|
pub sample_count: u32,
|
||||||
pub color_attachments: &'a [ColorAttachment<'a, A>],
|
pub color_attachments: &'a [ColorAttachment<'a, A>],
|
||||||
pub depth_stencil_attachment: Option<DepthStencilAttachment<'a, A>>,
|
pub depth_stencil_attachment: Option<DepthStencilAttachment<'a, A>>,
|
||||||
|
pub multiview: Option<NonZeroU32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -16,6 +16,7 @@ fn indexing_features() -> wgt::Features {
|
|||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct PhysicalDeviceFeatures {
|
pub struct PhysicalDeviceFeatures {
|
||||||
core: vk::PhysicalDeviceFeatures,
|
core: vk::PhysicalDeviceFeatures,
|
||||||
|
vulkan_1_1: Option<vk::PhysicalDeviceVulkan11Features>,
|
||||||
pub(super) vulkan_1_2: Option<vk::PhysicalDeviceVulkan12Features>,
|
pub(super) vulkan_1_2: Option<vk::PhysicalDeviceVulkan12Features>,
|
||||||
pub(super) descriptor_indexing: Option<vk::PhysicalDeviceDescriptorIndexingFeaturesEXT>,
|
pub(super) descriptor_indexing: Option<vk::PhysicalDeviceDescriptorIndexingFeaturesEXT>,
|
||||||
imageless_framebuffer: Option<vk::PhysicalDeviceImagelessFramebufferFeaturesKHR>,
|
imageless_framebuffer: Option<vk::PhysicalDeviceImagelessFramebufferFeaturesKHR>,
|
||||||
@ -23,6 +24,7 @@ pub struct PhysicalDeviceFeatures {
|
|||||||
image_robustness: Option<vk::PhysicalDeviceImageRobustnessFeaturesEXT>,
|
image_robustness: Option<vk::PhysicalDeviceImageRobustnessFeaturesEXT>,
|
||||||
robustness2: Option<vk::PhysicalDeviceRobustness2FeaturesEXT>,
|
robustness2: Option<vk::PhysicalDeviceRobustness2FeaturesEXT>,
|
||||||
depth_clip_enable: Option<vk::PhysicalDeviceDepthClipEnableFeaturesEXT>,
|
depth_clip_enable: Option<vk::PhysicalDeviceDepthClipEnableFeaturesEXT>,
|
||||||
|
multiview: Option<vk::PhysicalDeviceMultiviewFeaturesKHR>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is safe because the structs have `p_next: *mut c_void`, which we null out/never read.
|
// This is safe because the structs have `p_next: *mut c_void`, which we null out/never read.
|
||||||
@ -159,6 +161,15 @@ impl PhysicalDeviceFeatures {
|
|||||||
//.shader_resource_residency(requested_features.contains(wgt::Features::SHADER_RESOURCE_RESIDENCY))
|
//.shader_resource_residency(requested_features.contains(wgt::Features::SHADER_RESOURCE_RESIDENCY))
|
||||||
.geometry_shader(requested_features.contains(wgt::Features::SHADER_PRIMITIVE_INDEX))
|
.geometry_shader(requested_features.contains(wgt::Features::SHADER_PRIMITIVE_INDEX))
|
||||||
.build(),
|
.build(),
|
||||||
|
vulkan_1_1: if api_version >= vk::API_VERSION_1_1 {
|
||||||
|
Some(
|
||||||
|
vk::PhysicalDeviceVulkan11Features::builder()
|
||||||
|
.multiview(requested_features.contains(wgt::Features::MULTIVIEW))
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
vulkan_1_2: if api_version >= vk::API_VERSION_1_2 {
|
vulkan_1_2: if api_version >= vk::API_VERSION_1_2 {
|
||||||
Some(
|
Some(
|
||||||
vk::PhysicalDeviceVulkan12Features::builder()
|
vk::PhysicalDeviceVulkan12Features::builder()
|
||||||
@ -295,6 +306,15 @@ impl PhysicalDeviceFeatures {
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
|
multiview: if enabled_extensions.contains(&vk::KhrMultiviewFn::name()) {
|
||||||
|
Some(
|
||||||
|
vk::PhysicalDeviceMultiviewFeatures::builder()
|
||||||
|
.multiview(requested_features.contains(wgt::Features::MULTIVIEW))
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,6 +410,10 @@ impl PhysicalDeviceFeatures {
|
|||||||
|
|
||||||
let intel_windows = caps.properties.vendor_id == db::intel::VENDOR && cfg!(windows);
|
let intel_windows = caps.properties.vendor_id == db::intel::VENDOR && cfg!(windows);
|
||||||
|
|
||||||
|
if let Some(ref vulkan_1_1) = self.vulkan_1_1 {
|
||||||
|
features.set(F::MULTIVIEW, vulkan_1_1.multiview != 0);
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(ref vulkan_1_2) = self.vulkan_1_2 {
|
if let Some(ref vulkan_1_2) = self.vulkan_1_2 {
|
||||||
const STORAGE: F = F::STORAGE_RESOURCE_BINDING_ARRAY;
|
const STORAGE: F = F::STORAGE_RESOURCE_BINDING_ARRAY;
|
||||||
if Self::all_features_supported(
|
if Self::all_features_supported(
|
||||||
@ -479,6 +503,10 @@ impl PhysicalDeviceFeatures {
|
|||||||
features.set(F::DEPTH_CLIP_CONTROL, feature.depth_clip_enable != 0);
|
features.set(F::DEPTH_CLIP_CONTROL, feature.depth_clip_enable != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(ref multiview) = self.multiview {
|
||||||
|
features.set(F::MULTIVIEW, multiview.multiview != 0);
|
||||||
|
}
|
||||||
|
|
||||||
(features, dl_flags)
|
(features, dl_flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -522,6 +550,11 @@ impl PhysicalDeviceCapabilities {
|
|||||||
extensions.push(vk::KhrMaintenance1Fn::name());
|
extensions.push(vk::KhrMaintenance1Fn::name());
|
||||||
extensions.push(vk::KhrMaintenance2Fn::name());
|
extensions.push(vk::KhrMaintenance2Fn::name());
|
||||||
|
|
||||||
|
// Below Vulkan 1.1 we can get multiview from an extension
|
||||||
|
if requested_features.contains(wgt::Features::MULTIVIEW) {
|
||||||
|
extensions.push(vk::KhrMultiviewFn::name());
|
||||||
|
}
|
||||||
|
|
||||||
// `VK_AMD_negative_viewport_height` is obsoleted by `VK_KHR_maintenance1` and must not be enabled alongside `VK_KHR_maintenance1` or a 1.1+ device.
|
// `VK_AMD_negative_viewport_height` is obsoleted by `VK_KHR_maintenance1` and must not be enabled alongside `VK_KHR_maintenance1` or a 1.1+ device.
|
||||||
if !self.supports_extension(vk::KhrMaintenance1Fn::name()) {
|
if !self.supports_extension(vk::KhrMaintenance1Fn::name()) {
|
||||||
extensions.push(vk::AmdNegativeViewportHeightFn::name());
|
extensions.push(vk::AmdNegativeViewportHeightFn::name());
|
||||||
@ -727,6 +760,13 @@ impl super::InstanceShared {
|
|||||||
.features(core)
|
.features(core)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
if capabilities.properties.api_version >= vk::API_VERSION_1_1 {
|
||||||
|
features.vulkan_1_1 = Some(vk::PhysicalDeviceVulkan11Features::builder().build());
|
||||||
|
|
||||||
|
let mut_ref = features.vulkan_1_1.as_mut().unwrap();
|
||||||
|
mut_ref.p_next = mem::replace(&mut features2.p_next, mut_ref as *mut _ as *mut _);
|
||||||
|
}
|
||||||
|
|
||||||
if capabilities.properties.api_version >= vk::API_VERSION_1_2 {
|
if capabilities.properties.api_version >= vk::API_VERSION_1_2 {
|
||||||
features.vulkan_1_2 = Some(vk::PhysicalDeviceVulkan12Features::builder().build());
|
features.vulkan_1_2 = Some(vk::PhysicalDeviceVulkan12Features::builder().build());
|
||||||
|
|
||||||
@ -793,6 +833,7 @@ impl super::InstanceShared {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
null_p_next(&mut features.vulkan_1_1);
|
||||||
null_p_next(&mut features.vulkan_1_2);
|
null_p_next(&mut features.vulkan_1_2);
|
||||||
null_p_next(&mut features.descriptor_indexing);
|
null_p_next(&mut features.descriptor_indexing);
|
||||||
null_p_next(&mut features.imageless_framebuffer);
|
null_p_next(&mut features.imageless_framebuffer);
|
||||||
@ -998,6 +1039,7 @@ impl super::Adapter {
|
|||||||
raw_device: ash::Device,
|
raw_device: ash::Device,
|
||||||
handle_is_owned: bool,
|
handle_is_owned: bool,
|
||||||
enabled_extensions: &[&'static CStr],
|
enabled_extensions: &[&'static CStr],
|
||||||
|
features: wgt::Features,
|
||||||
uab_types: super::UpdateAfterBindTypes,
|
uab_types: super::UpdateAfterBindTypes,
|
||||||
family_index: u32,
|
family_index: u32,
|
||||||
queue_index: u32,
|
queue_index: u32,
|
||||||
@ -1044,7 +1086,8 @@ impl super::Adapter {
|
|||||||
|
|
||||||
let naga_options = {
|
let naga_options = {
|
||||||
use naga::back::spv;
|
use naga::back::spv;
|
||||||
let capabilities = [
|
|
||||||
|
let mut capabilities = vec![
|
||||||
spv::Capability::Shader,
|
spv::Capability::Shader,
|
||||||
spv::Capability::Matrix,
|
spv::Capability::Matrix,
|
||||||
spv::Capability::Sampled1D,
|
spv::Capability::Sampled1D,
|
||||||
@ -1058,6 +1101,11 @@ impl super::Adapter {
|
|||||||
spv::Capability::StorageImageExtendedFormats,
|
spv::Capability::StorageImageExtendedFormats,
|
||||||
//TODO: fill out the rest
|
//TODO: fill out the rest
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if features.contains(wgt::Features::MULTIVIEW) {
|
||||||
|
capabilities.push(spv::Capability::MultiView);
|
||||||
|
}
|
||||||
|
|
||||||
let mut flags = spv::WriterFlags::empty();
|
let mut flags = spv::WriterFlags::empty();
|
||||||
flags.set(
|
flags.set(
|
||||||
spv::WriterFlags::DEBUG,
|
spv::WriterFlags::DEBUG,
|
||||||
@ -1078,17 +1126,17 @@ impl super::Adapter {
|
|||||||
lang_version: (1, 0),
|
lang_version: (1, 0),
|
||||||
flags,
|
flags,
|
||||||
capabilities: Some(capabilities.iter().cloned().collect()),
|
capabilities: Some(capabilities.iter().cloned().collect()),
|
||||||
bounds_check_policies: naga::back::BoundsCheckPolicies {
|
bounds_check_policies: naga::proc::BoundsCheckPolicies {
|
||||||
index: naga::back::BoundsCheckPolicy::Restrict,
|
index: naga::proc::BoundsCheckPolicy::Restrict,
|
||||||
buffer: if self.private_caps.robust_buffer_access {
|
buffer: if self.private_caps.robust_buffer_access {
|
||||||
naga::back::BoundsCheckPolicy::Unchecked
|
naga::proc::BoundsCheckPolicy::Unchecked
|
||||||
} else {
|
} else {
|
||||||
naga::back::BoundsCheckPolicy::Restrict
|
naga::proc::BoundsCheckPolicy::Restrict
|
||||||
},
|
},
|
||||||
image: if self.private_caps.robust_image_access {
|
image: if self.private_caps.robust_image_access {
|
||||||
naga::back::BoundsCheckPolicy::Unchecked
|
naga::proc::BoundsCheckPolicy::Unchecked
|
||||||
} else {
|
} else {
|
||||||
naga::back::BoundsCheckPolicy::Restrict
|
naga::proc::BoundsCheckPolicy::Restrict
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -1222,6 +1270,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
|
|||||||
raw_device,
|
raw_device,
|
||||||
true,
|
true,
|
||||||
&enabled_extensions,
|
&enabled_extensions,
|
||||||
|
features,
|
||||||
uab_types,
|
uab_types,
|
||||||
family_info.queue_family_index,
|
family_info.queue_family_index,
|
||||||
0,
|
0,
|
||||||
|
@ -379,6 +379,15 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
|
|||||||
vk_image_views.push(at.view.raw);
|
vk_image_views.push(at.view.raw);
|
||||||
fb_key.attachments.push(at.view.attachment.clone());
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if let Some(ref ds) = desc.depth_stencil_attachment {
|
if let Some(ref ds) = desc.depth_stencil_attachment {
|
||||||
vk_clear_values.push(vk::ClearValue {
|
vk_clear_values.push(vk::ClearValue {
|
||||||
@ -393,8 +402,15 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
|
|||||||
stencil_ops: ds.stencil_ops,
|
stencil_ops: ds.stencil_ops,
|
||||||
});
|
});
|
||||||
fb_key.attachments.push(ds.target.view.attachment.clone());
|
fb_key.attachments.push(ds.target.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!(ds.target.view.layers, multiview);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rp_key.sample_count = fb_key.sample_count;
|
rp_key.sample_count = fb_key.sample_count;
|
||||||
|
rp_key.multiview = desc.multiview;
|
||||||
|
|
||||||
let render_area = vk::Rect2D {
|
let render_area = vk::Rect2D {
|
||||||
offset: vk::Offset2D { x: 0, y: 0 },
|
offset: vk::Offset2D { x: 0, y: 0 },
|
||||||
|
@ -5,7 +5,9 @@ use ash::{extensions::khr, vk};
|
|||||||
use inplace_it::inplace_or_alloc_from_iter;
|
use inplace_it::inplace_or_alloc_from_iter;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
use std::{borrow::Cow, collections::hash_map::Entry, ffi::CString, ptr, sync::Arc};
|
use std::{
|
||||||
|
borrow::Cow, collections::hash_map::Entry, ffi::CString, num::NonZeroU32, ptr, sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
impl super::DeviceShared {
|
impl super::DeviceShared {
|
||||||
pub(super) unsafe fn set_object_name(
|
pub(super) unsafe fn set_object_name(
|
||||||
@ -140,10 +142,30 @@ impl super::DeviceShared {
|
|||||||
vk_subpass.build()
|
vk_subpass.build()
|
||||||
}];
|
}];
|
||||||
|
|
||||||
let vk_info = vk::RenderPassCreateInfo::builder()
|
let mut vk_info = vk::RenderPassCreateInfo::builder()
|
||||||
.attachments(&vk_attachments)
|
.attachments(&vk_attachments)
|
||||||
.subpasses(&vk_subpasses);
|
.subpasses(&vk_subpasses);
|
||||||
|
|
||||||
|
let mut multiview_info;
|
||||||
|
let mask;
|
||||||
|
if let Some(multiview) = e.key().multiview {
|
||||||
|
// Sanity checks, better to panic here than cause a driver crash
|
||||||
|
assert!(multiview.get() <= 8);
|
||||||
|
assert!(multiview.get() > 1);
|
||||||
|
|
||||||
|
// Right now we enable all bits on the view masks and correlation masks.
|
||||||
|
// This means we're rendering to all views in the subpass, and that all views
|
||||||
|
// can be rendered concurrently.
|
||||||
|
mask = [(1 << multiview.get()) - 1];
|
||||||
|
|
||||||
|
// On Vulkan 1.1 or later, this is an alias for core functionality
|
||||||
|
multiview_info = vk::RenderPassMultiviewCreateInfoKHR::builder()
|
||||||
|
.view_masks(&mask)
|
||||||
|
.correlation_masks(&mask)
|
||||||
|
.build();
|
||||||
|
vk_info = vk_info.push_next(&mut multiview_info);
|
||||||
|
}
|
||||||
|
|
||||||
let raw = unsafe { self.raw.create_render_pass(&vk_info, None)? };
|
let raw = unsafe { self.raw.create_render_pass(&vk_info, None)? };
|
||||||
|
|
||||||
*e.insert(raw)
|
*e.insert(raw)
|
||||||
@ -605,10 +627,10 @@ impl super::Device {
|
|||||||
let temp_options;
|
let temp_options;
|
||||||
let options = if !runtime_checks {
|
let options = if !runtime_checks {
|
||||||
temp_options = naga::back::spv::Options {
|
temp_options = naga::back::spv::Options {
|
||||||
bounds_check_policies: naga::back::BoundsCheckPolicies {
|
bounds_check_policies: naga::proc::BoundsCheckPolicies {
|
||||||
index: naga::back::BoundsCheckPolicy::Unchecked,
|
index: naga::proc::BoundsCheckPolicy::Unchecked,
|
||||||
buffer: naga::back::BoundsCheckPolicy::Unchecked,
|
buffer: naga::proc::BoundsCheckPolicy::Unchecked,
|
||||||
image: naga::back::BoundsCheckPolicy::Unchecked,
|
image: naga::proc::BoundsCheckPolicy::Unchecked,
|
||||||
},
|
},
|
||||||
..self.naga_options.clone()
|
..self.naga_options.clone()
|
||||||
};
|
};
|
||||||
@ -843,12 +865,15 @@ impl crate::Device<super::Api> for super::Device {
|
|||||||
texture: &super::Texture,
|
texture: &super::Texture,
|
||||||
desc: &crate::TextureViewDescriptor,
|
desc: &crate::TextureViewDescriptor,
|
||||||
) -> Result<super::TextureView, crate::DeviceError> {
|
) -> Result<super::TextureView, crate::DeviceError> {
|
||||||
|
let subresource_range = conv::map_subresource_range(&desc.range, texture.aspects);
|
||||||
let mut vk_info = vk::ImageViewCreateInfo::builder()
|
let mut vk_info = vk::ImageViewCreateInfo::builder()
|
||||||
.flags(vk::ImageViewCreateFlags::empty())
|
.flags(vk::ImageViewCreateFlags::empty())
|
||||||
.image(texture.raw)
|
.image(texture.raw)
|
||||||
.view_type(conv::map_view_dimension(desc.dimension))
|
.view_type(conv::map_view_dimension(desc.dimension))
|
||||||
.format(self.shared.private_caps.map_texture_format(desc.format))
|
.format(self.shared.private_caps.map_texture_format(desc.format))
|
||||||
.subresource_range(conv::map_subresource_range(&desc.range, texture.aspects));
|
.subresource_range(subresource_range);
|
||||||
|
let layers =
|
||||||
|
NonZeroU32::new(subresource_range.layer_count).expect("Unexpected zero layer count");
|
||||||
|
|
||||||
let mut image_view_info;
|
let mut image_view_info;
|
||||||
let view_usage = if self.shared.private_caps.image_view_usage && !desc.usage.is_empty() {
|
let view_usage = if self.shared.private_caps.image_view_usage && !desc.usage.is_empty() {
|
||||||
@ -879,7 +904,11 @@ impl crate::Device<super::Api> for super::Device {
|
|||||||
view_format: desc.format,
|
view_format: desc.format,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(super::TextureView { raw, attachment })
|
Ok(super::TextureView {
|
||||||
|
raw,
|
||||||
|
layers,
|
||||||
|
attachment,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
unsafe fn destroy_texture_view(&self, view: super::TextureView) {
|
unsafe fn destroy_texture_view(&self, view: super::TextureView) {
|
||||||
if !self.shared.private_caps.imageless_framebuffers {
|
if !self.shared.private_caps.imageless_framebuffers {
|
||||||
@ -1286,10 +1315,10 @@ impl crate::Device<super::Api> for super::Device {
|
|||||||
}
|
}
|
||||||
let mut naga_options = self.naga_options.clone();
|
let mut naga_options = self.naga_options.clone();
|
||||||
if !desc.runtime_checks {
|
if !desc.runtime_checks {
|
||||||
naga_options.bounds_check_policies = naga::back::BoundsCheckPolicies {
|
naga_options.bounds_check_policies = naga::proc::BoundsCheckPolicies {
|
||||||
index: naga::back::BoundsCheckPolicy::Unchecked,
|
index: naga::proc::BoundsCheckPolicy::Unchecked,
|
||||||
buffer: naga::back::BoundsCheckPolicy::Unchecked,
|
buffer: naga::proc::BoundsCheckPolicy::Unchecked,
|
||||||
image: naga::back::BoundsCheckPolicy::Unchecked,
|
image: naga::proc::BoundsCheckPolicy::Unchecked,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Cow::Owned(
|
Cow::Owned(
|
||||||
@ -1335,6 +1364,7 @@ impl crate::Device<super::Api> for super::Device {
|
|||||||
];
|
];
|
||||||
let mut compatible_rp_key = super::RenderPassKey {
|
let mut compatible_rp_key = super::RenderPassKey {
|
||||||
sample_count: desc.multisample.count,
|
sample_count: desc.multisample.count,
|
||||||
|
multiview: desc.multiview,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let mut stages = ArrayVec::<_, 2>::new();
|
let mut stages = ArrayVec::<_, 2>::new();
|
||||||
|
@ -31,7 +31,7 @@ mod conv;
|
|||||||
mod device;
|
mod device;
|
||||||
mod instance;
|
mod instance;
|
||||||
|
|
||||||
use std::{borrow::Borrow, ffi::CStr, sync::Arc};
|
use std::{borrow::Borrow, ffi::CStr, num::NonZeroU32, sync::Arc};
|
||||||
|
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
use ash::{
|
use ash::{
|
||||||
@ -210,6 +210,7 @@ struct RenderPassKey {
|
|||||||
colors: ArrayVec<ColorAttachmentKey, { crate::MAX_COLOR_TARGETS }>,
|
colors: ArrayVec<ColorAttachmentKey, { crate::MAX_COLOR_TARGETS }>,
|
||||||
depth_stencil: Option<DepthStencilAttachmentKey>,
|
depth_stencil: Option<DepthStencilAttachmentKey>,
|
||||||
sample_count: u32,
|
sample_count: u32,
|
||||||
|
multiview: Option<NonZeroU32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||||
@ -373,6 +374,7 @@ impl Texture {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TextureView {
|
pub struct TextureView {
|
||||||
raw: vk::ImageView,
|
raw: vk::ImageView,
|
||||||
|
layers: NonZeroU32,
|
||||||
attachment: FramebufferAttachment,
|
attachment: FramebufferAttachment,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -526,6 +526,13 @@ bitflags::bitflags! {
|
|||||||
///
|
///
|
||||||
/// This is a native only feature.
|
/// This is a native only feature.
|
||||||
const SHADER_PRIMITIVE_INDEX = 1 << 39;
|
const SHADER_PRIMITIVE_INDEX = 1 << 39;
|
||||||
|
/// Enables multiview render passes and `builtin(view_index)` in vertex shaders.
|
||||||
|
///
|
||||||
|
/// Supported platforms:
|
||||||
|
/// - Vulkan
|
||||||
|
///
|
||||||
|
/// This is a native only feature.
|
||||||
|
const MULTIVIEW = 1 << 40;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,20 +135,20 @@ env_logger = "0.8"
|
|||||||
|
|
||||||
[dependencies.naga]
|
[dependencies.naga]
|
||||||
git = "https://github.com/gfx-rs/naga"
|
git = "https://github.com/gfx-rs/naga"
|
||||||
rev = "eda078d"
|
rev = "29571cc"
|
||||||
#version = "0.7"
|
#version = "0.7"
|
||||||
optional = true
|
optional = true
|
||||||
|
|
||||||
# used to test all the example shaders
|
# used to test all the example shaders
|
||||||
[dev-dependencies.naga]
|
[dev-dependencies.naga]
|
||||||
git = "https://github.com/gfx-rs/naga"
|
git = "https://github.com/gfx-rs/naga"
|
||||||
rev = "eda078d"
|
rev = "29571cc"
|
||||||
#version = "0.7"
|
#version = "0.7"
|
||||||
features = ["wgsl-in"]
|
features = ["wgsl-in"]
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies.naga]
|
[target.'cfg(target_arch = "wasm32")'.dependencies.naga]
|
||||||
git = "https://github.com/gfx-rs/naga"
|
git = "https://github.com/gfx-rs/naga"
|
||||||
rev = "eda078d"
|
rev = "29571cc"
|
||||||
#version = "0.7"
|
#version = "0.7"
|
||||||
features = ["wgsl-out"]
|
features = ["wgsl-out"]
|
||||||
|
|
||||||
|
@ -159,6 +159,7 @@ impl framework::Example for Example {
|
|||||||
primitive: wgpu::PrimitiveState::default(),
|
primitive: wgpu::PrimitiveState::default(),
|
||||||
depth_stencil: None,
|
depth_stencil: None,
|
||||||
multisample: wgpu::MultisampleState::default(),
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
// create compute pipeline
|
// create compute pipeline
|
||||||
|
@ -127,6 +127,7 @@ impl framework::Example for Example {
|
|||||||
},
|
},
|
||||||
depth_stencil: None,
|
depth_stencil: None,
|
||||||
multisample: wgpu::MultisampleState::default(),
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
let texture = {
|
let texture = {
|
||||||
|
@ -113,6 +113,7 @@ impl framework::Example for Example {
|
|||||||
},
|
},
|
||||||
depth_stencil: None,
|
depth_stencil: None,
|
||||||
multisample: wgpu::MultisampleState::default(),
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
let pipeline_triangle_regular =
|
let pipeline_triangle_regular =
|
||||||
@ -132,6 +133,7 @@ impl framework::Example for Example {
|
|||||||
primitive: wgpu::PrimitiveState::default(),
|
primitive: wgpu::PrimitiveState::default(),
|
||||||
depth_stencil: None,
|
depth_stencil: None,
|
||||||
multisample: wgpu::MultisampleState::default(),
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
let pipeline_lines = if device
|
let pipeline_lines = if device
|
||||||
@ -159,6 +161,7 @@ impl framework::Example for Example {
|
|||||||
},
|
},
|
||||||
depth_stencil: None,
|
depth_stencil: None,
|
||||||
multisample: wgpu::MultisampleState::default(),
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
@ -215,6 +218,7 @@ impl framework::Example for Example {
|
|||||||
primitive: wgpu::PrimitiveState::default(),
|
primitive: wgpu::PrimitiveState::default(),
|
||||||
depth_stencil: None,
|
depth_stencil: None,
|
||||||
multisample: wgpu::MultisampleState::default(),
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
}),
|
}),
|
||||||
bind_group_layout,
|
bind_group_layout,
|
||||||
)
|
)
|
||||||
|
@ -260,6 +260,7 @@ impl framework::Example for Example {
|
|||||||
},
|
},
|
||||||
depth_stencil: None,
|
depth_stencil: None,
|
||||||
multisample: wgpu::MultisampleState::default(),
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
let pipeline_wire = if device.features().contains(wgt::Features::POLYGON_MODE_LINE) {
|
let pipeline_wire = if device.features().contains(wgt::Features::POLYGON_MODE_LINE) {
|
||||||
@ -295,6 +296,7 @@ impl framework::Example for Example {
|
|||||||
},
|
},
|
||||||
depth_stencil: None,
|
depth_stencil: None,
|
||||||
multisample: wgpu::MultisampleState::default(),
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
});
|
});
|
||||||
Some(pipeline_wire)
|
Some(pipeline_wire)
|
||||||
} else {
|
} else {
|
||||||
|
@ -64,6 +64,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
|
|||||||
primitive: wgpu::PrimitiveState::default(),
|
primitive: wgpu::PrimitiveState::default(),
|
||||||
depth_stencil: None,
|
depth_stencil: None,
|
||||||
multisample: wgpu::MultisampleState::default(),
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut config = wgpu::SurfaceConfiguration {
|
let mut config = wgpu::SurfaceConfiguration {
|
||||||
|
@ -104,6 +104,7 @@ impl Example {
|
|||||||
},
|
},
|
||||||
depth_stencil: None,
|
depth_stencil: None,
|
||||||
multisample: wgpu::MultisampleState::default(),
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
let bind_group_layout = pipeline.get_bind_group_layout(0);
|
let bind_group_layout = pipeline.get_bind_group_layout(0);
|
||||||
@ -300,6 +301,7 @@ impl framework::Example for Example {
|
|||||||
},
|
},
|
||||||
depth_stencil: None,
|
depth_stencil: None,
|
||||||
multisample: wgpu::MultisampleState::default(),
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create bind group
|
// Create bind group
|
||||||
|
@ -72,6 +72,7 @@ impl Example {
|
|||||||
count: sample_count,
|
count: sample_count,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
multiview: None,
|
||||||
});
|
});
|
||||||
let mut encoder =
|
let mut encoder =
|
||||||
device.create_render_bundle_encoder(&wgpu::RenderBundleEncoderDescriptor {
|
device.create_render_bundle_encoder(&wgpu::RenderBundleEncoderDescriptor {
|
||||||
@ -79,6 +80,7 @@ impl Example {
|
|||||||
color_formats: &[config.format],
|
color_formats: &[config.format],
|
||||||
depth_stencil: None,
|
depth_stencil: None,
|
||||||
sample_count,
|
sample_count,
|
||||||
|
multiview: None,
|
||||||
});
|
});
|
||||||
encoder.set_pipeline(&pipeline);
|
encoder.set_pipeline(&pipeline);
|
||||||
encoder.set_vertex_buffer(0, vertex_buffer.slice(..));
|
encoder.set_vertex_buffer(0, vertex_buffer.slice(..));
|
||||||
|
@ -527,6 +527,7 @@ impl framework::Example for Example {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
multisample: wgpu::MultisampleState::default(),
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
Pass {
|
Pass {
|
||||||
@ -658,6 +659,7 @@ impl framework::Example for Example {
|
|||||||
bias: wgpu::DepthBiasState::default(),
|
bias: wgpu::DepthBiasState::default(),
|
||||||
}),
|
}),
|
||||||
multisample: wgpu::MultisampleState::default(),
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
Pass {
|
Pass {
|
||||||
|
@ -223,6 +223,7 @@ impl framework::Example for Skybox {
|
|||||||
bias: wgpu::DepthBiasState::default(),
|
bias: wgpu::DepthBiasState::default(),
|
||||||
}),
|
}),
|
||||||
multisample: wgpu::MultisampleState::default(),
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
});
|
});
|
||||||
let entity_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
let entity_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
label: Some("Entity"),
|
label: Some("Entity"),
|
||||||
@ -253,6 +254,7 @@ impl framework::Example for Skybox {
|
|||||||
bias: wgpu::DepthBiasState::default(),
|
bias: wgpu::DepthBiasState::default(),
|
||||||
}),
|
}),
|
||||||
multisample: wgpu::MultisampleState::default(),
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
|
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
|
||||||
|
@ -250,6 +250,7 @@ impl framework::Example for Example {
|
|||||||
},
|
},
|
||||||
depth_stencil: None,
|
depth_stencil: None,
|
||||||
multisample: wgpu::MultisampleState::default(),
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
@ -562,6 +562,7 @@ impl framework::Example for Example {
|
|||||||
}),
|
}),
|
||||||
// No multisampling is used.
|
// No multisampling is used.
|
||||||
multisample: wgpu::MultisampleState::default(),
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Same idea as the water pipeline.
|
// Same idea as the water pipeline.
|
||||||
@ -595,6 +596,7 @@ impl framework::Example for Example {
|
|||||||
bias: wgpu::DepthBiasState::default(),
|
bias: wgpu::DepthBiasState::default(),
|
||||||
}),
|
}),
|
||||||
multisample: wgpu::MultisampleState::default(),
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Done
|
// Done
|
||||||
|
@ -1285,6 +1285,7 @@ impl crate::Context for Context {
|
|||||||
},
|
},
|
||||||
targets: Borrowed(frag.targets),
|
targets: Borrowed(frag.targets),
|
||||||
}),
|
}),
|
||||||
|
multiview: desc.multiview,
|
||||||
};
|
};
|
||||||
|
|
||||||
let global = &self.0;
|
let global = &self.0;
|
||||||
@ -1506,6 +1507,7 @@ impl crate::Context for Context {
|
|||||||
color_formats: Borrowed(desc.color_formats),
|
color_formats: Borrowed(desc.color_formats),
|
||||||
depth_stencil: desc.depth_stencil,
|
depth_stencil: desc.depth_stencil,
|
||||||
sample_count: desc.sample_count,
|
sample_count: desc.sample_count,
|
||||||
|
multiview: desc.multiview,
|
||||||
};
|
};
|
||||||
match wgc::command::RenderBundleEncoder::new(&descriptor, device.id, None) {
|
match wgc::command::RenderBundleEncoder::new(&descriptor, device.id, None) {
|
||||||
Ok(id) => id,
|
Ok(id) => id,
|
||||||
|
@ -1294,6 +1294,9 @@ pub struct RenderPipelineDescriptor<'a> {
|
|||||||
pub multisample: MultisampleState,
|
pub multisample: MultisampleState,
|
||||||
/// The compiled fragment stage, its entry point, and the color targets.
|
/// The compiled fragment stage, its entry point, and the color targets.
|
||||||
pub fragment: Option<FragmentState<'a>>,
|
pub fragment: Option<FragmentState<'a>>,
|
||||||
|
/// 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>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Describes the attachments of a compute pass.
|
/// Describes the attachments of a compute pass.
|
||||||
@ -1349,6 +1352,8 @@ pub struct RenderBundleEncoderDescriptor<'a> {
|
|||||||
/// Sample count this render bundle is capable of rendering to. This must match the pipelines and
|
/// Sample count this render bundle is capable of rendering to. This must match the pipelines and
|
||||||
/// the renderpasses it is used in.
|
/// the renderpasses it is used in.
|
||||||
pub sample_count: u32,
|
pub sample_count: u32,
|
||||||
|
/// If this render bundle will rendering to multiple array layers in the attachments at the same time.
|
||||||
|
pub multiview: Option<NonZeroU32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Surface texture that can be rendered to.
|
/// Surface texture that can be rendered to.
|
||||||
|
@ -77,6 +77,7 @@ fn pulling_common(
|
|||||||
write_mask: wgpu::ColorWrites::ALL,
|
write_mask: wgpu::ColorWrites::ALL,
|
||||||
}],
|
}],
|
||||||
}),
|
}),
|
||||||
|
multiview: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
let dummy = ctx
|
let dummy = ctx
|
||||||
|
Loading…
Reference in New Issue
Block a user