mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Merge #71
71: Shadow example r=grovesNL a=kvark ~~I believe all the nuts and bolts are in place, just figuring out some details of making the shadow match between the rendering and sampling (hence the WIP).~~ Most importantly, this PR includes crucial fixes and improvements of our resource tracking, plus a few fixes in the bind group and texture creation code. Co-authored-by: Dzmitry Malyshau <kvarkus@gmail.com>
This commit is contained in:
6
Makefile
6
Makefile
@@ -30,7 +30,7 @@ else
|
||||
endif
|
||||
|
||||
|
||||
.PHONY: all check test doc clear lib-native lib-rust examples-native examples-rust gfx-cube
|
||||
.PHONY: all check test doc clear lib-native lib-rust examples-native examples-rust gfx
|
||||
|
||||
all: examples-native examples-rust examples-gfx
|
||||
|
||||
@@ -65,5 +65,5 @@ examples-rust: lib-rust examples/Cargo.toml $(wildcard wgpu-native/**/*.rs)
|
||||
examples-gfx: lib-rust gfx-examples/Cargo.toml $(wildcard gfx-examples/*.rs)
|
||||
cargo build --manifest-path gfx-examples/Cargo.toml --features $(FEATURE_RUST)
|
||||
|
||||
gfx-cube:
|
||||
cargo run --manifest-path gfx-examples/Cargo.toml --bin cube --features $(FEATURE_RUST)
|
||||
gfx:
|
||||
cargo run --manifest-path gfx-examples/Cargo.toml --bin $(name) --features $(FEATURE_RUST)
|
||||
|
||||
@@ -86,14 +86,14 @@ fn main() {
|
||||
});
|
||||
|
||||
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
|
||||
encoder.copy_buffer_tobuffer(&staging_buffer, 0, &storage_buffer, 0, size);
|
||||
encoder.copy_buffer_to_buffer(&staging_buffer, 0, &storage_buffer, 0, size);
|
||||
{
|
||||
let mut cpass = encoder.begin_compute_pass();
|
||||
cpass.set_pipeline(&compute_pipeline);
|
||||
cpass.set_bind_group(0, &bind_group);
|
||||
cpass.dispatch(numbers.len() as u32, 1, 1);
|
||||
}
|
||||
encoder.copy_buffer_tobuffer(&storage_buffer, 0, &staging_buffer, 0, size);
|
||||
encoder.copy_buffer_to_buffer(&storage_buffer, 0, &staging_buffer, 0, size);
|
||||
|
||||
// TODO: read the results back out of the staging buffer
|
||||
|
||||
|
||||
@@ -12,8 +12,13 @@ publish = false
|
||||
name = "cube"
|
||||
path = "src/cube.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "shadow"
|
||||
path = "src/shadow.rs"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
metal-auto-capture = ["wgpu/metal-auto-capture"]
|
||||
metal = ["wgpu/metal"]
|
||||
dx11 = ["wgpu/dx11"]
|
||||
dx12 = ["wgpu/dx12"]
|
||||
|
||||
@@ -11,4 +11,6 @@ layout(set = 0, binding = 0) uniform Locals {
|
||||
void main() {
|
||||
v_TexCoord = a_TexCoord;
|
||||
gl_Position = u_Transform * a_Pos;
|
||||
// convert from -1,1 Z to 0,1
|
||||
gl_Position.z = 0.5 * (gl_Position.z + gl_Position.w);
|
||||
}
|
||||
|
||||
4
gfx-examples/data/shadow-bake.frag
Normal file
4
gfx-examples/data/shadow-bake.frag
Normal file
@@ -0,0 +1,4 @@
|
||||
#version 450
|
||||
|
||||
void main() {
|
||||
}
|
||||
18
gfx-examples/data/shadow-bake.vert
Normal file
18
gfx-examples/data/shadow-bake.vert
Normal file
@@ -0,0 +1,18 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in ivec4 a_Pos;
|
||||
|
||||
layout(set = 0, binding = 0) uniform Globals {
|
||||
mat4 u_ViewProj;
|
||||
};
|
||||
|
||||
layout(set = 1, binding = 0) uniform Entity {
|
||||
mat4 u_World;
|
||||
vec4 u_Color;
|
||||
};
|
||||
|
||||
void main() {
|
||||
gl_Position = u_ViewProj * u_World * vec4(a_Pos);
|
||||
// convert from -1,1 Z to 0,1
|
||||
gl_Position.z = 0.5 * (gl_Position.z + gl_Position.w);
|
||||
}
|
||||
54
gfx-examples/data/shadow-forward.frag
Normal file
54
gfx-examples/data/shadow-forward.frag
Normal file
@@ -0,0 +1,54 @@
|
||||
#version 450
|
||||
|
||||
const int MAX_LIGHTS = 10;
|
||||
|
||||
layout(location = 0) in vec3 v_Normal;
|
||||
layout(location = 1) in vec4 v_Position;
|
||||
|
||||
layout(location = 0) out vec4 o_Target;
|
||||
|
||||
struct Light {
|
||||
mat4 proj;
|
||||
vec4 pos;
|
||||
vec4 color;
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 0) uniform Globals {
|
||||
mat4 u_ViewProj;
|
||||
uvec4 u_NumLights;
|
||||
};
|
||||
layout(set = 0, binding = 1) uniform Lights {
|
||||
Light u_Lights[MAX_LIGHTS];
|
||||
};
|
||||
layout(set = 0, binding = 2) uniform texture2DArray t_Shadow;
|
||||
layout(set = 0, binding = 3) uniform samplerShadow s_Shadow;
|
||||
|
||||
layout(set = 1, binding = 0) uniform Entity {
|
||||
mat4 u_World;
|
||||
vec4 u_Color;
|
||||
};
|
||||
|
||||
|
||||
void main() {
|
||||
vec3 normal = normalize(v_Normal);
|
||||
vec3 ambient = vec3(0.05, 0.05, 0.05);
|
||||
// accumulate color
|
||||
vec3 color = ambient;
|
||||
for (int i=0; i<int(u_NumLights.x) && i<MAX_LIGHTS; ++i) {
|
||||
Light light = u_Lights[i];
|
||||
// project into the light space
|
||||
vec4 light_local = light.proj * v_Position;
|
||||
// compute texture coordinates for shadow lookup
|
||||
light_local.xyw = (light_local.xyz/light_local.w + 1.0) / 2.0;
|
||||
light_local.z = i;
|
||||
// do the lookup, using HW PCF and comparison
|
||||
float shadow = texture(sampler2DArrayShadow(t_Shadow, s_Shadow), light_local);
|
||||
// compute Lambertian diffuse term
|
||||
vec3 light_dir = normalize(light.pos.xyz - v_Position.xyz);
|
||||
float diffuse = max(0.0, dot(normal, light_dir));
|
||||
// add light contribution
|
||||
color += shadow * diffuse * light.color.xyz;
|
||||
}
|
||||
// multiply the light by material color
|
||||
o_Target = vec4(color, 1.0) * u_Color;
|
||||
}
|
||||
24
gfx-examples/data/shadow-forward.vert
Normal file
24
gfx-examples/data/shadow-forward.vert
Normal file
@@ -0,0 +1,24 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in ivec4 a_Pos;
|
||||
layout(location = 1) in ivec4 a_Normal;
|
||||
|
||||
layout(location = 0) out vec3 v_Normal;
|
||||
layout(location = 1) out vec4 v_Position;
|
||||
|
||||
layout(set = 0, binding = 0) uniform Globals {
|
||||
mat4 u_ViewProj;
|
||||
uvec4 u_NumLights;
|
||||
};
|
||||
layout(set = 1, binding = 0) uniform Entity {
|
||||
mat4 u_World;
|
||||
vec4 u_Color;
|
||||
};
|
||||
|
||||
void main() {
|
||||
v_Normal = mat3(u_World) * vec3(a_Normal.xyz);
|
||||
v_Position = u_World * vec4(a_Pos);
|
||||
gl_Position = u_ViewProj * v_Position;
|
||||
// convert from -1,1 Z to 0,1
|
||||
gl_Position.z = 0.5 * (gl_Position.z + gl_Position.w);
|
||||
}
|
||||
@@ -83,7 +83,7 @@ fn create_texels(size: usize) -> Vec<u8> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
struct Cube {
|
||||
struct Example {
|
||||
vertex_buf: wgpu::Buffer,
|
||||
index_buf: wgpu::Buffer,
|
||||
index_count: usize,
|
||||
@@ -92,20 +92,20 @@ struct Cube {
|
||||
pipeline: wgpu::RenderPipeline,
|
||||
}
|
||||
|
||||
impl Cube {
|
||||
impl Example {
|
||||
fn generate_matrix(aspect_ratio: f32) -> cgmath::Matrix4<f32> {
|
||||
let mx_projection = cgmath::perspective(cgmath::Deg(45f32), aspect_ratio, 1.0, 10.0);
|
||||
let mx_view = cgmath::Matrix4::look_at(
|
||||
cgmath::Point3::new(1.5f32, -5.0, 3.0),
|
||||
cgmath::Point3::new(0f32, 0.0, 0.0),
|
||||
cgmath::Vector3::unit_z(),
|
||||
-cgmath::Vector3::unit_z(),
|
||||
);
|
||||
mx_projection * mx_view
|
||||
}
|
||||
}
|
||||
|
||||
impl framework::Example for Cube {
|
||||
fn init(device: &mut wgpu::Device, sc_desc: &wgpu::SwapChainDescriptor) -> Self {
|
||||
impl framework::Example for Example {
|
||||
fn init(sc_desc: &wgpu::SwapChainDescriptor, device: &mut wgpu::Device) -> Self {
|
||||
use std::mem;
|
||||
|
||||
let mut init_encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
||||
@@ -293,7 +293,7 @@ impl framework::Example for Cube {
|
||||
// Done
|
||||
let init_command_buf = init_encoder.finish();
|
||||
device.get_queue().submit(&[init_command_buf]);
|
||||
Cube {
|
||||
Example {
|
||||
vertex_buf,
|
||||
index_buf,
|
||||
index_count: index_data.len(),
|
||||
@@ -303,12 +303,14 @@ impl framework::Example for Cube {
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, event: wgpu::winit::WindowEvent) {
|
||||
if let wgpu::winit::WindowEvent::Resized(size) = event {
|
||||
let mx_total = Self::generate_matrix(size.width as f32 / size.height as f32);
|
||||
let mx_ref: &[f32; 16] = mx_total.as_ref();
|
||||
self.uniform_buf.set_sub_data(0, framework::cast_slice(&mx_ref[..]));
|
||||
}
|
||||
fn update(&mut self, _event: wgpu::winit::WindowEvent) {
|
||||
//empty
|
||||
}
|
||||
|
||||
fn resize(&mut self, sc_desc: &wgpu::SwapChainDescriptor, _device: &mut wgpu::Device) {
|
||||
let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32);
|
||||
let mx_ref: &[f32; 16] = mx_total.as_ref();
|
||||
self.uniform_buf.set_sub_data(0, framework::cast_slice(&mx_ref[..]));
|
||||
}
|
||||
|
||||
fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &mut wgpu::Device) {
|
||||
@@ -337,5 +339,5 @@ impl framework::Example for Cube {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
framework::run::<Cube>("cube");
|
||||
framework::run::<Example>("cube");
|
||||
}
|
||||
|
||||
@@ -30,7 +30,11 @@ pub fn load_glsl(name: &str, stage: ShaderStage) -> Vec<u8> {
|
||||
let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("data")
|
||||
.join(name);
|
||||
let code = read_to_string(path).unwrap();
|
||||
let code = match read_to_string(&path) {
|
||||
Ok(code) => code,
|
||||
Err(e) => panic!("Unable to read {:?}: {:?}", path, e),
|
||||
};
|
||||
|
||||
let mut output = glsl_to_spirv::compile(&code, ty).unwrap();
|
||||
let mut spv = Vec::new();
|
||||
output.read_to_end(&mut spv).unwrap();
|
||||
@@ -38,7 +42,8 @@ pub fn load_glsl(name: &str, stage: ShaderStage) -> Vec<u8> {
|
||||
}
|
||||
|
||||
pub trait Example {
|
||||
fn init(device: &mut wgpu::Device, sc_desc: &wgpu::SwapChainDescriptor) -> Self;
|
||||
fn init(sc_desc: &wgpu::SwapChainDescriptor, device: &mut wgpu::Device) -> Self;
|
||||
fn resize(&mut self, sc_desc: &wgpu::SwapChainDescriptor, device: &mut wgpu::Device);
|
||||
fn update(&mut self, event: wgpu::winit::WindowEvent);
|
||||
fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &mut wgpu::Device);
|
||||
}
|
||||
@@ -79,7 +84,7 @@ pub fn run<E: Example>(title: &str) {
|
||||
let mut swap_chain = device.create_swap_chain(&surface, &sc_desc);
|
||||
|
||||
info!("Initializing the example...");
|
||||
let mut example = E::init(&mut device, &sc_desc);
|
||||
let mut example = E::init(&sc_desc, &mut device);
|
||||
|
||||
info!("Entering render loop...");
|
||||
let mut running = true;
|
||||
@@ -95,7 +100,7 @@ pub fn run<E: Example>(title: &str) {
|
||||
sc_desc.width = physical.width as u32;
|
||||
sc_desc.height = physical.height as u32;
|
||||
swap_chain = device.create_swap_chain(&surface, &sc_desc);
|
||||
example.update(WindowEvent::Resized(size));
|
||||
example.resize(&sc_desc, &mut device);
|
||||
}
|
||||
Event::WindowEvent { event, .. } => match event {
|
||||
WindowEvent::KeyboardInput {
|
||||
@@ -119,5 +124,6 @@ pub fn run<E: Example>(title: &str) {
|
||||
|
||||
let frame = swap_chain.get_next_texture();
|
||||
example.render(&frame, &mut device);
|
||||
running &= !cfg!(feature = "metal-auto-capture");
|
||||
}
|
||||
}
|
||||
|
||||
755
gfx-examples/src/shadow.rs
Normal file
755
gfx-examples/src/shadow.rs
Normal file
@@ -0,0 +1,755 @@
|
||||
use std::mem;
|
||||
use std::ops::Range;
|
||||
use std::rc::Rc;
|
||||
|
||||
mod framework;
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Vertex {
|
||||
pos: [i8; 4],
|
||||
normal: [i8; 4],
|
||||
}
|
||||
|
||||
fn vertex(pos: [i8; 3], nor: [i8; 3]) -> Vertex {
|
||||
Vertex {
|
||||
pos: [pos[0], pos[1], pos[2], 1],
|
||||
normal: [nor[0], nor[1], nor[2], 0],
|
||||
}
|
||||
}
|
||||
|
||||
fn create_cube() -> (Vec<Vertex>, Vec<u16>) {
|
||||
let vertex_data = [
|
||||
// top (0, 0, 1)
|
||||
vertex([-1, -1, 1], [0, 0, 1]),
|
||||
vertex([ 1, -1, 1], [0, 0, 1]),
|
||||
vertex([ 1, 1, 1], [0, 0, 1]),
|
||||
vertex([-1, 1, 1], [0, 0, 1]),
|
||||
// bottom (0, 0, -1)
|
||||
vertex([-1, 1, -1], [0, 0, -1]),
|
||||
vertex([ 1, 1, -1], [0, 0, -1]),
|
||||
vertex([ 1, -1, -1], [0, 0, -1]),
|
||||
vertex([-1, -1, -1], [0, 0, -1]),
|
||||
// right (1, 0, 0)
|
||||
vertex([ 1, -1, -1], [1, 0, 0]),
|
||||
vertex([ 1, 1, -1], [1, 0, 0]),
|
||||
vertex([ 1, 1, 1], [1, 0, 0]),
|
||||
vertex([ 1, -1, 1], [1, 0, 0]),
|
||||
// left (-1, 0, 0)
|
||||
vertex([-1, -1, 1], [-1, 0, 0]),
|
||||
vertex([-1, 1, 1], [-1, 0, 0]),
|
||||
vertex([-1, 1, -1], [-1, 0, 0]),
|
||||
vertex([-1, -1, -1], [-1, 0, 0]),
|
||||
// front (0, 1, 0)
|
||||
vertex([ 1, 1, -1], [0, 1, 0]),
|
||||
vertex([-1, 1, -1], [0, 1, 0]),
|
||||
vertex([-1, 1, 1], [0, 1, 0]),
|
||||
vertex([ 1, 1, 1], [0, 1, 0]),
|
||||
// back (0, -1, 0)
|
||||
vertex([ 1, -1, 1], [0, -1, 0]),
|
||||
vertex([-1, -1, 1], [0, -1, 0]),
|
||||
vertex([-1, -1, -1], [0, -1, 0]),
|
||||
vertex([ 1, -1, -1], [0, -1, 0]),
|
||||
];
|
||||
|
||||
let index_data: &[u16] = &[
|
||||
0, 1, 2, 2, 3, 0, // top
|
||||
4, 5, 6, 6, 7, 4, // bottom
|
||||
8, 9, 10, 10, 11, 8, // right
|
||||
12, 13, 14, 14, 15, 12, // left
|
||||
16, 17, 18, 18, 19, 16, // front
|
||||
20, 21, 22, 22, 23, 20, // back
|
||||
];
|
||||
|
||||
(vertex_data.to_vec(), index_data.to_vec())
|
||||
}
|
||||
|
||||
fn create_plane(size: i8) -> (Vec<Vertex>, Vec<u16>) {
|
||||
let vertex_data = [
|
||||
vertex([ size, -size, 0], [0, 0, 1]),
|
||||
vertex([ size, size, 0], [0, 0, 1]),
|
||||
vertex([-size, -size, 0], [0, 0, 1]),
|
||||
vertex([-size, size, 0], [0, 0, 1]),
|
||||
];
|
||||
|
||||
let index_data: &[u16] = &[
|
||||
0, 1, 2,
|
||||
2, 1, 3
|
||||
];
|
||||
|
||||
(vertex_data.to_vec(), index_data.to_vec())
|
||||
}
|
||||
|
||||
|
||||
struct Entity {
|
||||
mx_world: cgmath::Matrix4<f32>,
|
||||
rotation_speed: f32,
|
||||
color: wgpu::Color,
|
||||
vertex_buf: Rc<wgpu::Buffer>,
|
||||
index_buf: Rc<wgpu::Buffer>,
|
||||
index_count: usize,
|
||||
bind_group: wgpu::BindGroup,
|
||||
uniform_buf: wgpu::Buffer,
|
||||
}
|
||||
|
||||
struct Light {
|
||||
pos: cgmath::Point3<f32>,
|
||||
color: wgpu::Color,
|
||||
fov: f32,
|
||||
depth: Range<f32>,
|
||||
target_view: wgpu::TextureView,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct LightRaw {
|
||||
proj: [[f32; 4]; 4],
|
||||
pos: [f32; 4],
|
||||
color: [f32; 4],
|
||||
}
|
||||
|
||||
impl Light {
|
||||
fn to_raw(&self) -> LightRaw {
|
||||
use cgmath::{EuclideanSpace, Deg, Point3, Vector3, Matrix4, PerspectiveFov};
|
||||
|
||||
let mx_view = Matrix4::look_at(
|
||||
self.pos,
|
||||
Point3::origin(),
|
||||
-Vector3::unit_z(),
|
||||
);
|
||||
let projection = PerspectiveFov {
|
||||
fovy: Deg(self.fov).into(),
|
||||
aspect: 1.0,
|
||||
near: self.depth.start,
|
||||
far: self.depth.end,
|
||||
};
|
||||
let mx_view_proj = cgmath::Matrix4::from(projection.to_perspective()) * mx_view;
|
||||
LightRaw {
|
||||
proj: *mx_view_proj.as_ref(),
|
||||
pos: [self.pos.x, self.pos.y, self.pos.z, 1.0],
|
||||
color: [self.color.r, self.color.g, self.color.b, 1.0],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct ForwardUniforms {
|
||||
proj: [[f32; 4]; 4],
|
||||
num_lights: [u32; 4],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct EntityUniforms {
|
||||
model: [[f32; 4]; 4],
|
||||
color: [f32; 4],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct ShadowUniforms {
|
||||
proj: [[f32; 4]; 4],
|
||||
}
|
||||
|
||||
struct Pass {
|
||||
pipeline: wgpu::RenderPipeline,
|
||||
bind_group: wgpu::BindGroup,
|
||||
uniform_buf: wgpu::Buffer,
|
||||
}
|
||||
|
||||
struct Example {
|
||||
entities: Vec<Entity>,
|
||||
lights: Vec<Light>,
|
||||
lights_are_dirty: bool,
|
||||
shadow_pass: Pass,
|
||||
forward_pass: Pass,
|
||||
forward_depth: wgpu::TextureView,
|
||||
light_uniform_buf: wgpu::Buffer,
|
||||
}
|
||||
|
||||
impl Example {
|
||||
const MAX_LIGHTS: usize = 10;
|
||||
const SHADOW_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::D32Float;
|
||||
const SHADOW_SIZE: wgpu::Extent3d = wgpu::Extent3d {
|
||||
width: 512,
|
||||
height: 512,
|
||||
depth: 1,
|
||||
};
|
||||
const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::D32Float;
|
||||
|
||||
fn generate_matrix(aspect_ratio: f32) -> cgmath::Matrix4<f32> {
|
||||
let mx_projection = cgmath::perspective(cgmath::Deg(45f32), aspect_ratio, 1.0, 20.0);
|
||||
let mx_view = cgmath::Matrix4::look_at(
|
||||
cgmath::Point3::new(3.0f32, -10.0, 6.0),
|
||||
cgmath::Point3::new(0f32, 0.0, 0.0),
|
||||
-cgmath::Vector3::unit_z(),
|
||||
);
|
||||
mx_projection * mx_view
|
||||
}
|
||||
}
|
||||
|
||||
impl framework::Example for Example {
|
||||
fn init(sc_desc: &wgpu::SwapChainDescriptor, device: &mut wgpu::Device) -> Self {
|
||||
// Create the vertex and index buffers
|
||||
let vertex_size = mem::size_of::<Vertex>();
|
||||
let (cube_vertex_data, cube_index_data) = create_cube();
|
||||
let cube_vertex_buf = Rc::new(device.create_buffer(&wgpu::BufferDescriptor {
|
||||
size: (cube_vertex_data.len() * vertex_size) as u32,
|
||||
usage: wgpu::BufferUsageFlags::VERTEX | wgpu::BufferUsageFlags::TRANSFER_DST,
|
||||
}));
|
||||
cube_vertex_buf.set_sub_data(0, framework::cast_slice(&cube_vertex_data));
|
||||
let cube_index_buf = Rc::new(device.create_buffer(&wgpu::BufferDescriptor {
|
||||
size: (cube_index_data.len() * 2) as u32,
|
||||
usage: wgpu::BufferUsageFlags::INDEX | wgpu::BufferUsageFlags::TRANSFER_DST,
|
||||
}));
|
||||
cube_index_buf.set_sub_data(0, framework::cast_slice(&cube_index_data));
|
||||
|
||||
let (plane_vertex_data, plane_index_data) = create_plane(7);
|
||||
let plane_vertex_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
size: (plane_vertex_data.len() * vertex_size) as u32,
|
||||
usage: wgpu::BufferUsageFlags::VERTEX | wgpu::BufferUsageFlags::TRANSFER_DST,
|
||||
});
|
||||
plane_vertex_buf.set_sub_data(0, framework::cast_slice(&plane_vertex_data));
|
||||
let plane_index_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
size: (plane_index_data.len() * 2) as u32,
|
||||
usage: wgpu::BufferUsageFlags::INDEX | wgpu::BufferUsageFlags::TRANSFER_DST,
|
||||
});
|
||||
plane_index_buf.set_sub_data(0, framework::cast_slice(&plane_index_data));
|
||||
let entity_uniform_size = mem::size_of::<EntityUniforms>() as u32;
|
||||
let plane_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
size: entity_uniform_size,
|
||||
usage: wgpu::BufferUsageFlags::UNIFORM | wgpu::BufferUsageFlags::TRANSFER_DST,
|
||||
});
|
||||
|
||||
let local_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
bindings: &[
|
||||
wgpu::BindGroupLayoutBinding {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStageFlags::VERTEX | wgpu::ShaderStageFlags::FRAGMENT,
|
||||
ty: wgpu::BindingType::UniformBuffer,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
let mut entities = vec![{
|
||||
use cgmath::SquareMatrix;
|
||||
|
||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &local_bind_group_layout,
|
||||
bindings: &[
|
||||
wgpu::Binding {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer {
|
||||
buffer: &plane_uniform_buf,
|
||||
range: 0 .. entity_uniform_size,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
Entity {
|
||||
mx_world: cgmath::Matrix4::identity(),
|
||||
rotation_speed: 0.0,
|
||||
color: wgpu::Color::WHITE,
|
||||
vertex_buf: Rc::new(plane_vertex_buf),
|
||||
index_buf: Rc::new(plane_index_buf),
|
||||
index_count: plane_index_data.len(),
|
||||
bind_group,
|
||||
uniform_buf: plane_uniform_buf,
|
||||
}
|
||||
}];
|
||||
|
||||
struct CubeDesc {
|
||||
offset: cgmath::Vector3<f32>,
|
||||
angle: f32,
|
||||
scale: f32,
|
||||
rotation: f32,
|
||||
}
|
||||
let cube_descs = [
|
||||
CubeDesc {
|
||||
offset: cgmath::vec3(-2.0, -2.0, 2.0),
|
||||
angle: 10.0,
|
||||
scale: 0.7,
|
||||
rotation: 1.0,
|
||||
},
|
||||
CubeDesc {
|
||||
offset: cgmath::vec3(2.0, -2.0, 2.0),
|
||||
angle: 50.0,
|
||||
scale: 1.3,
|
||||
rotation: 2.0,
|
||||
},
|
||||
CubeDesc {
|
||||
offset: cgmath::vec3(-2.0, 2.0, 2.0),
|
||||
angle: 140.0,
|
||||
scale: 1.1,
|
||||
rotation: 3.0,
|
||||
},
|
||||
CubeDesc {
|
||||
offset: cgmath::vec3(2.0, 2.0, 2.0),
|
||||
angle: 210.0,
|
||||
scale: 0.9,
|
||||
rotation: 4.0,
|
||||
},
|
||||
];
|
||||
|
||||
for cube in &cube_descs {
|
||||
use cgmath::{Deg, Decomposed, Quaternion, Rotation3, InnerSpace};
|
||||
|
||||
let transform = Decomposed {
|
||||
disp: cube.offset.clone(),
|
||||
rot: Quaternion::from_axis_angle(
|
||||
cube.offset.normalize(),
|
||||
Deg(cube.angle),
|
||||
),
|
||||
scale: cube.scale,
|
||||
};
|
||||
let uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
size: entity_uniform_size,
|
||||
usage: wgpu::BufferUsageFlags::UNIFORM | wgpu::BufferUsageFlags::TRANSFER_DST,
|
||||
});
|
||||
entities.push(Entity {
|
||||
mx_world: cgmath::Matrix4::from(transform),
|
||||
rotation_speed: cube.rotation,
|
||||
color: wgpu::Color::GREEN,
|
||||
vertex_buf: Rc::clone(&cube_vertex_buf),
|
||||
index_buf: Rc::clone(&cube_index_buf),
|
||||
index_count: cube_index_data.len(),
|
||||
bind_group: device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &local_bind_group_layout,
|
||||
bindings: &[
|
||||
wgpu::Binding {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer {
|
||||
buffer: &uniform_buf,
|
||||
range: 0 .. entity_uniform_size,
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
uniform_buf,
|
||||
});
|
||||
}
|
||||
|
||||
// Create other resources
|
||||
let shadow_sampler = device.create_sampler(&wgpu::SamplerDescriptor {
|
||||
r_address_mode: wgpu::AddressMode::ClampToEdge,
|
||||
s_address_mode: wgpu::AddressMode::ClampToEdge,
|
||||
t_address_mode: wgpu::AddressMode::ClampToEdge,
|
||||
mag_filter: wgpu::FilterMode::Linear,
|
||||
min_filter: wgpu::FilterMode::Linear,
|
||||
mipmap_filter: wgpu::FilterMode::Nearest,
|
||||
lod_min_clamp: -100.0,
|
||||
lod_max_clamp: 100.0,
|
||||
max_anisotropy: 0,
|
||||
compare_function: wgpu::CompareFunction::LessEqual,
|
||||
border_color: wgpu::BorderColor::TransparentBlack,
|
||||
});
|
||||
|
||||
let shadow_texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
size: Self::SHADOW_SIZE,
|
||||
array_size: Self::MAX_LIGHTS as u32,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: Self::SHADOW_FORMAT,
|
||||
usage: wgpu::TextureUsageFlags::OUTPUT_ATTACHMENT | wgpu::TextureUsageFlags::SAMPLED,
|
||||
});
|
||||
let shadow_view = shadow_texture.create_default_view();
|
||||
|
||||
let mut shadow_target_views = (0..2)
|
||||
.map(|i| Some(shadow_texture.create_view(&wgpu::TextureViewDescriptor {
|
||||
format: Self::SHADOW_FORMAT,
|
||||
dimension: wgpu::TextureViewDimension::D2,
|
||||
aspect: wgpu::TextureAspectFlags::DEPTH,
|
||||
base_mip_level: 0,
|
||||
level_count: 1,
|
||||
base_array_layer: i as u32,
|
||||
array_count: 1,
|
||||
})))
|
||||
.collect::<Vec<_>>();
|
||||
let lights = vec![
|
||||
Light {
|
||||
pos: cgmath::Point3::new(7.0, -5.0, 10.0),
|
||||
color: wgpu::Color { r: 0.5, g: 1.0, b: 0.5, a: 1.0 },
|
||||
fov: 60.0,
|
||||
depth: 1.0 .. 20.0,
|
||||
target_view: shadow_target_views[0].take().unwrap(),
|
||||
},
|
||||
Light {
|
||||
pos: cgmath::Point3::new(-5.0, 7.0, 10.0),
|
||||
color: wgpu::Color { r: 1.0, g: 0.5, b: 0.5, a: 1.0 },
|
||||
fov: 45.0,
|
||||
depth: 1.0 .. 20.0,
|
||||
target_view: shadow_target_views[1].take().unwrap(),
|
||||
},
|
||||
];
|
||||
let light_uniform_size = (Self::MAX_LIGHTS * mem::size_of::<LightRaw>()) as u32;
|
||||
let light_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
size: light_uniform_size,
|
||||
usage: wgpu::BufferUsageFlags::UNIFORM | wgpu::BufferUsageFlags::TRANSFER_DST,
|
||||
});
|
||||
|
||||
let vb_desc = wgpu::VertexBufferDescriptor {
|
||||
stride: vertex_size as u32,
|
||||
step_mode: wgpu::InputStepMode::Vertex,
|
||||
attributes: &[
|
||||
wgpu::VertexAttributeDescriptor {
|
||||
attribute_index: 0,
|
||||
format: wgpu::VertexFormat::IntR8G8B8A8,
|
||||
offset: 0,
|
||||
},
|
||||
wgpu::VertexAttributeDescriptor {
|
||||
attribute_index: 1,
|
||||
format: wgpu::VertexFormat::IntR8G8B8A8,
|
||||
offset: 4 * 1,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
let shadow_pass = {
|
||||
// Create pipeline layout
|
||||
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
bindings: &[
|
||||
wgpu::BindGroupLayoutBinding {
|
||||
binding: 0, // global
|
||||
visibility: wgpu::ShaderStageFlags::VERTEX,
|
||||
ty: wgpu::BindingType::UniformBuffer,
|
||||
},
|
||||
],
|
||||
});
|
||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
bind_group_layouts: &[
|
||||
&bind_group_layout,
|
||||
&local_bind_group_layout,
|
||||
],
|
||||
});
|
||||
|
||||
let uniform_size = mem::size_of::<ShadowUniforms>() as u32;
|
||||
let uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
size: uniform_size,
|
||||
usage: wgpu::BufferUsageFlags::UNIFORM | wgpu::BufferUsageFlags::TRANSFER_DST,
|
||||
});
|
||||
|
||||
// Create bind group
|
||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &bind_group_layout,
|
||||
bindings: &[
|
||||
wgpu::Binding {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer {
|
||||
buffer: &uniform_buf,
|
||||
range: 0 .. uniform_size,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// Create the render pipeline
|
||||
let vs_bytes = framework::load_glsl("shadow-bake.vert", framework::ShaderStage::Vertex);
|
||||
let fs_bytes = framework::load_glsl("shadow-bake.frag", framework::ShaderStage::Fragment);
|
||||
let vs_module = device.create_shader_module(&vs_bytes);
|
||||
let fs_module = device.create_shader_module(&fs_bytes);
|
||||
|
||||
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
layout: &pipeline_layout,
|
||||
vertex_stage: wgpu::PipelineStageDescriptor {
|
||||
module: &vs_module,
|
||||
entry_point: "main",
|
||||
},
|
||||
fragment_stage: wgpu::PipelineStageDescriptor {
|
||||
module: &fs_module,
|
||||
entry_point: "main",
|
||||
},
|
||||
rasterization_state: wgpu::RasterizationStateDescriptor {
|
||||
front_face: wgpu::FrontFace::Cw,
|
||||
cull_mode: wgpu::CullMode::Back,
|
||||
depth_bias: 2, // corresponds to bilinear filtering
|
||||
depth_bias_slope_scale: 2.0,
|
||||
depth_bias_clamp: wgpu::MAX_DEPTH_BIAS_CLAMP,
|
||||
},
|
||||
primitive_topology: wgpu::PrimitiveTopology::TriangleList,
|
||||
color_states: &[],
|
||||
depth_stencil_state: Some(wgpu::DepthStencilStateDescriptor {
|
||||
format: Self::SHADOW_FORMAT,
|
||||
depth_write_enabled: true,
|
||||
depth_compare: wgpu::CompareFunction::LessEqual,
|
||||
stencil_front: wgpu::StencilStateFaceDescriptor::IGNORE,
|
||||
stencil_back: wgpu::StencilStateFaceDescriptor::IGNORE,
|
||||
stencil_read_mask: 0,
|
||||
stencil_write_mask: 0,
|
||||
}),
|
||||
index_format: wgpu::IndexFormat::Uint16,
|
||||
vertex_buffers: &[vb_desc.clone()],
|
||||
sample_count: 1,
|
||||
});
|
||||
|
||||
Pass {
|
||||
pipeline,
|
||||
bind_group,
|
||||
uniform_buf,
|
||||
}
|
||||
};
|
||||
|
||||
let forward_pass = {
|
||||
// Create pipeline layout
|
||||
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
bindings: &[
|
||||
wgpu::BindGroupLayoutBinding {
|
||||
binding: 0, // global
|
||||
visibility: wgpu::ShaderStageFlags::VERTEX | wgpu::ShaderStageFlags::FRAGMENT,
|
||||
ty: wgpu::BindingType::UniformBuffer,
|
||||
},
|
||||
wgpu::BindGroupLayoutBinding {
|
||||
binding: 1, // lights
|
||||
visibility: wgpu::ShaderStageFlags::VERTEX | wgpu::ShaderStageFlags::FRAGMENT,
|
||||
ty: wgpu::BindingType::UniformBuffer,
|
||||
},
|
||||
wgpu::BindGroupLayoutBinding {
|
||||
binding: 2,
|
||||
visibility: wgpu::ShaderStageFlags::FRAGMENT,
|
||||
ty: wgpu::BindingType::SampledTexture,
|
||||
},
|
||||
wgpu::BindGroupLayoutBinding {
|
||||
binding: 3,
|
||||
visibility: wgpu::ShaderStageFlags::FRAGMENT,
|
||||
ty: wgpu::BindingType::Sampler,
|
||||
},
|
||||
],
|
||||
});
|
||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
bind_group_layouts: &[
|
||||
&bind_group_layout,
|
||||
&local_bind_group_layout,
|
||||
],
|
||||
});
|
||||
|
||||
let uniform_size = mem::size_of::<ForwardUniforms>() as u32;
|
||||
let uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
size: uniform_size,
|
||||
usage: wgpu::BufferUsageFlags::UNIFORM | wgpu::BufferUsageFlags::TRANSFER_DST,
|
||||
});
|
||||
let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32);
|
||||
let data = ForwardUniforms {
|
||||
proj: *mx_total.as_ref(),
|
||||
num_lights: [lights.len() as u32, 0, 0, 0],
|
||||
};
|
||||
uniform_buf.set_sub_data(0, framework::cast_slice(&[data]));
|
||||
|
||||
// Create bind group
|
||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &bind_group_layout,
|
||||
bindings: &[
|
||||
wgpu::Binding {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::Buffer {
|
||||
buffer: &uniform_buf,
|
||||
range: 0 .. uniform_size,
|
||||
},
|
||||
},
|
||||
wgpu::Binding {
|
||||
binding: 1,
|
||||
resource: wgpu::BindingResource::Buffer {
|
||||
buffer: &light_uniform_buf,
|
||||
range: 0 .. light_uniform_size,
|
||||
},
|
||||
},
|
||||
wgpu::Binding {
|
||||
binding: 2,
|
||||
resource: wgpu::BindingResource::TextureView(&shadow_view),
|
||||
},
|
||||
wgpu::Binding {
|
||||
binding: 3,
|
||||
resource: wgpu::BindingResource::Sampler(&shadow_sampler),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// Create the render pipeline
|
||||
let vs_bytes = framework::load_glsl("shadow-forward.vert", framework::ShaderStage::Vertex);
|
||||
let fs_bytes = framework::load_glsl("shadow-forward.frag", framework::ShaderStage::Fragment);
|
||||
let vs_module = device.create_shader_module(&vs_bytes);
|
||||
let fs_module = device.create_shader_module(&fs_bytes);
|
||||
|
||||
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
layout: &pipeline_layout,
|
||||
vertex_stage: wgpu::PipelineStageDescriptor {
|
||||
module: &vs_module,
|
||||
entry_point: "main",
|
||||
},
|
||||
fragment_stage: wgpu::PipelineStageDescriptor {
|
||||
module: &fs_module,
|
||||
entry_point: "main",
|
||||
},
|
||||
rasterization_state: wgpu::RasterizationStateDescriptor {
|
||||
front_face: wgpu::FrontFace::Cw,
|
||||
cull_mode: wgpu::CullMode::Back,
|
||||
depth_bias: 0,
|
||||
depth_bias_slope_scale: 0.0,
|
||||
depth_bias_clamp: wgpu::MAX_DEPTH_BIAS_CLAMP,
|
||||
},
|
||||
primitive_topology: wgpu::PrimitiveTopology::TriangleList,
|
||||
color_states: &[
|
||||
wgpu::ColorStateDescriptor {
|
||||
format: sc_desc.format,
|
||||
color: wgpu::BlendDescriptor::REPLACE,
|
||||
alpha: wgpu::BlendDescriptor::REPLACE,
|
||||
write_mask: wgpu::ColorWriteFlags::ALL,
|
||||
},
|
||||
],
|
||||
depth_stencil_state: Some(wgpu::DepthStencilStateDescriptor {
|
||||
format: Self::DEPTH_FORMAT,
|
||||
depth_write_enabled: true,
|
||||
depth_compare: wgpu::CompareFunction::Less,
|
||||
stencil_front: wgpu::StencilStateFaceDescriptor::IGNORE,
|
||||
stencil_back: wgpu::StencilStateFaceDescriptor::IGNORE,
|
||||
stencil_read_mask: 0,
|
||||
stencil_write_mask: 0,
|
||||
}),
|
||||
index_format: wgpu::IndexFormat::Uint16,
|
||||
vertex_buffers: &[vb_desc],
|
||||
sample_count: 1,
|
||||
});
|
||||
|
||||
Pass {
|
||||
pipeline,
|
||||
bind_group,
|
||||
uniform_buf,
|
||||
}
|
||||
};
|
||||
|
||||
let depth_texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
size: wgpu::Extent3d {
|
||||
width: sc_desc.width,
|
||||
height: sc_desc.height,
|
||||
depth: 1,
|
||||
},
|
||||
array_size: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: Self::DEPTH_FORMAT,
|
||||
usage: wgpu::TextureUsageFlags::OUTPUT_ATTACHMENT,
|
||||
});
|
||||
|
||||
Example {
|
||||
entities,
|
||||
lights,
|
||||
lights_are_dirty: true,
|
||||
shadow_pass,
|
||||
forward_pass,
|
||||
forward_depth: depth_texture.create_default_view(),
|
||||
light_uniform_buf,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, _event: wgpu::winit::WindowEvent) {
|
||||
//empty
|
||||
}
|
||||
|
||||
fn resize(&mut self, sc_desc: &wgpu::SwapChainDescriptor, device: &mut wgpu::Device) {
|
||||
let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32);
|
||||
let mx_ref: &[f32; 16] = mx_total.as_ref();
|
||||
self.forward_pass.uniform_buf.set_sub_data(0, framework::cast_slice(&mx_ref[..]));
|
||||
|
||||
let depth_texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||
size: wgpu::Extent3d {
|
||||
width: sc_desc.width,
|
||||
height: sc_desc.height,
|
||||
depth: 1,
|
||||
},
|
||||
array_size: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: Self::DEPTH_FORMAT,
|
||||
usage: wgpu::TextureUsageFlags::OUTPUT_ATTACHMENT,
|
||||
});
|
||||
self.forward_depth = depth_texture.create_default_view();
|
||||
}
|
||||
|
||||
fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &mut wgpu::Device) {
|
||||
for entity in &mut self.entities {
|
||||
if entity.rotation_speed != 0.0 {
|
||||
let rotation = cgmath::Matrix4::from_angle_x(cgmath::Deg(entity.rotation_speed));
|
||||
entity.mx_world = entity.mx_world * rotation;
|
||||
}
|
||||
let data = EntityUniforms {
|
||||
model: *entity.mx_world.as_ref(),
|
||||
color: [entity.color.r, entity.color.g, entity.color.b, entity.color.a],
|
||||
};
|
||||
entity.uniform_buf.set_sub_data(0, framework::cast_slice(&[data]));
|
||||
}
|
||||
if self.lights_are_dirty {
|
||||
self.lights_are_dirty = false;
|
||||
let raw = self.lights
|
||||
.iter()
|
||||
.map(|light| light.to_raw())
|
||||
.collect::<Vec<_>>();
|
||||
self.light_uniform_buf.set_sub_data(0, framework::cast_slice(&raw));
|
||||
}
|
||||
|
||||
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
|
||||
|
||||
for (i, light) in self.lights.iter().enumerate() {
|
||||
// The light uniform buffer already has the projection,
|
||||
// let's just copy it over to the shadow uniform buffer.
|
||||
encoder.copy_buffer_to_buffer(
|
||||
&self.light_uniform_buf,
|
||||
(i * mem::size_of::<LightRaw>()) as u32,
|
||||
&self.shadow_pass.uniform_buf,
|
||||
0,
|
||||
64,
|
||||
);
|
||||
|
||||
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
color_attachments: &[],
|
||||
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor {
|
||||
attachment: &light.target_view,
|
||||
depth_load_op: wgpu::LoadOp::Clear,
|
||||
depth_store_op: wgpu::StoreOp::Store,
|
||||
stencil_load_op: wgpu::LoadOp::Clear,
|
||||
stencil_store_op: wgpu::StoreOp::Store,
|
||||
clear_depth: 1.0,
|
||||
clear_stencil: 0,
|
||||
}),
|
||||
});
|
||||
pass.set_pipeline(&self.shadow_pass.pipeline);
|
||||
pass.set_bind_group(0, &self.shadow_pass.bind_group);
|
||||
|
||||
for entity in &self.entities {
|
||||
pass.set_bind_group(1, &entity.bind_group);
|
||||
pass.set_index_buffer(&entity.index_buf, 0);
|
||||
pass.set_vertex_buffers(&[(&entity.vertex_buf, 0)]);
|
||||
pass.draw_indexed(0 .. entity.index_count as u32, 0, 0..1);
|
||||
}
|
||||
}
|
||||
|
||||
// forward pass
|
||||
{
|
||||
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
|
||||
attachment: &frame.view,
|
||||
load_op: wgpu::LoadOp::Clear,
|
||||
store_op: wgpu::StoreOp::Store,
|
||||
clear_color: wgpu::Color { r: 0.1, g: 0.2, b: 0.3, a: 1.0 },
|
||||
}],
|
||||
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor {
|
||||
attachment: &self.forward_depth,
|
||||
depth_load_op: wgpu::LoadOp::Clear,
|
||||
depth_store_op: wgpu::StoreOp::Store,
|
||||
stencil_load_op: wgpu::LoadOp::Clear,
|
||||
stencil_store_op: wgpu::StoreOp::Store,
|
||||
clear_depth: 1.0,
|
||||
clear_stencil: 0,
|
||||
}),
|
||||
});
|
||||
pass.set_pipeline(&self.forward_pass.pipeline);
|
||||
pass.set_bind_group(0, &self.forward_pass.bind_group);
|
||||
|
||||
for entity in &self.entities {
|
||||
pass.set_bind_group(1, &entity.bind_group);
|
||||
pass.set_index_buffer(&entity.index_buf, 0);
|
||||
pass.set_vertex_buffers(&[(&entity.vertex_buf, 0)]);
|
||||
pass.draw_indexed(0 .. entity.index_count as u32, 0, 0..1);
|
||||
}
|
||||
}
|
||||
|
||||
device
|
||||
.get_queue()
|
||||
.submit(&[encoder.finish()]);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
framework::run::<Example>("shadow");
|
||||
}
|
||||
@@ -18,6 +18,7 @@ crate-type = ["lib", "cdylib", "staticlib"]
|
||||
[features]
|
||||
default = []
|
||||
local = ["winit", "gfx-backend-empty/winit"]
|
||||
metal-auto-capture = ["gfx-backend-metal/auto-capture"]
|
||||
|
||||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::track::{BufferTracker, TextureTracker};
|
||||
use crate::track::TrackerSet;
|
||||
use crate::{
|
||||
LifeGuard, WeaklyStored,
|
||||
BindGroupLayoutId, BufferId, SamplerId, TextureViewId,
|
||||
@@ -84,6 +84,5 @@ pub struct BindGroup<B: hal::Backend> {
|
||||
pub(crate) raw: B::DescriptorSet,
|
||||
pub(crate) layout_id: WeaklyStored<BindGroupLayoutId>,
|
||||
pub(crate) life_guard: LifeGuard,
|
||||
pub(crate) used_buffers: BufferTracker,
|
||||
pub(crate) used_textures: TextureTracker,
|
||||
pub(crate) used: TrackerSet,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::CommandBuffer;
|
||||
use crate::track::Tracker;
|
||||
use crate::track::TrackerSet;
|
||||
use crate::{DeviceId, LifeGuard, Stored, SubmissionIndex};
|
||||
|
||||
use hal::command::RawCommandBuffer;
|
||||
@@ -86,8 +86,7 @@ impl<B: hal::Backend> CommandAllocator<B> {
|
||||
recorded_thread_id: thread_id,
|
||||
device_id,
|
||||
life_guard: LifeGuard::new(),
|
||||
buffer_tracker: Tracker::new(),
|
||||
texture_tracker: Tracker::new(),
|
||||
trackers: TrackerSet::new(),
|
||||
swap_chain_links: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::command::bind::{Binder};
|
||||
use crate::hub::HUB;
|
||||
use crate::track::{BufferTracker, TextureTracker};
|
||||
use crate::track::TrackerSet;
|
||||
use crate::{
|
||||
Stored, CommandBuffer,
|
||||
BindGroupId, CommandBufferId, ComputePassId, ComputePipelineId,
|
||||
@@ -16,8 +16,7 @@ pub struct ComputePass<B: hal::Backend> {
|
||||
raw: B::CommandBuffer,
|
||||
cmb_id: Stored<CommandBufferId>,
|
||||
binder: Binder,
|
||||
buffer_tracker: BufferTracker,
|
||||
texture_tracker: TextureTracker,
|
||||
trackers: TrackerSet,
|
||||
}
|
||||
|
||||
impl<B: hal::Backend> ComputePass<B> {
|
||||
@@ -26,8 +25,7 @@ impl<B: hal::Backend> ComputePass<B> {
|
||||
raw,
|
||||
cmb_id,
|
||||
binder: Binder::default(),
|
||||
buffer_tracker: BufferTracker::new(),
|
||||
texture_tracker: TextureTracker::new(),
|
||||
trackers: TrackerSet::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,6 +34,8 @@ impl<B: hal::Backend> ComputePass<B> {
|
||||
pub extern "C" fn wgpu_compute_pass_end_pass(pass_id: ComputePassId) -> CommandBufferId {
|
||||
let pass = HUB.compute_passes.unregister(pass_id);
|
||||
|
||||
//TODO: transitions?
|
||||
|
||||
HUB.command_buffers
|
||||
.write()
|
||||
.get_mut(pass.cmb_id.value)
|
||||
@@ -69,13 +69,15 @@ pub extern "C" fn wgpu_compute_pass_set_bind_group(
|
||||
//Note: currently, WebGPU compute passes have synchronization defined
|
||||
// at a dispatch granularity, so we insert the necessary barriers here.
|
||||
|
||||
//TODO: have `TrackerSet::consume()` ?
|
||||
CommandBuffer::insert_barriers(
|
||||
&mut pass.raw,
|
||||
pass.buffer_tracker.consume_by_replace(&bind_group.used_buffers),
|
||||
pass.texture_tracker.consume_by_replace(&bind_group.used_textures),
|
||||
pass.trackers.buffers.consume_by_replace(&bind_group.used.buffers),
|
||||
pass.trackers.textures.consume_by_replace(&bind_group.used.textures),
|
||||
&*HUB.buffers.read(),
|
||||
&*HUB.textures.read(),
|
||||
);
|
||||
pass.trackers.views.consume(&bind_group.used.views);
|
||||
|
||||
if let Some(pipeline_layout_id) = pass.binder.provide_entry(index as usize, bind_group_id, bind_group) {
|
||||
let pipeline_layout_guard = HUB.pipeline_layouts.read();
|
||||
|
||||
@@ -15,7 +15,7 @@ use crate::device::{
|
||||
};
|
||||
use crate::hub::{HUB, Storage};
|
||||
use crate::swap_chain::{SwapChainLink, SwapImageEpoch};
|
||||
use crate::track::{BufferTracker, TextureTracker};
|
||||
use crate::track::TrackerSet;
|
||||
use crate::conv;
|
||||
use crate::{
|
||||
BufferHandle, TextureHandle,
|
||||
@@ -85,8 +85,7 @@ pub struct CommandBuffer<B: hal::Backend> {
|
||||
recorded_thread_id: ThreadId,
|
||||
device_id: Stored<DeviceId>,
|
||||
pub(crate) life_guard: LifeGuard,
|
||||
pub(crate) buffer_tracker: BufferTracker,
|
||||
pub(crate) texture_tracker: TextureTracker,
|
||||
pub(crate) trackers: TrackerSet,
|
||||
pub(crate) swap_chain_links: Vec<SwapChainLink<SwapImageEpoch>>,
|
||||
}
|
||||
|
||||
@@ -184,7 +183,7 @@ pub fn command_encoder_begin_render_pass(
|
||||
};
|
||||
|
||||
let rp_key = {
|
||||
let tracker = &mut cmb.texture_tracker;
|
||||
let trackers = &mut cmb.trackers;
|
||||
let swap_chain_links = &mut cmb.swap_chain_links;
|
||||
|
||||
let depth_stencil_key = depth_stencil_attachment.map(|at| {
|
||||
@@ -194,7 +193,12 @@ pub fn command_encoder_begin_render_pass(
|
||||
} else {
|
||||
extent = Some(view.extent);
|
||||
}
|
||||
let query = tracker.query(&view.texture_id, TextureUsageFlags::empty());
|
||||
trackers.views.query(at.attachment, &view.life_guard.ref_count);
|
||||
let query = trackers.textures.query(
|
||||
view.texture_id.value,
|
||||
&view.texture_id.ref_count,
|
||||
TextureUsageFlags::empty(),
|
||||
);
|
||||
let (_, layout) = conv::map_texture_state(
|
||||
query.usage,
|
||||
hal::format::Aspects::DEPTH | hal::format::Aspects::STENCIL,
|
||||
@@ -232,7 +236,12 @@ pub fn command_encoder_begin_render_pass(
|
||||
} else {
|
||||
extent = Some(view.extent);
|
||||
}
|
||||
let query = tracker.query(&view.texture_id, TextureUsageFlags::empty());
|
||||
trackers.views.query(at.attachment, &view.life_guard.ref_count);
|
||||
let query = trackers.textures.query(
|
||||
view.texture_id.value,
|
||||
&view.texture_id.ref_count,
|
||||
TextureUsageFlags::empty(),
|
||||
);
|
||||
let (_, layout) = conv::map_texture_state(query.usage, hal::format::Aspects::COLOR);
|
||||
hal::pass::Attachment {
|
||||
format: Some(conv::map_texture_format(view.format)),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::command::bind::Binder;
|
||||
use crate::hub::HUB;
|
||||
use crate::resource::BufferUsageFlags;
|
||||
use crate::track::{BufferTracker, TextureTracker};
|
||||
use crate::track::TrackerSet;
|
||||
use crate::{
|
||||
CommandBuffer, Stored,
|
||||
BindGroupId, BufferId, CommandBufferId, RenderPassId, RenderPipelineId,
|
||||
@@ -16,8 +16,7 @@ pub struct RenderPass<B: hal::Backend> {
|
||||
raw: B::CommandBuffer,
|
||||
cmb_id: Stored<CommandBufferId>,
|
||||
binder: Binder,
|
||||
buffer_tracker: BufferTracker,
|
||||
texture_tracker: TextureTracker,
|
||||
trackers: TrackerSet,
|
||||
}
|
||||
|
||||
impl<B: hal::Backend> RenderPass<B> {
|
||||
@@ -26,8 +25,7 @@ impl<B: hal::Backend> RenderPass<B> {
|
||||
raw,
|
||||
cmb_id,
|
||||
binder: Binder::default(),
|
||||
buffer_tracker: BufferTracker::new(),
|
||||
texture_tracker: TextureTracker::new(),
|
||||
trackers: TrackerSet::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,16 +40,27 @@ pub extern "C" fn wgpu_render_pass_end_pass(pass_id: RenderPassId) -> CommandBuf
|
||||
let mut cmb_guard = HUB.command_buffers.write();
|
||||
let cmb = cmb_guard.get_mut(pass.cmb_id.value);
|
||||
|
||||
if let Some(ref mut last) = cmb.raw.last_mut() {
|
||||
CommandBuffer::insert_barriers(
|
||||
last,
|
||||
cmb.buffer_tracker.consume_by_replace(&pass.buffer_tracker),
|
||||
cmb.texture_tracker.consume_by_replace(&pass.texture_tracker),
|
||||
&*HUB.buffers.read(),
|
||||
&*HUB.textures.read(),
|
||||
);
|
||||
unsafe { last.finish() };
|
||||
match cmb.raw.last_mut() {
|
||||
Some(ref mut last) => {
|
||||
CommandBuffer::insert_barriers(
|
||||
last,
|
||||
cmb.trackers.buffers.consume_by_replace(&pass.trackers.buffers),
|
||||
cmb.trackers.textures.consume_by_replace(&pass.trackers.textures),
|
||||
&*HUB.buffers.read(),
|
||||
&*HUB.textures.read(),
|
||||
);
|
||||
unsafe { last.finish() };
|
||||
}
|
||||
None => {
|
||||
cmb.trackers.buffers
|
||||
.consume_by_extend(&pass.trackers.buffers)
|
||||
.unwrap();
|
||||
cmb.trackers.textures
|
||||
.consume_by_extend(&pass.trackers.textures)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
cmb.trackers.views.consume(&pass.trackers.views);
|
||||
|
||||
cmb.raw.push(pass.raw);
|
||||
pass.cmb_id.value
|
||||
@@ -65,7 +74,7 @@ pub extern "C" fn wgpu_render_pass_set_index_buffer(
|
||||
let buffer_guard = HUB.buffers.read();
|
||||
|
||||
let pass = pass_guard.get_mut(pass_id);
|
||||
let buffer = pass.buffer_tracker
|
||||
let buffer = pass.trackers.buffers
|
||||
.get_with_extended_usage(
|
||||
&*buffer_guard,
|
||||
buffer_id,
|
||||
@@ -102,7 +111,7 @@ pub extern "C" fn wgpu_render_pass_set_vertex_buffers(
|
||||
|
||||
let pass = pass_guard.get_mut(pass_id);
|
||||
for &id in buffers {
|
||||
pass.buffer_tracker
|
||||
pass.trackers.buffers
|
||||
.get_with_extended_usage(
|
||||
&*buffer_guard,
|
||||
id,
|
||||
@@ -174,12 +183,13 @@ pub extern "C" fn wgpu_render_pass_set_bind_group(
|
||||
let bind_group_guard = HUB.bind_groups.read();
|
||||
let bind_group = bind_group_guard.get(bind_group_id);
|
||||
|
||||
pass.buffer_tracker
|
||||
.consume_by_extend(&bind_group.used_buffers)
|
||||
pass.trackers.buffers
|
||||
.consume_by_extend(&bind_group.used.buffers)
|
||||
.unwrap();
|
||||
pass.texture_tracker
|
||||
.consume_by_extend(&bind_group.used_textures)
|
||||
pass.trackers.textures
|
||||
.consume_by_extend(&bind_group.used.textures)
|
||||
.unwrap();
|
||||
pass.trackers.views.consume(&bind_group.used.views);
|
||||
|
||||
if let Some(pipeline_layout_id) = pass.binder.provide_entry(index as usize, bind_group_id, bind_group) {
|
||||
let pipeline_layout_guard = HUB.pipeline_layouts.read();
|
||||
|
||||
@@ -45,7 +45,7 @@ pub extern "C" fn wgpu_command_buffer_copy_buffer_to_buffer(
|
||||
let cmb = cmb_guard.get_mut(command_buffer_id);
|
||||
let buffer_guard = HUB.buffers.read();
|
||||
|
||||
let (src_buffer, src_usage) = cmb.buffer_tracker
|
||||
let (src_buffer, src_usage) = cmb.trackers.buffers
|
||||
.get_with_replaced_usage(
|
||||
&*buffer_guard,
|
||||
src,
|
||||
@@ -59,7 +59,7 @@ pub extern "C" fn wgpu_command_buffer_copy_buffer_to_buffer(
|
||||
range: None .. None,
|
||||
});
|
||||
|
||||
let (dst_buffer, dst_usage) = cmb.buffer_tracker
|
||||
let (dst_buffer, dst_usage) = cmb.trackers.buffers
|
||||
.get_with_replaced_usage(
|
||||
&*buffer_guard,
|
||||
dst,
|
||||
@@ -105,7 +105,7 @@ pub extern "C" fn wgpu_command_buffer_copy_buffer_to_texture(
|
||||
let buffer_guard = HUB.buffers.read();
|
||||
let texture_guard = HUB.textures.read();
|
||||
|
||||
let (src_buffer, src_usage) = cmb.buffer_tracker
|
||||
let (src_buffer, src_usage) = cmb.trackers.buffers
|
||||
.get_with_replaced_usage(
|
||||
&*buffer_guard,
|
||||
source.buffer,
|
||||
@@ -119,7 +119,7 @@ pub extern "C" fn wgpu_command_buffer_copy_buffer_to_texture(
|
||||
range: None .. None,
|
||||
});
|
||||
|
||||
let (dst_texture, dst_usage) = cmb.texture_tracker
|
||||
let (dst_texture, dst_usage) = cmb.trackers.textures
|
||||
.get_with_replaced_usage(
|
||||
&*texture_guard,
|
||||
destination.texture,
|
||||
@@ -188,7 +188,7 @@ pub extern "C" fn wgpu_command_buffer_copy_texture_to_buffer(
|
||||
let buffer_guard = HUB.buffers.read();
|
||||
let texture_guard = HUB.textures.read();
|
||||
|
||||
let (src_texture, src_usage) = cmb.texture_tracker
|
||||
let (src_texture, src_usage) = cmb.trackers.textures
|
||||
.get_with_replaced_usage(
|
||||
&*texture_guard,
|
||||
source.texture,
|
||||
@@ -205,7 +205,7 @@ pub extern "C" fn wgpu_command_buffer_copy_texture_to_buffer(
|
||||
});
|
||||
assert!(src_texture.swap_chain_link.is_none()); //TODO
|
||||
|
||||
let (dst_buffer, dst_usage) = cmb.buffer_tracker
|
||||
let (dst_buffer, dst_usage) = cmb.trackers.buffers
|
||||
.get_with_replaced_usage(
|
||||
&*buffer_guard,
|
||||
destination.buffer,
|
||||
@@ -263,14 +263,14 @@ pub extern "C" fn wgpu_command_buffer_copy_texture_to_texture(
|
||||
let cmb = cmb_guard.get_mut(command_buffer_id);
|
||||
let texture_guard = HUB.textures.read();
|
||||
|
||||
let (src_texture, src_usage) = cmb.texture_tracker
|
||||
let (src_texture, src_usage) = cmb.trackers.textures
|
||||
.get_with_replaced_usage(
|
||||
&*texture_guard,
|
||||
source.texture,
|
||||
TextureUsageFlags::TRANSFER_SRC,
|
||||
)
|
||||
.unwrap();
|
||||
let (dst_texture, dst_usage) = cmb.texture_tracker
|
||||
let (dst_texture, dst_usage) = cmb.trackers.textures
|
||||
.get_with_replaced_usage(
|
||||
&*texture_guard,
|
||||
destination.texture,
|
||||
|
||||
@@ -291,6 +291,7 @@ pub fn map_texture_format(texture_format: resource::TextureFormat) -> hal::forma
|
||||
R8g8b8a8Unorm => H::Rgba8Unorm,
|
||||
R8g8b8a8Uint => H::Rgba8Uint,
|
||||
B8g8r8a8Unorm => H::Bgra8Unorm,
|
||||
D32Float => H::D32Float,
|
||||
D32FloatS8Uint => H::D32FloatS8Uint,
|
||||
}
|
||||
}
|
||||
@@ -303,6 +304,7 @@ pub fn map_vertex_format(vertex_format: pipeline::VertexFormat) -> hal::format::
|
||||
FloatR32G32B32 => H::Rgb32Float,
|
||||
FloatR32G32 => H::Rg32Float,
|
||||
FloatR32 => H::R32Float,
|
||||
IntR8G8B8A8 => H::Rgba8Int,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,21 +315,25 @@ fn checked_u32_as_u16(value: u32) -> u16 {
|
||||
|
||||
pub fn map_texture_dimension_size(
|
||||
dimension: resource::TextureDimension,
|
||||
Extent3d {
|
||||
width,
|
||||
height,
|
||||
depth,
|
||||
}: Extent3d,
|
||||
Extent3d { width, height, depth }: Extent3d,
|
||||
array_size: u32,
|
||||
) -> hal::image::Kind {
|
||||
use hal::image::Kind as H;
|
||||
use crate::resource::TextureDimension::*;
|
||||
match dimension {
|
||||
D1 => {
|
||||
assert_eq!(height, 1);
|
||||
H::D1(width, checked_u32_as_u16(depth))
|
||||
assert_eq!(depth, 1);
|
||||
H::D1(width, checked_u32_as_u16(array_size))
|
||||
}
|
||||
D2 => {
|
||||
assert_eq!(depth, 1);
|
||||
H::D2(width, height, checked_u32_as_u16(array_size), 1) // TODO: Samples
|
||||
}
|
||||
D3 => {
|
||||
assert_eq!(array_size, 1);
|
||||
H::D3(width, height, depth)
|
||||
}
|
||||
D2 => H::D2(width, height, checked_u32_as_u16(depth), 1), // TODO: Samples
|
||||
D3 => H::D3(width, height, depth),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{binding_model, command, conv, pipeline, resource, swap_chain};
|
||||
use crate::hub::HUB;
|
||||
use crate::track::{BufferTracker, TextureTracker, TrackPermit};
|
||||
use crate::track::{TrackerSet, TrackPermit};
|
||||
use crate::{
|
||||
LifeGuard, RefCount, Stored, SubmissionIndex, WeaklyStored,
|
||||
};
|
||||
@@ -15,19 +15,21 @@ use crate::{
|
||||
};
|
||||
|
||||
use back;
|
||||
use hal::backend::FastHashMap;
|
||||
use hal::command::RawCommandBuffer;
|
||||
use hal::queue::RawCommandQueue;
|
||||
use hal::{self,
|
||||
use hal::{
|
||||
self,
|
||||
DescriptorPool as _DescriptorPool,
|
||||
Device as _Device,
|
||||
Surface as _Surface,
|
||||
};
|
||||
use log::trace;
|
||||
use log::{info, trace};
|
||||
//use rendy_memory::{allocator, Config, Heaps};
|
||||
use parking_lot::{Mutex};
|
||||
|
||||
use std::{ffi, iter, slice};
|
||||
use std::collections::hash_map::{Entry, HashMap};
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
|
||||
@@ -64,6 +66,7 @@ pub(crate) struct FramebufferKey {
|
||||
}
|
||||
impl Eq for FramebufferKey {}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum ResourceId {
|
||||
Buffer(BufferId),
|
||||
Texture(TextureId),
|
||||
@@ -99,6 +102,7 @@ unsafe impl<B: hal::Backend> Sync for DestroyedResources<B> {}
|
||||
|
||||
impl<B: hal::Backend> DestroyedResources<B> {
|
||||
fn add(&mut self, resource_id: ResourceId, ref_count: RefCount) {
|
||||
debug_assert!(!self.referenced.iter().any(|r| r.0 == resource_id));
|
||||
self.referenced.push((resource_id, ref_count));
|
||||
}
|
||||
|
||||
@@ -140,29 +144,32 @@ impl<B: hal::Backend> DestroyedResources<B> {
|
||||
impl DestroyedResources<back::Backend> {
|
||||
fn triage_referenced(
|
||||
&mut self,
|
||||
buffer_tracker: &mut BufferTracker,
|
||||
texture_tracker: &mut TextureTracker,
|
||||
trackers: &mut TrackerSet,
|
||||
) {
|
||||
for i in (0..self.referenced.len()).rev() {
|
||||
// one in resource itself, and one here in this list
|
||||
let num_refs = self.referenced[i].1.load();
|
||||
if num_refs <= 2 {
|
||||
assert_eq!(num_refs, 2);
|
||||
// Before destruction, a resource is expected to have the following strong refs:
|
||||
// 1. in resource itself
|
||||
// 2. in the device tracker
|
||||
// 3. in this list
|
||||
if num_refs <= 3 {
|
||||
let resource_id = self.referenced.swap_remove(i).0;
|
||||
assert_eq!(num_refs, 3, "Resource {:?} misses some references", resource_id);
|
||||
let (submit_index, resource) = match resource_id {
|
||||
ResourceId::Buffer(id) => {
|
||||
buffer_tracker.remove(id);
|
||||
trackers.buffers.remove(id);
|
||||
let buf = HUB.buffers.unregister(id);
|
||||
let si = buf.life_guard.submission_index.load(Ordering::Acquire);
|
||||
(si, Resource::Buffer(buf))
|
||||
}
|
||||
ResourceId::Texture(id) => {
|
||||
texture_tracker.remove(id);
|
||||
trackers.textures.remove(id);
|
||||
let tex = HUB.textures.unregister(id);
|
||||
let si = tex.life_guard.submission_index.load(Ordering::Acquire);
|
||||
(si, Resource::Texture(tex))
|
||||
}
|
||||
ResourceId::TextureView(id) => {
|
||||
trackers.views.remove(id);
|
||||
let view = HUB.texture_views.unregister(id);
|
||||
let si = view.life_guard.submission_index.load(Ordering::Acquire);
|
||||
(si, Resource::TextureView(view))
|
||||
@@ -189,11 +196,10 @@ pub struct Device<B: hal::Backend> {
|
||||
//mem_allocator: Heaps<B::Memory>,
|
||||
pub(crate) com_allocator: command::CommandAllocator<B>,
|
||||
life_guard: LifeGuard,
|
||||
buffer_tracker: Mutex<BufferTracker>,
|
||||
pub(crate) texture_tracker: Mutex<TextureTracker>,
|
||||
pub(crate) trackers: Mutex<TrackerSet>,
|
||||
mem_props: hal::MemoryProperties,
|
||||
pub(crate) render_passes: Mutex<HashMap<RenderPassKey, B::RenderPass>>,
|
||||
pub(crate) framebuffers: Mutex<HashMap<FramebufferKey, B::Framebuffer>>,
|
||||
pub(crate) render_passes: Mutex<FastHashMap<RenderPassKey, B::RenderPass>>,
|
||||
pub(crate) framebuffers: Mutex<FastHashMap<FramebufferKey, B::Framebuffer>>,
|
||||
desc_pool: Mutex<B::DescriptorPool>,
|
||||
destroyed: Mutex<DestroyedResources<B>>,
|
||||
}
|
||||
@@ -264,11 +270,10 @@ impl<B: hal::Backend> Device<B> {
|
||||
com_allocator: command::CommandAllocator::new(queue_group.family()),
|
||||
queue_group,
|
||||
life_guard,
|
||||
buffer_tracker: Mutex::new(BufferTracker::new()),
|
||||
texture_tracker: Mutex::new(TextureTracker::new()),
|
||||
trackers: Mutex::new(TrackerSet::new()),
|
||||
mem_props,
|
||||
render_passes: Mutex::new(HashMap::new()),
|
||||
framebuffers: Mutex::new(HashMap::new()),
|
||||
render_passes: Mutex::new(FastHashMap::default()),
|
||||
framebuffers: Mutex::new(FastHashMap::default()),
|
||||
desc_pool,
|
||||
destroyed: Mutex::new(DestroyedResources {
|
||||
referenced: Vec::new(),
|
||||
@@ -343,12 +348,10 @@ pub fn device_track_buffer(
|
||||
let query = HUB.devices
|
||||
.read()
|
||||
.get(device_id)
|
||||
.buffer_tracker
|
||||
.trackers
|
||||
.lock()
|
||||
.query(
|
||||
&Stored { value: buffer_id, ref_count },
|
||||
resource::BufferUsageFlags::empty(),
|
||||
);
|
||||
.buffers
|
||||
.query(buffer_id, &ref_count, resource::BufferUsageFlags::empty());
|
||||
assert!(query.initialized);
|
||||
}
|
||||
|
||||
@@ -385,7 +388,7 @@ pub fn device_create_texture(
|
||||
device_id: DeviceId,
|
||||
desc: &resource::TextureDescriptor,
|
||||
) -> resource::Texture<back::Backend> {
|
||||
let kind = conv::map_texture_dimension_size(desc.dimension, desc.size);
|
||||
let kind = conv::map_texture_dimension_size(desc.dimension, desc.size, desc.array_size);
|
||||
let format = conv::map_texture_format(desc.format);
|
||||
let aspects = format.surface_desc().aspects;
|
||||
let usage = conv::map_texture_usage(desc.usage, aspects);
|
||||
@@ -442,8 +445,8 @@ pub fn device_create_texture(
|
||||
format: desc.format,
|
||||
full_range: hal::image::SubresourceRange {
|
||||
aspects,
|
||||
levels: 0..1, //TODO: mips
|
||||
layers: 0..1, //TODO
|
||||
levels: 0 .. 1, //TODO: mips
|
||||
layers: 0 .. desc.array_size as u16,
|
||||
},
|
||||
swap_chain_link: None,
|
||||
life_guard: LifeGuard::new(),
|
||||
@@ -458,12 +461,10 @@ pub fn device_track_texture(
|
||||
let query = HUB.devices
|
||||
.read()
|
||||
.get(device_id)
|
||||
.texture_tracker
|
||||
.trackers
|
||||
.lock()
|
||||
.query(
|
||||
&Stored { value: texture_id, ref_count },
|
||||
resource::TextureUsageFlags::UNINITIALIZED,
|
||||
);
|
||||
.textures
|
||||
.query(texture_id, &ref_count, resource::TextureUsageFlags::UNINITIALIZED);
|
||||
assert!(query.initialized);
|
||||
}
|
||||
|
||||
@@ -520,6 +521,26 @@ pub fn texture_create_view(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn device_track_view(
|
||||
texture_id: TextureId,
|
||||
view_id: BufferId,
|
||||
ref_count: RefCount,
|
||||
) {
|
||||
let device_id = HUB.textures
|
||||
.read()
|
||||
.get(texture_id)
|
||||
.device_id
|
||||
.value;
|
||||
let initialized = HUB.devices
|
||||
.read()
|
||||
.get(device_id)
|
||||
.trackers
|
||||
.lock()
|
||||
.views
|
||||
.query(view_id, &ref_count);
|
||||
assert!(initialized);
|
||||
}
|
||||
|
||||
#[cfg(feature = "local")]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wgpu_texture_create_view(
|
||||
@@ -527,7 +548,11 @@ pub extern "C" fn wgpu_texture_create_view(
|
||||
desc: &resource::TextureViewDescriptor,
|
||||
) -> TextureViewId {
|
||||
let view = texture_create_view(texture_id, desc);
|
||||
HUB.texture_views.register(view)
|
||||
let texture_id = view.texture_id.value;
|
||||
let ref_count = view.life_guard.ref_count.clone();
|
||||
let id = HUB.texture_views.register(view);
|
||||
device_track_view(texture_id, id, ref_count);
|
||||
id
|
||||
}
|
||||
|
||||
pub fn texture_create_default_view(
|
||||
@@ -537,8 +562,10 @@ pub fn texture_create_default_view(
|
||||
let texture = texture_guard.get(texture_id);
|
||||
|
||||
let view_kind = match texture.kind {
|
||||
hal::image::Kind::D1(..) => hal::image::ViewKind::D1,
|
||||
hal::image::Kind::D2(..) => hal::image::ViewKind::D2, //TODO: array
|
||||
hal::image::Kind::D1(_, 1) => hal::image::ViewKind::D1,
|
||||
hal::image::Kind::D1(..) => hal::image::ViewKind::D1Array,
|
||||
hal::image::Kind::D2(_, _, 1, _) => hal::image::ViewKind::D2,
|
||||
hal::image::Kind::D2(..) => hal::image::ViewKind::D2Array,
|
||||
hal::image::Kind::D3(..) => hal::image::ViewKind::D3,
|
||||
};
|
||||
|
||||
@@ -575,7 +602,11 @@ pub fn texture_create_default_view(
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wgpu_texture_create_default_view(texture_id: TextureId) -> TextureViewId {
|
||||
let view = texture_create_default_view(texture_id);
|
||||
HUB.texture_views.register(view)
|
||||
let texture_id = view.texture_id.value;
|
||||
let ref_count = view.life_guard.ref_count.clone();
|
||||
let id = HUB.texture_views.register(view);
|
||||
device_track_view(texture_id, id, ref_count);
|
||||
id
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -679,7 +710,7 @@ pub fn device_create_bind_group_layout(
|
||||
hal::pso::DescriptorSetLayoutBinding {
|
||||
binding: binding.binding,
|
||||
ty: conv::map_binding_type(binding.ty),
|
||||
count: bindings.len(),
|
||||
count: 1, //TODO: consolidate
|
||||
stage_flags: conv::map_shader_stage_flags(binding.visibility),
|
||||
immutable_samplers: false, // TODO
|
||||
}
|
||||
@@ -771,12 +802,11 @@ pub fn device_create_bind_group(
|
||||
|
||||
//TODO: group writes into contiguous sections
|
||||
let mut writes = Vec::new();
|
||||
let mut used_buffers = BufferTracker::new();
|
||||
let mut used_textures = TextureTracker::new();
|
||||
let mut used = TrackerSet::new();
|
||||
for b in bindings {
|
||||
let descriptor = match b.resource {
|
||||
binding_model::BindingResource::Buffer(ref bb) => {
|
||||
let buffer = used_buffers
|
||||
let buffer = used.buffers
|
||||
.get_with_extended_usage(
|
||||
&*buffer_guard,
|
||||
bb.buffer,
|
||||
@@ -792,7 +822,8 @@ pub fn device_create_bind_group(
|
||||
}
|
||||
binding_model::BindingResource::TextureView(id) => {
|
||||
let view = texture_view_guard.get(id);
|
||||
used_textures
|
||||
used.views.query(id, &view.life_guard.ref_count);
|
||||
used.textures
|
||||
.transit(
|
||||
view.texture_id.value,
|
||||
&view.texture_id.ref_count,
|
||||
@@ -820,8 +851,7 @@ pub fn device_create_bind_group(
|
||||
raw: desc_set,
|
||||
layout_id: WeaklyStored(desc.layout),
|
||||
life_guard: LifeGuard::new(),
|
||||
used_buffers,
|
||||
used_textures,
|
||||
used,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -916,8 +946,7 @@ pub extern "C" fn wgpu_queue_submit(
|
||||
.life_guard
|
||||
.submission_index
|
||||
.fetch_add(1, Ordering::Relaxed);
|
||||
let mut buffer_tracker = device.buffer_tracker.lock();
|
||||
let mut texture_tracker = device.texture_tracker.lock();
|
||||
let mut trackers = device.trackers.lock();
|
||||
|
||||
//TODO: if multiple command buffers are submitted, we can re-use the last
|
||||
// native command buffer of the previous chain instead of always creating
|
||||
@@ -934,14 +963,14 @@ pub extern "C" fn wgpu_queue_submit(
|
||||
// update submission IDs
|
||||
comb.life_guard.submission_index
|
||||
.store(old_submit_index, Ordering::Release);
|
||||
for id in comb.buffer_tracker.used() {
|
||||
for id in comb.trackers.buffers.used() {
|
||||
buffer_guard
|
||||
.get(id)
|
||||
.life_guard
|
||||
.submission_index
|
||||
.store(old_submit_index, Ordering::Release);
|
||||
}
|
||||
for id in comb.texture_tracker.used() {
|
||||
for id in comb.trackers.textures.used() {
|
||||
texture_guard
|
||||
.get(id)
|
||||
.life_guard
|
||||
@@ -958,13 +987,15 @@ pub extern "C" fn wgpu_queue_submit(
|
||||
);
|
||||
}
|
||||
//TODO: fix the consume
|
||||
let TrackerSet { ref mut buffers, ref mut textures, ref mut views } = *trackers;
|
||||
command::CommandBuffer::insert_barriers(
|
||||
&mut transit,
|
||||
buffer_tracker.consume_by_replace(&comb.buffer_tracker),
|
||||
texture_tracker.consume_by_replace(&comb.texture_tracker),
|
||||
buffers.consume_by_replace(&comb.trackers.buffers),
|
||||
textures.consume_by_replace(&comb.trackers.textures),
|
||||
&*buffer_guard,
|
||||
&*texture_guard,
|
||||
);
|
||||
views.consume(&comb.trackers.views);
|
||||
unsafe {
|
||||
transit.finish();
|
||||
}
|
||||
@@ -1014,7 +1045,7 @@ pub extern "C" fn wgpu_queue_submit(
|
||||
|
||||
let last_done = {
|
||||
let mut destroyed = device.destroyed.lock();
|
||||
destroyed.triage_referenced(&mut *buffer_tracker, &mut *texture_tracker);
|
||||
destroyed.triage_referenced(&mut *trackers);
|
||||
let last_done = destroyed.cleanup(&device.raw);
|
||||
|
||||
destroyed.active.push(ActiveSubmission {
|
||||
@@ -1315,8 +1346,9 @@ pub fn device_create_swap_chain(
|
||||
device_id: DeviceId,
|
||||
surface_id: SurfaceId,
|
||||
desc: &swap_chain::SwapChainDescriptor,
|
||||
outdated: swap_chain::OutdatedFrame,
|
||||
) -> Vec<resource::Texture<back::Backend>> {
|
||||
info!("creating swap chain {:?}", desc);
|
||||
|
||||
let device_guard = HUB.devices.read();
|
||||
let device = device_guard.get(device_id);
|
||||
let mut surface_guard = HUB.surfaces.write();
|
||||
@@ -1329,6 +1361,7 @@ pub fn device_create_swap_chain(
|
||||
surface.raw.compatibility(&adapter.physical_device)
|
||||
};
|
||||
let num_frames = caps.image_count.start; //TODO: configure?
|
||||
let usage = conv::map_texture_usage(desc.usage, hal::format::Aspects::COLOR);
|
||||
let config = hal::SwapchainConfig::new(
|
||||
desc.width,
|
||||
desc.height,
|
||||
@@ -1336,7 +1369,6 @@ pub fn device_create_swap_chain(
|
||||
num_frames, //TODO: configure?
|
||||
);
|
||||
|
||||
let usage = conv::map_texture_usage(desc.usage, hal::format::Aspects::COLOR);
|
||||
if let Some(formats) = formats {
|
||||
assert!(formats.contains(&config.format),
|
||||
"Requested format {:?} is not in supported list: {:?}",
|
||||
@@ -1351,10 +1383,12 @@ pub fn device_create_swap_chain(
|
||||
|
||||
let (old_raw, sem_available, command_pool) = match surface.swap_chain.take() {
|
||||
Some(mut old) => {
|
||||
assert_eq!(old.device_id.value, device_id);
|
||||
let mut destroyed = device.destroyed.lock();
|
||||
destroyed.add(ResourceId::Texture(old.outdated.texture_id.value), old.outdated.texture_id.ref_count);
|
||||
destroyed.add(ResourceId::TextureView(old.outdated.view_id.value), old.outdated.view_id.ref_count);
|
||||
assert_eq!(old.device_id.value, device_id);
|
||||
for frame in old.frames {
|
||||
destroyed.add(ResourceId::Texture(frame.texture_id.value), frame.texture_id.ref_count);
|
||||
destroyed.add(ResourceId::TextureView(frame.view_id.value), frame.view_id.ref_count);
|
||||
}
|
||||
unsafe {
|
||||
old.command_pool.reset()
|
||||
};
|
||||
@@ -1389,10 +1423,10 @@ pub fn device_create_swap_chain(
|
||||
value: device_id,
|
||||
ref_count: device.life_guard.ref_count.clone(),
|
||||
},
|
||||
desc: desc.clone(),
|
||||
frames: Vec::with_capacity(num_frames as usize),
|
||||
acquired: Vec::with_capacity(1), //TODO: get it from gfx-hal?
|
||||
sem_available,
|
||||
outdated,
|
||||
command_pool,
|
||||
});
|
||||
|
||||
@@ -1423,7 +1457,7 @@ pub fn device_create_swap_chain(
|
||||
}
|
||||
|
||||
#[cfg(feature = "local")]
|
||||
fn swap_chain_populate_textures(
|
||||
pub fn swap_chain_populate_textures(
|
||||
swap_chain_id: SwapChainId,
|
||||
textures: Vec<resource::Texture<back::Backend>>,
|
||||
) {
|
||||
@@ -1435,6 +1469,7 @@ fn swap_chain_populate_textures(
|
||||
.unwrap();
|
||||
let device_guard = HUB.devices.read();
|
||||
let device = device_guard.get(swap_chain.device_id.value);
|
||||
let mut trackers = device.trackers.lock();
|
||||
|
||||
for (i, mut texture) in textures.into_iter().enumerate() {
|
||||
let format = texture.format;
|
||||
@@ -1460,9 +1495,11 @@ fn swap_chain_populate_textures(
|
||||
ref_count: texture.life_guard.ref_count.clone(),
|
||||
value: HUB.textures.register(texture),
|
||||
};
|
||||
device.texture_tracker
|
||||
.lock()
|
||||
.query(&texture_id, resource::TextureUsageFlags::UNINITIALIZED);
|
||||
trackers.textures.query(
|
||||
texture_id.value,
|
||||
&texture_id.ref_count,
|
||||
resource::TextureUsageFlags::UNINITIALIZED,
|
||||
);
|
||||
|
||||
let view = resource::TextureView {
|
||||
raw: view_raw,
|
||||
@@ -1473,12 +1510,18 @@ fn swap_chain_populate_textures(
|
||||
is_owned_by_swap_chain: true,
|
||||
life_guard: LifeGuard::new(),
|
||||
};
|
||||
let view_id = Stored {
|
||||
ref_count: view.life_guard.ref_count.clone(),
|
||||
value: HUB.texture_views.register(view),
|
||||
};
|
||||
trackers.views.query(
|
||||
view_id.value,
|
||||
&view_id.ref_count,
|
||||
);
|
||||
|
||||
swap_chain.frames.push(swap_chain::Frame {
|
||||
texture_id,
|
||||
view_id: Stored {
|
||||
ref_count: view.life_guard.ref_count.clone(),
|
||||
value: HUB.texture_views.register(view),
|
||||
},
|
||||
view_id,
|
||||
fence: device.raw.create_fence(true).unwrap(),
|
||||
sem_available: device.raw.create_semaphore().unwrap(),
|
||||
sem_present: device.raw.create_semaphore().unwrap(),
|
||||
@@ -1494,26 +1537,7 @@ pub extern "C" fn wgpu_device_create_swap_chain(
|
||||
surface_id: SurfaceId,
|
||||
desc: &swap_chain::SwapChainDescriptor,
|
||||
) -> SwapChainId {
|
||||
let outdated = {
|
||||
let outdated_texture = device_create_texture(device_id, &desc.to_texture_desc());
|
||||
let texture_id = Stored {
|
||||
ref_count: outdated_texture.life_guard.ref_count.clone(),
|
||||
value: HUB.textures.register(outdated_texture),
|
||||
};
|
||||
device_track_texture(device_id, texture_id.value, texture_id.ref_count.clone());
|
||||
|
||||
let outdated_view = texture_create_default_view(texture_id.value);
|
||||
let view_id = Stored {
|
||||
ref_count: outdated_view.life_guard.ref_count.clone(),
|
||||
value: HUB.texture_views.register(outdated_view),
|
||||
};
|
||||
swap_chain::OutdatedFrame {
|
||||
texture_id,
|
||||
view_id,
|
||||
}
|
||||
};
|
||||
|
||||
let textures = device_create_swap_chain(device_id, surface_id, desc, outdated);
|
||||
let textures = device_create_swap_chain(device_id, surface_id, desc);
|
||||
swap_chain_populate_textures(surface_id, textures);
|
||||
surface_id
|
||||
}
|
||||
@@ -1532,8 +1556,9 @@ pub extern "C" fn wgpu_buffer_set_sub_data(
|
||||
//Note: this is just doing `update_buffer`, which is limited to 64KB
|
||||
|
||||
trace!("transit {:?} to transfer dst", buffer_id);
|
||||
let barrier = device.buffer_tracker
|
||||
let barrier = device.trackers
|
||||
.lock()
|
||||
.buffers
|
||||
.transit(
|
||||
buffer_id,
|
||||
&buffer.life_guard.ref_count,
|
||||
@@ -1581,3 +1606,8 @@ pub extern "C" fn wgpu_buffer_set_sub_data(
|
||||
|
||||
device.com_allocator.after_submit(comb);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wgpu_device_destroy(device_id: BufferId) {
|
||||
HUB.devices.unregister(device_id);
|
||||
}
|
||||
@@ -51,6 +51,10 @@ type SubmissionIndex = usize;
|
||||
#[derive(Debug)]
|
||||
pub struct RefCount(ptr::NonNull<AtomicUsize>);
|
||||
|
||||
unsafe impl Send for RefCount {}
|
||||
unsafe impl Sync for RefCount {}
|
||||
|
||||
|
||||
impl RefCount {
|
||||
const MAX: usize = 1 << 24;
|
||||
|
||||
@@ -80,10 +84,6 @@ struct LifeGuard {
|
||||
submission_index: AtomicUsize,
|
||||
}
|
||||
|
||||
//TODO: reconsider this
|
||||
unsafe impl Send for LifeGuard {}
|
||||
unsafe impl Sync for LifeGuard {}
|
||||
|
||||
impl LifeGuard {
|
||||
fn new() -> Self {
|
||||
let bx = Box::new(AtomicUsize::new(1));
|
||||
@@ -100,9 +100,6 @@ struct Stored<T> {
|
||||
ref_count: RefCount,
|
||||
}
|
||||
|
||||
unsafe impl<T> Send for Stored<T> {}
|
||||
unsafe impl<T> Sync for Stored<T> {}
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||
struct WeaklyStored<T>(T);
|
||||
|
||||
|
||||
@@ -129,6 +129,7 @@ pub enum VertexFormat {
|
||||
FloatR32G32B32 = 1,
|
||||
FloatR32G32 = 2,
|
||||
FloatR32 = 3,
|
||||
IntR8G8B8A8 = 4,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
||||
@@ -61,7 +61,8 @@ pub enum TextureFormat {
|
||||
R8g8b8a8Unorm = 0,
|
||||
R8g8b8a8Uint = 1,
|
||||
B8g8r8a8Unorm = 2,
|
||||
D32FloatS8Uint = 3,
|
||||
D32Float = 3,
|
||||
D32FloatS8Uint = 4,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
@@ -137,12 +138,13 @@ pub struct TextureViewDescriptor {
|
||||
pub struct TextureView<B: hal::Backend> {
|
||||
pub(crate) raw: B::ImageView,
|
||||
pub(crate) texture_id: Stored<TextureId>,
|
||||
//TODO: store device_id for quick access?
|
||||
pub(crate) format: TextureFormat,
|
||||
pub(crate) extent: hal::image::Extent,
|
||||
pub(crate) samples: hal::image::NumSamples,
|
||||
pub(crate) is_owned_by_swap_chain: bool,
|
||||
#[cfg_attr(not(feature = "local"), allow(dead_code))]
|
||||
pub(crate) life_guard: LifeGuard, //TODO: use
|
||||
pub(crate) life_guard: LifeGuard,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
||||
@@ -45,26 +45,20 @@ pub(crate) struct Frame<B: hal::Backend> {
|
||||
pub comb: hal::command::CommandBuffer<B, hal::General, hal::command::MultiShot>,
|
||||
}
|
||||
|
||||
pub struct OutdatedFrame {
|
||||
pub(crate) texture_id: Stored<TextureId>,
|
||||
pub(crate) view_id: Stored<TextureViewId>,
|
||||
}
|
||||
|
||||
const OUTDATED_IMAGE_INDEX: u32 = !0;
|
||||
//TODO: does it need a ref-counted lifetime?
|
||||
|
||||
pub struct SwapChain<B: hal::Backend> {
|
||||
pub(crate) raw: B::Swapchain,
|
||||
pub(crate) device_id: Stored<DeviceId>,
|
||||
pub(crate) desc: SwapChainDescriptor,
|
||||
pub(crate) frames: Vec<Frame<B>>,
|
||||
pub(crate) acquired: Vec<hal::SwapImageIndex>,
|
||||
pub(crate) sem_available: B::Semaphore,
|
||||
pub(crate) outdated: OutdatedFrame,
|
||||
#[cfg_attr(not(feature = "local"), allow(dead_code))] //TODO: remove
|
||||
pub(crate) command_pool: hal::CommandPool<B, hal::General>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SwapChainDescriptor {
|
||||
pub usage: resource::TextureUsageFlags,
|
||||
pub format: resource::TextureFormat,
|
||||
@@ -98,51 +92,72 @@ pub struct SwapChainOutput {
|
||||
pub extern "C" fn wgpu_swap_chain_get_next_texture(
|
||||
swap_chain_id: SwapChainId,
|
||||
) -> SwapChainOutput {
|
||||
let (image_index, device_id, descriptor) = {
|
||||
let mut surface_guard = HUB.surfaces.write();
|
||||
let swap_chain = surface_guard
|
||||
.get_mut(swap_chain_id)
|
||||
.swap_chain
|
||||
.as_mut()
|
||||
.unwrap();
|
||||
let sync = hal::FrameSync::Semaphore(&swap_chain.sem_available);
|
||||
let result = unsafe {
|
||||
swap_chain.raw.acquire_image(!0, sync)
|
||||
};
|
||||
(result.ok(), swap_chain.device_id.value, swap_chain.desc.clone())
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "local"))]
|
||||
let _ = descriptor;
|
||||
#[cfg(feature = "local")]
|
||||
{
|
||||
use crate::device::{device_create_swap_chain, swap_chain_populate_textures};
|
||||
if image_index.is_none() {
|
||||
warn!("acquire_image failed, re-creating");
|
||||
let textures = device_create_swap_chain(device_id, swap_chain_id, &descriptor);
|
||||
swap_chain_populate_textures(swap_chain_id, textures);
|
||||
}
|
||||
}
|
||||
|
||||
let mut surface_guard = HUB.surfaces.write();
|
||||
let swap_chain = surface_guard
|
||||
.get_mut(swap_chain_id)
|
||||
.swap_chain
|
||||
.as_mut()
|
||||
.unwrap();
|
||||
|
||||
let image_index = match image_index {
|
||||
Some(index) => index,
|
||||
None => {
|
||||
let sync = hal::FrameSync::Semaphore(&swap_chain.sem_available);
|
||||
unsafe { swap_chain.raw.acquire_image(!0, sync) }.unwrap()
|
||||
}
|
||||
};
|
||||
|
||||
let device_guard = HUB.devices.read();
|
||||
let device = device_guard.get(swap_chain.device_id.value);
|
||||
let device = device_guard.get(device_id);
|
||||
|
||||
assert_ne!(swap_chain.acquired.len(), swap_chain.acquired.capacity(),
|
||||
"Unable to acquire any more swap chain images before presenting");
|
||||
swap_chain.acquired.push(image_index);
|
||||
|
||||
match {
|
||||
let sync = hal::FrameSync::Semaphore(&swap_chain.sem_available);
|
||||
unsafe { swap_chain.raw.acquire_image(!0, sync) }
|
||||
} {
|
||||
Ok(image_index) => {
|
||||
swap_chain.acquired.push(image_index);
|
||||
let frame = &mut swap_chain.frames[image_index as usize];
|
||||
unsafe {
|
||||
device.raw.wait_for_fence(&frame.fence, !0).unwrap();
|
||||
}
|
||||
let frame = &mut swap_chain.frames[image_index as usize];
|
||||
unsafe {
|
||||
device.raw.wait_for_fence(&frame.fence, !0).unwrap();
|
||||
}
|
||||
mem::swap(&mut frame.sem_available, &mut swap_chain.sem_available);
|
||||
|
||||
mem::swap(&mut frame.sem_available, &mut swap_chain.sem_available);
|
||||
match HUB.textures
|
||||
.read()
|
||||
.get(frame.texture_id.value)
|
||||
.swap_chain_link
|
||||
{
|
||||
Some(ref link) => *link.epoch.lock() += 1,
|
||||
None => unreachable!(),
|
||||
}
|
||||
|
||||
let texture_guard = HUB.textures.read();
|
||||
let texture = texture_guard.get(frame.texture_id.value);
|
||||
match texture.swap_chain_link {
|
||||
Some(ref link) => *link.epoch.lock() += 1,
|
||||
None => unreachable!(),
|
||||
}
|
||||
|
||||
SwapChainOutput {
|
||||
texture_id: frame.texture_id.value,
|
||||
view_id: frame.view_id.value,
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("acquire_image failed: {:?}", e);
|
||||
swap_chain.acquired.push(OUTDATED_IMAGE_INDEX);
|
||||
SwapChainOutput {
|
||||
texture_id: swap_chain.outdated.texture_id.value,
|
||||
view_id: swap_chain.outdated.view_id.value,
|
||||
}
|
||||
}
|
||||
SwapChainOutput {
|
||||
texture_id: frame.texture_id.value,
|
||||
view_id: frame.view_id.value,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,13 +173,7 @@ pub extern "C" fn wgpu_swap_chain_present(
|
||||
.unwrap();
|
||||
|
||||
let image_index = swap_chain.acquired.remove(0);
|
||||
let frame = match swap_chain.frames.get_mut(image_index as usize) {
|
||||
Some(frame) => frame,
|
||||
None => {
|
||||
assert_eq!(image_index, OUTDATED_IMAGE_INDEX);
|
||||
return
|
||||
}
|
||||
};
|
||||
let frame = &mut swap_chain.frames[image_index as usize];
|
||||
|
||||
let mut device_guard = HUB.devices.write();
|
||||
let device = device_guard.get_mut(swap_chain.device_id.value);
|
||||
@@ -179,8 +188,9 @@ pub extern "C" fn wgpu_swap_chain_present(
|
||||
//TODO: support for swapchain being sampled or read by the shader?
|
||||
|
||||
trace!("transit {:?} to present", frame.texture_id.value);
|
||||
let barrier = device.texture_tracker
|
||||
let barrier = device.trackers
|
||||
.lock()
|
||||
.textures
|
||||
.transit(
|
||||
frame.texture_id.value,
|
||||
&texture.life_guard.ref_count,
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
use crate::hub::{Id, Storage};
|
||||
use crate::resource::{BufferUsageFlags, TextureUsageFlags};
|
||||
use crate::{BufferId, RefCount, Stored, TextureId, WeaklyStored};
|
||||
use crate::{
|
||||
RefCount, WeaklyStored,
|
||||
BufferId, TextureId, TextureViewId,
|
||||
};
|
||||
|
||||
use std::borrow::Borrow;
|
||||
use std::collections::hash_map::{Entry, HashMap};
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::hash::Hash;
|
||||
use std::mem;
|
||||
use std::ops::{BitOr, Range};
|
||||
|
||||
use bitflags::bitflags;
|
||||
use hal::backend::FastHashMap;
|
||||
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
@@ -70,20 +74,38 @@ struct Track<U> {
|
||||
last: U,
|
||||
}
|
||||
|
||||
unsafe impl<U> Send for Track<U> {}
|
||||
unsafe impl<U> Sync for Track<U> {}
|
||||
|
||||
//TODO: consider having `I` as an associated type of `U`?
|
||||
pub struct Tracker<I, U> {
|
||||
map: HashMap<WeaklyStored<I>, Track<U>>,
|
||||
map: FastHashMap<WeaklyStored<I>, Track<U>>,
|
||||
}
|
||||
pub type BufferTracker = Tracker<BufferId, BufferUsageFlags>;
|
||||
pub type TextureTracker = Tracker<TextureId, TextureUsageFlags>;
|
||||
pub struct DummyTracker<I> {
|
||||
map: FastHashMap<WeaklyStored<I>, RefCount>,
|
||||
}
|
||||
pub type TextureViewTracker = DummyTracker<TextureViewId>;
|
||||
|
||||
impl<I: Clone + Hash + Eq, U: Copy + GenericUsage + BitOr<Output = U> + PartialEq> Tracker<I, U> {
|
||||
pub struct TrackerSet {
|
||||
pub buffers: BufferTracker,
|
||||
pub textures: TextureTracker,
|
||||
pub views: TextureViewTracker,
|
||||
//TODO: samplers
|
||||
}
|
||||
|
||||
impl TrackerSet {
|
||||
pub fn new() -> Self {
|
||||
Tracker {
|
||||
map: HashMap::new(),
|
||||
TrackerSet {
|
||||
buffers: BufferTracker::new(),
|
||||
textures: TextureTracker::new(),
|
||||
views: TextureViewTracker::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Clone + Hash + Eq> DummyTracker<I> {
|
||||
pub fn new() -> Self {
|
||||
DummyTracker {
|
||||
map: FastHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,11 +115,42 @@ impl<I: Clone + Hash + Eq, U: Copy + GenericUsage + BitOr<Output = U> + PartialE
|
||||
}
|
||||
|
||||
/// Get the last usage on a resource.
|
||||
pub(crate) fn query(&mut self, stored: &Stored<I>, default: U) -> Query<U> {
|
||||
match self.map.entry(WeaklyStored(stored.value.clone())) {
|
||||
pub(crate) fn query(&mut self, id: I, ref_count: &RefCount) -> bool {
|
||||
match self.map.entry(WeaklyStored(id)) {
|
||||
Entry::Vacant(e) => {
|
||||
e.insert(ref_count.clone());
|
||||
true
|
||||
}
|
||||
Entry::Occupied(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume another tacker.
|
||||
pub fn consume(&mut self, other: &Self) {
|
||||
for (id, ref_count) in &other.map {
|
||||
self.query(id.0.clone(), ref_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Clone + Hash + Eq, U: Copy + GenericUsage + BitOr<Output = U> + PartialEq> Tracker<I, U> {
|
||||
pub fn new() -> Self {
|
||||
Tracker {
|
||||
map: FastHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove an id from the tracked map.
|
||||
pub(crate) fn remove(&mut self, id: I) -> bool {
|
||||
self.map.remove(&WeaklyStored(id)).is_some()
|
||||
}
|
||||
|
||||
/// Get the last usage on a resource.
|
||||
pub(crate) fn query(&mut self, id: I, ref_count: &RefCount, default: U) -> Query<U> {
|
||||
match self.map.entry(WeaklyStored(id)) {
|
||||
Entry::Vacant(e) => {
|
||||
e.insert(Track {
|
||||
ref_count: stored.ref_count.clone(),
|
||||
ref_count: ref_count.clone(),
|
||||
init: default,
|
||||
last: default,
|
||||
});
|
||||
|
||||
@@ -16,6 +16,7 @@ license = "MPL-2.0"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
metal-auto-capture = ["wgpu-native/metal-auto-capture"]
|
||||
metal = ["wgpu-native/gfx-backend-metal"]
|
||||
dx11 = ["wgpu-native/gfx-backend-dx11"]
|
||||
dx12 = ["wgpu-native/gfx-backend-dx12"]
|
||||
|
||||
@@ -16,12 +16,13 @@ pub use wgn::{
|
||||
BufferDescriptor, BufferUsageFlags,
|
||||
IndexFormat, InputStepMode, ShaderAttributeIndex, VertexAttributeDescriptor, VertexFormat,
|
||||
Color, CommandEncoderDescriptor,
|
||||
ColorStateDescriptor, DepthStencilStateDescriptor,
|
||||
ColorStateDescriptor, DepthStencilStateDescriptor, StencilStateFaceDescriptor, StencilOperation,
|
||||
DeviceDescriptor, Extensions, Extent3d, LoadOp, Origin3d, PowerPreference, PrimitiveTopology,
|
||||
RenderPassColorAttachmentDescriptor, RenderPassDepthStencilAttachmentDescriptor,
|
||||
ShaderModuleDescriptor, ShaderStageFlags, StoreOp, SwapChainDescriptor,
|
||||
SamplerDescriptor, AddressMode, FilterMode, BorderColor, CompareFunction,
|
||||
TextureDescriptor, TextureDimension, TextureFormat, TextureUsageFlags, TextureViewDescriptor,
|
||||
TextureDescriptor, TextureDimension, TextureFormat, TextureUsageFlags,
|
||||
TextureViewDescriptor, TextureViewDimension, TextureAspectFlags,
|
||||
};
|
||||
|
||||
|
||||
@@ -53,10 +54,12 @@ pub struct Buffer {
|
||||
|
||||
pub struct Texture {
|
||||
id: wgn::TextureId,
|
||||
owned: bool,
|
||||
}
|
||||
|
||||
pub struct TextureView {
|
||||
id: wgn::TextureViewId,
|
||||
owned: bool,
|
||||
}
|
||||
|
||||
pub struct Sampler {
|
||||
@@ -151,6 +154,7 @@ pub struct PipelineStageDescriptor<'a> {
|
||||
pub entry_point: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct VertexBufferDescriptor<'a> {
|
||||
pub stride: u32,
|
||||
pub step_mode: InputStepMode,
|
||||
@@ -425,6 +429,7 @@ impl Device {
|
||||
pub fn create_texture(&self, desc: &TextureDescriptor) -> Texture {
|
||||
Texture {
|
||||
id: wgn::wgpu_device_create_texture(self.id, desc),
|
||||
owned: true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,6 +446,14 @@ impl Device {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Device {
|
||||
fn drop(&mut self) {
|
||||
//TODO: make this work in general
|
||||
#[cfg(feature = "metal-auto-capture")]
|
||||
wgn::wgpu_device_destroy(self.id);
|
||||
}
|
||||
}
|
||||
|
||||
impl Buffer {
|
||||
pub fn set_sub_data(&self, offset: u32, data: &[u8]) {
|
||||
wgn::wgpu_buffer_set_sub_data(self.id, offset, data.len() as u32, data.as_ptr());
|
||||
@@ -457,25 +470,31 @@ impl Texture {
|
||||
pub fn create_view(&self, desc: &TextureViewDescriptor) -> TextureView {
|
||||
TextureView {
|
||||
id: wgn::wgpu_texture_create_view(self.id, desc),
|
||||
owned: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_default_view(&self) -> TextureView {
|
||||
TextureView {
|
||||
id: wgn::wgpu_texture_create_default_view(self.id),
|
||||
owned: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Texture {
|
||||
fn drop(&mut self) {
|
||||
wgn::wgpu_texture_destroy(self.id);
|
||||
if self.owned {
|
||||
wgn::wgpu_texture_destroy(self.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TextureView {
|
||||
fn drop(&mut self) {
|
||||
wgn::wgpu_texture_view_destroy(self.id);
|
||||
if self.owned {
|
||||
wgn::wgpu_texture_view_destroy(self.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -533,7 +552,7 @@ impl CommandEncoder {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn copy_buffer_tobuffer(
|
||||
pub fn copy_buffer_to_buffer(
|
||||
&mut self,
|
||||
source: &Buffer,
|
||||
source_offset: u32,
|
||||
@@ -697,8 +716,12 @@ impl SwapChain {
|
||||
SwapChainOutput {
|
||||
texture: Texture {
|
||||
id: output.texture_id,
|
||||
owned: false,
|
||||
},
|
||||
view: TextureView {
|
||||
id: output.view_id,
|
||||
owned: false,
|
||||
},
|
||||
view: TextureView { id: output.view_id },
|
||||
swap_chain_id: &self.id,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user