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)",
"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)",
"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)",
"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 }
lazy_static = "1"
log = { version = "0.4", features = ["release_max_level_error"] }
parking_lot = "0.11"
renderdoc = { version = "0.3", optional = true }
typed-arena = "2"

View file

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

View file

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