mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-22 06:44:14 +00:00
Move texture-array example over to wgsl (#2618)
This commit is contained in:
parent
bc850d2a0e
commit
e54a36ee78
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1032,7 +1032,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "naga"
|
||||
version = "0.8.0"
|
||||
source = "git+https://github.com/gfx-rs/naga?rev=85056524#850565243d1d0d03215f13246c94d63e1d4c51cd"
|
||||
source = "git+https://github.com/gfx-rs/naga?rev=1aa91549#1aa9154964238af8c692cf521ff90e1f2395e147"
|
||||
dependencies = [
|
||||
"bit-set",
|
||||
"bitflags",
|
||||
|
@ -170,9 +170,6 @@ fn deserialize_features(features: &wgpu_types::Features) -> Vec<&'static str> {
|
||||
) {
|
||||
return_features.push("uniform-buffer-and-storage-buffer-texture-non-uniform-indexing");
|
||||
}
|
||||
if features.contains(wgpu_types::Features::UNSIZED_BINDING_ARRAY) {
|
||||
return_features.push("unsized-binding-array");
|
||||
}
|
||||
if features.contains(wgpu_types::Features::ADDRESS_MODE_CLAMP_TO_BORDER) {
|
||||
return_features.push("address-mode-clamp-to-border");
|
||||
}
|
||||
@ -341,10 +338,6 @@ impl From<GpuRequiredFeatures> for wgpu_types::Features {
|
||||
.0
|
||||
.contains("uniform-buffer-and-storage-buffer-texture-non-uniform-indexing"),
|
||||
);
|
||||
features.set(
|
||||
wgpu_types::Features::UNSIZED_BINDING_ARRAY,
|
||||
required_features.0.contains("unsized-binding-array"),
|
||||
);
|
||||
features.set(
|
||||
wgpu_types::Features::ADDRESS_MODE_CLAMP_TO_BORDER,
|
||||
required_features.0.contains("address-mode-clamp-to-border"),
|
||||
|
@ -1,5 +1,5 @@
|
||||
(
|
||||
features: 0x0000_0020_0000_0000,
|
||||
features: 0x0000_0010_0000_0000,
|
||||
expectations: [
|
||||
(
|
||||
name: "Quad",
|
||||
|
@ -40,7 +40,7 @@ thiserror = "1"
|
||||
|
||||
[dependencies.naga]
|
||||
git = "https://github.com/gfx-rs/naga"
|
||||
rev = "85056524"
|
||||
rev = "1aa91549"
|
||||
#version = "0.8"
|
||||
features = ["span", "validate", "wgsl-in"]
|
||||
|
||||
|
@ -1145,6 +1145,25 @@ impl<A: HalApi> Device<A> {
|
||||
self.features
|
||||
.contains(wgt::Features::SHADER_PRIMITIVE_INDEX),
|
||||
);
|
||||
caps.set(
|
||||
Caps::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
|
||||
self.features.contains(
|
||||
wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
|
||||
),
|
||||
);
|
||||
caps.set(
|
||||
Caps::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
|
||||
self.features.contains(
|
||||
wgt::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
|
||||
),
|
||||
);
|
||||
// TODO: This needs a proper wgpu feature
|
||||
caps.set(
|
||||
Caps::SAMPLER_NON_UNIFORM_INDEXING,
|
||||
self.features.contains(
|
||||
wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
|
||||
),
|
||||
);
|
||||
let info = naga::valid::Validator::new(naga::valid::ValidationFlags::all(), caps)
|
||||
.validate(&module)
|
||||
.map_err(|inner| {
|
||||
|
@ -867,7 +867,14 @@ impl Interface {
|
||||
Some(ref br) => br.clone(),
|
||||
_ => continue,
|
||||
};
|
||||
let ty = match module.types[var.ty].inner {
|
||||
let naga_ty = &module.types[var.ty].inner;
|
||||
|
||||
let inner_ty = match *naga_ty {
|
||||
naga::TypeInner::BindingArray { base, .. } => &module.types[base].inner,
|
||||
ref ty => ty,
|
||||
};
|
||||
|
||||
let ty = match *inner_ty {
|
||||
naga::TypeInner::Image {
|
||||
dim,
|
||||
arrayed,
|
||||
|
@ -91,14 +91,14 @@ js-sys = { version = "0.3" }
|
||||
|
||||
[dependencies.naga]
|
||||
git = "https://github.com/gfx-rs/naga"
|
||||
rev = "85056524"
|
||||
rev = "1aa91549"
|
||||
#version = "0.8"
|
||||
|
||||
# DEV dependencies
|
||||
|
||||
[dev-dependencies.naga]
|
||||
git = "https://github.com/gfx-rs/naga"
|
||||
rev = "85056524"
|
||||
rev = "1aa91549"
|
||||
#version = "0.8"
|
||||
features = ["wgsl-in"]
|
||||
|
||||
|
@ -91,6 +91,18 @@ impl super::Adapter {
|
||||
)
|
||||
});
|
||||
|
||||
let mut shader_model_support: d3d12::D3D12_FEATURE_DATA_SHADER_MODEL =
|
||||
d3d12::D3D12_FEATURE_DATA_SHADER_MODEL {
|
||||
HighestShaderModel: d3d12::D3D_SHADER_MODEL_6_0,
|
||||
};
|
||||
assert_eq!(0, unsafe {
|
||||
device.CheckFeatureSupport(
|
||||
d3d12::D3D12_FEATURE_SHADER_MODEL,
|
||||
&mut shader_model_support as *mut _ as *mut _,
|
||||
mem::size_of::<d3d12::D3D12_FEATURE_DATA_SHADER_MODEL>() as _,
|
||||
)
|
||||
});
|
||||
|
||||
let mut workarounds = super::Workarounds::default();
|
||||
|
||||
let info = wgt::AdapterInfo {
|
||||
@ -175,11 +187,6 @@ impl super::Adapter {
|
||||
| wgt::Features::DEPTH_CLIP_CONTROL
|
||||
| wgt::Features::INDIRECT_FIRST_INSTANCE
|
||||
| wgt::Features::MAPPABLE_PRIMARY_BUFFERS
|
||||
//TODO: Naga part
|
||||
//| wgt::Features::TEXTURE_BINDING_ARRAY
|
||||
//| wgt::Features::BUFFER_BINDING_ARRAY
|
||||
//| wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY
|
||||
//| wgt::Features::UNSIZED_BINDING_ARRAY
|
||||
| wgt::Features::MULTI_DRAW_INDIRECT
|
||||
| wgt::Features::MULTI_DRAW_INDIRECT_COUNT
|
||||
| wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER
|
||||
@ -204,6 +211,13 @@ impl super::Adapter {
|
||||
!= d3d12::D3D12_CONSERVATIVE_RASTERIZATION_TIER_NOT_SUPPORTED,
|
||||
);
|
||||
|
||||
features.set(
|
||||
wgt::Features::TEXTURE_BINDING_ARRAY
|
||||
| wgt::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING
|
||||
| wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
|
||||
shader_model_support.HighestShaderModel >= d3d12::D3D_SHADER_MODEL_5_1,
|
||||
);
|
||||
|
||||
let base = wgt::Limits::default();
|
||||
|
||||
Some(crate::ExposedAdapter {
|
||||
@ -282,7 +296,7 @@ impl super::Adapter {
|
||||
impl crate::Adapter<super::Api> for super::Adapter {
|
||||
unsafe fn open(
|
||||
&self,
|
||||
features: wgt::Features,
|
||||
_features: wgt::Features,
|
||||
_limits: &wgt::Limits,
|
||||
) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
|
||||
let queue = {
|
||||
@ -297,13 +311,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
|
||||
.into_device_result("Queue creation")?
|
||||
};
|
||||
|
||||
let device = super::Device::new(
|
||||
self.device,
|
||||
queue,
|
||||
features,
|
||||
self.private_caps,
|
||||
&self.library,
|
||||
)?;
|
||||
let device = super::Device::new(self.device, queue, self.private_caps, &self.library)?;
|
||||
Ok(crate::OpenDevice {
|
||||
device,
|
||||
queue: super::Queue {
|
||||
|
@ -21,7 +21,6 @@ impl super::Device {
|
||||
pub(super) fn new(
|
||||
raw: native::Device,
|
||||
present_queue: native::CommandQueue,
|
||||
features: wgt::Features,
|
||||
private_caps: super::PrivateCapabilities,
|
||||
library: &Arc<native::D3D12Lib>,
|
||||
) -> Result<Self, crate::DeviceError> {
|
||||
@ -87,7 +86,6 @@ impl super::Device {
|
||||
let capacity_samplers = 2_048;
|
||||
|
||||
let shared = super::DeviceShared {
|
||||
features,
|
||||
zero_buffer,
|
||||
cmd_signatures: super::CommandSignatures {
|
||||
draw: raw
|
||||
@ -222,13 +220,6 @@ impl super::Device {
|
||||
compile_flags |=
|
||||
d3dcompiler::D3DCOMPILE_DEBUG | d3dcompiler::D3DCOMPILE_SKIP_OPTIMIZATION;
|
||||
}
|
||||
if self
|
||||
.shared
|
||||
.features
|
||||
.contains(wgt::Features::UNSIZED_BINDING_ARRAY)
|
||||
{
|
||||
compile_flags |= d3dcompiler::D3DCOMPILE_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES;
|
||||
}
|
||||
|
||||
let source_name = match stage.module.raw_name {
|
||||
Some(ref cstr) => cstr.as_c_str().as_ptr(),
|
||||
@ -691,16 +682,17 @@ impl crate::Device<super::Api> for super::Device {
|
||||
) -> Result<super::BindGroupLayout, crate::DeviceError> {
|
||||
let (mut num_buffer_views, mut num_samplers, mut num_texture_views) = (0, 0, 0);
|
||||
for entry in desc.entries.iter() {
|
||||
let count = entry.count.map_or(1, NonZeroU32::get);
|
||||
match entry.ty {
|
||||
wgt::BindingType::Buffer {
|
||||
has_dynamic_offset: true,
|
||||
..
|
||||
} => {}
|
||||
wgt::BindingType::Buffer { .. } => num_buffer_views += 1,
|
||||
wgt::BindingType::Buffer { .. } => num_buffer_views += count,
|
||||
wgt::BindingType::Texture { .. } | wgt::BindingType::StorageTexture { .. } => {
|
||||
num_texture_views += 1
|
||||
num_texture_views += count
|
||||
}
|
||||
wgt::BindingType::Sampler { .. } => num_samplers += 1,
|
||||
wgt::BindingType::Sampler { .. } => num_samplers += count,
|
||||
}
|
||||
}
|
||||
|
||||
@ -858,7 +850,10 @@ impl crate::Device<super::Api> for super::Device {
|
||||
group: index as u32,
|
||||
binding: entry.binding,
|
||||
},
|
||||
bt.clone(),
|
||||
hlsl::BindTarget {
|
||||
binding_array_size: entry.count.map(NonZeroU32::get),
|
||||
..bt.clone()
|
||||
},
|
||||
);
|
||||
ranges.push(native::DescriptorRange::new(
|
||||
range_ty,
|
||||
@ -866,7 +861,7 @@ impl crate::Device<super::Api> for super::Device {
|
||||
native_binding(bt),
|
||||
d3d12::D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
|
||||
));
|
||||
bt.register += 1;
|
||||
bt.register += entry.count.map(NonZeroU32::get).unwrap_or(1);
|
||||
}
|
||||
if ranges.len() > range_base {
|
||||
log::debug!(
|
||||
@ -894,7 +889,10 @@ impl crate::Device<super::Api> for super::Device {
|
||||
group: index as u32,
|
||||
binding: entry.binding,
|
||||
},
|
||||
bind_sampler.clone(),
|
||||
hlsl::BindTarget {
|
||||
binding_array_size: entry.count.map(NonZeroU32::get),
|
||||
..bind_sampler.clone()
|
||||
},
|
||||
);
|
||||
ranges.push(native::DescriptorRange::new(
|
||||
range_ty,
|
||||
@ -902,7 +900,7 @@ impl crate::Device<super::Api> for super::Device {
|
||||
native_binding(&bind_sampler),
|
||||
d3d12::D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
|
||||
));
|
||||
bind_sampler.register += 1;
|
||||
bind_sampler.register += entry.count.map(NonZeroU32::get).unwrap_or(1);
|
||||
}
|
||||
if ranges.len() > range_base {
|
||||
log::debug!(
|
||||
@ -953,7 +951,10 @@ impl crate::Device<super::Api> for super::Device {
|
||||
group: index as u32,
|
||||
binding: entry.binding,
|
||||
},
|
||||
bt.clone(),
|
||||
hlsl::BindTarget {
|
||||
binding_array_size: entry.count.map(NonZeroU32::get),
|
||||
..bt.clone()
|
||||
},
|
||||
);
|
||||
info.dynamic_buffers.push(kind);
|
||||
|
||||
@ -969,7 +970,7 @@ impl crate::Device<super::Api> for super::Device {
|
||||
native_binding(bt),
|
||||
));
|
||||
|
||||
bt.register += 1;
|
||||
bt.register += entry.count.map_or(1, NonZeroU32::get);
|
||||
}
|
||||
|
||||
bind_group_infos.push(info);
|
||||
@ -1082,82 +1083,97 @@ impl crate::Device<super::Api> for super::Device {
|
||||
has_dynamic_offset: true,
|
||||
..
|
||||
} => {
|
||||
let data = &desc.buffers[entry.resource_index as usize];
|
||||
dynamic_buffers.push(data.resolve_address());
|
||||
let start = entry.resource_index as usize;
|
||||
let end = start + entry.count as usize;
|
||||
for data in &desc.buffers[start..end] {
|
||||
dynamic_buffers.push(data.resolve_address());
|
||||
}
|
||||
}
|
||||
wgt::BindingType::Buffer { ty, .. } => {
|
||||
let data = &desc.buffers[entry.resource_index as usize];
|
||||
let gpu_address = data.resolve_address();
|
||||
let size = data.resolve_size() as u32;
|
||||
let inner = cpu_views.as_mut().unwrap();
|
||||
let cpu_index = inner.stage.len() as u32;
|
||||
let handle = desc.layout.cpu_heap_views.as_ref().unwrap().at(cpu_index);
|
||||
match ty {
|
||||
wgt::BufferBindingType::Uniform => {
|
||||
let size_mask =
|
||||
d3d12::D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - 1;
|
||||
let raw_desc = d3d12::D3D12_CONSTANT_BUFFER_VIEW_DESC {
|
||||
BufferLocation: gpu_address,
|
||||
SizeInBytes: ((size - 1) | size_mask) + 1,
|
||||
};
|
||||
self.raw.CreateConstantBufferView(&raw_desc, handle);
|
||||
}
|
||||
wgt::BufferBindingType::Storage { read_only: true } => {
|
||||
let mut raw_desc = d3d12::D3D12_SHADER_RESOURCE_VIEW_DESC {
|
||||
Format: dxgiformat::DXGI_FORMAT_R32_TYPELESS,
|
||||
Shader4ComponentMapping:
|
||||
view::D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING,
|
||||
ViewDimension: d3d12::D3D12_SRV_DIMENSION_BUFFER,
|
||||
u: mem::zeroed(),
|
||||
};
|
||||
*raw_desc.u.Buffer_mut() = d3d12::D3D12_BUFFER_SRV {
|
||||
FirstElement: data.offset / 4,
|
||||
NumElements: size / 4,
|
||||
StructureByteStride: 0,
|
||||
Flags: d3d12::D3D12_BUFFER_SRV_FLAG_RAW,
|
||||
};
|
||||
self.raw.CreateShaderResourceView(
|
||||
data.buffer.resource.as_mut_ptr(),
|
||||
&raw_desc,
|
||||
handle,
|
||||
);
|
||||
}
|
||||
wgt::BufferBindingType::Storage { read_only: false } => {
|
||||
let mut raw_desc = d3d12::D3D12_UNORDERED_ACCESS_VIEW_DESC {
|
||||
Format: dxgiformat::DXGI_FORMAT_R32_TYPELESS,
|
||||
ViewDimension: d3d12::D3D12_UAV_DIMENSION_BUFFER,
|
||||
u: mem::zeroed(),
|
||||
};
|
||||
*raw_desc.u.Buffer_mut() = d3d12::D3D12_BUFFER_UAV {
|
||||
FirstElement: data.offset / 4,
|
||||
NumElements: size / 4,
|
||||
StructureByteStride: 0,
|
||||
CounterOffsetInBytes: 0,
|
||||
Flags: d3d12::D3D12_BUFFER_UAV_FLAG_RAW,
|
||||
};
|
||||
self.raw.CreateUnorderedAccessView(
|
||||
data.buffer.resource.as_mut_ptr(),
|
||||
ptr::null_mut(),
|
||||
&raw_desc,
|
||||
handle,
|
||||
);
|
||||
let start = entry.resource_index as usize;
|
||||
let end = start + entry.count as usize;
|
||||
for data in &desc.buffers[start..end] {
|
||||
let gpu_address = data.resolve_address();
|
||||
let size = data.resolve_size() as u32;
|
||||
let inner = cpu_views.as_mut().unwrap();
|
||||
let cpu_index = inner.stage.len() as u32;
|
||||
let handle = desc.layout.cpu_heap_views.as_ref().unwrap().at(cpu_index);
|
||||
match ty {
|
||||
wgt::BufferBindingType::Uniform => {
|
||||
let size_mask =
|
||||
d3d12::D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - 1;
|
||||
let raw_desc = d3d12::D3D12_CONSTANT_BUFFER_VIEW_DESC {
|
||||
BufferLocation: gpu_address,
|
||||
SizeInBytes: ((size - 1) | size_mask) + 1,
|
||||
};
|
||||
self.raw.CreateConstantBufferView(&raw_desc, handle);
|
||||
}
|
||||
wgt::BufferBindingType::Storage { read_only: true } => {
|
||||
let mut raw_desc = d3d12::D3D12_SHADER_RESOURCE_VIEW_DESC {
|
||||
Format: dxgiformat::DXGI_FORMAT_R32_TYPELESS,
|
||||
Shader4ComponentMapping:
|
||||
view::D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING,
|
||||
ViewDimension: d3d12::D3D12_SRV_DIMENSION_BUFFER,
|
||||
u: mem::zeroed(),
|
||||
};
|
||||
*raw_desc.u.Buffer_mut() = d3d12::D3D12_BUFFER_SRV {
|
||||
FirstElement: data.offset / 4,
|
||||
NumElements: size / 4,
|
||||
StructureByteStride: 0,
|
||||
Flags: d3d12::D3D12_BUFFER_SRV_FLAG_RAW,
|
||||
};
|
||||
self.raw.CreateShaderResourceView(
|
||||
data.buffer.resource.as_mut_ptr(),
|
||||
&raw_desc,
|
||||
handle,
|
||||
);
|
||||
}
|
||||
wgt::BufferBindingType::Storage { read_only: false } => {
|
||||
let mut raw_desc = d3d12::D3D12_UNORDERED_ACCESS_VIEW_DESC {
|
||||
Format: dxgiformat::DXGI_FORMAT_R32_TYPELESS,
|
||||
ViewDimension: d3d12::D3D12_UAV_DIMENSION_BUFFER,
|
||||
u: mem::zeroed(),
|
||||
};
|
||||
*raw_desc.u.Buffer_mut() = d3d12::D3D12_BUFFER_UAV {
|
||||
FirstElement: data.offset / 4,
|
||||
NumElements: size / 4,
|
||||
StructureByteStride: 0,
|
||||
CounterOffsetInBytes: 0,
|
||||
Flags: d3d12::D3D12_BUFFER_UAV_FLAG_RAW,
|
||||
};
|
||||
self.raw.CreateUnorderedAccessView(
|
||||
data.buffer.resource.as_mut_ptr(),
|
||||
ptr::null_mut(),
|
||||
&raw_desc,
|
||||
handle,
|
||||
);
|
||||
}
|
||||
}
|
||||
inner.stage.push(handle);
|
||||
}
|
||||
inner.stage.push(handle);
|
||||
}
|
||||
wgt::BindingType::Texture { .. } => {
|
||||
let data = &desc.textures[entry.resource_index as usize];
|
||||
let handle = data.view.handle_srv.unwrap();
|
||||
cpu_views.as_mut().unwrap().stage.push(handle.raw);
|
||||
let start = entry.resource_index as usize;
|
||||
let end = start + entry.count as usize;
|
||||
for data in &desc.textures[start..end] {
|
||||
let handle = data.view.handle_srv.unwrap();
|
||||
cpu_views.as_mut().unwrap().stage.push(handle.raw);
|
||||
}
|
||||
}
|
||||
wgt::BindingType::StorageTexture { .. } => {
|
||||
let data = &desc.textures[entry.resource_index as usize];
|
||||
let handle = data.view.handle_uav.unwrap();
|
||||
cpu_views.as_mut().unwrap().stage.push(handle.raw);
|
||||
let start = entry.resource_index as usize;
|
||||
let end = start + entry.count as usize;
|
||||
for data in &desc.textures[start..end] {
|
||||
let handle = data.view.handle_uav.unwrap();
|
||||
cpu_views.as_mut().unwrap().stage.push(handle.raw);
|
||||
}
|
||||
}
|
||||
wgt::BindingType::Sampler { .. } => {
|
||||
let data = &desc.samplers[entry.resource_index as usize];
|
||||
cpu_samplers.as_mut().unwrap().stage.push(data.handle.raw);
|
||||
let start = entry.resource_index as usize;
|
||||
let end = start + entry.count as usize;
|
||||
for data in &desc.samplers[start..end] {
|
||||
cpu_samplers.as_mut().unwrap().stage.push(data.handle.raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -199,7 +199,6 @@ impl CommandSignatures {
|
||||
}
|
||||
|
||||
struct DeviceShared {
|
||||
features: wgt::Features,
|
||||
zero_buffer: native::Resource,
|
||||
cmd_signatures: CommandSignatures,
|
||||
heap_views: descriptor::GeneralHeap,
|
||||
|
@ -1,5 +1,6 @@
|
||||
use parking_lot::Mutex;
|
||||
use std::{
|
||||
num::NonZeroU32,
|
||||
ptr,
|
||||
sync::{atomic, Arc},
|
||||
thread, time,
|
||||
@ -73,6 +74,13 @@ impl super::Device {
|
||||
)
|
||||
.map_err(|e| crate::PipelineError::Linkage(stage_bit, format!("MSL: {:?}", e)))?;
|
||||
|
||||
log::debug!(
|
||||
"Naga generated shader for entry point '{}' and stage {:?}\n{}",
|
||||
stage.entry_point,
|
||||
naga_stage,
|
||||
&source
|
||||
);
|
||||
|
||||
let options = mtl::CompileOptions::new();
|
||||
options.set_language_version(self.shared.private_caps.msl_version);
|
||||
|
||||
@ -558,10 +566,12 @@ impl crate::Device<super::Api> for super::Device {
|
||||
}
|
||||
|
||||
let mut target = naga::back::msl::BindTarget::default();
|
||||
let count = entry.count.map_or(1, NonZeroU32::get);
|
||||
target.binding_array_size = entry.count.map(NonZeroU32::get);
|
||||
match entry.ty {
|
||||
wgt::BindingType::Buffer { ty, .. } => {
|
||||
target.buffer = Some(info.counters.buffers as _);
|
||||
info.counters.buffers += 1;
|
||||
info.counters.buffers += count;
|
||||
if let wgt::BufferBindingType::Storage { read_only } = ty {
|
||||
target.mutable = !read_only;
|
||||
}
|
||||
@ -570,15 +580,15 @@ impl crate::Device<super::Api> for super::Device {
|
||||
target.sampler = Some(naga::back::msl::BindSamplerTarget::Resource(
|
||||
info.counters.samplers as _,
|
||||
));
|
||||
info.counters.samplers += 1;
|
||||
info.counters.samplers += count;
|
||||
}
|
||||
wgt::BindingType::Texture { .. } => {
|
||||
target.texture = Some(info.counters.textures as _);
|
||||
info.counters.textures += 1;
|
||||
info.counters.textures += count;
|
||||
}
|
||||
wgt::BindingType::StorageTexture { access, .. } => {
|
||||
target.texture = Some(info.counters.textures as _);
|
||||
info.counters.textures += 1;
|
||||
info.counters.textures += count;
|
||||
target.mutable = match access {
|
||||
wgt::StorageTextureAccess::ReadOnly => false,
|
||||
wgt::StorageTextureAccess::WriteOnly => true,
|
||||
@ -667,6 +677,8 @@ impl crate::Device<super::Api> for super::Device {
|
||||
index: naga::proc::BoundsCheckPolicy::ReadZeroSkipWrite,
|
||||
buffer: naga::proc::BoundsCheckPolicy::ReadZeroSkipWrite,
|
||||
image: naga::proc::BoundsCheckPolicy::ReadZeroSkipWrite,
|
||||
// TODO: support bounds checks on binding arrays
|
||||
binding_array: naga::proc::BoundsCheckPolicy::Unchecked,
|
||||
},
|
||||
},
|
||||
total_push_constants,
|
||||
@ -689,7 +701,7 @@ impl crate::Device<super::Api> for super::Device {
|
||||
..
|
||||
} = layout.ty
|
||||
{
|
||||
dynamic_offsets_count += 1;
|
||||
dynamic_offsets_count += size;
|
||||
}
|
||||
if !layout.visibility.contains(stage_bit) {
|
||||
continue;
|
||||
@ -700,39 +712,44 @@ impl crate::Device<super::Api> for super::Device {
|
||||
has_dynamic_offset,
|
||||
..
|
||||
} => {
|
||||
debug_assert_eq!(size, 1);
|
||||
let source = &desc.buffers[entry.resource_index as usize];
|
||||
let remaining_size =
|
||||
wgt::BufferSize::new(source.buffer.size - source.offset);
|
||||
let binding_size = match ty {
|
||||
wgt::BufferBindingType::Storage { .. } => {
|
||||
source.size.or(remaining_size)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
bg.buffers.push(super::BufferResource {
|
||||
ptr: source.buffer.as_raw(),
|
||||
offset: source.offset,
|
||||
dynamic_index: if has_dynamic_offset {
|
||||
Some(dynamic_offsets_count - 1)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
binding_size,
|
||||
binding_location: layout.binding,
|
||||
});
|
||||
let start = entry.resource_index as usize;
|
||||
let end = start + size as usize;
|
||||
bg.buffers
|
||||
.extend(desc.buffers[start..end].iter().map(|source| {
|
||||
let remaining_size =
|
||||
wgt::BufferSize::new(source.buffer.size - source.offset);
|
||||
let binding_size = match ty {
|
||||
wgt::BufferBindingType::Storage { .. } => {
|
||||
source.size.or(remaining_size)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
super::BufferResource {
|
||||
ptr: source.buffer.as_raw(),
|
||||
offset: source.offset,
|
||||
dynamic_index: if has_dynamic_offset {
|
||||
Some(dynamic_offsets_count - 1)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
binding_size,
|
||||
binding_location: layout.binding,
|
||||
}
|
||||
}));
|
||||
counter.buffers += 1;
|
||||
}
|
||||
wgt::BindingType::Sampler { .. } => {
|
||||
let res = desc.samplers[entry.resource_index as usize].as_raw();
|
||||
bg.samplers.push(res);
|
||||
counter.samplers += 1;
|
||||
let start = entry.resource_index as usize;
|
||||
let end = start + size as usize;
|
||||
bg.samplers
|
||||
.extend(desc.samplers[start..end].iter().map(|samp| samp.as_raw()));
|
||||
counter.samplers += size;
|
||||
}
|
||||
wgt::BindingType::Texture { .. } | wgt::BindingType::StorageTexture { .. } => {
|
||||
let start = entry.resource_index;
|
||||
let end = start + size;
|
||||
let start = entry.resource_index as usize;
|
||||
let end = start + size as usize;
|
||||
bg.textures.extend(
|
||||
desc.textures[start as usize..end as usize]
|
||||
desc.textures[start..end]
|
||||
.iter()
|
||||
.map(|tex| tex.view.as_raw()),
|
||||
);
|
||||
|
@ -3,13 +3,12 @@ use super::conv;
|
||||
use ash::{extensions::khr, vk};
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use std::{ffi::CStr, sync::Arc};
|
||||
use std::{collections::BTreeMap, ffi::CStr, sync::Arc};
|
||||
|
||||
//TODO: const fn?
|
||||
fn indexing_features() -> wgt::Features {
|
||||
wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING
|
||||
| wgt::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING
|
||||
| wgt::Features::UNSIZED_BINDING_ARRAY
|
||||
}
|
||||
|
||||
/// Aggregate of the `vk::PhysicalDevice*Features` structs used by `gfx`.
|
||||
@ -212,9 +211,6 @@ impl PhysicalDeviceFeatures {
|
||||
uab_types.contains(super::UpdateAfterBindTypes::STORAGE_BUFFER),
|
||||
)
|
||||
.descriptor_binding_partially_bound(needs_partially_bound)
|
||||
.runtime_descriptor_array(
|
||||
requested_features.contains(wgt::Features::UNSIZED_BINDING_ARRAY),
|
||||
)
|
||||
//.sampler_filter_minmax(requested_features.contains(wgt::Features::SAMPLER_REDUCTION))
|
||||
.imageless_framebuffer(private_caps.imageless_framebuffers)
|
||||
.timeline_semaphore(private_caps.timeline_semaphores)
|
||||
@ -253,9 +249,6 @@ impl PhysicalDeviceFeatures {
|
||||
uab_types.contains(super::UpdateAfterBindTypes::STORAGE_BUFFER),
|
||||
)
|
||||
.descriptor_binding_partially_bound(needs_partially_bound)
|
||||
.runtime_descriptor_array(
|
||||
requested_features.contains(wgt::Features::UNSIZED_BINDING_ARRAY),
|
||||
)
|
||||
.build(),
|
||||
)
|
||||
} else {
|
||||
@ -471,9 +464,6 @@ impl PhysicalDeviceFeatures {
|
||||
) {
|
||||
features.insert(F::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING);
|
||||
}
|
||||
if vulkan_1_2.runtime_descriptor_array != 0 {
|
||||
features |= F::UNSIZED_BINDING_ARRAY;
|
||||
}
|
||||
if vulkan_1_2.descriptor_binding_partially_bound != 0 && !intel_windows {
|
||||
features |= F::PARTIALLY_BOUND_BINDING_ARRAY;
|
||||
}
|
||||
@ -519,9 +509,6 @@ impl PhysicalDeviceFeatures {
|
||||
if descriptor_indexing.descriptor_binding_partially_bound != 0 && !intel_windows {
|
||||
features |= F::PARTIALLY_BOUND_BINDING_ARRAY;
|
||||
}
|
||||
if descriptor_indexing.runtime_descriptor_array != 0 {
|
||||
features |= F::UNSIZED_BINDING_ARRAY;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref feature) = self.depth_clip_enable {
|
||||
@ -1183,6 +1170,13 @@ impl super::Adapter {
|
||||
capabilities.push(spv::Capability::MultiView);
|
||||
}
|
||||
|
||||
if features.intersects(
|
||||
wgt::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING
|
||||
| wgt::Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
|
||||
) {
|
||||
capabilities.push(spv::Capability::ShaderNonUniform);
|
||||
}
|
||||
|
||||
let mut flags = spv::WriterFlags::empty();
|
||||
flags.set(
|
||||
spv::WriterFlags::DEBUG,
|
||||
@ -1215,7 +1209,11 @@ impl super::Adapter {
|
||||
} else {
|
||||
naga::proc::BoundsCheckPolicy::Restrict
|
||||
},
|
||||
// TODO: support bounds checks on binding arrays
|
||||
binding_array: naga::proc::BoundsCheckPolicy::Unchecked,
|
||||
},
|
||||
// We need to build this separately for each invocation, so just default it out here
|
||||
binding_map: BTreeMap::default(),
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -6,7 +6,12 @@ use inplace_it::inplace_or_alloc_from_iter;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use std::{
|
||||
borrow::Cow, collections::hash_map::Entry, ffi::CString, num::NonZeroU32, ptr, sync::Arc,
|
||||
borrow::Cow,
|
||||
collections::{hash_map::Entry, BTreeMap},
|
||||
ffi::CString,
|
||||
num::NonZeroU32,
|
||||
ptr,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
impl super::DeviceShared {
|
||||
@ -628,6 +633,7 @@ impl super::Device {
|
||||
&self,
|
||||
stage: &crate::ProgrammableStage<super::Api>,
|
||||
naga_stage: naga::ShaderStage,
|
||||
binding_map: &naga::back::spv::BindingMap,
|
||||
) -> Result<CompiledStage, crate::PipelineError> {
|
||||
let stage_flags = crate::auxil::map_naga_stage(naga_stage);
|
||||
let vk_module = match *stage.module {
|
||||
@ -640,16 +646,21 @@ impl super::Device {
|
||||
entry_point: stage.entry_point.to_string(),
|
||||
shader_stage: naga_stage,
|
||||
};
|
||||
let temp_options;
|
||||
let options = if !runtime_checks {
|
||||
temp_options = naga::back::spv::Options {
|
||||
bounds_check_policies: naga::proc::BoundsCheckPolicies {
|
||||
let needs_temp_options = !runtime_checks || !binding_map.is_empty();
|
||||
let mut temp_options;
|
||||
let options = if needs_temp_options {
|
||||
temp_options = self.naga_options.clone();
|
||||
if !runtime_checks {
|
||||
temp_options.bounds_check_policies = naga::proc::BoundsCheckPolicies {
|
||||
index: naga::proc::BoundsCheckPolicy::Unchecked,
|
||||
buffer: naga::proc::BoundsCheckPolicy::Unchecked,
|
||||
image: naga::proc::BoundsCheckPolicy::Unchecked,
|
||||
},
|
||||
..self.naga_options.clone()
|
||||
};
|
||||
binding_array: naga::proc::BoundsCheckPolicy::Unchecked,
|
||||
};
|
||||
}
|
||||
if !binding_map.is_empty() {
|
||||
temp_options.binding_map = binding_map.clone();
|
||||
}
|
||||
&temp_options
|
||||
} else {
|
||||
&self.naga_options
|
||||
@ -1100,6 +1111,13 @@ impl crate::Device<super::Api> for super::Device {
|
||||
|
||||
let vk_info = vk::DescriptorSetLayoutCreateInfo::builder().bindings(&vk_bindings);
|
||||
|
||||
let binding_arrays = desc
|
||||
.entries
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(idx, entry)| entry.count.map(|count| (idx as u32, count)))
|
||||
.collect();
|
||||
|
||||
let mut binding_flag_info;
|
||||
let binding_flag_vec;
|
||||
let mut requires_update_after_bind = false;
|
||||
@ -1176,6 +1194,7 @@ impl crate::Device<super::Api> for super::Device {
|
||||
raw,
|
||||
desc_count,
|
||||
types: types.into_boxed_slice(),
|
||||
binding_arrays,
|
||||
requires_update_after_bind,
|
||||
})
|
||||
}
|
||||
@ -1220,7 +1239,25 @@ impl crate::Device<super::Api> for super::Device {
|
||||
.set_object_name(vk::ObjectType::PIPELINE_LAYOUT, raw, label);
|
||||
}
|
||||
|
||||
Ok(super::PipelineLayout { raw })
|
||||
let mut binding_arrays = BTreeMap::new();
|
||||
for (group, &layout) in desc.bind_group_layouts.iter().enumerate() {
|
||||
for &(binding, binding_array_size) in &layout.binding_arrays {
|
||||
binding_arrays.insert(
|
||||
naga::ResourceBinding {
|
||||
group: group as u32,
|
||||
binding,
|
||||
},
|
||||
naga::back::spv::BindingInfo {
|
||||
binding_array_size: Some(binding_array_size.get()),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(super::PipelineLayout {
|
||||
raw,
|
||||
binding_arrays,
|
||||
})
|
||||
}
|
||||
unsafe fn destroy_pipeline_layout(&self, pipeline_layout: super::PipelineLayout) {
|
||||
self.shared
|
||||
@ -1266,11 +1303,15 @@ impl crate::Device<super::Api> for super::Device {
|
||||
write = match ty {
|
||||
vk::DescriptorType::SAMPLER => {
|
||||
let index = sampler_infos.len();
|
||||
let binding = desc.samplers[entry.resource_index as usize];
|
||||
let vk_info = vk::DescriptorImageInfo::builder()
|
||||
.sampler(binding.raw)
|
||||
.build();
|
||||
sampler_infos.push(vk_info);
|
||||
let start = entry.resource_index;
|
||||
let end = start + entry.count;
|
||||
sampler_infos.extend(desc.samplers[start as usize..end as usize].iter().map(
|
||||
|binding| {
|
||||
vk::DescriptorImageInfo::builder()
|
||||
.sampler(binding.raw)
|
||||
.build()
|
||||
},
|
||||
));
|
||||
write.image_info(&sampler_infos[index..])
|
||||
}
|
||||
vk::DescriptorType::SAMPLED_IMAGE | vk::DescriptorType::STORAGE_IMAGE => {
|
||||
@ -1344,6 +1385,7 @@ impl crate::Device<super::Api> for super::Device {
|
||||
index: naga::proc::BoundsCheckPolicy::Unchecked,
|
||||
buffer: naga::proc::BoundsCheckPolicy::Unchecked,
|
||||
image: naga::proc::BoundsCheckPolicy::Unchecked,
|
||||
binding_array: naga::proc::BoundsCheckPolicy::Unchecked,
|
||||
};
|
||||
}
|
||||
Cow::Owned(
|
||||
@ -1425,11 +1467,19 @@ impl crate::Device<super::Api> for super::Device {
|
||||
.primitive_restart_enable(desc.primitive.strip_index_format.is_some())
|
||||
.build();
|
||||
|
||||
let compiled_vs = self.compile_stage(&desc.vertex_stage, naga::ShaderStage::Vertex)?;
|
||||
let compiled_vs = self.compile_stage(
|
||||
&desc.vertex_stage,
|
||||
naga::ShaderStage::Vertex,
|
||||
&desc.layout.binding_arrays,
|
||||
)?;
|
||||
stages.push(compiled_vs.create_info);
|
||||
let compiled_fs = match desc.fragment_stage {
|
||||
Some(ref stage) => {
|
||||
let compiled = self.compile_stage(stage, naga::ShaderStage::Fragment)?;
|
||||
let compiled = self.compile_stage(
|
||||
stage,
|
||||
naga::ShaderStage::Fragment,
|
||||
&desc.layout.binding_arrays,
|
||||
)?;
|
||||
stages.push(compiled.create_info);
|
||||
Some(compiled)
|
||||
}
|
||||
@ -1604,7 +1654,11 @@ impl crate::Device<super::Api> for super::Device {
|
||||
&self,
|
||||
desc: &crate::ComputePipelineDescriptor<super::Api>,
|
||||
) -> Result<super::ComputePipeline, crate::PipelineError> {
|
||||
let compiled = self.compile_stage(&desc.stage, naga::ShaderStage::Compute)?;
|
||||
let compiled = self.compile_stage(
|
||||
&desc.stage,
|
||||
naga::ShaderStage::Compute,
|
||||
&desc.layout.binding_arrays,
|
||||
)?;
|
||||
|
||||
let vk_infos = [{
|
||||
vk::ComputePipelineCreateInfo::builder()
|
||||
|
@ -398,12 +398,15 @@ pub struct BindGroupLayout {
|
||||
raw: vk::DescriptorSetLayout,
|
||||
desc_count: gpu_descriptor::DescriptorTotalCount,
|
||||
types: Box<[(vk::DescriptorType, u32)]>,
|
||||
/// Map of binding index to size,
|
||||
binding_arrays: Vec<(u32, NonZeroU32)>,
|
||||
requires_update_after_bind: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PipelineLayout {
|
||||
raw: vk::PipelineLayout,
|
||||
binding_arrays: naga::back::spv::BindingMap,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -348,16 +348,6 @@ bitflags::bitflags! {
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const PARTIALLY_BOUND_BINDING_ARRAY = 1 << 22;
|
||||
/// Allows the user to create unsized uniform arrays of bindings:
|
||||
///
|
||||
/// eg. `uniform texture2D textures[]`.
|
||||
///
|
||||
/// Supported platforms:
|
||||
/// - DX12
|
||||
/// - Vulkan 1.2+ (or VK_EXT_descriptor_indexing)'s runtimeDescriptorArray feature
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const UNSIZED_BINDING_ARRAY = 1 << 23;
|
||||
/// Allows the user to call [`RenderPass::multi_draw_indirect`] and [`RenderPass::multi_draw_indexed_indirect`].
|
||||
///
|
||||
/// Allows multiple indirect calls to be dispatched from a single buffer.
|
||||
@ -367,7 +357,7 @@ bitflags::bitflags! {
|
||||
/// - Vulkan
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const MULTI_DRAW_INDIRECT = 1 << 24;
|
||||
const MULTI_DRAW_INDIRECT = 1 << 23;
|
||||
/// Allows the user to call [`RenderPass::multi_draw_indirect_count`] and [`RenderPass::multi_draw_indexed_indirect_count`].
|
||||
///
|
||||
/// This allows the use of a buffer containing the actual number of draw calls.
|
||||
@ -377,7 +367,7 @@ bitflags::bitflags! {
|
||||
/// - Vulkan 1.2+ (or VK_KHR_draw_indirect_count)
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const MULTI_DRAW_INDIRECT_COUNT = 1 << 25;
|
||||
const MULTI_DRAW_INDIRECT_COUNT = 1 << 24;
|
||||
/// Allows the use of push constants: small, fast bits of memory that can be updated
|
||||
/// inside a [`RenderPass`].
|
||||
///
|
||||
@ -394,7 +384,7 @@ bitflags::bitflags! {
|
||||
/// - OpenGL (emulated with uniforms)
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const PUSH_CONSTANTS = 1 << 26;
|
||||
const PUSH_CONSTANTS = 1 << 25;
|
||||
/// Allows the use of [`AddressMode::ClampToBorder`] with a border color
|
||||
/// other than [`SamplerBorderColor::Zero`].
|
||||
///
|
||||
@ -406,7 +396,7 @@ bitflags::bitflags! {
|
||||
/// - OpenGL
|
||||
///
|
||||
/// This is a web and native feature.
|
||||
const ADDRESS_MODE_CLAMP_TO_BORDER = 1 << 27;
|
||||
const ADDRESS_MODE_CLAMP_TO_BORDER = 1 << 26;
|
||||
/// Allows the user to set [`PolygonMode::Line`] in [`PrimitiveState::polygon_mode`]
|
||||
///
|
||||
/// This allows drawing polygons/triangles as lines (wireframe) instead of filled
|
||||
@ -417,7 +407,7 @@ bitflags::bitflags! {
|
||||
/// - Metal
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const POLYGON_MODE_LINE = 1 << 28;
|
||||
const POLYGON_MODE_LINE = 1 << 27;
|
||||
/// Allows the user to set [`PolygonMode::Point`] in [`PrimitiveState::polygon_mode`]
|
||||
///
|
||||
/// This allows only drawing the vertices of polygons/triangles instead of filled
|
||||
@ -427,7 +417,7 @@ bitflags::bitflags! {
|
||||
/// - Vulkan
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const POLYGON_MODE_POINT = 1 << 29;
|
||||
const POLYGON_MODE_POINT = 1 << 28;
|
||||
/// Enables ETC family of compressed textures. All ETC textures use 4x4 pixel blocks.
|
||||
/// ETC2 RGB and RGBA1 are 8 bytes per block. RTC2 RGBA8 and EAC are 16 bytes per block.
|
||||
///
|
||||
@ -442,7 +432,7 @@ bitflags::bitflags! {
|
||||
/// - Mobile (some)
|
||||
///
|
||||
/// This is a native-only feature.
|
||||
const TEXTURE_COMPRESSION_ETC2 = 1 << 30;
|
||||
const TEXTURE_COMPRESSION_ETC2 = 1 << 29;
|
||||
/// Enables ASTC family of compressed textures. ASTC textures use pixel blocks varying from 4x4 to 12x12.
|
||||
/// Blocks are always 16 bytes.
|
||||
///
|
||||
@ -457,7 +447,7 @@ bitflags::bitflags! {
|
||||
/// - Mobile (some)
|
||||
///
|
||||
/// This is a native-only feature.
|
||||
const TEXTURE_COMPRESSION_ASTC_LDR = 1 << 31;
|
||||
const TEXTURE_COMPRESSION_ASTC_LDR = 1 << 30;
|
||||
/// Enables device specific texture format features.
|
||||
///
|
||||
/// See `TextureFormatFeatures` for a listing of the features in question.
|
||||
@ -469,7 +459,7 @@ bitflags::bitflags! {
|
||||
/// This extension does not enable additional formats.
|
||||
///
|
||||
/// This is a native-only feature.
|
||||
const TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES = 1 << 32;
|
||||
const TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES = 1 << 31;
|
||||
/// Enables 64-bit floating point types in SPIR-V shaders.
|
||||
///
|
||||
/// Note: even when supported by GPU hardware, 64-bit floating point operations are
|
||||
@ -479,7 +469,7 @@ bitflags::bitflags! {
|
||||
/// - Vulkan
|
||||
///
|
||||
/// This is a native-only feature.
|
||||
const SHADER_FLOAT64 = 1 << 33;
|
||||
const SHADER_FLOAT64 = 1 << 32;
|
||||
/// Enables using 64-bit types for vertex attributes.
|
||||
///
|
||||
/// Requires SHADER_FLOAT64.
|
||||
@ -487,7 +477,7 @@ bitflags::bitflags! {
|
||||
/// Supported Platforms: N/A
|
||||
///
|
||||
/// This is a native-only feature.
|
||||
const VERTEX_ATTRIBUTE_64BIT = 1 << 34;
|
||||
const VERTEX_ATTRIBUTE_64BIT = 1 << 33;
|
||||
/// Allows the user to set a overestimation-conservative-rasterization in [`PrimitiveState::conservative`]
|
||||
///
|
||||
/// Processing of degenerate triangles/lines is hardware specific.
|
||||
@ -497,7 +487,7 @@ bitflags::bitflags! {
|
||||
/// - Vulkan
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const CONSERVATIVE_RASTERIZATION = 1 << 35;
|
||||
const CONSERVATIVE_RASTERIZATION = 1 << 34;
|
||||
/// Enables bindings of writable storage buffers and textures visible to vertex shaders.
|
||||
///
|
||||
/// Note: some (tiled-based) platforms do not support vertex shaders with any side-effects.
|
||||
@ -506,14 +496,14 @@ bitflags::bitflags! {
|
||||
/// - All
|
||||
///
|
||||
/// This is a native-only feature.
|
||||
const VERTEX_WRITABLE_STORAGE = 1 << 36;
|
||||
const VERTEX_WRITABLE_STORAGE = 1 << 35;
|
||||
/// Enables clear to zero for textures.
|
||||
///
|
||||
/// Supported platforms:
|
||||
/// - All
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const CLEAR_TEXTURE = 1 << 37;
|
||||
const CLEAR_TEXTURE = 1 << 36;
|
||||
/// Enables creating shader modules from SPIR-V binary data (unsafe).
|
||||
///
|
||||
/// SPIR-V data is not parsed or interpreted in any way; you can use
|
||||
@ -525,7 +515,7 @@ bitflags::bitflags! {
|
||||
/// Vulkan implementation.
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const SPIRV_SHADER_PASSTHROUGH = 1 << 38;
|
||||
const SPIRV_SHADER_PASSTHROUGH = 1 << 37;
|
||||
/// Enables `builtin(primitive_index)` in fragment shaders.
|
||||
///
|
||||
/// Note: enables geometry processing for pipelines using the builtin.
|
||||
@ -536,14 +526,14 @@ bitflags::bitflags! {
|
||||
/// - Vulkan
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const SHADER_PRIMITIVE_INDEX = 1 << 39;
|
||||
const SHADER_PRIMITIVE_INDEX = 1 << 38;
|
||||
/// Enables multiview render passes and `builtin(view_index)` in vertex shaders.
|
||||
///
|
||||
/// Supported platforms:
|
||||
/// - Vulkan
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const MULTIVIEW = 1 << 40;
|
||||
const MULTIVIEW = 1 << 39;
|
||||
/// Enables normalized `16-bit` texture formats.
|
||||
///
|
||||
/// Supported platforms:
|
||||
@ -552,7 +542,7 @@ bitflags::bitflags! {
|
||||
/// - Metal
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const TEXTURE_FORMAT_16BIT_NORM = 1 << 41;
|
||||
const TEXTURE_FORMAT_16BIT_NORM = 1 << 40;
|
||||
/// Allows the use of [`AddressMode::ClampToBorder`] with a border color
|
||||
/// of [`SamplerBorderColor::Zero`].
|
||||
///
|
||||
@ -564,12 +554,12 @@ bitflags::bitflags! {
|
||||
/// - OpenGL
|
||||
///
|
||||
/// This is a native only feature.
|
||||
const ADDRESS_MODE_CLAMP_TO_ZERO = 1 << 42;
|
||||
const ADDRESS_MODE_CLAMP_TO_ZERO = 1 << 41;
|
||||
/// Supported Platforms:
|
||||
/// - Metal
|
||||
///
|
||||
/// This is a native-only feature.
|
||||
const TEXTURE_COMPRESSION_ASTC_HDR = 1 << 43;
|
||||
const TEXTURE_COMPRESSION_ASTC_HDR = 1 << 42;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,6 @@ test = true
|
||||
|
||||
[[example]]
|
||||
name="texture-arrays"
|
||||
required-features = ["spirv"]
|
||||
test = true
|
||||
|
||||
[[example]]
|
||||
@ -139,20 +138,20 @@ env_logger = "0.9"
|
||||
|
||||
[dependencies.naga]
|
||||
git = "https://github.com/gfx-rs/naga"
|
||||
rev = "85056524"
|
||||
rev = "1aa91549"
|
||||
#version = "0.8"
|
||||
optional = true
|
||||
|
||||
# used to test all the example shaders
|
||||
[dev-dependencies.naga]
|
||||
git = "https://github.com/gfx-rs/naga"
|
||||
rev = "85056524"
|
||||
rev = "1aa91549"
|
||||
#version = "0.8"
|
||||
features = ["wgsl-in"]
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies.naga]
|
||||
git = "https://github.com/gfx-rs/naga"
|
||||
rev = "85056524"
|
||||
rev = "1aa91549"
|
||||
#version = "0.8"
|
||||
features = ["wgsl-out"]
|
||||
|
||||
|
@ -21,7 +21,6 @@ All framework-based examples render to the window and are reftested against the
|
||||
| implicit layout | | | | :star: | | | | | | |
|
||||
| sampled color textures | :star: | :star: | :star: | :star: | | | :star: | :star: | :star: | :star: |
|
||||
| storage textures | :star: | | | | | | | | | |
|
||||
| binding array | | | | | | | | :star: | | |
|
||||
| comparison samplers | | | | | | :star: | | | | |
|
||||
| subresource views | | | | :star: | | :star: | | | | |
|
||||
| cubemaps | | | | | | | :star: | | | |
|
||||
@ -36,9 +35,9 @@ All framework-based examples render to the window and are reftested against the
|
||||
| compute passes | :star: | | | | | | | | | |
|
||||
| error scopes | | | :star: | | | | | | | |
|
||||
| *optional extensions* | | | | | | | | :star: | | |
|
||||
| - SPIR-V shaders | | | | | | | | :star: | | |
|
||||
| - binding indexing | | | | | | | | :star: | | |
|
||||
| - push constants | | | | | | | | :star: | | |
|
||||
| - SPIR-V shaders | | | | | | | | | | |
|
||||
| - binding array | | | | | | | | :star: | | |
|
||||
| - push constants | | | | | | | | | | |
|
||||
| - depth clamping | | | | | | :star: | | | | |
|
||||
| - compressed textures | | | | | | | :star: | | | |
|
||||
| - polygon mode | | | :star: | | | | | | | |
|
||||
|
@ -1,19 +0,0 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 v_TexCoord;
|
||||
layout(location = 1) flat in int v_Index; // dynamically non-uniform
|
||||
layout(location = 0) out vec4 o_Color;
|
||||
|
||||
layout(set = 0, binding = 0) uniform texture2D u_Textures[2];
|
||||
layout(set = 0, binding = 1) uniform sampler u_Sampler[2];
|
||||
|
||||
void main() {
|
||||
if (v_Index == 0) {
|
||||
o_Color = vec4(texture(sampler2D(u_Textures[0], u_Sampler[0]), v_TexCoord).rgb, 1.0);
|
||||
} else if (v_Index == 1) {
|
||||
o_Color = vec4(texture(sampler2D(u_Textures[1], u_Sampler[1]), v_TexCoord).rgb, 1.0);
|
||||
} else {
|
||||
// We need to write something to output color
|
||||
o_Color = vec4(0.0, 0.0, 1.0, 0.0);
|
||||
}
|
||||
}
|
Binary file not shown.
61
wgpu/examples/texture-arrays/indexing.wgsl
Normal file
61
wgpu/examples/texture-arrays/indexing.wgsl
Normal file
@ -0,0 +1,61 @@
|
||||
struct VertexInput {
|
||||
@location(0) position: vec2<f32>,
|
||||
@location(1) tex_coord: vec2<f32>,
|
||||
@location(2) index: i32,
|
||||
}
|
||||
|
||||
struct VertexOutput {
|
||||
@builtin(position) position: vec4<f32>,
|
||||
@location(0) tex_coord: vec2<f32>,
|
||||
@location(1) index: i32,
|
||||
}
|
||||
|
||||
@vertex
|
||||
fn vert_main(vertex: VertexInput) -> VertexOutput {
|
||||
var outval: VertexOutput;
|
||||
outval.position = vec4<f32>(vertex.position.x, vertex.position.y, 0.0, 1.0);
|
||||
outval.tex_coord = vertex.tex_coord;
|
||||
outval.index = vertex.index;
|
||||
return outval;
|
||||
}
|
||||
|
||||
struct FragmentInput {
|
||||
@location(0) tex_coord: vec2<f32>,
|
||||
@location(1) index: i32,
|
||||
}
|
||||
|
||||
@group(0) @binding(0)
|
||||
var texture_array_top: binding_array<texture_2d<f32>>;
|
||||
@group(0) @binding(1)
|
||||
var texture_array_bottom: binding_array<texture_2d<f32>>;
|
||||
@group(0) @binding(2)
|
||||
var sampler_array: binding_array<sampler>;
|
||||
|
||||
struct Uniforms {
|
||||
index: u32,
|
||||
}
|
||||
|
||||
@group(0) @binding(3)
|
||||
var<uniform> uniforms: Uniforms;
|
||||
|
||||
@fragment
|
||||
fn uniform_main(fragment: FragmentInput) -> @location(0) vec4<f32> {
|
||||
var outval: vec3<f32>;
|
||||
if fragment.tex_coord.y <= 0.5 {
|
||||
outval = textureSampleLevel(
|
||||
texture_array_top[uniforms.index],
|
||||
sampler_array[uniforms.index],
|
||||
fragment.tex_coord,
|
||||
0.0
|
||||
).rgb;
|
||||
} else {
|
||||
outval = textureSampleLevel(
|
||||
texture_array_bottom[uniforms.index],
|
||||
sampler_array[uniforms.index],
|
||||
fragment.tex_coord,
|
||||
0.0
|
||||
).rgb;
|
||||
}
|
||||
|
||||
return vec4<f32>(outval.x, outval.y, outval.z, 1.0);
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
mod framework;
|
||||
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use std::num::NonZeroU32;
|
||||
use std::num::{NonZeroU32, NonZeroU64};
|
||||
use wgpu::util::DeviceExt;
|
||||
|
||||
#[repr(C)]
|
||||
@ -51,12 +51,16 @@ fn create_indices() -> Vec<u16> {
|
||||
enum Color {
|
||||
Red,
|
||||
Green,
|
||||
Blue,
|
||||
White,
|
||||
}
|
||||
|
||||
fn create_texture_data(color: Color) -> [u8; 4] {
|
||||
match color {
|
||||
Color::Red => [255, 0, 0, 255],
|
||||
Color::Green => [0, 255, 0, 255],
|
||||
Color::Blue => [0, 0, 255, 255],
|
||||
Color::White => [255, 255, 255, 255],
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,18 +75,10 @@ struct Example {
|
||||
|
||||
impl framework::Example for Example {
|
||||
fn optional_features() -> wgpu::Features {
|
||||
wgpu::Features::UNSIZED_BINDING_ARRAY
|
||||
| wgpu::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING
|
||||
| wgpu::Features::PUSH_CONSTANTS
|
||||
wgpu::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING
|
||||
}
|
||||
fn required_features() -> wgpu::Features {
|
||||
wgpu::Features::TEXTURE_BINDING_ARRAY | wgpu::Features::SPIRV_SHADER_PASSTHROUGH
|
||||
}
|
||||
fn required_limits() -> wgpu::Limits {
|
||||
wgpu::Limits {
|
||||
max_push_constant_size: 4,
|
||||
..wgpu::Limits::default()
|
||||
}
|
||||
wgpu::Features::TEXTURE_BINDING_ARRAY
|
||||
}
|
||||
fn init(
|
||||
config: &wgpu::SurfaceConfiguration,
|
||||
@ -91,24 +87,45 @@ impl framework::Example for Example {
|
||||
queue: &wgpu::Queue,
|
||||
) -> Self {
|
||||
let mut uniform_workaround = false;
|
||||
let vs_module = device.create_shader_module(&wgpu::include_spirv!("shader.vert.spv"));
|
||||
let fs_source = match device.features() {
|
||||
f if f.contains(wgpu::Features::UNSIZED_BINDING_ARRAY) => {
|
||||
wgpu::include_spirv_raw!("unsized-non-uniform.frag.spv")
|
||||
}
|
||||
f if f.contains(
|
||||
wgpu::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
|
||||
) =>
|
||||
{
|
||||
wgpu::include_spirv_raw!("non-uniform.frag.spv")
|
||||
}
|
||||
f if f.contains(wgpu::Features::TEXTURE_BINDING_ARRAY) => {
|
||||
uniform_workaround = true;
|
||||
wgpu::include_spirv_raw!("uniform.frag.spv")
|
||||
}
|
||||
_ => unreachable!(),
|
||||
let base_shader_module = device.create_shader_module(&wgpu::include_wgsl!("indexing.wgsl"));
|
||||
let env_override = match std::env::var("WGPU_TEXTURE_ARRAY_STYLE") {
|
||||
Ok(value) => match &*value.to_lowercase() {
|
||||
"nonuniform" | "non_uniform" => Some(true),
|
||||
"uniform" => Some(false),
|
||||
_ => None,
|
||||
},
|
||||
Err(_) => None,
|
||||
};
|
||||
let fs_module = unsafe { device.create_shader_module_spirv(&fs_source) };
|
||||
let fragment_entry_point = match (device.features(), env_override) {
|
||||
(_, Some(false)) => {
|
||||
uniform_workaround = true;
|
||||
"uniform_main"
|
||||
}
|
||||
(_, Some(true)) => "non_uniform_main",
|
||||
(f, _)
|
||||
if f.contains(
|
||||
wgpu::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
|
||||
) =>
|
||||
{
|
||||
"non_uniform_main"
|
||||
}
|
||||
_ => {
|
||||
uniform_workaround = true;
|
||||
"uniform_main"
|
||||
}
|
||||
};
|
||||
let non_uniform_shader_module;
|
||||
// TODO: Because naga's capibilities are evaluated on validate, not on write, we cannot make a shader module with unsupported
|
||||
// capabilities even if we don't use it. So for now put it in a separate module.
|
||||
let fragment_shader_module = if !uniform_workaround {
|
||||
non_uniform_shader_module =
|
||||
device.create_shader_module(&wgpu::include_wgsl!("non_uniform_indexing.wgsl"));
|
||||
&non_uniform_shader_module
|
||||
} else {
|
||||
&base_shader_module
|
||||
};
|
||||
|
||||
println!("Using fragment entry point '{}'", fragment_entry_point);
|
||||
|
||||
let vertex_size = std::mem::size_of::<Vertex>();
|
||||
let vertex_data = create_vertices();
|
||||
@ -125,8 +142,19 @@ impl framework::Example for Example {
|
||||
usage: wgpu::BufferUsages::INDEX,
|
||||
});
|
||||
|
||||
let mut texture_index_buffer_contents = vec![0u32; 128];
|
||||
texture_index_buffer_contents[0] = 0;
|
||||
texture_index_buffer_contents[64] = 1;
|
||||
let texture_index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Index Buffer"),
|
||||
contents: bytemuck::cast_slice(&texture_index_buffer_contents),
|
||||
usage: wgpu::BufferUsages::UNIFORM,
|
||||
});
|
||||
|
||||
let red_texture_data = create_texture_data(Color::Red);
|
||||
let green_texture_data = create_texture_data(Color::Green);
|
||||
let blue_texture_data = create_texture_data(Color::Blue);
|
||||
let white_texture_data = create_texture_data(Color::White);
|
||||
|
||||
let texture_descriptor = wgpu::TextureDescriptor {
|
||||
size: wgpu::Extent3d::default(),
|
||||
@ -145,9 +173,19 @@ impl framework::Example for Example {
|
||||
label: Some("green"),
|
||||
..texture_descriptor
|
||||
});
|
||||
let blue_texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: Some("blue"),
|
||||
..texture_descriptor
|
||||
});
|
||||
let white_texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
label: Some("white"),
|
||||
..texture_descriptor
|
||||
});
|
||||
|
||||
let red_texture_view = red_texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
let green_texture_view = green_texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
let blue_texture_view = blue_texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
let white_texture_view = white_texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
|
||||
queue.write_texture(
|
||||
red_texture.as_image_copy(),
|
||||
@ -169,6 +207,26 @@ impl framework::Example for Example {
|
||||
},
|
||||
wgpu::Extent3d::default(),
|
||||
);
|
||||
queue.write_texture(
|
||||
blue_texture.as_image_copy(),
|
||||
&blue_texture_data,
|
||||
wgpu::ImageDataLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: Some(NonZeroU32::new(4).unwrap()),
|
||||
rows_per_image: None,
|
||||
},
|
||||
wgpu::Extent3d::default(),
|
||||
);
|
||||
queue.write_texture(
|
||||
white_texture.as_image_copy(),
|
||||
&white_texture_data,
|
||||
wgpu::ImageDataLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: Some(NonZeroU32::new(4).unwrap()),
|
||||
rows_per_image: None,
|
||||
},
|
||||
wgpu::Extent3d::default(),
|
||||
);
|
||||
|
||||
let sampler = device.create_sampler(&wgpu::SamplerDescriptor::default());
|
||||
|
||||
@ -188,9 +246,29 @@ impl framework::Example for Example {
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 1,
|
||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||
ty: wgpu::BindingType::Texture {
|
||||
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||
view_dimension: wgpu::TextureViewDimension::D2,
|
||||
multisampled: false,
|
||||
},
|
||||
count: NonZeroU32::new(2),
|
||||
},
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 2,
|
||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
|
||||
count: NonZeroU32::new(2),
|
||||
},
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 3,
|
||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||
ty: wgpu::BindingType::Buffer {
|
||||
ty: wgpu::BufferBindingType::Uniform,
|
||||
has_dynamic_offset: true,
|
||||
min_binding_size: Some(NonZeroU64::new(4).unwrap()),
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@ -205,8 +283,23 @@ impl framework::Example for Example {
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
resource: wgpu::BindingResource::TextureViewArray(&[
|
||||
&blue_texture_view,
|
||||
&white_texture_view,
|
||||
]),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 2,
|
||||
resource: wgpu::BindingResource::SamplerArray(&[&sampler, &sampler]),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 3,
|
||||
resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
|
||||
buffer: &texture_index_buffer,
|
||||
offset: 0,
|
||||
size: Some(NonZeroU64::new(4).unwrap()),
|
||||
}),
|
||||
},
|
||||
],
|
||||
layout: &bind_group_layout,
|
||||
label: Some("bind group"),
|
||||
@ -215,14 +308,7 @@ impl framework::Example for Example {
|
||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("main"),
|
||||
bind_group_layouts: &[&bind_group_layout],
|
||||
push_constant_ranges: if uniform_workaround {
|
||||
&[wgpu::PushConstantRange {
|
||||
stages: wgpu::ShaderStages::FRAGMENT,
|
||||
range: 0..4,
|
||||
}]
|
||||
} else {
|
||||
&[]
|
||||
},
|
||||
push_constant_ranges: &[],
|
||||
});
|
||||
|
||||
let index_format = wgpu::IndexFormat::Uint16;
|
||||
@ -231,8 +317,8 @@ impl framework::Example for Example {
|
||||
label: None,
|
||||
layout: Some(&pipeline_layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module: &vs_module,
|
||||
entry_point: "main",
|
||||
module: &base_shader_module,
|
||||
entry_point: "vert_main",
|
||||
buffers: &[wgpu::VertexBufferLayout {
|
||||
array_stride: vertex_size as wgpu::BufferAddress,
|
||||
step_mode: wgpu::VertexStepMode::Vertex,
|
||||
@ -240,8 +326,8 @@ impl framework::Example for Example {
|
||||
}],
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &fs_module,
|
||||
entry_point: "main",
|
||||
module: fragment_shader_module,
|
||||
entry_point: fragment_entry_point,
|
||||
targets: &[config.format.into()],
|
||||
}),
|
||||
primitive: wgpu::PrimitiveState {
|
||||
@ -298,15 +384,15 @@ impl framework::Example for Example {
|
||||
});
|
||||
|
||||
rpass.set_pipeline(&self.pipeline);
|
||||
rpass.set_bind_group(0, &self.bind_group, &[]);
|
||||
rpass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
|
||||
rpass.set_index_buffer(self.index_buffer.slice(..), self.index_format);
|
||||
if self.uniform_workaround {
|
||||
rpass.set_push_constants(wgpu::ShaderStages::FRAGMENT, 0, bytemuck::cast_slice(&[0]));
|
||||
rpass.set_bind_group(0, &self.bind_group, &[0]);
|
||||
rpass.draw_indexed(0..6, 0, 0..1);
|
||||
rpass.set_push_constants(wgpu::ShaderStages::FRAGMENT, 0, bytemuck::cast_slice(&[1]));
|
||||
rpass.set_bind_group(0, &self.bind_group, &[256]);
|
||||
rpass.draw_indexed(6..12, 0, 0..1);
|
||||
} else {
|
||||
rpass.set_bind_group(0, &self.bind_group, &[0]);
|
||||
rpass.draw_indexed(0..12, 0, 0..1);
|
||||
}
|
||||
|
||||
@ -320,60 +406,28 @@ fn main() {
|
||||
framework::run::<Example>("texture-arrays");
|
||||
}
|
||||
|
||||
// This fails due to an issue with naga https://github.com/gfx-rs/wgpu/issues/1532
|
||||
#[test]
|
||||
fn texture_arrays_constant() {
|
||||
framework::test::<Example>(framework::FrameworkRefTest {
|
||||
image_path: "/examples/texture-arrays/screenshot.png",
|
||||
width: 1024,
|
||||
height: 768,
|
||||
optional_features: wgpu::Features::default(),
|
||||
base_test_parameters: framework::test_common::TestParameters::default().failure(),
|
||||
tolerance: 0,
|
||||
max_outliers: 0,
|
||||
});
|
||||
}
|
||||
|
||||
// This fails due to an issue with naga https://github.com/gfx-rs/wgpu/issues/1532
|
||||
#[test]
|
||||
fn texture_arrays_uniform() {
|
||||
framework::test::<Example>(framework::FrameworkRefTest {
|
||||
image_path: "/examples/texture-arrays/screenshot.png",
|
||||
width: 1024,
|
||||
height: 768,
|
||||
optional_features: wgpu::Features::TEXTURE_BINDING_ARRAY | wgpu::Features::PUSH_CONSTANTS,
|
||||
base_test_parameters: framework::test_common::TestParameters::default().failure(),
|
||||
optional_features: wgpu::Features::empty(),
|
||||
base_test_parameters: framework::test_common::TestParameters::default(),
|
||||
tolerance: 0,
|
||||
max_outliers: 0,
|
||||
});
|
||||
}
|
||||
|
||||
// This fails due to an issue with naga https://github.com/gfx-rs/wgpu/issues/1532
|
||||
#[test]
|
||||
fn texture_arrays_non_uniform() {
|
||||
framework::test::<Example>(framework::FrameworkRefTest {
|
||||
image_path: "/examples/texture-arrays/screenshot.png",
|
||||
width: 1024,
|
||||
height: 768,
|
||||
optional_features: wgpu::Features::TEXTURE_BINDING_ARRAY
|
||||
| wgpu::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
|
||||
base_test_parameters: framework::test_common::TestParameters::default().failure(),
|
||||
tolerance: 0,
|
||||
max_outliers: 0,
|
||||
});
|
||||
}
|
||||
|
||||
// This fails due to an issue with naga https://github.com/gfx-rs/wgpu/issues/1532
|
||||
#[test]
|
||||
fn texture_arrays_unsized_non_uniform() {
|
||||
framework::test::<Example>(framework::FrameworkRefTest {
|
||||
image_path: "/examples/texture-arrays/screenshot.png",
|
||||
width: 1024,
|
||||
height: 768,
|
||||
optional_features: wgpu::Features::TEXTURE_BINDING_ARRAY
|
||||
| wgpu::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING
|
||||
| wgpu::Features::UNSIZED_BINDING_ARRAY,
|
||||
base_test_parameters: framework::test_common::TestParameters::default().failure(),
|
||||
optional_features:
|
||||
wgpu::Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
|
||||
base_test_parameters: framework::test_common::TestParameters::default(),
|
||||
tolerance: 0,
|
||||
max_outliers: 0,
|
||||
});
|
||||
|
@ -1,14 +0,0 @@
|
||||
#version 450
|
||||
|
||||
#extension GL_EXT_nonuniform_qualifier : require
|
||||
|
||||
layout(location = 0) in vec2 v_TexCoord;
|
||||
layout(location = 1) nonuniformEXT flat in int v_Index; // dynamically non-uniform
|
||||
layout(location = 0) out vec4 o_Color;
|
||||
|
||||
layout(set = 0, binding = 0) uniform texture2D u_Textures[2];
|
||||
layout(set = 0, binding = 1) uniform sampler u_Sampler[2];
|
||||
|
||||
void main() {
|
||||
o_Color = vec4(texture(sampler2D(u_Textures[v_Index], u_Sampler[v_Index]), v_TexCoord).rgb, 1.0);
|
||||
}
|
Binary file not shown.
33
wgpu/examples/texture-arrays/non_uniform_indexing.wgsl
Normal file
33
wgpu/examples/texture-arrays/non_uniform_indexing.wgsl
Normal file
@ -0,0 +1,33 @@
|
||||
struct FragmentInput {
|
||||
@location(0) tex_coord: vec2<f32>,
|
||||
@location(1) index: i32,
|
||||
}
|
||||
|
||||
@group(0) @binding(0)
|
||||
var texture_array_top: binding_array<texture_2d<f32>>;
|
||||
@group(0) @binding(1)
|
||||
var texture_array_bottom: binding_array<texture_2d<f32>>;
|
||||
@group(0) @binding(2)
|
||||
var sampler_array: binding_array<sampler>;
|
||||
|
||||
@fragment
|
||||
fn non_uniform_main(fragment: FragmentInput) -> @location(0) vec4<f32> {
|
||||
var outval: vec3<f32>;
|
||||
if fragment.tex_coord.y <= 0.5 {
|
||||
outval = textureSampleLevel(
|
||||
texture_array_top[fragment.index],
|
||||
sampler_array[fragment.index],
|
||||
fragment.tex_coord,
|
||||
0.0
|
||||
).rgb;
|
||||
} else {
|
||||
outval = textureSampleLevel(
|
||||
texture_array_bottom[fragment.index],
|
||||
sampler_array[fragment.index],
|
||||
fragment.tex_coord,
|
||||
0.0
|
||||
).rgb;
|
||||
}
|
||||
|
||||
return vec4<f32>(outval.x, outval.y, outval.z, 1.0);
|
||||
}
|
BIN
wgpu/examples/texture-arrays/screenshot.png
Normal file
BIN
wgpu/examples/texture-arrays/screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.4 KiB |
@ -1,13 +0,0 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 a_Pos;
|
||||
layout(location = 1) in vec2 a_TexCoord;
|
||||
layout(location = 2) in int a_Index;
|
||||
layout(location = 0) out vec2 v_TexCoord;
|
||||
layout(location = 1) flat out int v_Index;
|
||||
|
||||
void main() {
|
||||
v_TexCoord = a_TexCoord;
|
||||
v_Index = a_Index;
|
||||
gl_Position = vec4(a_Pos, 0.0, 1.0);
|
||||
}
|
Binary file not shown.
@ -1,15 +0,0 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 v_TexCoord;
|
||||
layout(location = 1) flat in int v_Index; // dynamically non-uniform
|
||||
layout(location = 0) out vec4 o_Color;
|
||||
|
||||
layout(set = 0, binding = 0) uniform texture2D u_Textures[2];
|
||||
layout(set = 0, binding = 1) uniform sampler u_Sampler[2];
|
||||
layout(push_constant) uniform Uniforms {
|
||||
int u_Index; // dynamically uniform
|
||||
};
|
||||
|
||||
void main() {
|
||||
o_Color = vec4(texture(sampler2D(u_Textures[u_Index], u_Sampler[u_Index]), v_TexCoord).rgb, 1.0);
|
||||
}
|
Binary file not shown.
@ -1,14 +0,0 @@
|
||||
#version 450
|
||||
|
||||
#extension GL_EXT_nonuniform_qualifier : require
|
||||
|
||||
layout(location = 0) in vec2 v_TexCoord;
|
||||
layout(location = 1) nonuniformEXT flat in int v_Index; // dynamically non-uniform
|
||||
layout(location = 0) out vec4 o_Color;
|
||||
|
||||
layout(set = 0, binding = 0) uniform texture2D u_Textures[];
|
||||
layout(set = 0, binding = 1) uniform sampler u_Sampler[];
|
||||
|
||||
void main() {
|
||||
o_Color = vec4(texture(sampler2D(u_Textures[v_Index], u_Sampler[v_Index]), v_TexCoord).rgb, 1.0);
|
||||
}
|
Binary file not shown.
@ -1329,8 +1329,8 @@ impl crate::Context for Context {
|
||||
));
|
||||
if let Some(cause) = error {
|
||||
if let wgc::pipeline::CreateRenderPipelineError::Internal { stage, ref error } = cause {
|
||||
log::warn!("Shader translation error for stage {:?}: {}", stage, error);
|
||||
log::warn!("Please report it to https://github.com/gfx-rs/naga");
|
||||
log::error!("Shader translation error for stage {:?}: {}", stage, error);
|
||||
log::error!("Please report it to https://github.com/gfx-rs/naga");
|
||||
}
|
||||
self.handle_error(
|
||||
&device.error_sink,
|
||||
|
Loading…
Reference in New Issue
Block a user