Support recording swapchain commands from multiple threads

This commit is contained in:
Dzmitry Malyshau 2020-08-23 01:19:16 -04:00 committed by Dzmitry Malyshau
parent d4fbf6c0a8
commit bbd2e78d26
4 changed files with 54 additions and 26 deletions

1
Cargo.lock generated
View file

@ -593,6 +593,7 @@ dependencies = [
"gfx-hal 0.6.0 (git+https://github.com/gfx-rs/gfx)", "gfx-hal 0.6.0 (git+https://github.com/gfx-rs/gfx)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"renderdoc 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "renderdoc 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"typed-arena 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "typed-arena 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]

View file

@ -23,6 +23,7 @@ copyless = "0.1.1"
env_logger = { version = "0.7", optional = true } env_logger = { version = "0.7", optional = true }
lazy_static = "1" lazy_static = "1"
log = { version = "0.4", features = ["release_max_level_error"] } log = { version = "0.4", features = ["release_max_level_error"] }
parking_lot = "0.11"
renderdoc = { version = "0.3", optional = true } renderdoc = { version = "0.3", optional = true }
typed-arena = "2" typed-arena = "2"

View file

@ -1,3 +1,5 @@
use super::*;
use hal::{ use hal::{
adapter::PhysicalDevice, adapter::PhysicalDevice,
buffer::IndexBufferView, buffer::IndexBufferView,
@ -10,6 +12,9 @@ use hal::{
{command as com, memory, pass, pso, queue}, {Features, Instance}, {command as com, memory, pass, pso, queue}, {Features, Instance},
}; };
use parking_lot::Mutex;
use typed_arena::Arena;
#[cfg(feature = "gfx-backend-metal")] #[cfg(feature = "gfx-backend-metal")]
use std::env; use std::env;
use std::{ use std::{
@ -19,9 +24,6 @@ use std::{
os::raw::{c_int, c_void}, os::raw::{c_int, c_void},
ptr, str, ptr, str,
}; };
use typed_arena::Arena;
use super::*;
const VERSION: (u32, u32, u32) = (1, 0, 66); const VERSION: (u32, u32, u32) = (1, 0, 66);
const DRIVER_VERSION: u32 = 1; const DRIVER_VERSION: u32 = 1;
@ -3292,16 +3294,20 @@ pub unsafe extern "C" fn gfxBeginCommandBuffer(
pBeginInfo: *const VkCommandBufferBeginInfo, pBeginInfo: *const VkCommandBufferBeginInfo,
) -> VkResult { ) -> VkResult {
let info = &*pBeginInfo; let info = &*pBeginInfo;
let fb_resolve;
let inheritance = match info.pInheritanceInfo.as_ref() { let inheritance = match info.pInheritanceInfo.as_ref() {
Some(ii) => com::CommandBufferInheritanceInfo { Some(ii) => com::CommandBufferInheritanceInfo {
subpass: ii.renderPass.as_ref().map(|rp| pass::Subpass { subpass: ii.renderPass.as_ref().map(|rp| pass::Subpass {
main_pass: &rp.raw, main_pass: &rp.raw,
index: ii.subpass as _, index: ii.subpass as _,
}), }),
framebuffer: ii framebuffer: match ii.framebuffer.as_ref() {
.framebuffer Some(fbo) => {
.as_ref() fb_resolve = fbo.resolve(ii.renderPass);
.map(|fbo| fbo.resolve(ii.renderPass)), Some(&*fb_resolve)
}
None => None,
},
occlusion_query_enable: ii.occlusionQueryEnable != VK_FALSE, occlusion_query_enable: ii.occlusionQueryEnable != VK_FALSE,
occlusion_query_flags: conv::map_query_control(ii.queryFlags), occlusion_query_flags: conv::map_query_control(ii.queryFlags),
pipeline_statistics: conv::map_pipeline_statistics(ii.pipelineStatistics), pipeline_statistics: conv::map_pipeline_statistics(ii.pipelineStatistics),
@ -4110,7 +4116,7 @@ pub unsafe extern "C" fn gfxCmdBeginRenderPass(
commandBuffer.begin_render_pass( commandBuffer.begin_render_pass(
&info.renderPass.raw, &info.renderPass.raw,
framebuffer, &*framebuffer,
render_area, render_area,
clear_values, clear_values,
contents, contents,
@ -4375,7 +4381,7 @@ pub unsafe extern "C" fn gfxCreateSwapchainKHR(
count: info.minImageCount as u8, count: info.minImageCount as u8,
current_index: 0, current_index: 0,
active: None, active: None,
lazy_framebuffers: Vec::with_capacity(1), lazy_framebuffers: Mutex::new(Vec::with_capacity(1)),
}; };
*pSwapchain = Handle::new(swapchain); *pSwapchain = Handle::new(swapchain);
VkResult::VK_SUCCESS VkResult::VK_SUCCESS
@ -4709,7 +4715,7 @@ pub unsafe extern "C" fn gfxQueuePresentKHR(
} else { } else {
warn!("Swapchain frame {} is stale, can't be presented.", *index); warn!("Swapchain frame {} is stale, can't be presented.", *index);
} }
for framebuffer in sc.lazy_framebuffers.drain(..) { for framebuffer in sc.lazy_framebuffers.lock().drain(..) {
sc.gpu.device.destroy_framebuffer(framebuffer) sc.gpu.device.destroy_framebuffer(framebuffer)
} }
} }

View file

@ -39,11 +39,12 @@ mod conv;
mod handle; mod handle;
mod impls; mod impls;
use crate::back::Backend as B; use crate::{
use crate::handle::{DispatchHandle, Handle}; back::Backend as B,
handle::{DispatchHandle, Handle},
};
use std::collections::HashMap; use std::{collections::HashMap, slice};
use std::slice;
pub use crate::impls::*; pub use crate::impls::*;
@ -157,11 +158,26 @@ pub enum Framebuffer {
}, },
} }
enum FramebufferResolve<'a> {
Native(&'a <B as hal::Backend>::Framebuffer),
Lazy(parking_lot::MappedMutexGuard<'a, <B as hal::Backend>::Framebuffer>),
}
impl std::ops::Deref for FramebufferResolve<'_> {
type Target = <B as hal::Backend>::Framebuffer;
fn deref(&self) -> &Self::Target {
match *self {
FramebufferResolve::Native(fb) => fb,
FramebufferResolve::Lazy(ref guard) => &*guard,
}
}
}
impl Framebuffer { impl Framebuffer {
fn resolve(&self, render_pass: VkRenderPass) -> &<B as hal::Backend>::Framebuffer { fn resolve(&self, render_pass: VkRenderPass) -> FramebufferResolve {
let mut sc = None; let mut sc = None;
match *self { match *self {
Framebuffer::Native(ref fbo) => fbo, Framebuffer::Native(ref fbo) => FramebufferResolve::Native(fbo),
Framebuffer::Lazy { extent, ref views } => { Framebuffer::Lazy { extent, ref views } => {
for view in views { for view in views {
if let Some(&mut ImageView::SwapchainFrame { ref swapchain, .. }) = if let Some(&mut ImageView::SwapchainFrame { ref swapchain, .. }) =
@ -189,13 +205,19 @@ impl Framebuffer {
let sc = sc.expect("No swapchain frames detected"); let sc = sc.expect("No swapchain frames detected");
let gpu = sc.gpu; let gpu = sc.gpu;
sc.lazy_framebuffers.push(unsafe {
use hal::device::Device; FramebufferResolve::Lazy(parking_lot::MutexGuard::map(
gpu.device sc.lazy_framebuffers.lock(),
.create_framebuffer(&render_pass.raw, attachments, extent) |lazy_framebuffers| {
.unwrap() lazy_framebuffers.push(unsafe {
}); use hal::device::Device;
sc.lazy_framebuffers.last().unwrap() gpu.device
.create_framebuffer(&render_pass.raw, attachments, extent)
.unwrap()
});
lazy_framebuffers.last_mut().unwrap()
},
))
} }
} }
} }
@ -227,9 +249,7 @@ pub struct Swapchain<B: hal::Backend> {
count: u8, count: u8,
current_index: u8, current_index: u8,
active: Option<<B::Surface as hal::window::PresentationSurface<B>>::SwapchainImage>, active: Option<<B::Surface as hal::window::PresentationSurface<B>>::SwapchainImage>,
// This is totally unsafe: if multiple threads would start recording render passes into lazy_framebuffers: parking_lot::Mutex<Vec<<B as hal::Backend>::Framebuffer>>,
// that uses this swapchain, we'd have a race condition.
lazy_framebuffers: Vec<<B as hal::Backend>::Framebuffer>,
} }
/* automatically generated by rust-bindgen */ /* automatically generated by rust-bindgen */