mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
[rs] Merge #360
360: Implement TEXTURE_BINDING_ARRAY extension r=kvark a=cwfitzgerald This extends https://github.com/gfx-rs/wgpu/pull/711 into wgpu-rs. Notable changes: - Added an example showing off both this extension and the future descriptor indexing extension. - Changed the framework so there is a static function showing what extensions you need. This is provided by the trait,, which defaults to no extensions, so existing examples and new ones don't have to care about extensions. Co-authored-by: Connor Fitzgerald <connorwadefitzgerald@gmail.com>
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
wgpu/examples/texture-arrays/main.rs
Normal file
318
wgpu/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
wgpu/examples/texture-arrays/shader.frag
Normal file
18
wgpu/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
wgpu/examples/texture-arrays/shader.frag.spv
Normal file
BIN
wgpu/examples/texture-arrays/shader.frag.spv
Normal file
Binary file not shown.
13
wgpu/examples/texture-arrays/shader.vert
Normal file
13
wgpu/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
wgpu/examples/texture-arrays/shader.vert.spv
Normal file
BIN
wgpu/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
wgpu/src/lib.rs
132
wgpu/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,
|
||||
};
|
||||
|
||||
@@ -628,10 +628,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.
|
||||
@@ -640,118 +642,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