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:
bors[bot]
2019-02-23 07:50:17 +00:00
27 changed files with 1250 additions and 237 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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"]

View File

@@ -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);
}

View File

@@ -0,0 +1,4 @@
#version 450
void main() {
}

View 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);
}

View 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;
}

View 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);
}

View File

@@ -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");
}

View File

@@ -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
View 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");
}

View File

@@ -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"

View File

@@ -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,
}

View File

@@ -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(),
}
}

View File

@@ -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();

View File

@@ -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)),

View File

@@ -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();

View File

@@ -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,

View File

@@ -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),
}
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -129,6 +129,7 @@ pub enum VertexFormat {
FloatR32G32B32 = 1,
FloatR32G32 = 2,
FloatR32 = 3,
IntR8G8B8A8 = 4,
}
#[repr(C)]

View File

@@ -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)]

View File

@@ -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,

View File

@@ -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,
});

View File

@@ -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"]

View File

@@ -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,
}
}