[rs] Implement SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING

This commit is contained in:
Connor Fitzgerald
2020-06-11 13:45:51 -04:00
parent 4804fe496b
commit 8b60da572f
13 changed files with 201 additions and 39 deletions

View File

@@ -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" }

View File

@@ -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);
}
}

View File

@@ -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);

View 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);
}

Binary file not shown.

View 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);
}

Binary file not shown.

View 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);
}

View File

@@ -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,

View File

@@ -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)

View File

@@ -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 {