mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-25 16:24:24 +00:00
Merge #69
69: Swapchain resize r=kvark a=kvark Based on #67 Here are the steps (as outlined on Gitter) that this PR follows: 1. create a dummy frame in the swapchain (`SwapChain::outdated`). We return it when we aren't able to acquire a real frame. No synchronization is done atm, but shouldn't be anything critical there. 2. handle the errors on acquire and present, use the dummy frame where needed. Presentation errors are just ignored, while acquiring errors are forcing the dummy frame. The idea is that the user would know about a swapchain resize from some kind of event loop / WSI, and thus they'd know when they should actually re-create it. 3. associate surface with a swapchain. We merge the IDs since there can't be multiple swapchains on the same surface in the near future. Merging simplifies a lot of things in the implementation, but this is to be revised for sure once we get a better look on the browser integration. 4. when the swapchain is re-created, consume the old one associated with a surface. Co-authored-by: Dzmitry Malyshau <kvarkus@gmail.com>
This commit is contained in:
commit
022087b0b8
@ -88,9 +88,22 @@ struct Cube {
|
|||||||
index_buf: wgpu::Buffer,
|
index_buf: wgpu::Buffer,
|
||||||
index_count: usize,
|
index_count: usize,
|
||||||
bind_group: wgpu::BindGroup,
|
bind_group: wgpu::BindGroup,
|
||||||
|
uniform_buf: wgpu::Buffer,
|
||||||
pipeline: wgpu::RenderPipeline,
|
pipeline: wgpu::RenderPipeline,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Cube {
|
||||||
|
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(),
|
||||||
|
);
|
||||||
|
mx_projection * mx_view
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl framework::Example for Cube {
|
impl framework::Example for Cube {
|
||||||
fn init(device: &mut wgpu::Device, sc_desc: &wgpu::SwapChainDescriptor) -> Self {
|
fn init(device: &mut wgpu::Device, sc_desc: &wgpu::SwapChainDescriptor) -> Self {
|
||||||
use std::mem;
|
use std::mem;
|
||||||
@ -196,18 +209,9 @@ impl framework::Example for Cube {
|
|||||||
size: 64,
|
size: 64,
|
||||||
usage: wgpu::BufferUsageFlags::UNIFORM | wgpu::BufferUsageFlags::TRANSFER_DST,
|
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 aspect_ratio = sc_desc.width as f32 / sc_desc.height as f32;
|
let mx_ref: &[f32; 16] = mx_total.as_ref();
|
||||||
let mx_projection = cgmath::perspective(cgmath::Deg(45f32), aspect_ratio, 1.0, 10.0);
|
uniform_buf.set_sub_data(0, framework::cast_slice(&mx_ref[..]));
|
||||||
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(),
|
|
||||||
);
|
|
||||||
let mx_total = mx_projection * mx_view;
|
|
||||||
let mx_raw: &[f32; 16] = mx_total.as_ref();
|
|
||||||
uniform_buf.set_sub_data(0, framework::cast_slice(&mx_raw[..]));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create bind group
|
// Create bind group
|
||||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
@ -294,11 +298,17 @@ impl framework::Example for Cube {
|
|||||||
index_buf,
|
index_buf,
|
||||||
index_count: index_data.len(),
|
index_count: index_data.len(),
|
||||||
bind_group,
|
bind_group,
|
||||||
|
uniform_buf,
|
||||||
pipeline,
|
pipeline,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, _event: wgpu::winit::WindowEvent) {
|
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 render(&mut self, frame: &wgpu::SwapChainOutput, device: &mut wgpu::Device) {
|
fn render(&mut self, frame: &wgpu::SwapChainOutput, device: &mut wgpu::Device) {
|
||||||
|
@ -70,7 +70,7 @@ pub fn run<E: Example>(title: &str) {
|
|||||||
.to_physical(window.get_hidpi_factor());
|
.to_physical(window.get_hidpi_factor());
|
||||||
|
|
||||||
let surface = instance.create_surface(&window);
|
let surface = instance.create_surface(&window);
|
||||||
let sc_desc = wgpu::SwapChainDescriptor {
|
let mut sc_desc = wgpu::SwapChainDescriptor {
|
||||||
usage: wgpu::TextureUsageFlags::OUTPUT_ATTACHMENT,
|
usage: wgpu::TextureUsageFlags::OUTPUT_ATTACHMENT,
|
||||||
format: wgpu::TextureFormat::B8g8r8a8Unorm,
|
format: wgpu::TextureFormat::B8g8r8a8Unorm,
|
||||||
width: size.width as u32,
|
width: size.width as u32,
|
||||||
@ -91,7 +91,11 @@ pub fn run<E: Example>(title: &str) {
|
|||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let physical = size.to_physical(window.get_hidpi_factor());
|
let physical = size.to_physical(window.get_hidpi_factor());
|
||||||
info!("Resized to {:?}", physical);
|
info!("Resizing to {:?}", physical);
|
||||||
|
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));
|
||||||
}
|
}
|
||||||
Event::WindowEvent { event, .. } => match event {
|
Event::WindowEvent { event, .. } => match event {
|
||||||
WindowEvent::KeyboardInput {
|
WindowEvent::KeyboardInput {
|
||||||
|
@ -435,10 +435,10 @@ typedef struct {
|
|||||||
WGPUByteArray code;
|
WGPUByteArray code;
|
||||||
} WGPUShaderModuleDescriptor;
|
} WGPUShaderModuleDescriptor;
|
||||||
|
|
||||||
typedef WGPUId WGPUSwapChainId;
|
|
||||||
|
|
||||||
typedef WGPUId WGPUSurfaceId;
|
typedef WGPUId WGPUSurfaceId;
|
||||||
|
|
||||||
|
typedef WGPUSurfaceId WGPUSwapChainId;
|
||||||
|
|
||||||
typedef uint32_t WGPUTextureUsageFlags;
|
typedef uint32_t WGPUTextureUsageFlags;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -98,9 +98,8 @@ unsafe impl<B: hal::Backend> Send for DestroyedResources<B> {}
|
|||||||
unsafe impl<B: hal::Backend> Sync for DestroyedResources<B> {}
|
unsafe impl<B: hal::Backend> Sync for DestroyedResources<B> {}
|
||||||
|
|
||||||
impl<B: hal::Backend> DestroyedResources<B> {
|
impl<B: hal::Backend> DestroyedResources<B> {
|
||||||
fn add(&mut self, resource_id: ResourceId, life_guard: &LifeGuard) {
|
fn add(&mut self, resource_id: ResourceId, ref_count: RefCount) {
|
||||||
self.referenced
|
self.referenced.push((resource_id, ref_count));
|
||||||
.push((resource_id, life_guard.ref_count.clone()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the last submission index that is done.
|
/// Returns the last submission index that is done.
|
||||||
@ -139,7 +138,11 @@ impl<B: hal::Backend> DestroyedResources<B> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DestroyedResources<back::Backend> {
|
impl DestroyedResources<back::Backend> {
|
||||||
fn triage_referenced(&mut self) {
|
fn triage_referenced(
|
||||||
|
&mut self,
|
||||||
|
buffer_tracker: &mut BufferTracker,
|
||||||
|
texture_tracker: &mut TextureTracker,
|
||||||
|
) {
|
||||||
for i in (0..self.referenced.len()).rev() {
|
for i in (0..self.referenced.len()).rev() {
|
||||||
// one in resource itself, and one here in this list
|
// one in resource itself, and one here in this list
|
||||||
let num_refs = self.referenced[i].1.load();
|
let num_refs = self.referenced[i].1.load();
|
||||||
@ -148,11 +151,13 @@ impl DestroyedResources<back::Backend> {
|
|||||||
let resource_id = self.referenced.swap_remove(i).0;
|
let resource_id = self.referenced.swap_remove(i).0;
|
||||||
let (submit_index, resource) = match resource_id {
|
let (submit_index, resource) = match resource_id {
|
||||||
ResourceId::Buffer(id) => {
|
ResourceId::Buffer(id) => {
|
||||||
|
buffer_tracker.remove(id);
|
||||||
let buf = HUB.buffers.unregister(id);
|
let buf = HUB.buffers.unregister(id);
|
||||||
let si = buf.life_guard.submission_index.load(Ordering::Acquire);
|
let si = buf.life_guard.submission_index.load(Ordering::Acquire);
|
||||||
(si, Resource::Buffer(buf))
|
(si, Resource::Buffer(buf))
|
||||||
}
|
}
|
||||||
ResourceId::Texture(id) => {
|
ResourceId::Texture(id) => {
|
||||||
|
texture_tracker.remove(id);
|
||||||
let tex = HUB.textures.unregister(id);
|
let tex = HUB.textures.unregister(id);
|
||||||
let si = tex.life_guard.submission_index.load(Ordering::Acquire);
|
let si = tex.life_guard.submission_index.load(Ordering::Acquire);
|
||||||
(si, Resource::Texture(tex))
|
(si, Resource::Texture(tex))
|
||||||
@ -369,7 +374,10 @@ pub extern "C" fn wgpu_buffer_destroy(buffer_id: BufferId) {
|
|||||||
.get(buffer.device_id.value)
|
.get(buffer.device_id.value)
|
||||||
.destroyed
|
.destroyed
|
||||||
.lock()
|
.lock()
|
||||||
.add(ResourceId::Buffer(buffer_id), &buffer.life_guard);
|
.add(
|
||||||
|
ResourceId::Buffer(buffer_id),
|
||||||
|
buffer.life_guard.ref_count.clone(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -579,7 +587,10 @@ pub extern "C" fn wgpu_texture_destroy(texture_id: TextureId) {
|
|||||||
.get(texture.device_id.value)
|
.get(texture.device_id.value)
|
||||||
.destroyed
|
.destroyed
|
||||||
.lock()
|
.lock()
|
||||||
.add(ResourceId::Texture(texture_id), &texture.life_guard);
|
.add(
|
||||||
|
ResourceId::Texture(texture_id),
|
||||||
|
texture.life_guard.ref_count.clone(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -595,7 +606,10 @@ pub extern "C" fn wgpu_texture_view_destroy(texture_view_id: TextureViewId) {
|
|||||||
.get(device_id)
|
.get(device_id)
|
||||||
.destroyed
|
.destroyed
|
||||||
.lock()
|
.lock()
|
||||||
.add(ResourceId::TextureView(texture_view_id), &view.life_guard);
|
.add(
|
||||||
|
ResourceId::TextureView(texture_view_id),
|
||||||
|
view.life_guard.ref_count.clone(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -902,6 +916,8 @@ pub extern "C" fn wgpu_queue_submit(
|
|||||||
.life_guard
|
.life_guard
|
||||||
.submission_index
|
.submission_index
|
||||||
.fetch_add(1, Ordering::Relaxed);
|
.fetch_add(1, Ordering::Relaxed);
|
||||||
|
let mut buffer_tracker = device.buffer_tracker.lock();
|
||||||
|
let mut texture_tracker = device.texture_tracker.lock();
|
||||||
|
|
||||||
//TODO: if multiple command buffers are submitted, we can re-use the last
|
//TODO: if multiple command buffers are submitted, we can re-use the last
|
||||||
// native command buffer of the previous chain instead of always creating
|
// native command buffer of the previous chain instead of always creating
|
||||||
@ -910,8 +926,6 @@ pub extern "C" fn wgpu_queue_submit(
|
|||||||
let mut command_buffer_guard = HUB.command_buffers.write();
|
let mut command_buffer_guard = HUB.command_buffers.write();
|
||||||
let buffer_guard = HUB.buffers.read();
|
let buffer_guard = HUB.buffers.read();
|
||||||
let texture_guard = HUB.textures.read();
|
let texture_guard = HUB.textures.read();
|
||||||
let mut buffer_tracker = device.buffer_tracker.lock();
|
|
||||||
let mut texture_tracker = device.texture_tracker.lock();
|
|
||||||
|
|
||||||
// finish all the command buffers first
|
// finish all the command buffers first
|
||||||
for &cmb_id in command_buffer_ids {
|
for &cmb_id in command_buffer_ids {
|
||||||
@ -965,17 +979,20 @@ pub extern "C" fn wgpu_queue_submit(
|
|||||||
let fence = device.raw.create_fence(false).unwrap();
|
let fence = device.raw.create_fence(false).unwrap();
|
||||||
{
|
{
|
||||||
let command_buffer_guard = HUB.command_buffers.read();
|
let command_buffer_guard = HUB.command_buffers.read();
|
||||||
let swap_chain_guard = HUB.swap_chains.read();
|
let surface_guard = HUB.surfaces.read();
|
||||||
|
|
||||||
let wait_semaphores = swap_chain_links
|
let wait_semaphores = swap_chain_links
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|link| {
|
.flat_map(|link| {
|
||||||
//TODO: check the epoch
|
//TODO: check the epoch
|
||||||
let sem = &swap_chain_guard
|
surface_guard
|
||||||
.get(link.swap_chain_id.0)
|
.get(link.swap_chain_id.0)
|
||||||
.frames[link.image_index as usize]
|
.swap_chain
|
||||||
.sem_available;
|
.as_ref()
|
||||||
(sem, hal::pso::PipelineStage::COLOR_ATTACHMENT_OUTPUT)
|
.map(|swap_chain| (
|
||||||
|
&swap_chain.frames[link.image_index as usize].sem_available,
|
||||||
|
hal::pso::PipelineStage::COLOR_ATTACHMENT_OUTPUT,
|
||||||
|
))
|
||||||
});
|
});
|
||||||
|
|
||||||
let submission =
|
let submission =
|
||||||
@ -997,7 +1014,7 @@ pub extern "C" fn wgpu_queue_submit(
|
|||||||
|
|
||||||
let last_done = {
|
let last_done = {
|
||||||
let mut destroyed = device.destroyed.lock();
|
let mut destroyed = device.destroyed.lock();
|
||||||
destroyed.triage_referenced();
|
destroyed.triage_referenced(&mut *buffer_tracker, &mut *texture_tracker);
|
||||||
let last_done = destroyed.cleanup(&device.raw);
|
let last_done = destroyed.cleanup(&device.raw);
|
||||||
|
|
||||||
destroyed.active.push(ActiveSubmission {
|
destroyed.active.push(ActiveSubmission {
|
||||||
@ -1294,12 +1311,12 @@ pub extern "C" fn wgpu_device_create_compute_pipeline(
|
|||||||
HUB.compute_pipelines.register(pipeline)
|
HUB.compute_pipelines.register(pipeline)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn device_create_swap_chain(
|
pub fn device_create_swap_chain(
|
||||||
device_id: DeviceId,
|
device_id: DeviceId,
|
||||||
surface_id: SurfaceId,
|
surface_id: SurfaceId,
|
||||||
desc: &swap_chain::SwapChainDescriptor,
|
desc: &swap_chain::SwapChainDescriptor,
|
||||||
) -> (swap_chain::SwapChain<back::Backend>, Vec<resource::Texture<back::Backend>>) {
|
outdated: swap_chain::OutdatedFrame,
|
||||||
|
) -> Vec<resource::Texture<back::Backend>> {
|
||||||
let device_guard = HUB.devices.read();
|
let device_guard = HUB.devices.read();
|
||||||
let device = device_guard.get(device_id);
|
let device = device_guard.get(device_id);
|
||||||
let mut surface_guard = HUB.surfaces.write();
|
let mut surface_guard = HUB.surfaces.write();
|
||||||
@ -1331,25 +1348,42 @@ pub fn device_create_swap_chain(
|
|||||||
"Requested size {}x{} is outside of the supported range: {:?}",
|
"Requested size {}x{} is outside of the supported range: {:?}",
|
||||||
desc.width, desc.height, caps.extents);
|
desc.width, desc.height, caps.extents);
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
unsafe {
|
||||||
|
old.command_pool.reset()
|
||||||
|
};
|
||||||
|
(Some(old.raw), old.sem_available, old.command_pool)
|
||||||
|
}
|
||||||
|
_ => unsafe {
|
||||||
|
let sem_available = device.raw
|
||||||
|
.create_semaphore()
|
||||||
|
.unwrap();
|
||||||
|
let command_pool = device.raw
|
||||||
|
.create_command_pool_typed(
|
||||||
|
&device.queue_group,
|
||||||
|
hal::pool::CommandPoolCreateFlags::RESET_INDIVIDUAL,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
(None, sem_available, command_pool)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let (raw, backbuffer) = unsafe {
|
let (raw, backbuffer) = unsafe {
|
||||||
device.raw
|
device.raw
|
||||||
.create_swapchain(
|
.create_swapchain(
|
||||||
&mut surface.raw,
|
&mut surface.raw,
|
||||||
config.with_image_usage(usage),
|
config.with_image_usage(usage),
|
||||||
None,
|
old_raw,
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
let command_pool = unsafe {
|
surface.swap_chain = Some(swap_chain::SwapChain {
|
||||||
device.raw
|
|
||||||
.create_command_pool_typed(
|
|
||||||
&device.queue_group,
|
|
||||||
hal::pool::CommandPoolCreateFlags::RESET_INDIVIDUAL,
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
};
|
|
||||||
|
|
||||||
let swap_chain = swap_chain::SwapChain {
|
|
||||||
raw,
|
raw,
|
||||||
device_id: Stored {
|
device_id: Stored {
|
||||||
value: device_id,
|
value: device_id,
|
||||||
@ -1357,16 +1391,17 @@ pub fn device_create_swap_chain(
|
|||||||
},
|
},
|
||||||
frames: Vec::with_capacity(num_frames as usize),
|
frames: Vec::with_capacity(num_frames as usize),
|
||||||
acquired: Vec::with_capacity(1), //TODO: get it from gfx-hal?
|
acquired: Vec::with_capacity(1), //TODO: get it from gfx-hal?
|
||||||
sem_available: device.raw.create_semaphore().unwrap(),
|
sem_available,
|
||||||
|
outdated,
|
||||||
command_pool,
|
command_pool,
|
||||||
};
|
});
|
||||||
|
|
||||||
let images = match backbuffer {
|
let images = match backbuffer {
|
||||||
hal::Backbuffer::Images(images) => images,
|
hal::Backbuffer::Images(images) => images,
|
||||||
hal::Backbuffer::Framebuffer(_) => panic!("Deprecated API detected!"),
|
hal::Backbuffer::Framebuffer(_) => panic!("Deprecated API detected!"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let textures = images
|
images
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|raw| resource::Texture {
|
.map(|raw| resource::Texture {
|
||||||
raw,
|
raw,
|
||||||
@ -1384,9 +1419,7 @@ pub fn device_create_swap_chain(
|
|||||||
swap_chain_link: None,
|
swap_chain_link: None,
|
||||||
life_guard: LifeGuard::new(),
|
life_guard: LifeGuard::new(),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect()
|
||||||
|
|
||||||
(swap_chain, textures)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "local")]
|
#[cfg(feature = "local")]
|
||||||
@ -1394,8 +1427,12 @@ fn swap_chain_populate_textures(
|
|||||||
swap_chain_id: SwapChainId,
|
swap_chain_id: SwapChainId,
|
||||||
textures: Vec<resource::Texture<back::Backend>>,
|
textures: Vec<resource::Texture<back::Backend>>,
|
||||||
) {
|
) {
|
||||||
let mut swap_chain_guard = HUB.swap_chains.write();
|
let mut surface_guard = HUB.surfaces.write();
|
||||||
let swap_chain = swap_chain_guard.get_mut(swap_chain_id);
|
let swap_chain = surface_guard
|
||||||
|
.get_mut(swap_chain_id)
|
||||||
|
.swap_chain
|
||||||
|
.as_mut()
|
||||||
|
.unwrap();
|
||||||
let device_guard = HUB.devices.read();
|
let device_guard = HUB.devices.read();
|
||||||
let device = device_guard.get(swap_chain.device_id.value);
|
let device = device_guard.get(swap_chain.device_id.value);
|
||||||
|
|
||||||
@ -1457,10 +1494,28 @@ pub extern "C" fn wgpu_device_create_swap_chain(
|
|||||||
surface_id: SurfaceId,
|
surface_id: SurfaceId,
|
||||||
desc: &swap_chain::SwapChainDescriptor,
|
desc: &swap_chain::SwapChainDescriptor,
|
||||||
) -> SwapChainId {
|
) -> SwapChainId {
|
||||||
let (swap_chain, textures) = device_create_swap_chain(device_id, surface_id, desc);
|
let outdated = {
|
||||||
let id = HUB.swap_chains.register(swap_chain);
|
let outdated_texture = device_create_texture(device_id, &desc.to_texture_desc());
|
||||||
swap_chain_populate_textures(id, textures);
|
let texture_id = Stored {
|
||||||
id
|
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);
|
||||||
|
swap_chain_populate_textures(surface_id, textures);
|
||||||
|
surface_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ use crate::{
|
|||||||
RenderPassHandle, ComputePassHandle,
|
RenderPassHandle, ComputePassHandle,
|
||||||
PipelineLayoutHandle, RenderPipelineHandle, ComputePipelineHandle, ShaderModuleHandle,
|
PipelineLayoutHandle, RenderPipelineHandle, ComputePipelineHandle, ShaderModuleHandle,
|
||||||
BufferHandle, SamplerHandle, TextureHandle, TextureViewHandle,
|
BufferHandle, SamplerHandle, TextureHandle, TextureViewHandle,
|
||||||
SurfaceHandle, SwapChainHandle,
|
SurfaceHandle,
|
||||||
};
|
};
|
||||||
|
|
||||||
use hal::backend::FastHashMap;
|
use hal::backend::FastHashMap;
|
||||||
@ -126,7 +126,6 @@ pub struct Hub {
|
|||||||
pub(crate) texture_views: Arc<Registry<TextureViewHandle>>,
|
pub(crate) texture_views: Arc<Registry<TextureViewHandle>>,
|
||||||
pub(crate) samplers: Arc<Registry<SamplerHandle>>,
|
pub(crate) samplers: Arc<Registry<SamplerHandle>>,
|
||||||
pub(crate) surfaces: Arc<Registry<SurfaceHandle>>,
|
pub(crate) surfaces: Arc<Registry<SurfaceHandle>>,
|
||||||
pub(crate) swap_chains: Arc<Registry<SwapChainHandle>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
@ -54,10 +54,7 @@ pub extern "C" fn wgpu_instance_create_surface_from_winit(
|
|||||||
.read()
|
.read()
|
||||||
.get(instance_id)
|
.get(instance_id)
|
||||||
.create_surface(window);
|
.create_surface(window);
|
||||||
let surface = SurfaceHandle {
|
let surface = SurfaceHandle::new(raw);
|
||||||
raw,
|
|
||||||
};
|
|
||||||
|
|
||||||
HUB.surfaces.register(surface)
|
HUB.surfaces.register(surface)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,12 +68,11 @@ pub fn instance_create_surface_from_xlib(
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
|
|
||||||
#[cfg(all(unix, feature = "gfx-backend-vulkan"))]
|
#[cfg(all(unix, feature = "gfx-backend-vulkan"))]
|
||||||
SurfaceHandle {
|
SurfaceHandle::new(HUB.instances
|
||||||
raw: HUB.instances
|
.read()
|
||||||
.read()
|
.get(instance_id)
|
||||||
.get(instance_id)
|
.create_surface_from_xlib(display, window)
|
||||||
.create_surface_from_xlib(display, window),
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "local")]
|
#[cfg(feature = "local")]
|
||||||
@ -99,12 +95,11 @@ pub fn instance_create_surface_from_macos_layer(
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
|
|
||||||
#[cfg(feature = "gfx-backend-metal")]
|
#[cfg(feature = "gfx-backend-metal")]
|
||||||
SurfaceHandle {
|
SurfaceHandle::new(HUB.instances
|
||||||
raw: HUB.instances
|
.read()
|
||||||
.read()
|
.get(instance_id)
|
||||||
.get(instance_id)
|
.create_surface_from_layer(layer as *mut _)
|
||||||
.create_surface_from_layer(layer as *mut _),
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "local")]
|
#[cfg(feature = "local")]
|
||||||
@ -139,9 +134,7 @@ pub fn instance_create_surface_from_windows_hwnd(
|
|||||||
.create_surface_from_hwnd(hinstance, hwnd);
|
.create_surface_from_hwnd(hinstance, hwnd);
|
||||||
|
|
||||||
#[cfg_attr(not(target_os = "windows"), allow(unreachable_code))]
|
#[cfg_attr(not(target_os = "windows"), allow(unreachable_code))]
|
||||||
SurfaceHandle {
|
SurfaceHandle::new(raw)
|
||||||
raw,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "local")]
|
#[cfg(feature = "local")]
|
||||||
|
@ -219,5 +219,4 @@ type ComputePassHandle = ComputePass<back::Backend>;
|
|||||||
// Swap chain
|
// Swap chain
|
||||||
pub type SurfaceId = hub::Id;
|
pub type SurfaceId = hub::Id;
|
||||||
type SurfaceHandle = Surface<back::Backend>;
|
type SurfaceHandle = Surface<back::Backend>;
|
||||||
pub type SwapChainId = hub::Id;
|
pub type SwapChainId = SurfaceId;
|
||||||
type SwapChainHandle = SwapChain<back::Backend>;
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::{Stored, WeaklyStored,
|
use crate::{
|
||||||
|
Extent3d, Stored, WeaklyStored,
|
||||||
DeviceId, SwapChainId, TextureId, TextureViewId,
|
DeviceId, SwapChainId, TextureId, TextureViewId,
|
||||||
};
|
};
|
||||||
use crate::{conv, resource};
|
use crate::{conv, resource};
|
||||||
@ -8,7 +9,7 @@ use crate::track::{TrackPermit};
|
|||||||
|
|
||||||
use hal;
|
use hal;
|
||||||
use hal::{Device as _Device, Swapchain as _Swapchain};
|
use hal::{Device as _Device, Swapchain as _Swapchain};
|
||||||
use log::trace;
|
use log::{trace, warn};
|
||||||
|
|
||||||
use std::{iter, mem};
|
use std::{iter, mem};
|
||||||
|
|
||||||
@ -23,6 +24,16 @@ pub(crate) struct SwapChainLink<E> {
|
|||||||
|
|
||||||
pub struct Surface<B: hal::Backend> {
|
pub struct Surface<B: hal::Backend> {
|
||||||
pub(crate) raw: B::Surface,
|
pub(crate) raw: B::Surface,
|
||||||
|
pub(crate) swap_chain: Option<SwapChain<B>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: hal::Backend> Surface<B> {
|
||||||
|
pub(crate) fn new(raw: B::Surface) -> Self {
|
||||||
|
Surface {
|
||||||
|
raw,
|
||||||
|
swap_chain: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct Frame<B: hal::Backend> {
|
pub(crate) struct Frame<B: hal::Backend> {
|
||||||
@ -34,6 +45,12 @@ pub(crate) struct Frame<B: hal::Backend> {
|
|||||||
pub comb: hal::command::CommandBuffer<B, hal::General, hal::command::MultiShot>,
|
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?
|
//TODO: does it need a ref-counted lifetime?
|
||||||
|
|
||||||
pub struct SwapChain<B: hal::Backend> {
|
pub struct SwapChain<B: hal::Backend> {
|
||||||
@ -42,6 +59,7 @@ pub struct SwapChain<B: hal::Backend> {
|
|||||||
pub(crate) frames: Vec<Frame<B>>,
|
pub(crate) frames: Vec<Frame<B>>,
|
||||||
pub(crate) acquired: Vec<hal::SwapImageIndex>,
|
pub(crate) acquired: Vec<hal::SwapImageIndex>,
|
||||||
pub(crate) sem_available: B::Semaphore,
|
pub(crate) sem_available: B::Semaphore,
|
||||||
|
pub(crate) outdated: OutdatedFrame,
|
||||||
#[cfg_attr(not(feature = "local"), allow(dead_code))] //TODO: remove
|
#[cfg_attr(not(feature = "local"), allow(dead_code))] //TODO: remove
|
||||||
pub(crate) command_pool: hal::CommandPool<B, hal::General>,
|
pub(crate) command_pool: hal::CommandPool<B, hal::General>,
|
||||||
}
|
}
|
||||||
@ -54,6 +72,22 @@ pub struct SwapChainDescriptor {
|
|||||||
pub height: u32,
|
pub height: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SwapChainDescriptor {
|
||||||
|
pub fn to_texture_desc(&self) -> resource::TextureDescriptor {
|
||||||
|
resource::TextureDescriptor {
|
||||||
|
size: Extent3d {
|
||||||
|
width: self.width,
|
||||||
|
height: self.height,
|
||||||
|
depth: 1,
|
||||||
|
},
|
||||||
|
array_size: 1,
|
||||||
|
dimension: resource::TextureDimension::D2,
|
||||||
|
format: self.format,
|
||||||
|
usage: self.usage,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct SwapChainOutput {
|
pub struct SwapChainOutput {
|
||||||
pub texture_id: TextureId,
|
pub texture_id: TextureId,
|
||||||
@ -64,37 +98,51 @@ pub struct SwapChainOutput {
|
|||||||
pub extern "C" fn wgpu_swap_chain_get_next_texture(
|
pub extern "C" fn wgpu_swap_chain_get_next_texture(
|
||||||
swap_chain_id: SwapChainId,
|
swap_chain_id: SwapChainId,
|
||||||
) -> SwapChainOutput {
|
) -> SwapChainOutput {
|
||||||
let mut swap_chain_guard = HUB.swap_chains.write();
|
let mut surface_guard = HUB.surfaces.write();
|
||||||
let swap_chain = swap_chain_guard.get_mut(swap_chain_id);
|
let swap_chain = surface_guard
|
||||||
assert_ne!(swap_chain.acquired.len(), swap_chain.acquired.capacity(),
|
.get_mut(swap_chain_id)
|
||||||
"Unable to acquire any more swap chain images before presenting");
|
.swap_chain
|
||||||
|
.as_mut()
|
||||||
|
.unwrap();
|
||||||
let device_guard = HUB.devices.read();
|
let device_guard = HUB.devices.read();
|
||||||
let device = device_guard.get(swap_chain.device_id.value);
|
let device = device_guard.get(swap_chain.device_id.value);
|
||||||
|
|
||||||
let image_index = unsafe {
|
assert_ne!(swap_chain.acquired.len(), swap_chain.acquired.capacity(),
|
||||||
|
"Unable to acquire any more swap chain images before presenting");
|
||||||
|
|
||||||
|
match {
|
||||||
let sync = hal::FrameSync::Semaphore(&swap_chain.sem_available);
|
let sync = hal::FrameSync::Semaphore(&swap_chain.sem_available);
|
||||||
swap_chain.raw.acquire_image(!0, sync).unwrap()
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
swap_chain.acquired.push(image_index);
|
mem::swap(&mut frame.sem_available, &mut swap_chain.sem_available);
|
||||||
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);
|
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!(),
|
||||||
|
}
|
||||||
|
|
||||||
let texture_guard = HUB.textures.read();
|
SwapChainOutput {
|
||||||
let texture = texture_guard.get(frame.texture_id.value);
|
texture_id: frame.texture_id.value,
|
||||||
match texture.swap_chain_link {
|
view_id: frame.view_id.value,
|
||||||
Some(ref link) => *link.epoch.lock() += 1,
|
}
|
||||||
None => unreachable!(),
|
}
|
||||||
}
|
Err(e) => {
|
||||||
|
warn!("acquire_image failed: {:?}", e);
|
||||||
SwapChainOutput {
|
swap_chain.acquired.push(OUTDATED_IMAGE_INDEX);
|
||||||
texture_id: frame.texture_id.value,
|
SwapChainOutput {
|
||||||
view_id: frame.view_id.value,
|
texture_id: swap_chain.outdated.texture_id.value,
|
||||||
|
view_id: swap_chain.outdated.view_id.value,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,13 +150,24 @@ pub extern "C" fn wgpu_swap_chain_get_next_texture(
|
|||||||
pub extern "C" fn wgpu_swap_chain_present(
|
pub extern "C" fn wgpu_swap_chain_present(
|
||||||
swap_chain_id: SwapChainId,
|
swap_chain_id: SwapChainId,
|
||||||
) {
|
) {
|
||||||
let mut swap_chain_guard = HUB.swap_chains.write();
|
let mut surface_guard = HUB.surfaces.write();
|
||||||
let swap_chain = swap_chain_guard.get_mut(swap_chain_id);
|
let swap_chain = surface_guard
|
||||||
let mut device_guard = HUB.devices.write();
|
.get_mut(swap_chain_id)
|
||||||
let device = device_guard.get_mut(swap_chain.device_id.value);
|
.swap_chain
|
||||||
|
.as_mut()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let image_index = swap_chain.acquired.remove(0);
|
let image_index = swap_chain.acquired.remove(0);
|
||||||
let frame = &mut swap_chain.frames[image_index as usize];
|
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 mut device_guard = HUB.devices.write();
|
||||||
|
let device = device_guard.get_mut(swap_chain.device_id.value);
|
||||||
|
|
||||||
let texture_guard = HUB.textures.read();
|
let texture_guard = HUB.textures.read();
|
||||||
let texture = texture_guard.get(frame.texture_id.value);
|
let texture = texture_guard.get(frame.texture_id.value);
|
||||||
@ -138,7 +197,7 @@ pub extern "C" fn wgpu_swap_chain_present(
|
|||||||
range: texture.full_range.clone(),
|
range: texture.full_range.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
unsafe {
|
let err = unsafe {
|
||||||
frame.comb.begin(false);
|
frame.comb.begin(false);
|
||||||
frame.comb.pipeline_barrier(
|
frame.comb.pipeline_barrier(
|
||||||
all_image_stages() .. hal::pso::PipelineStage::COLOR_ATTACHMENT_OUTPUT,
|
all_image_stages() .. hal::pso::PipelineStage::COLOR_ATTACHMENT_OUTPUT,
|
||||||
@ -157,11 +216,13 @@ pub extern "C" fn wgpu_swap_chain_present(
|
|||||||
device.raw.reset_fence(&frame.fence).unwrap();
|
device.raw.reset_fence(&frame.fence).unwrap();
|
||||||
let queue = &mut device.queue_group.queues[0];
|
let queue = &mut device.queue_group.queues[0];
|
||||||
queue.submit(submission, Some(&frame.fence));
|
queue.submit(submission, Some(&frame.fence));
|
||||||
queue
|
queue.present(
|
||||||
.present(
|
iter::once((&swap_chain.raw, image_index)),
|
||||||
iter::once((&swap_chain.raw, image_index)),
|
iter::once(&frame.sem_present),
|
||||||
iter::once(&frame.sem_present),
|
)
|
||||||
)
|
};
|
||||||
.unwrap();
|
|
||||||
|
if let Err(e) = err {
|
||||||
|
warn!("present failed: {:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,6 +87,11 @@ impl<I: Clone + Hash + Eq, U: Copy + GenericUsage + BitOr<Output = U> + PartialE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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.
|
/// Get the last usage on a resource.
|
||||||
pub(crate) fn query(&mut self, stored: &Stored<I>, default: U) -> Query<U> {
|
pub(crate) fn query(&mut self, stored: &Stored<I>, default: U) -> Query<U> {
|
||||||
match self.map.entry(WeaklyStored(stored.value.clone())) {
|
match self.map.entry(WeaklyStored(stored.value.clone())) {
|
||||||
|
Loading…
Reference in New Issue
Block a user