mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
[rs] Implement SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING
This commit is contained in:
@@ -28,14 +28,14 @@ vulkan = ["wgc/gfx-backend-vulkan"]
|
||||
package = "wgpu-core"
|
||||
version = "0.5"
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "ad34c37127c8361bc2b07e8775816b2bbf8c0a73"
|
||||
rev = "2dd3439475de6ea59488a91ea7d66096d3aecbbf"
|
||||
features = ["raw-window-handle"]
|
||||
|
||||
[dependencies.wgt]
|
||||
package = "wgpu-types"
|
||||
version = "0.5"
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "ad34c37127c8361bc2b07e8775816b2bbf8c0a73"
|
||||
rev = "2dd3439475de6ea59488a91ea7d66096d3aecbbf"
|
||||
|
||||
[dependencies]
|
||||
arrayvec = "0.5"
|
||||
@@ -73,7 +73,7 @@ test = true
|
||||
#gfx-backend-vulkan = { version = "0.5.0", path = "../gfx/src/backend/vulkan" }
|
||||
#gfx-backend-dx12 = { version = "0.5.0", path = "../gfx/src/backend/dx12" }
|
||||
#gfx-backend-dx11 = { version = "0.5.0", path = "../gfx/src/backend/dx11" }
|
||||
#gfx-backend-metal = { version = "0.5.0", path = "../gfx/src/backend/dx11" }
|
||||
#gfx-backend-metal = { version = "0.5.0", path = "../gfx/src/backend/metal" }
|
||||
#gfx-descriptor = { version = "0.1.0", path = "../gfx-extras/gfx-descriptor" }
|
||||
#gfx-memory = { version = "0.1.0", path = "../gfx-extras/gfx-memory" }
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 v_TexCoord;
|
||||
layout(location = 1) flat in int v_Index;
|
||||
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];
|
||||
@@ -13,6 +13,7 @@ void main() {
|
||||
} else if (v_Index == 1) {
|
||||
o_Color = vec4(texture(sampler2D(u_Textures[1], u_Sampler), v_TexCoord).rgb, 1.0);
|
||||
} else {
|
||||
o_Color = vec4(0.0, 0.0, 1.0, 1.0);
|
||||
// We need to write something to output color
|
||||
o_Color = vec4(0.0, 0.0, 1.0, 0.0);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -14,6 +14,21 @@ struct Vertex {
|
||||
unsafe impl Pod for Vertex {}
|
||||
unsafe impl Zeroable for Vertex {}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
struct Uniform {
|
||||
index: u32,
|
||||
}
|
||||
|
||||
unsafe impl Pod for Uniform {}
|
||||
unsafe impl Zeroable for Uniform {}
|
||||
|
||||
struct UniformWorkaroundData {
|
||||
bind_group_layout: wgpu::BindGroupLayout,
|
||||
bind_group0: wgpu::BindGroup,
|
||||
bind_group1: wgpu::BindGroup,
|
||||
}
|
||||
|
||||
fn vertex(pos: [i8; 2], tc: [i8; 2], index: i8) -> Vertex {
|
||||
Vertex {
|
||||
_pos: [pos[0] as f32, pos[1] as f32],
|
||||
@@ -66,12 +81,13 @@ struct Example {
|
||||
bind_group: wgpu::BindGroup,
|
||||
vertex_buffer: wgpu::Buffer,
|
||||
index_buffer: wgpu::Buffer,
|
||||
uniform_workaround_data: Option<UniformWorkaroundData>,
|
||||
}
|
||||
|
||||
impl framework::Example for Example {
|
||||
fn needed_extensions() -> (wgpu::Extensions, wgpu::UnsafeExtensions) {
|
||||
(
|
||||
wgpu::Extensions::SAMPLED_TEXTURE_BINDING_ARRAY,
|
||||
wgpu::Extensions::BINDING_INDEXING,
|
||||
wgpu::UnsafeExtensions::disallow(),
|
||||
)
|
||||
}
|
||||
@@ -80,12 +96,30 @@ impl framework::Example for Example {
|
||||
device: &wgpu::Device,
|
||||
queue: &wgpu::Queue,
|
||||
) -> (Self, Option<wgpu::CommandBuffer>) {
|
||||
let device_extensions = device.extensions();
|
||||
|
||||
assert!(
|
||||
device_extensions.contains(wgpu::Extensions::SAMPLED_TEXTURE_BINDING_ARRAY),
|
||||
"Graphics Device does not support SAMPLED_TEXTURE_BINDING_ARRAY extension"
|
||||
);
|
||||
let mut uniform_workaround = false;
|
||||
let vs_bytes: &[u8] = include_bytes!("shader.vert.spv");
|
||||
let fs_bytes: &[u8] = match device.capabilities() {
|
||||
c if c.contains(wgpu::Capabilities::UNSIZED_BINDING_ARRAY) => {
|
||||
include_bytes!("unsized-non-uniform.frag.spv")
|
||||
}
|
||||
c if c.contains(wgpu::Capabilities::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING) => {
|
||||
include_bytes!("non-uniform.frag.spv")
|
||||
}
|
||||
c if c.contains(wgpu::Capabilities::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING) => {
|
||||
uniform_workaround = true;
|
||||
include_bytes!("uniform.frag.spv")
|
||||
}
|
||||
c if c.contains(wgpu::Capabilities::SAMPLED_TEXTURE_BINDING_ARRAY) => {
|
||||
include_bytes!("constant.frag.spv")
|
||||
}
|
||||
_ => {
|
||||
panic!("Graphics adapter does not support any of the capabilities needed for this example");
|
||||
}
|
||||
};
|
||||
let vs_module =
|
||||
device.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(vs_bytes)).unwrap());
|
||||
let fs_module =
|
||||
device.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(fs_bytes)).unwrap());
|
||||
|
||||
let vertex_size = std::mem::size_of::<Vertex>();
|
||||
let vertex_data = create_vertices();
|
||||
@@ -98,6 +132,54 @@ impl framework::Example for Example {
|
||||
let index_buffer = device
|
||||
.create_buffer_with_data(bytemuck::cast_slice(&index_data), wgpu::BufferUsage::INDEX);
|
||||
|
||||
let uniform_workaround_data = if uniform_workaround {
|
||||
let buffer0 = device.create_buffer_with_data(
|
||||
&bytemuck::cast_slice(&[Uniform { index: 0 }]),
|
||||
wgpu::BufferUsage::UNIFORM,
|
||||
);
|
||||
let buffer1 = device.create_buffer_with_data(
|
||||
&bytemuck::cast_slice(&[Uniform { index: 1 }]),
|
||||
wgpu::BufferUsage::UNIFORM,
|
||||
);
|
||||
|
||||
let bind_group_layout =
|
||||
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
bindings: &[wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStage::FRAGMENT,
|
||||
ty: wgpu::BindingType::UniformBuffer { dynamic: false },
|
||||
..wgpu::BindGroupLayoutEntry::default()
|
||||
}],
|
||||
label: Some("uniform workaround bind group layout"),
|
||||
});
|
||||
|
||||
let bind_group0 = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &bind_group_layout,
|
||||
bindings: &[wgpu::Binding {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer(buffer0.slice(..)),
|
||||
}],
|
||||
label: Some("uniform workaround bind group 0"),
|
||||
});
|
||||
|
||||
let bind_group1 = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &bind_group_layout,
|
||||
bindings: &[wgpu::Binding {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer(buffer1.slice(..)),
|
||||
}],
|
||||
label: Some("uniform workaround bind group 1"),
|
||||
});
|
||||
|
||||
Some(UniformWorkaroundData {
|
||||
bind_group_layout,
|
||||
bind_group0,
|
||||
bind_group1,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let red_texture_data = create_texture_data(Color::RED);
|
||||
let green_texture_data = create_texture_data(Color::GREEN);
|
||||
|
||||
@@ -206,16 +288,15 @@ impl framework::Example for Example {
|
||||
label: Some("bind group"),
|
||||
});
|
||||
|
||||
let vs_bytes = include_bytes!("shader.vert.spv");
|
||||
let fs_bytes = include_bytes!("shader.frag.spv");
|
||||
let vs_module = device
|
||||
.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&vs_bytes[..])).unwrap());
|
||||
let fs_module = device
|
||||
.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&fs_bytes[..])).unwrap());
|
||||
|
||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
bind_group_layouts: &[&bind_group_layout],
|
||||
});
|
||||
let pipeline_layout = if let Some(ref workaround) = uniform_workaround_data {
|
||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
bind_group_layouts: &[&bind_group_layout, &workaround.bind_group_layout],
|
||||
})
|
||||
} else {
|
||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
bind_group_layouts: &[&bind_group_layout],
|
||||
})
|
||||
};
|
||||
|
||||
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
layout: &pipeline_layout,
|
||||
@@ -261,6 +342,7 @@ impl framework::Example for Example {
|
||||
index_buffer,
|
||||
bind_group,
|
||||
pipeline,
|
||||
uniform_workaround_data,
|
||||
},
|
||||
None,
|
||||
)
|
||||
@@ -305,7 +387,14 @@ impl framework::Example for Example {
|
||||
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(..));
|
||||
rpass.draw_indexed(0..12, 0, 0..1);
|
||||
if let Some(ref workaround) = self.uniform_workaround_data {
|
||||
rpass.set_bind_group(1, &workaround.bind_group0, &[]);
|
||||
rpass.draw_indexed(0..6, 0, 0..1);
|
||||
rpass.set_bind_group(1, &workaround.bind_group1, &[]);
|
||||
rpass.draw_indexed(6..12, 0, 0..1);
|
||||
} else {
|
||||
rpass.draw_indexed(0..12, 0, 0..1);
|
||||
}
|
||||
|
||||
drop(rpass);
|
||||
|
||||
|
||||
14
wgpu/examples/texture-arrays/non-uniform.frag
Normal file
14
wgpu/examples/texture-arrays/non-uniform.frag
Normal file
@@ -0,0 +1,14 @@
|
||||
#version 450
|
||||
|
||||
#extension GL_EXT_nonuniform_qualifier : require
|
||||
|
||||
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;
|
||||
|
||||
void main() {
|
||||
o_Color = vec4(texture(sampler2D(u_Textures[v_Index], u_Sampler), v_TexCoord).rgb, 1.0);
|
||||
}
|
||||
BIN
wgpu/examples/texture-arrays/non-uniform.frag.spv
Normal file
BIN
wgpu/examples/texture-arrays/non-uniform.frag.spv
Normal file
Binary file not shown.
15
wgpu/examples/texture-arrays/uniform.frag
Normal file
15
wgpu/examples/texture-arrays/uniform.frag
Normal file
@@ -0,0 +1,15 @@
|
||||
#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;
|
||||
layout(set = 1, binding = 0) uniform Uniforms {
|
||||
int u_Index; // dynamically uniform
|
||||
};
|
||||
|
||||
void main() {
|
||||
o_Color = vec4(texture(sampler2D(u_Textures[u_Index], u_Sampler), v_TexCoord).rgb, 1.0);
|
||||
}
|
||||
BIN
wgpu/examples/texture-arrays/uniform.frag.spv
Normal file
BIN
wgpu/examples/texture-arrays/uniform.frag.spv
Normal file
Binary file not shown.
14
wgpu/examples/texture-arrays/unsized-non-uniform.frag
Normal file
14
wgpu/examples/texture-arrays/unsized-non-uniform.frag
Normal file
@@ -0,0 +1,14 @@
|
||||
#version 450
|
||||
|
||||
#extension GL_EXT_nonuniform_qualifier : require
|
||||
|
||||
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[];
|
||||
layout(set = 0, binding = 1) uniform sampler u_Sampler;
|
||||
|
||||
void main() {
|
||||
o_Color = vec4(texture(sampler2D(u_Textures[v_Index], u_Sampler), v_TexCoord).rgb, 1.0);
|
||||
}
|
||||
BIN
wgpu/examples/texture-arrays/unsized-non-uniform.frag.spv
Normal file
BIN
wgpu/examples/texture-arrays/unsized-non-uniform.frag.spv
Normal file
Binary file not shown.
@@ -1,8 +1,8 @@
|
||||
use crate::{
|
||||
backend::native_gpu_future, BindGroupDescriptor, BindGroupLayoutDescriptor, BindingResource,
|
||||
BufferDescriptor, CommandEncoderDescriptor, ComputePipelineDescriptor, Extensions, Limits,
|
||||
MapMode, PipelineLayoutDescriptor, RenderPipelineDescriptor, SamplerDescriptor,
|
||||
SwapChainStatus, TextureDescriptor, TextureViewDescriptor,
|
||||
BufferDescriptor, Capabilities, CommandEncoderDescriptor, ComputePipelineDescriptor,
|
||||
Extensions, Limits, MapMode, PipelineLayoutDescriptor, RenderPipelineDescriptor,
|
||||
SamplerDescriptor, SwapChainStatus, TextureDescriptor, TextureViewDescriptor,
|
||||
};
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
@@ -354,6 +354,10 @@ impl crate::Context for Context {
|
||||
gfx_select!(*adapter => self.adapter_limits(*adapter))
|
||||
}
|
||||
|
||||
fn adapter_capabilities(&self, adapter: &Self::AdapterId) -> Capabilities {
|
||||
gfx_select!(*adapter => self.adapter_capabilities(*adapter))
|
||||
}
|
||||
|
||||
fn device_extensions(&self, device: &Self::DeviceId) -> Extensions {
|
||||
gfx_select!(*device => self.device_extensions(*device))
|
||||
}
|
||||
@@ -362,6 +366,10 @@ impl crate::Context for Context {
|
||||
gfx_select!(*device => self.device_limits(*device))
|
||||
}
|
||||
|
||||
fn device_capabilities(&self, device: &Self::DeviceId) -> Capabilities {
|
||||
gfx_select!(*device => self.device_capabilities(*device))
|
||||
}
|
||||
|
||||
fn device_create_swap_chain(
|
||||
&self,
|
||||
device: &Self::DeviceId,
|
||||
|
||||
@@ -725,6 +725,11 @@ impl crate::Context for Context {
|
||||
wgt::Limits::default()
|
||||
}
|
||||
|
||||
fn adapter_capabilities(&self, _adapter: &Self::AdapterId) -> wgt::Capabilities {
|
||||
// TODO: webgpu doesn't support capabilities, so return an empty set of capabilities
|
||||
wgt::Capabilities::default()
|
||||
}
|
||||
|
||||
fn device_extensions(&self, _device: &Self::DeviceId) -> wgt::Extensions {
|
||||
// TODO: web-sys has no way of getting extensions on devices
|
||||
wgt::Extensions::empty()
|
||||
@@ -735,6 +740,11 @@ impl crate::Context for Context {
|
||||
wgt::Limits::default()
|
||||
}
|
||||
|
||||
fn device_capabilities(&self, _device: &Self::DeviceId) -> wgt::Capabilities {
|
||||
// TODO: webgpu doesn't support capabilities, so return an empty set of capabilities
|
||||
wgt::Capabilities::default()
|
||||
}
|
||||
|
||||
fn device_create_swap_chain(
|
||||
&self,
|
||||
device: &Self::DeviceId,
|
||||
@@ -863,9 +873,9 @@ impl crate::Context for Context {
|
||||
view: ref texture_view,
|
||||
read_only_depth_stencil: _,
|
||||
} => JsValue::from(texture_view.id.0.clone()),
|
||||
BindingResource::TextureViewArray(..) => {
|
||||
panic!("Web backend does not support TEXTURE_BINDING_ARRAY extension")
|
||||
}
|
||||
BindingResource::TextureViewArray(..) => panic!(
|
||||
"Web backend does not support SAMPLED_TEXTURE_BINDING_ARRAY extension"
|
||||
),
|
||||
};
|
||||
|
||||
web_sys::GpuBindGroupEntry::new(binding.binding, &mapped_resource)
|
||||
|
||||
@@ -21,14 +21,15 @@ pub use wgc::instance::{AdapterInfo, DeviceType};
|
||||
pub use wgt::{
|
||||
read_spirv, AddressMode, Backend, BackendBit, BindGroupLayoutDescriptor, BindGroupLayoutEntry,
|
||||
BindingType, BlendDescriptor, BlendFactor, BlendOperation, BufferAddress, BufferSize,
|
||||
BufferUsage, Color, ColorStateDescriptor, ColorWrite, CommandBufferDescriptor, CompareFunction,
|
||||
CullMode, DepthStencilStateDescriptor, DeviceDescriptor, DynamicOffset, Extensions, Extent3d,
|
||||
FilterMode, FrontFace, IndexFormat, InputStepMode, Limits, LoadOp, Origin3d, PowerPreference,
|
||||
PresentMode, PrimitiveTopology, RasterizationStateDescriptor, RenderBundleEncoderDescriptor,
|
||||
ShaderLocation, ShaderStage, StencilOperation, StencilStateFaceDescriptor, StoreOp,
|
||||
SwapChainDescriptor, SwapChainStatus, TextureAspect, TextureComponentType, TextureDataLayout,
|
||||
TextureDimension, TextureFormat, TextureUsage, TextureViewDimension, UnsafeExtensions,
|
||||
VertexAttributeDescriptor, VertexFormat, BIND_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT,
|
||||
BufferUsage, Capabilities, Color, ColorStateDescriptor, ColorWrite, CommandBufferDescriptor,
|
||||
CompareFunction, CullMode, DepthStencilStateDescriptor, DeviceDescriptor, DynamicOffset,
|
||||
Extensions, Extent3d, FilterMode, FrontFace, IndexFormat, InputStepMode, Limits, LoadOp,
|
||||
Origin3d, PowerPreference, PresentMode, PrimitiveTopology, RasterizationStateDescriptor,
|
||||
RenderBundleEncoderDescriptor, ShaderLocation, ShaderStage, StencilOperation,
|
||||
StencilStateFaceDescriptor, StoreOp, SwapChainDescriptor, SwapChainStatus, TextureAspect,
|
||||
TextureComponentType, TextureDataLayout, TextureDimension, TextureFormat, TextureUsage,
|
||||
TextureViewDimension, UnsafeExtensions, VertexAttributeDescriptor, VertexFormat,
|
||||
BIND_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT,
|
||||
};
|
||||
|
||||
use backend::Context as C;
|
||||
@@ -143,9 +144,11 @@ trait Context: Sized {
|
||||
) -> Self::RequestDeviceFuture;
|
||||
fn adapter_extensions(&self, adapter: &Self::AdapterId) -> Extensions;
|
||||
fn adapter_limits(&self, adapter: &Self::AdapterId) -> Limits;
|
||||
fn adapter_capabilities(&self, adapter: &Self::AdapterId) -> Capabilities;
|
||||
|
||||
fn device_extensions(&self, device: &Self::DeviceId) -> Extensions;
|
||||
fn device_limits(&self, device: &Self::DeviceId) -> Limits;
|
||||
fn device_capabilities(&self, device: &Self::DeviceId) -> Capabilities;
|
||||
fn device_create_swap_chain(
|
||||
&self,
|
||||
device: &Self::DeviceId,
|
||||
@@ -1013,10 +1016,14 @@ impl Adapter {
|
||||
Context::adapter_limits(&*self.context, &self.id)
|
||||
}
|
||||
|
||||
pub fn capabilities(&self) -> Capabilities {
|
||||
Context::adapter_capabilities(&*self.context, &self.id)
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub fn get_info(&self) -> AdapterInfo {
|
||||
//wgn::adapter_get_info(self.id)
|
||||
unimplemented!()
|
||||
let context = &self.context;
|
||||
wgc::gfx_select!(self.id => context.adapter_get_info(self.id))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1034,6 +1041,10 @@ impl Device {
|
||||
Context::device_limits(&*self.context, &self.id)
|
||||
}
|
||||
|
||||
pub fn capabilities(&self) -> Capabilities {
|
||||
Context::device_capabilities(&*self.context, &self.id)
|
||||
}
|
||||
|
||||
/// Creates a shader module from SPIR-V source code.
|
||||
pub fn create_shader_module(&self, spv: &[u32]) -> ShaderModule {
|
||||
ShaderModule {
|
||||
|
||||
Reference in New Issue
Block a user