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:
@@ -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.
Reference in New Issue
Block a user