Implement TEXTURE_BINDING_ARRAY extension

This commit is contained in:
Connor Fitzgerald
2020-06-09 13:05:44 -04:00
parent 7b866b1a1b
commit f8be38cc01
16 changed files with 419 additions and 190 deletions

View File

@@ -28,19 +28,20 @@ vulkan = ["wgc/gfx-backend-vulkan"]
package = "wgpu-core"
version = "0.5"
git = "https://github.com/gfx-rs/wgpu"
rev = "eaf8f4af87237373105b016832662e7943b3899c"
rev = "64ae59072db443eb1e47ee14d77370eec9f4b012"
features = ["raw-window-handle"]
[dependencies.wgt]
package = "wgpu-types"
version = "0.5"
git = "https://github.com/gfx-rs/wgpu"
rev = "eaf8f4af87237373105b016832662e7943b3899c"
rev = "64ae59072db443eb1e47ee14d77370eec9f4b012"
[dependencies]
arrayvec = "0.5"
futures = "0.3"
smallvec = "1"
typed-arena = "2.0.1"
raw-window-handle = "0.3"
parking_lot = "0.10"
@@ -72,6 +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-descriptor = { version = "0.1.0", path = "../gfx-extras/gfx-descriptor" }
#gfx-memory = { version = "0.1.0", path = "../gfx-extras/gfx-memory" }

View File

@@ -57,6 +57,7 @@ impl framework::Example for Example {
binding: 0,
visibility: wgpu::ShaderStage::COMPUTE,
ty: wgpu::BindingType::UniformBuffer { dynamic: false },
..Default::default()
},
wgpu::BindGroupLayoutEntry {
binding: 1,
@@ -65,6 +66,7 @@ impl framework::Example for Example {
dynamic: false,
readonly: false,
},
..Default::default()
},
wgpu::BindGroupLayoutEntry {
binding: 2,
@@ -73,6 +75,7 @@ impl framework::Example for Example {
dynamic: false,
readonly: false,
},
..Default::default()
},
],
label: None,

View File

@@ -139,6 +139,7 @@ impl framework::Example for Example {
binding: 0,
visibility: wgpu::ShaderStage::VERTEX,
ty: wgpu::BindingType::UniformBuffer { dynamic: false },
..Default::default()
},
wgpu::BindGroupLayoutEntry {
binding: 1,
@@ -148,11 +149,13 @@ impl framework::Example for Example {
component_type: wgpu::TextureComponentType::Float,
dimension: wgpu::TextureViewDimension::D2,
},
..Default::default()
},
wgpu::BindGroupLayoutEntry {
binding: 2,
visibility: wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Sampler { comparison: false },
..Default::default()
},
],
});

View File

@@ -30,6 +30,9 @@ pub enum ShaderStage {
}
pub trait Example: 'static + Sized {
fn needed_extensions() -> (wgt::Extensions, wgt::UnsafeExtensions) {
(wgpu::Extensions::empty(), wgt::UnsafeExtensions::disallow())
}
fn init(
sc_desc: &wgpu::SwapChainDescriptor,
device: &wgpu::Device,
@@ -60,23 +63,27 @@ async fn run_async<E: Example>(event_loop: EventLoop<()>, window: Window) {
(size, surface)
};
let (needed_extensions, unsafe_extensions) = E::needed_extensions();
let adapter = instance
.request_adapter(
&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::Default,
compatible_surface: Some(&surface),
},
wgpu::UnsafeExtensions::disallow(),
unsafe_extensions,
wgpu::BackendBit::PRIMARY,
)
.await
.unwrap();
let adapter_extensions = adapter.extensions();
let trace_dir = std::env::var("WGPU_TRACE");
let (device, queue) = adapter
.request_device(
&wgpu::DeviceDescriptor {
extensions: wgpu::Extensions::empty(),
extensions: adapter_extensions & needed_extensions,
limits: wgpu::Limits::default(),
shader_validation: true,
},

View File

@@ -72,6 +72,7 @@ async fn execute_gpu(numbers: Vec<u32>) -> Vec<u32> {
dynamic: false,
readonly: false,
},
..Default::default()
}],
});

View File

@@ -92,11 +92,13 @@ impl Example {
component_type: wgpu::TextureComponentType::Float,
dimension: wgpu::TextureViewDimension::D2,
},
..Default::default()
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Sampler { comparison: false },
..Default::default()
},
],
label: None,
@@ -231,6 +233,7 @@ impl framework::Example for Example {
binding: 0,
visibility: wgpu::ShaderStage::VERTEX,
ty: wgpu::BindingType::UniformBuffer { dynamic: false },
..Default::default()
},
wgpu::BindGroupLayoutEntry {
binding: 1,
@@ -240,11 +243,13 @@ impl framework::Example for Example {
multisampled: false,
dimension: wgpu::TextureViewDimension::D2,
},
..Default::default()
},
wgpu::BindGroupLayoutEntry {
binding: 2,
visibility: wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Sampler { comparison: false },
..Default::default()
},
],
label: None,

View File

@@ -248,6 +248,7 @@ impl framework::Example for Example {
binding: 0,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::UniformBuffer { dynamic: false },
..Default::default()
}],
label: None,
});
@@ -430,6 +431,7 @@ impl framework::Example for Example {
binding: 0, // global
visibility: wgpu::ShaderStage::VERTEX,
ty: wgpu::BindingType::UniformBuffer { dynamic: false },
..Default::default()
}],
label: None,
});
@@ -518,11 +520,13 @@ impl framework::Example for Example {
binding: 0, // global
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::UniformBuffer { dynamic: false },
..Default::default()
},
wgpu::BindGroupLayoutEntry {
binding: 1, // lights
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::UniformBuffer { dynamic: false },
..Default::default()
},
wgpu::BindGroupLayoutEntry {
binding: 2,
@@ -532,11 +536,13 @@ impl framework::Example for Example {
component_type: wgpu::TextureComponentType::Float,
dimension: wgpu::TextureViewDimension::D2Array,
},
..Default::default()
},
wgpu::BindGroupLayoutEntry {
binding: 3,
visibility: wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Sampler { comparison: true },
..Default::default()
},
],
label: None,

View File

@@ -46,6 +46,7 @@ impl framework::Example for Skybox {
binding: 0,
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::UniformBuffer { dynamic: false },
..Default::default()
},
wgpu::BindGroupLayoutEntry {
binding: 1,
@@ -55,11 +56,13 @@ impl framework::Example for Skybox {
multisampled: false,
dimension: wgpu::TextureViewDimension::Cube,
},
..Default::default()
},
wgpu::BindGroupLayoutEntry {
binding: 2,
visibility: wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Sampler { comparison: false },
..Default::default()
},
],
label: None,

View File

@@ -0,0 +1,318 @@
#[path = "../framework.rs"]
mod framework;
use bytemuck::{Pod, Zeroable};
#[repr(C)]
#[derive(Clone, Copy)]
struct Vertex {
_pos: [f32; 2],
_tex_coord: [f32; 2],
_index: u32,
}
unsafe impl Pod for Vertex {}
unsafe impl Zeroable for Vertex {}
fn vertex(pos: [i8; 2], tc: [i8; 2], index: i8) -> Vertex {
Vertex {
_pos: [pos[0] as f32, pos[1] as f32],
_tex_coord: [tc[0] as f32, tc[1] as f32],
_index: index as u32,
}
}
fn create_vertices() -> Vec<Vertex> {
vec![
// left rectangle
vertex([-1, -1], [0, 1], 0),
vertex([-1, 1], [0, 0], 0),
vertex([0, 1], [1, 0], 0),
vertex([0, -1], [1, 1], 0),
// right rectangle
vertex([0, -1], [0, 1], 1),
vertex([0, 1], [0, 0], 1),
vertex([1, 1], [1, 0], 1),
vertex([1, -1], [1, 1], 1),
]
}
fn create_indices() -> Vec<u16> {
vec![
// Left rectangle
0, 1, 2, // 1st
2, 0, 3, // 2nd
// Right rectangle
4, 5, 6, // 1st
6, 4, 7, // 2nd
]
}
#[derive(Copy, Clone)]
enum Color {
RED,
GREEN,
}
fn create_texture_data(color: Color) -> [u8; 4] {
match color {
Color::RED => [255, 0, 0, 255],
Color::GREEN => [0, 255, 0, 255],
}
}
struct Example {
pipeline: wgpu::RenderPipeline,
bind_group: wgpu::BindGroup,
vertex_buffer: wgpu::Buffer,
index_buffer: wgpu::Buffer,
}
impl framework::Example for Example {
fn needed_extensions() -> (wgpu::Extensions, wgpu::UnsafeExtensions) {
(
wgpu::Extensions::TEXTURE_BINDING_ARRAY,
wgpu::UnsafeExtensions::disallow(),
)
}
fn init(
sc_desc: &wgpu::SwapChainDescriptor,
device: &wgpu::Device,
queue: &wgpu::Queue,
) -> (Self, Option<wgpu::CommandBuffer>) {
let device_extensions = device.extensions();
assert!(
device_extensions.contains(wgpu::Extensions::TEXTURE_BINDING_ARRAY),
"Graphics Device does not support TEXTURE_BINDING_ARRAY extension"
);
let vertex_size = std::mem::size_of::<Vertex>();
let vertex_data = create_vertices();
let vertex_buffer = device.create_buffer_with_data(
bytemuck::cast_slice(&vertex_data),
wgpu::BufferUsage::VERTEX,
);
let index_data = create_indices();
let index_buffer = device
.create_buffer_with_data(bytemuck::cast_slice(&index_data), wgpu::BufferUsage::INDEX);
let red_texture_data = create_texture_data(Color::RED);
let green_texture_data = create_texture_data(Color::GREEN);
let texture_descriptor = wgpu::TextureDescriptor {
size: wgpu::Extent3d {
width: 1,
height: 1,
depth: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8UnormSrgb,
usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST,
label: None,
};
let red_texture = device.create_texture(&wgpu::TextureDescriptor {
label: Some("red"),
..texture_descriptor
});
let green_texture = device.create_texture(&wgpu::TextureDescriptor {
label: Some("green"),
..texture_descriptor
});
let red_texture_view = red_texture.create_default_view();
let green_texture_view = green_texture.create_default_view();
queue.write_texture(
wgpu::TextureCopyView {
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
texture: &red_texture,
},
&red_texture_data,
wgpu::TextureDataLayout {
offset: 0,
bytes_per_row: 4,
rows_per_image: 0,
},
wgpu::Extent3d {
width: 1,
height: 1,
depth: 1,
},
);
queue.write_texture(
wgpu::TextureCopyView {
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
texture: &green_texture,
},
&green_texture_data,
wgpu::TextureDataLayout {
offset: 0,
bytes_per_row: 4,
rows_per_image: 0,
},
wgpu::Extent3d {
width: 1,
height: 1,
depth: 1,
},
);
let sampler = device.create_sampler(&wgpu::SamplerDescriptor::default());
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
bindings: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::SampledTexture {
component_type: wgpu::TextureComponentType::Float,
dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: Some(2),
..Default::default()
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::Sampler { comparison: false },
..Default::default()
},
],
label: Some("bind group layout"),
});
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
bindings: &[
wgpu::Binding {
binding: 0,
resource: wgpu::BindingResource::TextureViewArray(&[
red_texture_view,
green_texture_view,
]),
},
wgpu::Binding {
binding: 1,
resource: wgpu::BindingResource::Sampler(&sampler),
},
],
layout: &bind_group_layout,
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 = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
layout: &pipeline_layout,
vertex_stage: wgpu::ProgrammableStageDescriptor {
module: &vs_module,
entry_point: "main",
},
fragment_stage: Some(wgpu::ProgrammableStageDescriptor {
module: &fs_module,
entry_point: "main",
}),
rasterization_state: Some(wgpu::RasterizationStateDescriptor {
front_face: wgpu::FrontFace::Ccw,
cull_mode: wgpu::CullMode::None,
depth_bias: 0,
depth_bias_slope_scale: 0.0,
depth_bias_clamp: 0.0,
}),
primitive_topology: wgpu::PrimitiveTopology::TriangleList,
color_states: &[wgpu::ColorStateDescriptor {
format: sc_desc.format,
color_blend: wgpu::BlendDescriptor::REPLACE,
alpha_blend: wgpu::BlendDescriptor::REPLACE,
write_mask: wgpu::ColorWrite::ALL,
}],
depth_stencil_state: None,
vertex_state: wgpu::VertexStateDescriptor {
index_format: wgpu::IndexFormat::Uint16,
vertex_buffers: &[wgpu::VertexBufferDescriptor {
stride: vertex_size as wgpu::BufferAddress,
step_mode: wgpu::InputStepMode::Vertex,
attributes: &wgpu::vertex_attr_array![0 => Float2, 1 => Float2, 2 => Int],
}],
},
sample_count: 1,
sample_mask: !0,
alpha_to_coverage_enabled: false,
});
(
Self {
vertex_buffer,
index_buffer,
bind_group,
pipeline,
},
None,
)
}
fn resize(
&mut self,
_sc_desc: &wgpu::SwapChainDescriptor,
_device: &wgpu::Device,
_queue: &wgpu::Queue,
) {
// noop
}
fn update(&mut self, _event: winit::event::WindowEvent) {
// noop
}
fn render(
&mut self,
frame: &wgpu::SwapChainTexture,
device: &wgpu::Device,
_queue: &wgpu::Queue,
) -> wgpu::CommandBuffer {
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("primary"),
});
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
attachment: &frame.view,
resolve_target: None,
load_op: wgpu::LoadOp::Clear,
store_op: wgpu::StoreOp::Store,
clear_color: wgpu::Color {
r: 0.0,
g: 0.0,
b: 0.0,
a: 1.0,
},
}],
depth_stencil_attachment: None,
});
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(..));
rpass.draw_indexed(0..12, 0, 0..1);
drop(rpass);
encoder.finish()
}
}
fn main() {
framework::run::<Example>("texture-arrays");
}

View File

@@ -0,0 +1,18 @@
#version 450
layout(location = 0) in vec2 v_TexCoord;
layout(location = 1) flat in int v_Index;
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() {
if (v_Index == 0) {
o_Color = vec4(texture(sampler2D(u_Textures[0], u_Sampler), v_TexCoord).rgb, 1.0);
} 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);
}
}

Binary file not shown.

View File

@@ -0,0 +1,13 @@
#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.

View File

@@ -1,14 +1,15 @@
use crate::{
backend::native_gpu_future, BindGroupDescriptor, BindGroupLayoutDescriptor, BindingResource,
BindingType, BufferDescriptor, CommandEncoderDescriptor, ComputePipelineDescriptor, Extensions,
Limits, MapMode, PipelineLayoutDescriptor, RenderPipelineDescriptor, SamplerDescriptor,
SwapChainStatus, TextureDescriptor, TextureViewDescriptor, TextureViewDimension,
BufferDescriptor, CommandEncoderDescriptor, ComputePipelineDescriptor, Extensions, Limits,
MapMode, PipelineLayoutDescriptor, RenderPipelineDescriptor, SamplerDescriptor,
SwapChainStatus, TextureDescriptor, TextureViewDescriptor,
};
use arrayvec::ArrayVec;
use futures::future::{ready, Ready};
use smallvec::SmallVec;
use std::{ffi::CString, marker::PhantomData, ops::Range, ptr, slice};
use typed_arena::Arena;
macro_rules! gfx_select {
($id:expr => $global:ident.$method:ident( $($param:expr),+ )) => {
@@ -291,64 +292,9 @@ impl crate::Context for Context {
device: &Self::DeviceId,
desc: &BindGroupLayoutDescriptor,
) -> Self::BindGroupLayoutId {
use wgc::binding_model as bm;
let temp_layouts = desc
.bindings
.iter()
.map(|bind| bm::BindGroupLayoutEntry {
binding: bind.binding,
visibility: bind.visibility,
ty: match bind.ty {
BindingType::UniformBuffer { .. } => bm::BindingType::UniformBuffer,
BindingType::StorageBuffer {
readonly: false, ..
} => bm::BindingType::StorageBuffer,
BindingType::StorageBuffer { readonly: true, .. } => {
bm::BindingType::ReadonlyStorageBuffer
}
BindingType::Sampler { comparison: false } => bm::BindingType::Sampler,
BindingType::Sampler { .. } => bm::BindingType::ComparisonSampler,
BindingType::SampledTexture { .. } => bm::BindingType::SampledTexture,
BindingType::StorageTexture { readonly: true, .. } => {
bm::BindingType::ReadonlyStorageTexture
}
BindingType::StorageTexture { .. } => bm::BindingType::WriteonlyStorageTexture,
},
has_dynamic_offset: match bind.ty {
BindingType::UniformBuffer { dynamic }
| BindingType::StorageBuffer { dynamic, .. } => dynamic,
_ => false,
},
multisampled: match bind.ty {
BindingType::SampledTexture { multisampled, .. } => multisampled,
_ => false,
},
view_dimension: match bind.ty {
BindingType::SampledTexture { dimension, .. }
| BindingType::StorageTexture { dimension, .. } => dimension,
_ => TextureViewDimension::D2,
},
texture_component_type: match bind.ty {
BindingType::SampledTexture { component_type, .. }
| BindingType::StorageTexture { component_type, .. } => component_type,
_ => wgt::TextureComponentType::Float,
},
storage_texture_format: match bind.ty {
BindingType::StorageTexture { format, .. } => format,
_ => wgt::TextureFormat::Rgb10a2Unorm, // doesn't matter
},
})
.collect::<Vec<_>>();
let owned_label = OwnedLabel::new(desc.label.as_deref());
gfx_select!(*device => self.device_create_bind_group_layout(
*device,
&bm::BindGroupLayoutDescriptor {
entries: temp_layouts.as_ptr(),
entries_length: temp_layouts.len(),
label: owned_label.as_ptr(),
},
desc,
PhantomData
))
.unwrap()
@@ -361,13 +307,14 @@ impl crate::Context for Context {
) -> Self::BindGroupId {
use wgc::binding_model as bm;
let texture_view_arena: Arena<wgc::id::TextureViewId> = Arena::new();
let bindings = desc
.bindings
.iter()
.map(|binding| bm::BindGroupEntry {
binding: binding.binding,
resource: match &binding.resource {
BindingResource::Buffer(buffer_slice) => {
resource: match binding.resource {
BindingResource::Buffer(ref buffer_slice) => {
bm::BindingResource::Buffer(bm::BufferBinding {
buffer: buffer_slice.buffer.id,
offset: buffer_slice.offset,
@@ -380,18 +327,22 @@ impl crate::Context for Context {
BindingResource::TextureView(ref texture_view) => {
bm::BindingResource::TextureView(texture_view.id)
}
BindingResource::TextureViewArray(texture_view_array) => {
bm::BindingResource::TextureViewArray(
texture_view_arena
.alloc_extend(texture_view_array.iter().map(|view| view.id)),
)
}
},
})
.collect::<Vec<_>>();
let owned_label = OwnedLabel::new(desc.label.as_deref());
gfx_select!(*device => self.device_create_bind_group(
*device,
&bm::BindGroupDescriptor {
label: desc.label,
layout: desc.layout.id,
entries: bindings.as_ptr(),
entries_length: bindings.len(),
label: owned_label.as_ptr(),
bindings: &bindings,
},
PhantomData
))

View File

@@ -773,8 +773,14 @@ impl crate::Context for Context {
bt::ReadonlyStorageTexture
}
BindingType::StorageTexture { .. } => bt::WriteonlyStorageTexture,
_ => unreachable!(),
};
assert!(
bind.count.is_none(),
"The web backend doesn't support arrays of bindings"
);
let mut mapped_entry = web_sys::GpuBindGroupLayoutEntry::new(
bind.binding,
mapped_type,
@@ -848,6 +854,9 @@ impl crate::Context for Context {
BindingResource::TextureView(ref texture_view) => {
JsValue::from(texture_view.id.0.clone())
}
BindingResource::TextureViewArray(..) => {
panic!("Web backend does not support TEXTURE_BINDING_ARRAY extension")
}
};
web_sys::GpuBindGroupEntry::new(binding.binding, &mapped_resource)

View File

@@ -19,15 +19,15 @@ use parking_lot::Mutex;
#[cfg(not(target_arch = "wasm32"))]
pub use wgc::instance::{AdapterInfo, DeviceType};
pub use wgt::{
read_spirv, AddressMode, Backend, BackendBit, 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, ShaderLocation, ShaderStage, StencilOperation,
StencilStateFaceDescriptor, StoreOp, SwapChainDescriptor, SwapChainStatus, TextureAspect,
TextureComponentType, TextureDataLayout, TextureDimension, TextureFormat, TextureUsage,
TextureViewDimension, UnsafeExtensions, VertexAttributeDescriptor, VertexFormat,
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, 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,
};
@@ -606,10 +606,12 @@ pub struct Queue {
}
/// A resource that can be bound to a pipeline.
#[non_exhaustive]
pub enum BindingResource<'a> {
Buffer(BufferSlice<'a>),
Sampler(&'a Sampler),
TextureView(&'a TextureView),
TextureViewArray(&'a [TextureView]),
}
/// A bindable resource and the slot to bind it to.
@@ -618,118 +620,6 @@ pub struct Binding<'a> {
pub resource: BindingResource<'a>,
}
/// Specific type of a binding.
/// WebGPU spec: https://gpuweb.github.io/gpuweb/#dictdef-gpubindgrouplayoutentry
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum BindingType {
/// A buffer for uniform values.
///
/// Example GLSL syntax:
/// ```cpp,ignore
/// layout(std140, binding = 0)
/// uniform Globals {
/// vec2 aUniform;
/// vec2 anotherUniform;
/// };
/// ```
UniformBuffer {
/// Indicates that the binding has a dynamic offset.
/// One offset must be passed to [RenderPass::set_bind_group] for each dynamic binding in increasing order of binding number.
dynamic: bool,
},
/// A storage buffer.
///
/// Example GLSL syntax:
/// ```cpp,ignore
/// layout (set=0, binding=0) buffer myStorageBuffer {
/// vec4 myElement[];
/// };
/// ```
StorageBuffer {
/// Indicates that the binding has a dynamic offset.
/// One offset must be passed to [RenderPass::set_bind_group] for each dynamic binding in increasing order of binding number.
dynamic: bool,
/// The buffer can only be read in the shader and it must be annotated with `readonly`.
///
/// Example GLSL syntax:
/// ```cpp,ignore
/// layout (set=0, binding=0) readonly buffer myStorageBuffer {
/// vec4 myElement[];
/// };
/// ```
readonly: bool,
},
/// A sampler that can be used to sample a texture.
///
/// Example GLSL syntax:
/// ```cpp,ignore
/// layout(binding = 0)
/// uniform sampler s;
/// ```
Sampler {
/// Use as a comparison sampler instead of a normal sampler.
/// For more info take a look at the analogous functionality in OpenGL: https://www.khronos.org/opengl/wiki/Sampler_Object#Comparison_mode.
comparison: bool,
},
/// A texture.
///
/// Example GLSL syntax:
/// ```cpp,ignore
/// layout(binding = 0)
/// uniform texture2D t;
/// ```
SampledTexture {
/// Dimension of the texture view that is going to be sampled.
dimension: TextureViewDimension,
/// Component type of the texture.
/// This must be compatible with the format of the texture.
component_type: TextureComponentType,
/// True if the texture has a sample count greater than 1.
multisampled: bool,
},
/// A storage texture.
/// Example GLSL syntax:
/// ```cpp,ignore
/// layout(set=0, binding=0, r32f) uniform image2D myStorageImage;
/// ```
/// Note that the texture format must be specified in the shader as well.
/// A list of valid formats can be found in the specification here: https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.html#layout-qualifiers
StorageTexture {
/// Dimension of the texture view that is going to be sampled.
dimension: TextureViewDimension,
/// Component type of the texture.
/// This must be compatible with the format of the texture.
component_type: TextureComponentType,
/// Format of the texture.
format: TextureFormat,
/// The texture can only be read in the shader and it must be annotated with `readonly`.
///
/// Example GLSL syntax:
/// ```cpp,ignore
/// layout(set=0, binding=0, r32f) readonly uniform image2D myStorageImage;
/// ```
readonly: bool,
},
}
/// A description of a single binding inside a bind group.
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct BindGroupLayoutEntry {
pub binding: u32,
pub visibility: ShaderStage,
pub ty: BindingType,
}
/// A description of a bind group layout.
#[derive(Clone, Debug)]
pub struct BindGroupLayoutDescriptor<'a> {
pub bindings: &'a [BindGroupLayoutEntry],
/// An optional label to apply to the bind group layout.
/// This can be useful for debugging and performance analysis.
pub label: Option<&'a str>,
}
/// A description of a group of bindings and the resources to be bound.
#[derive(Clone)]
pub struct BindGroupDescriptor<'a> {