mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Implement TEXTURE_BINDING_ARRAY extension
This commit is contained in:
@@ -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" }
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
@@ -72,6 +72,7 @@ async fn execute_gpu(numbers: Vec<u32>) -> Vec<u32> {
|
||||
dynamic: false,
|
||||
readonly: false,
|
||||
},
|
||||
..Default::default()
|
||||
}],
|
||||
});
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
318
examples/texture-arrays/main.rs
Normal file
318
examples/texture-arrays/main.rs
Normal 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");
|
||||
}
|
||||
18
examples/texture-arrays/shader.frag
Normal file
18
examples/texture-arrays/shader.frag
Normal 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);
|
||||
}
|
||||
}
|
||||
BIN
examples/texture-arrays/shader.frag.spv
Normal file
BIN
examples/texture-arrays/shader.frag.spv
Normal file
Binary file not shown.
13
examples/texture-arrays/shader.vert
Normal file
13
examples/texture-arrays/shader.vert
Normal 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);
|
||||
}
|
||||
BIN
examples/texture-arrays/shader.vert.spv
Normal file
BIN
examples/texture-arrays/shader.vert.spv
Normal file
Binary file not shown.
@@ -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
|
||||
))
|
||||
|
||||
@@ -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)
|
||||
|
||||
132
src/lib.rs
132
src/lib.rs
@@ -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> {
|
||||
|
||||
Reference in New Issue
Block a user