diff --git a/Cargo.lock b/Cargo.lock index 3e1b4c6..b980c45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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)", ] diff --git a/libportability-gfx/Cargo.toml b/libportability-gfx/Cargo.toml index 0eeec3a..5ccbb78 100644 --- a/libportability-gfx/Cargo.toml +++ b/libportability-gfx/Cargo.toml @@ -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" diff --git a/libportability-gfx/src/impls.rs b/libportability-gfx/src/impls.rs index b383750..a64d828 100644 --- a/libportability-gfx/src/impls.rs +++ b/libportability-gfx/src/impls.rs @@ -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) } } diff --git a/libportability-gfx/src/lib.rs b/libportability-gfx/src/lib.rs index b66cd34..997db86 100644 --- a/libportability-gfx/src/lib.rs +++ b/libportability-gfx/src/lib.rs @@ -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 ::Framebuffer), + Lazy(parking_lot::MappedMutexGuard<'a, ::Framebuffer>), +} + +impl std::ops::Deref for FramebufferResolve<'_> { + type Target = ::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) -> &::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 { - use hal::device::Device; - gpu.device - .create_framebuffer(&render_pass.raw, attachments, extent) - .unwrap() - }); - sc.lazy_framebuffers.last().unwrap() + + 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() + }); + lazy_framebuffers.last_mut().unwrap() + }, + )) } } } @@ -227,9 +249,7 @@ pub struct Swapchain { count: u8, current_index: u8, active: Option<>::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<::Framebuffer>, + lazy_framebuffers: parking_lot::Mutex::Framebuffer>>, } /* automatically generated by rust-bindgen */