1731: hal/dx12: support base vertex/instance r=cwfitzgerald a=kvark

**Connections**
Fixes #1725
Depends on https://github.com/gfx-rs/naga/pull/1141, https://github.com/gfx-rs/d3d12-rs/pull/34, and https://github.com/gfx-rs/d3d12-rs/pull/35 (thanks `@msiglreith` for quick reviews!).

**Description**
We allocate one root parameter covering the special constant buffer view with root constants. We set the root constants for each draw, but only on change.

This PR does *not* handle the indirect case. I'll follow-up with this.

**Testing**
Not thoroughly tested, but `@cwfitzgerald` already implemented a test for this, and this PR enables it on DX12.
Also, examples still seem to work :)


Co-authored-by: Dzmitry Malyshau <kvarkus@gmail.com>
This commit is contained in:
bors[bot] 2021-07-27 13:01:30 +00:00 committed by GitHub
commit 2940347ba3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 186 additions and 136 deletions

5
Cargo.lock generated
View File

@ -459,8 +459,7 @@ dependencies = [
[[package]]
name = "d3d12"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "091ed1b25fe47c7ff129fc440c23650b6114f36aa00bc7212cc8041879294428"
source = "git+https://github.com/gfx-rs/d3d12-rs?rev=79f29c8#79f29c8809d3dc4f97785815567e5efda20e639a"
dependencies = [
"bitflags",
"libloading 0.7.0",
@ -965,7 +964,7 @@ dependencies = [
[[package]]
name = "naga"
version = "0.5.0"
source = "git+https://github.com/gfx-rs/naga?rev=e97c8f9#e97c8f944121a58bbc908ecb64bdf97d4ada039d"
source = "git+https://github.com/gfx-rs/naga?rev=a7ac13a#a7ac13a61d63620b8a0821db9176ed467fc282f7"
dependencies = [
"bit-set",
"bitflags",

View File

@ -36,7 +36,7 @@ thiserror = "1"
[dependencies.naga]
git = "https://github.com/gfx-rs/naga"
rev = "e97c8f9"
rev = "a7ac13a"
features = ["wgsl-in"]
[dependencies.wgt]

View File

@ -1723,6 +1723,7 @@ impl<A: HalApi> Device<A> {
.collect::<Vec<_>>();
let hal_desc = hal::PipelineLayoutDescriptor {
label: desc.label.borrow_option(),
flags: hal::PipelineLayoutFlags::BASE_VERTEX_INSTANCE,
bind_group_layouts: &bgl_vec,
push_constant_ranges: desc.push_constant_ranges.as_ref(),
};

View File

@ -47,7 +47,7 @@ glow = { git = "https://github.com/grovesNL/glow", rev = "0864897a28bbdd43f89f4f
# backend: Dx12
bit-set = { version = "0.5", optional = true }
native = { package = "d3d12", version = "0.4", features = ["libloading"], optional = true }
native = { package = "d3d12", git = "https://github.com/gfx-rs/d3d12-rs", rev = "79f29c8", features = ["libloading"], optional = true }
range-alloc = { version = "0.1", optional = true }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
@ -65,11 +65,11 @@ core-graphics-types = "0.1"
[dependencies.naga]
git = "https://github.com/gfx-rs/naga"
rev = "e97c8f9"
rev = "a7ac13a"
[dev-dependencies.naga]
git = "https://github.com/gfx-rs/naga"
rev = "e97c8f9"
rev = "a7ac13a"
features = ["wgsl-in"]
[dev-dependencies]

View File

@ -199,6 +199,7 @@ impl<A: hal::Api> Example<A> {
let pipeline_layout_desc = hal::PipelineLayoutDescriptor {
label: None,
flags: hal::PipelineLayoutFlags::empty(),
bind_group_layouts: &[&global_group_layout, &local_group_layout],
push_constant_ranges: &[],
};

View File

@ -43,7 +43,7 @@ impl super::CommandEncoder {
self.pass.clear();
}
unsafe fn prepare_draw(&mut self) {
unsafe fn prepare_draw(&mut self, base_vertex: i32, base_instance: u32) {
let list = self.list.unwrap();
while self.pass.dirty_vertex_buffers != 0 {
let index = self.pass.dirty_vertex_buffers.trailing_zeros();
@ -54,6 +54,24 @@ impl super::CommandEncoder {
self.pass.vertex_buffers.as_ptr().offset(index as isize),
);
}
if let Some(root_index) = self.pass.layout.special_constants_root_index {
let needs_update = match self.pass.root_elements[root_index as usize] {
super::RootElement::SpecialConstantBuffer {
base_vertex: other_vertex,
base_instance: other_instance,
} => base_vertex != other_vertex || base_instance != other_instance,
_ => true,
};
if needs_update {
self.pass.root_elements[root_index as usize] =
super::RootElement::SpecialConstantBuffer {
base_vertex,
base_instance,
};
list.set_graphics_root_constant(root_index, base_vertex as u32, 0);
list.set_graphics_root_constant(root_index, base_instance, 1);
}
}
}
fn update_root_elements(&self, range: Range<super::RootIndex>) {
@ -63,6 +81,17 @@ impl super::CommandEncoder {
for index in range {
match self.pass.root_elements[index as usize] {
super::RootElement::Empty => {}
super::RootElement::SpecialConstantBuffer {
base_vertex,
base_instance,
} => match self.pass.kind {
Pk::Render => {
list.set_graphics_root_constant(index, base_vertex as u32, 0);
list.set_graphics_root_constant(index, base_instance, 1);
}
Pk::Compute => (),
Pk::Transfer => (),
},
super::RootElement::Table(descriptor) => match self.pass.kind {
Pk::Render => list.set_graphics_root_descriptor_table(index, descriptor),
Pk::Compute => list.set_compute_root_descriptor_table(index, descriptor),
@ -94,6 +123,18 @@ impl super::CommandEncoder {
}
}
}
fn reset_signature(&mut self, layout: &super::PipelineLayoutShared) {
if let Some(root_index) = layout.special_constants_root_index {
self.pass.root_elements[root_index as usize] =
super::RootElement::SpecialConstantBuffer {
base_vertex: 0,
base_instance: 0,
};
}
self.pass.layout = layout.clone();
self.update_root_elements(0..layout.total_root_elements);
}
}
impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
@ -653,14 +694,13 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
root_index += 1;
}
let update_range = if self.pass.signature == layout.raw {
info.base_root_index..root_index as super::RootIndex
if self.pass.layout.signature == layout.shared.signature {
let update_range = info.base_root_index..root_index as super::RootIndex;
self.update_root_elements(update_range);
} else {
// D3D12 requires full reset on signature change
self.pass.signature = layout.raw;
0..layout.total_root_elements
self.reset_signature(&layout.shared);
};
self.update_root_elements(update_range);
}
unsafe fn set_push_constants(
&mut self,
@ -690,11 +730,10 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
unsafe fn set_render_pipeline(&mut self, pipeline: &super::RenderPipeline) {
let list = self.list.unwrap();
if self.pass.signature != pipeline.signature {
if self.pass.layout.signature != pipeline.layout.signature {
// D3D12 requires full reset on signature change
list.set_graphics_root_signature(pipeline.signature);
self.pass.signature = pipeline.signature;
self.update_root_elements(0..pipeline.total_root_elements);
list.set_graphics_root_signature(pipeline.layout.signature);
self.reset_signature(&pipeline.layout);
};
list.set_pipeline_state(pipeline.raw);
@ -772,7 +811,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
start_instance: u32,
instance_count: u32,
) {
self.prepare_draw();
self.prepare_draw(start_vertex as i32, start_instance);
self.list
.unwrap()
.draw(vertex_count, instance_count, start_vertex, start_instance);
@ -785,7 +824,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
start_instance: u32,
instance_count: u32,
) {
self.prepare_draw();
self.prepare_draw(base_vertex, start_instance);
self.list.unwrap().draw_indexed(
index_count,
instance_count,
@ -800,7 +839,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
offset: wgt::BufferAddress,
draw_count: u32,
) {
self.prepare_draw();
self.prepare_draw(0, 0);
self.list.unwrap().ExecuteIndirect(
self.shared.cmd_signatures.draw.as_mut_ptr(),
draw_count,
@ -816,7 +855,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
offset: wgt::BufferAddress,
draw_count: u32,
) {
self.prepare_draw();
self.prepare_draw(0, 0);
self.list.unwrap().ExecuteIndirect(
self.shared.cmd_signatures.draw_indexed.as_mut_ptr(),
draw_count,
@ -834,7 +873,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
count_offset: wgt::BufferAddress,
max_count: u32,
) {
self.prepare_draw();
self.prepare_draw(0, 0);
self.list.unwrap().ExecuteIndirect(
self.shared.cmd_signatures.draw.as_mut_ptr(),
max_count,
@ -852,7 +891,7 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
count_offset: wgt::BufferAddress,
max_count: u32,
) {
self.prepare_draw();
self.prepare_draw(0, 0);
self.list.unwrap().ExecuteIndirect(
self.shared.cmd_signatures.draw_indexed.as_mut_ptr(),
max_count,
@ -875,11 +914,10 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
unsafe fn set_compute_pipeline(&mut self, pipeline: &super::ComputePipeline) {
let list = self.list.unwrap();
if self.pass.signature != pipeline.signature {
if self.pass.layout.signature != pipeline.layout.signature {
// D3D12 requires full reset on signature change
list.set_compute_root_signature(pipeline.signature);
self.pass.signature = pipeline.signature;
self.update_root_elements(0..pipeline.total_root_elements);
list.set_compute_root_signature(pipeline.layout.signature);
self.reset_signature(&pipeline.layout);
};
list.set_pipeline_state(pipeline.raw);

View File

@ -703,28 +703,53 @@ impl crate::Device<super::Api> for super::Device {
// This is easier than trying to patch up the offset on the shader side.
//
// Root signature layout:
// Root Constants: Register: Offset/4, Space: 0
// Root Constants: Parameter=0, Space=0
// Special constant buffer: Space=0
// ...
// (bind group [3]) - Space: 1
// (bind group [3]) - Space=0
// View descriptor table, if any
// Sampler descriptor table, if any
// Root descriptors (for dynamic offset buffers)
// (bind group [2]) - Space: 2
// (bind group [2]) - Space=0
// ...
// (bind group [0]) - Space: 4
// (bind group [0]) - Space=0
//Note: lower bind group indices are put futher down the root signature. See:
// https://microsoft.github.io/DirectX-Specs/d3d/ResourceBinding.html#binding-model
fn native_binding(bt: &hlsl::BindTarget) -> native::Binding {
native::Binding {
space: bt.space as u32,
register: bt.register,
}
}
let mut binding_map = hlsl::BindingMap::default();
let root_constants: &[()] = &[];
let (mut bind_cbv, mut bind_srv, mut bind_uav, mut bind_sampler) = (
hlsl::BindTarget::default(),
hlsl::BindTarget::default(),
hlsl::BindTarget::default(),
hlsl::BindTarget::default(),
);
let mut parameters = Vec::new();
// Number of elements in the root signature.
let total_parameters = root_constants.len() + desc.bind_group_layouts.len() * 2;
// Guarantees that no re-allocation is done, and our pointers are valid
let mut parameters = Vec::with_capacity(total_parameters);
let (special_constants_root_index, special_constants_binding) = if desc
.flags
.contains(crate::PipelineLayoutFlags::BASE_VERTEX_INSTANCE)
{
let parameter_index = parameters.len();
parameters.push(native::RootParameter::constants(
native::ShaderVisibility::VS,
native_binding(&bind_cbv),
2, // 0 = base vertex, 1 = base instance
));
let binding = bind_cbv.clone();
bind_cbv.register += 1;
(Some(parameter_index as u32), Some(binding))
} else {
(None, None)
};
let root_space_offset = if !root_constants.is_empty() { 1 } else { 0 };
// Collect the whole number of bindings we will create upfront.
// It allows us to preallocate enough storage to avoid reallocation,
// which could cause invalid pointers.
@ -745,8 +770,7 @@ impl crate::Device<super::Api> for super::Device {
let mut bind_group_infos =
arrayvec::ArrayVec::<super::BindGroupInfo, { crate::MAX_BIND_GROUPS }>::default();
for (index, bgl) in desc.bind_group_layouts.iter().enumerate() {
let space = root_space_offset + (desc.bind_group_layouts.len() - 1 - index) as u32;
for (index, bgl) in desc.bind_group_layouts.iter().enumerate().rev() {
let mut info = super::BindGroupInfo {
tables: super::TableTypes::empty(),
base_root_index: parameters.len() as u32,
@ -767,8 +791,6 @@ impl crate::Device<super::Api> for super::Device {
}
}
let (mut num_cbv, mut num_srv, mut num_uav) = (0, 0, 0);
// SRV/CBV/UAV descriptor tables
let mut range_base = ranges.len();
for entry in bgl.entries.iter() {
@ -780,31 +802,27 @@ impl crate::Device<super::Api> for super::Device {
| wgt::BindingType::Sampler { .. } => continue,
ref other => conv::map_binding_type(other),
};
let reg_ref = match range_ty {
native::DescriptorRangeType::CBV => &mut num_cbv,
native::DescriptorRangeType::SRV => &mut num_srv,
native::DescriptorRangeType::UAV => &mut num_uav,
let bt = match range_ty {
native::DescriptorRangeType::CBV => &mut bind_cbv,
native::DescriptorRangeType::SRV => &mut bind_srv,
native::DescriptorRangeType::UAV => &mut bind_uav,
native::DescriptorRangeType::Sampler => unreachable!(),
};
let register = *reg_ref;
*reg_ref += 1;
binding_map.insert(
naga::ResourceBinding {
group: index as u32,
binding: entry.binding,
},
hlsl::BindTarget {
space: space as u8,
register,
},
bt.clone(),
);
ranges.push(native::DescriptorRange::new(
range_ty,
entry.count.map_or(1, |count| count.get()),
native::Binding { space, register },
native_binding(bt),
d3d12::D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
));
bt.register += 1;
}
if ranges.len() > range_base {
parameters.push(native::RootParameter::descriptor_table(
@ -821,23 +839,20 @@ impl crate::Device<super::Api> for super::Device {
wgt::BindingType::Sampler { .. } => native::DescriptorRangeType::Sampler,
_ => continue,
};
let register = (ranges.len() - range_base) as u32;
binding_map.insert(
naga::ResourceBinding {
group: index as u32,
binding: entry.binding,
},
hlsl::BindTarget {
space: space as u8,
register,
},
bind_sampler.clone(),
);
ranges.push(native::DescriptorRange::new(
range_ty,
entry.count.map_or(1, |count| count.get()),
native::Binding { space, register },
native_binding(&bind_sampler),
d3d12::D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
));
bind_sampler.register += 1;
}
if ranges.len() > range_base {
parameters.push(native::RootParameter::descriptor_table(
@ -859,49 +874,22 @@ impl crate::Device<super::Api> for super::Device {
_ => continue,
};
let (kind, param, register) = match buffer_ty {
wgt::BufferBindingType::Uniform => {
let binding = native::Binding {
space,
register: num_cbv,
};
(
super::BufferViewKind::Constant,
native::RootParameter::cbv_descriptor(
dynamic_buffers_visibility,
binding,
),
&mut num_cbv,
)
}
wgt::BufferBindingType::Storage { read_only: true } => {
let binding = native::Binding {
space,
register: num_srv,
};
(
super::BufferViewKind::ShaderResource,
native::RootParameter::srv_descriptor(
dynamic_buffers_visibility,
binding,
),
&mut num_srv,
)
}
wgt::BufferBindingType::Storage { read_only: false } => {
let binding = native::Binding {
space,
register: num_uav,
};
(
super::BufferViewKind::UnorderedAccess,
native::RootParameter::uav_descriptor(
dynamic_buffers_visibility,
binding,
),
&mut num_uav,
)
}
let (kind, parameter_ty, bt) = match buffer_ty {
wgt::BufferBindingType::Uniform => (
super::BufferViewKind::Constant,
d3d12::D3D12_ROOT_PARAMETER_TYPE_CBV,
&mut bind_cbv,
),
wgt::BufferBindingType::Storage { read_only: true } => (
super::BufferViewKind::ShaderResource,
d3d12::D3D12_ROOT_PARAMETER_TYPE_SRV,
&mut bind_srv,
),
wgt::BufferBindingType::Storage { read_only: false } => (
super::BufferViewKind::UnorderedAccess,
d3d12::D3D12_ROOT_PARAMETER_TYPE_UAV,
&mut bind_uav,
),
};
binding_map.insert(
@ -909,15 +897,16 @@ impl crate::Device<super::Api> for super::Device {
group: index as u32,
binding: entry.binding,
},
hlsl::BindTarget {
space: space as u8,
register: *register,
},
bt.clone(),
);
*register += 1;
info.dynamic_buffers.push(kind);
parameters.push(param);
parameters.push(native::RootParameter::descriptor(
parameter_ty,
dynamic_buffers_visibility,
native_binding(bt),
));
bt.register += 1;
}
bind_group_infos.push(info);
@ -961,18 +950,22 @@ impl crate::Device<super::Api> for super::Device {
}
Ok(super::PipelineLayout {
raw,
shared: super::PipelineLayoutShared {
signature: raw,
total_root_elements: parameters.len() as super::RootIndex,
special_constants_root_index,
},
bind_group_infos,
total_root_elements: total_parameters as super::RootIndex,
naga_options: hlsl::Options {
shader_model: hlsl::ShaderModel::V5_1,
binding_map,
fake_missing_bindings: false,
special_constants_binding,
},
})
}
unsafe fn destroy_pipeline_layout(&self, pipeline_layout: super::PipelineLayout) {
pipeline_layout.raw.destroy();
pipeline_layout.shared.signature.destroy();
}
unsafe fn create_bind_group(
@ -1224,7 +1217,7 @@ impl crate::Device<super::Api> for super::Device {
};
let raw_desc = d3d12::D3D12_GRAPHICS_PIPELINE_STATE_DESC {
pRootSignature: desc.layout.raw.as_mut_ptr(),
pRootSignature: desc.layout.shared.signature.as_mut_ptr(),
VS: *native::Shader::from_blob(blob_vs),
PS: if blob_fs.is_null() {
*native::Shader::null()
@ -1314,8 +1307,7 @@ impl crate::Device<super::Api> for super::Device {
Ok(super::RenderPipeline {
raw,
signature: desc.layout.raw,
total_root_elements: desc.layout.total_root_elements,
layout: desc.layout.shared.clone(),
topology,
vertex_strides,
})
@ -1331,7 +1323,7 @@ impl crate::Device<super::Api> for super::Device {
let blob_cs = self.load_shader(&desc.stage, desc.layout, naga::ShaderStage::Compute)?;
let pair = self.raw.create_compute_pipeline_state(
desc.layout.raw,
desc.layout.shared.signature,
native::Shader::from_blob(blob_cs),
0,
native::CachedPSO::null(),
@ -1351,8 +1343,7 @@ impl crate::Device<super::Api> for super::Device {
Ok(super::ComputePipeline {
raw,
signature: desc.layout.raw,
total_root_elements: desc.layout.total_root_elements,
layout: desc.layout.shared.clone(),
})
}
unsafe fn destroy_compute_pipeline(&self, pipeline: super::ComputePipeline) {

View File

@ -280,7 +280,10 @@ struct PassResolve {
#[derive(Clone, Copy)]
enum RootElement {
Empty,
//Constant(u32),
SpecialConstantBuffer {
base_vertex: i32,
base_instance: u32,
},
/// Descriptor table.
Table(native::GpuDescriptor),
/// Descriptor for a buffer that has dynamic offset.
@ -300,7 +303,7 @@ enum PassKind {
struct PassState {
has_label: bool,
resolves: ArrayVec<PassResolve, { crate::MAX_COLOR_TARGETS }>,
signature: native::RootSignature,
layout: PipelineLayoutShared,
root_elements: [RootElement; MAX_ROOT_ELEMENTS],
vertex_buffers: [d3d12::D3D12_VERTEX_BUFFER_VIEW; crate::MAX_VERTEX_BUFFERS],
dirty_vertex_buffers: usize,
@ -312,7 +315,11 @@ impl PassState {
PassState {
has_label: false,
resolves: ArrayVec::new(),
signature: native::RootSignature::null(),
layout: PipelineLayoutShared {
signature: native::RootSignature::null(),
total_root_elements: 0,
special_constants_root_index: None,
},
root_elements: [RootElement::Empty; MAX_ROOT_ELEMENTS],
vertex_buffers: [unsafe { mem::zeroed() }; crate::MAX_VERTEX_BUFFERS],
dirty_vertex_buffers: 0,
@ -468,7 +475,7 @@ bitflags::bitflags! {
}
}
// Index into the root signature.
// Element (also known as parameter) index into the root signature.
type RootIndex = u32;
struct BindGroupInfo {
@ -477,18 +484,24 @@ struct BindGroupInfo {
dynamic_buffers: Vec<BufferViewKind>,
}
#[derive(Clone)]
struct PipelineLayoutShared {
signature: native::RootSignature,
total_root_elements: RootIndex,
special_constants_root_index: Option<RootIndex>,
}
unsafe impl Send for PipelineLayoutShared {}
unsafe impl Sync for PipelineLayoutShared {}
pub struct PipelineLayout {
raw: native::RootSignature,
shared: PipelineLayoutShared,
// Storing for each associated bind group, which tables we created
// in the root signature. This is required for binding descriptor sets.
bind_group_infos: ArrayVec<BindGroupInfo, { crate::MAX_BIND_GROUPS }>,
total_root_elements: RootIndex,
naga_options: naga::back::hlsl::Options,
}
unsafe impl Send for PipelineLayout {}
unsafe impl Sync for PipelineLayout {}
#[derive(Debug)]
pub struct ShaderModule {
naga: crate::NagaShader,
@ -497,8 +510,7 @@ pub struct ShaderModule {
pub struct RenderPipeline {
raw: native::PipelineState,
signature: native::RootSignature,
total_root_elements: RootIndex,
layout: PipelineLayoutShared,
topology: d3d12::D3D12_PRIMITIVE_TOPOLOGY,
vertex_strides: [Option<NonZeroU32>; crate::MAX_VERTEX_BUFFERS],
}
@ -508,8 +520,7 @@ unsafe impl Sync for RenderPipeline {}
pub struct ComputePipeline {
raw: native::PipelineState,
signature: native::RootSignature,
total_root_elements: RootIndex,
layout: PipelineLayoutShared,
}
unsafe impl Send for ComputePipeline {}

View File

@ -505,6 +505,14 @@ bitflags!(
}
);
bitflags!(
/// Pipeline layout creation flags.
pub struct PipelineLayoutFlags: u32 {
/// Include support for base vertex/instance drawing.
const BASE_VERTEX_INSTANCE = 0x1;
}
);
bitflags!(
/// Texture format capability flags.
pub struct TextureFormatCapabilities: u32 {
@ -785,6 +793,7 @@ pub struct BindGroupLayoutDescriptor<'a> {
#[derive(Clone, Debug)]
pub struct PipelineLayoutDescriptor<'a, A: Api> {
pub label: Label<'a>,
pub flags: PipelineLayoutFlags,
pub bind_group_layouts: &'a [&'a A::BindGroupLayout],
pub push_constant_ranges: &'a [wgt::PushConstantRange],
}

View File

@ -75,13 +75,13 @@ env_logger = "0.8"
[dependencies.naga]
git = "https://github.com/gfx-rs/naga"
rev = "e97c8f9"
rev = "a7ac13a"
optional = true
# used to test all the example shaders
[dev-dependencies.naga]
git = "https://github.com/gfx-rs/naga"
rev = "e97c8f9"
rev = "a7ac13a"
features = ["wgsl-in"]
[[example]]

View File

@ -472,8 +472,8 @@ fn skybox() {
height: 768,
optional_features: wgpu::Features::default(),
base_test_parameters: framework::test_common::TestParameters::default()
.backend_failure(wgpu::Backends::VULKAN | wgpu::Backends::GL),
tolerance: 2,
.backend_failure(wgpu::Backends::GL),
tolerance: 3,
max_outliers: 3,
});
}

View File

@ -143,7 +143,7 @@ fn draw_vertex_offset() {
initialize_test(
TestParameters::default()
.test_features()
.backend_failure(wgpu::Backends::DX12 | wgpu::Backends::DX11),
.backend_failure(wgpu::Backends::DX11),
|ctx| {
pulling_common(ctx, &[0, 1, 2, 3, 4, 5], |cmb| {
cmb.draw(0..3, 0..1);
@ -167,7 +167,7 @@ fn draw_instanced_offset() {
initialize_test(
TestParameters::default()
.test_features()
.backend_failure(wgpu::Backends::DX12 | wgpu::Backends::DX11),
.backend_failure(wgpu::Backends::DX11),
|ctx| {
pulling_common(ctx, &[0, 1, 2, 3, 4, 5], |cmb| {
cmb.draw(0..3, 0..1);