diff --git a/Cargo.lock b/Cargo.lock index 3535581b6..98263098c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -441,7 +441,7 @@ dependencies = [ [[package]] name = "gfx-auxil" version = "0.5.0" -source = "git+https://github.com/gfx-rs/gfx?rev=6b3a1e36939473f0062232baf11e1deacd6605f4#6b3a1e36939473f0062232baf11e1deacd6605f4" +source = "git+https://github.com/gfx-rs/gfx?rev=006f0c00782d5f602b4afa8e1fa9ffc2085af997#006f0c00782d5f602b4afa8e1fa9ffc2085af997" dependencies = [ "fxhash", "gfx-hal", @@ -451,7 +451,7 @@ dependencies = [ [[package]] name = "gfx-backend-dx11" version = "0.6.0" -source = "git+https://github.com/gfx-rs/gfx?rev=6b3a1e36939473f0062232baf11e1deacd6605f4#6b3a1e36939473f0062232baf11e1deacd6605f4" +source = "git+https://github.com/gfx-rs/gfx?rev=006f0c00782d5f602b4afa8e1fa9ffc2085af997#006f0c00782d5f602b4afa8e1fa9ffc2085af997" dependencies = [ "arrayvec", "bitflags", @@ -472,7 +472,7 @@ dependencies = [ [[package]] name = "gfx-backend-dx12" version = "0.6.2" -source = "git+https://github.com/gfx-rs/gfx?rev=6b3a1e36939473f0062232baf11e1deacd6605f4#6b3a1e36939473f0062232baf11e1deacd6605f4" +source = "git+https://github.com/gfx-rs/gfx?rev=006f0c00782d5f602b4afa8e1fa9ffc2085af997#006f0c00782d5f602b4afa8e1fa9ffc2085af997" dependencies = [ "arrayvec", "bit-set", @@ -492,7 +492,7 @@ dependencies = [ [[package]] name = "gfx-backend-empty" version = "0.6.0" -source = "git+https://github.com/gfx-rs/gfx?rev=6b3a1e36939473f0062232baf11e1deacd6605f4#6b3a1e36939473f0062232baf11e1deacd6605f4" +source = "git+https://github.com/gfx-rs/gfx?rev=006f0c00782d5f602b4afa8e1fa9ffc2085af997#006f0c00782d5f602b4afa8e1fa9ffc2085af997" dependencies = [ "gfx-hal", "log", @@ -502,7 +502,7 @@ dependencies = [ [[package]] name = "gfx-backend-gl" version = "0.6.0" -source = "git+https://github.com/gfx-rs/gfx?rev=6b3a1e36939473f0062232baf11e1deacd6605f4#6b3a1e36939473f0062232baf11e1deacd6605f4" +source = "git+https://github.com/gfx-rs/gfx?rev=006f0c00782d5f602b4afa8e1fa9ffc2085af997#006f0c00782d5f602b4afa8e1fa9ffc2085af997" dependencies = [ "arrayvec", "bitflags", @@ -525,7 +525,7 @@ dependencies = [ [[package]] name = "gfx-backend-metal" version = "0.6.0" -source = "git+https://github.com/gfx-rs/gfx?rev=6b3a1e36939473f0062232baf11e1deacd6605f4#6b3a1e36939473f0062232baf11e1deacd6605f4" +source = "git+https://github.com/gfx-rs/gfx?rev=006f0c00782d5f602b4afa8e1fa9ffc2085af997#006f0c00782d5f602b4afa8e1fa9ffc2085af997" dependencies = [ "arrayvec", "bitflags", @@ -535,7 +535,6 @@ dependencies = [ "foreign-types", "gfx-auxil", "gfx-hal", - "lazy_static", "log", "metal", "naga", @@ -550,7 +549,7 @@ dependencies = [ [[package]] name = "gfx-backend-vulkan" version = "0.6.5" -source = "git+https://github.com/gfx-rs/gfx?rev=6b3a1e36939473f0062232baf11e1deacd6605f4#6b3a1e36939473f0062232baf11e1deacd6605f4" +source = "git+https://github.com/gfx-rs/gfx?rev=006f0c00782d5f602b4afa8e1fa9ffc2085af997#006f0c00782d5f602b4afa8e1fa9ffc2085af997" dependencies = [ "arrayvec", "ash", @@ -558,10 +557,10 @@ dependencies = [ "core-graphics-types", "gfx-hal", "inplace_it", - "lazy_static", "log", "naga", "objc", + "parking_lot 0.11.0", "raw-window-handle", "smallvec", "winapi 0.3.9", @@ -570,7 +569,7 @@ dependencies = [ [[package]] name = "gfx-hal" version = "0.6.0" -source = "git+https://github.com/gfx-rs/gfx?rev=6b3a1e36939473f0062232baf11e1deacd6605f4#6b3a1e36939473f0062232baf11e1deacd6605f4" +source = "git+https://github.com/gfx-rs/gfx?rev=006f0c00782d5f602b4afa8e1fa9ffc2085af997#006f0c00782d5f602b4afa8e1fa9ffc2085af997" dependencies = [ "bitflags", "naga", @@ -580,9 +579,9 @@ dependencies = [ [[package]] name = "glow" -version = "0.6.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1625b792e2f9267116dd41eb7d325e0ea2572ceba5069451906745e04f852f33" +checksum = "3eac04632dc8c047fb70d658f8479583e1bb084859f67a150227769a10fc161f" dependencies = [ "js-sys", "slotmap", @@ -1209,7 +1208,7 @@ dependencies = [ [[package]] name = "range-alloc" version = "0.1.1" -source = "git+https://github.com/gfx-rs/gfx?rev=6b3a1e36939473f0062232baf11e1deacd6605f4#6b3a1e36939473f0062232baf11e1deacd6605f4" +source = "git+https://github.com/gfx-rs/gfx?rev=006f0c00782d5f602b4afa8e1fa9ffc2085af997#006f0c00782d5f602b4afa8e1fa9ffc2085af997" [[package]] name = "raw-window-handle" diff --git a/Cargo.toml b/Cargo.toml index ba911fe77..d329d430a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ members = [ "wgpu-types", ] -#[patch."https://github.com/gfx-rs/gfx"] +[patch."https://github.com/gfx-rs/gfx"] #hal = { package = "gfx-hal", path = "../gfx/src/hal" } #gfx-backend-vulkan = { path = "../gfx/src/backend/vulkan", features = ["naga"] } #gfx-backend-metal = { path = "../gfx/src/backend/metal", features = ["naga"] } @@ -15,5 +15,5 @@ members = [ #gfx-backend-dx11 = { path = "../gfx/src/backend/dx11" } #gfx-backend-empty = { path = "../gfx/src/backend/empty" } -#[patch."https://github.com/gfx-rs/naga"] +[patch."https://github.com/gfx-rs/naga"] #naga = { path = "../naga" } diff --git a/wgpu-core/Cargo.toml b/wgpu-core/Cargo.toml index ce0a960c3..1c7e30544 100644 --- a/wgpu-core/Cargo.toml +++ b/wgpu-core/Cargo.toml @@ -36,24 +36,24 @@ thiserror = "1" gpu-alloc = { git = "https://github.com/zakarumych/gpu-alloc", rev = "29e761f24edc50e28d238e723503b146d55d222e", features = ["tracing"] } gpu-descriptor = { git = "https://github.com/zakarumych/gpu-descriptor", rev = "df74fd8c7bea03149058a41aab0e4fe04077b266", features = ["tracing"] } -hal = { package = "gfx-hal", git = "https://github.com/gfx-rs/gfx", rev = "6b3a1e36939473f0062232baf11e1deacd6605f4" } -gfx-backend-empty = { git = "https://github.com/gfx-rs/gfx", rev = "6b3a1e36939473f0062232baf11e1deacd6605f4" } +hal = { package = "gfx-hal", git = "https://github.com/gfx-rs/gfx", rev = "006f0c00782d5f602b4afa8e1fa9ffc2085af997" } +gfx-backend-empty = { git = "https://github.com/gfx-rs/gfx", rev = "006f0c00782d5f602b4afa8e1fa9ffc2085af997" } [target.'cfg(all(not(target_arch = "wasm32"), all(unix, not(target_os = "ios"), not(target_os = "macos"))))'.dependencies] -gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "6b3a1e36939473f0062232baf11e1deacd6605f4", features = ["naga"] } -gfx-backend-gl = { git = "https://github.com/gfx-rs/gfx", rev = "6b3a1e36939473f0062232baf11e1deacd6605f4", features = ["naga"] } +gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "006f0c00782d5f602b4afa8e1fa9ffc2085af997", features = ["naga"] } +gfx-backend-gl = { git = "https://github.com/gfx-rs/gfx", rev = "006f0c00782d5f602b4afa8e1fa9ffc2085af997", features = ["naga"] } [target.'cfg(all(not(target_arch = "wasm32"), any(target_os = "ios", target_os = "macos")))'.dependencies] -gfx-backend-metal = { git = "https://github.com/gfx-rs/gfx", rev = "6b3a1e36939473f0062232baf11e1deacd6605f4", features = ["naga"] } -gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "6b3a1e36939473f0062232baf11e1deacd6605f4", optional = true } +gfx-backend-metal = { git = "https://github.com/gfx-rs/gfx", rev = "006f0c00782d5f602b4afa8e1fa9ffc2085af997", features = ["naga"] } +gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "006f0c00782d5f602b4afa8e1fa9ffc2085af997", optional = true } [target.'cfg(all(not(target_arch = "wasm32"), windows))'.dependencies] -gfx-backend-dx12 = { git = "https://github.com/gfx-rs/gfx", rev = "6b3a1e36939473f0062232baf11e1deacd6605f4" } -gfx-backend-dx11 = { git = "https://github.com/gfx-rs/gfx", rev = "6b3a1e36939473f0062232baf11e1deacd6605f4" } -gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "6b3a1e36939473f0062232baf11e1deacd6605f4", features = ["naga"] } +gfx-backend-dx12 = { git = "https://github.com/gfx-rs/gfx", rev = "006f0c00782d5f602b4afa8e1fa9ffc2085af997" } +gfx-backend-dx11 = { git = "https://github.com/gfx-rs/gfx", rev = "006f0c00782d5f602b4afa8e1fa9ffc2085af997" } +gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "006f0c00782d5f602b4afa8e1fa9ffc2085af997", features = ["naga"] } [target.'cfg(target_arch = "wasm32")'.dependencies] -gfx-backend-gl = { git = "https://github.com/gfx-rs/gfx", rev = "6b3a1e36939473f0062232baf11e1deacd6605f4", features = ["naga"] } +gfx-backend-gl = { git = "https://github.com/gfx-rs/gfx", rev = "006f0c00782d5f602b4afa8e1fa9ffc2085af997", features = ["naga"] } [dependencies.naga] git = "https://github.com/gfx-rs/naga" diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index b9cfbde0c..6a19f9378 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -43,7 +43,7 @@ pub struct CommandBuffer { recorded_thread_id: ThreadId, pub(crate) device_id: Stored, pub(crate) trackers: TrackerSet, - pub(crate) used_swap_chains: SmallVec<[(Stored, B::Framebuffer); 1]>, + pub(crate) used_swap_chains: SmallVec<[Stored; 1]>, limits: wgt::Limits, private_features: PrivateFeatures, has_labels: bool, @@ -217,7 +217,7 @@ impl Global { Ok(cmd_buf) => { cmd_buf.is_recording = false; // stop tracking the swapchain image, if used - for (ref sc_id, _) in cmd_buf.used_swap_chains.iter() { + for sc_id in cmd_buf.used_swap_chains.iter() { let view_id = swap_chain_guard[sc_id.value] .acquired_view_id .as_ref() diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 88f55599d..262147a24 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -11,8 +11,8 @@ use crate::{ }, conv, device::{ - AttachmentData, AttachmentDataVec, Device, FramebufferKey, RenderPassCompatibilityError, - RenderPassContext, RenderPassKey, MAX_COLOR_TARGETS, MAX_VERTEX_BUFFERS, + AttachmentData, AttachmentDataVec, Device, RenderPassCompatibilityError, RenderPassContext, + RenderPassKey, RenderPassLock, MAX_COLOR_TARGETS, MAX_VERTEX_BUFFERS, }, hub::{GfxBackend, Global, GlobalIdentityHandlerFactory, Storage, Token}, id, @@ -42,6 +42,7 @@ use std::{ borrow::{Borrow, Cow}, collections::hash_map::Entry, fmt, iter, + marker::PhantomData, num::NonZeroU32, ops::Range, str, @@ -503,15 +504,14 @@ struct RenderAttachment<'a> { new_use: TextureUse, } -type UsedSwapChainInfo = Option<(Stored, F)>; - struct RenderPassInfo<'a, B: hal::Backend> { context: RenderPassContext, trackers: TrackerSet, render_attachments: AttachmentDataVec>, - used_swapchain_with_framebuffer: UsedSwapChainInfo, + used_swap_chain: Option>, is_ds_read_only: bool, extent: wgt::Extent3d, + _phantom: PhantomData, } impl<'a, B: GfxBackend> RenderPassInfo<'a, B> { @@ -543,7 +543,6 @@ impl<'a, B: GfxBackend> RenderPassInfo<'a, B> { let mut depth_stencil_aspects = hal::format::Aspects::empty(); let mut used_swap_chain = None::>; let mut trackers = TrackerSet::new(B::VARIANT); - let mut used_swapchain_with_framebuffer = None; let mut add_view = |view: &TextureView| { if let Some(ex) = extent { @@ -809,8 +808,11 @@ impl<'a, B: GfxBackend> RenderPassInfo<'a, B> { return Err(RenderPassErrorInner::InvalidSampleCount(sample_count)); } - let mut render_pass_cache = device.render_passes.lock(); - let render_pass = match render_pass_cache.entry(rp_key.clone()) { + let RenderPassLock { + ref mut render_passes, + ref mut framebuffers, + } = *device.render_passes.lock(); + let render_pass = match render_passes.entry(rp_key.clone()) { Entry::Occupied(e) => e.into_mut(), Entry::Vacant(entry) => { let color_ids: [hal::pass::AttachmentRef; MAX_COLOR_TARGETS] = [ @@ -871,82 +873,40 @@ impl<'a, B: GfxBackend> RenderPassInfo<'a, B> { } }; - let mut framebuffer_cache; - let fb_key = FramebufferKey { + let view_data = AttachmentData { colors: color_attachments .iter() - .map(|at| id::Valid(at.attachment)) + .map(|at| view_guard.get(at.attachment).unwrap()) .collect(), resolves: color_attachments .iter() .filter_map(|at| at.resolve_target) - .map(id::Valid) + .map(|attachment| view_guard.get(attachment).unwrap()) .collect(), - depth_stencil: depth_stencil_attachment.map(|at| id::Valid(at.attachment)), + depth_stencil: depth_stencil_attachment + .map(|at| view_guard.get(at.attachment).unwrap()), }; + let fb_key = view_data.map(|view| view.framebuffer_attachment.clone()); let context = RenderPassContext { - attachments: AttachmentData { - colors: fb_key - .colors - .iter() - .map(|&at| view_guard[at].format) - .collect(), - resolves: fb_key - .resolves - .iter() - .map(|&at| view_guard[at].format) - .collect(), - depth_stencil: fb_key.depth_stencil.map(|at| view_guard[at].format), - }, + attachments: view_data.map(|view| view.format), sample_count, }; - let framebuffer = match used_swap_chain.take() { - Some(sc_id) => { - // Always create a new framebuffer and delete it after presentation. - let attachments = fb_key - .all() - .map(|&id| match view_guard[id].inner { - TextureViewInner::Native { ref raw, .. } => raw, - TextureViewInner::SwapChain { ref image, .. } => Borrow::borrow(image), - }) - .collect::>(); - let framebuffer = unsafe { + // Cache framebuffers by the device. + let framebuffer = match framebuffers.entry(fb_key) { + Entry::Occupied(e) => e.into_mut(), + Entry::Vacant(e) => { + let fb = unsafe { device .raw - .create_framebuffer(&render_pass, attachments, extent.unwrap()) + .create_framebuffer( + &render_pass, + e.key().all().map(|fat| fat.clone()), + extent.unwrap(), + ) .or(Err(RenderPassErrorInner::OutOfMemory))? }; - used_swapchain_with_framebuffer = Some((sc_id, framebuffer)); - &mut used_swapchain_with_framebuffer.as_mut().unwrap().1 - } - None => { - // Cache framebuffers by the device. - framebuffer_cache = device.framebuffers.lock(); - match framebuffer_cache.entry(fb_key) { - Entry::Occupied(e) => e.into_mut(), - Entry::Vacant(e) => { - let fb = { - let attachments = e - .key() - .all() - .map(|&id| match view_guard[id].inner { - TextureViewInner::Native { ref raw, .. } => raw, - TextureViewInner::SwapChain { ref image, .. } => { - Borrow::borrow(image) - } - }) - .collect::>(); - unsafe { - device - .raw - .create_framebuffer(&render_pass, attachments, extent.unwrap()) - .or(Err(RenderPassErrorInner::OutOfMemory))? - } - }; - e.insert(fb) - } - } + e.insert(fb) } }; @@ -959,59 +919,75 @@ impl<'a, B: GfxBackend> RenderPassInfo<'a, B> { h: ex.height as _, } }; + let raw_views = view_data.map(|view| match view.inner { + TextureViewInner::Native { ref raw, .. } => raw, + TextureViewInner::SwapChain { ref image, .. } => Borrow::borrow(image), + }); - let clear_values = color_attachments + let attachments = color_attachments .iter() .zip(&rp_key.colors) - .flat_map(|(at, (rat, _layout))| { - match at.channel.load_op { - LoadOp::Load => None, - LoadOp::Clear => { - use hal::format::ChannelType; - //TODO: validate sign/unsign and normalized ranges of the color values - let value = match rat.format.unwrap().base_format().1 { - ChannelType::Unorm - | ChannelType::Snorm - | ChannelType::Ufloat - | ChannelType::Sfloat - | ChannelType::Uscaled - | ChannelType::Sscaled - | ChannelType::Srgb => hal::command::ClearColor { - float32: conv::map_color_f32(&at.channel.clear_value), - }, - ChannelType::Sint => hal::command::ClearColor { - sint32: conv::map_color_i32(&at.channel.clear_value), - }, - ChannelType::Uint => hal::command::ClearColor { - uint32: conv::map_color_u32(&at.channel.clear_value), - }, - }; - Some(hal::command::ClearValue { color: value }) - } - } - }) - .chain(depth_stencil_attachment.and_then(|at| { - match (at.depth.load_op, at.stencil.load_op) { - (LoadOp::Load, LoadOp::Load) => None, - (LoadOp::Clear, _) | (_, LoadOp::Clear) => { - let value = hal::command::ClearDepthStencil { - depth: at.depth.clear_value, - stencil: at.stencil.clear_value, - }; - Some(hal::command::ClearValue { - depth_stencil: value, - }) - } + .zip(raw_views.colors) + .map( + |((at, (rat, _layout)), image_view)| hal::command::RenderAttachmentInfo { + image_view, + clear_value: match at.channel.load_op { + LoadOp::Load => Default::default(), + LoadOp::Clear => { + use hal::format::ChannelType; + //TODO: validate sign/unsign and normalized ranges of the color values + let value = match rat.format.unwrap().base_format().1 { + ChannelType::Unorm + | ChannelType::Snorm + | ChannelType::Ufloat + | ChannelType::Sfloat + | ChannelType::Uscaled + | ChannelType::Sscaled + | ChannelType::Srgb => hal::command::ClearColor { + float32: conv::map_color_f32(&at.channel.clear_value), + }, + ChannelType::Sint => hal::command::ClearColor { + sint32: conv::map_color_i32(&at.channel.clear_value), + }, + ChannelType::Uint => hal::command::ClearColor { + uint32: conv::map_color_u32(&at.channel.clear_value), + }, + }; + hal::command::ClearValue { color: value } + } + }, + }, + ) + .chain(raw_views.resolves.into_iter().map(|image_view| { + hal::command::RenderAttachmentInfo { + image_view, + clear_value: Default::default(), } })) - .collect::>(); + .chain(depth_stencil_attachment.zip(raw_views.depth_stencil).map( + |(at, image_view)| hal::command::RenderAttachmentInfo { + image_view, + clear_value: match (at.depth.load_op, at.stencil.load_op) { + (LoadOp::Load, LoadOp::Load) => Default::default(), + (LoadOp::Clear, _) | (_, LoadOp::Clear) => { + let value = hal::command::ClearDepthStencil { + depth: at.depth.clear_value, + stencil: at.stencil.clear_value, + }; + hal::command::ClearValue { + depth_stencil: value, + } + } + }, + }, + )); unsafe { raw.begin_render_pass( render_pass, framebuffer, rect, - clear_values, + attachments, hal::command::SubpassContents::Inline, ); raw.set_scissors(0, iter::once(&rect)); @@ -1028,20 +1004,21 @@ impl<'a, B: GfxBackend> RenderPassInfo<'a, B> { context, trackers, render_attachments, - used_swapchain_with_framebuffer, + used_swap_chain, is_ds_read_only, extent: wgt::Extent3d { width: attachment_width.ok_or(RenderPassErrorInner::MissingAttachments)?, height: attachment_height.ok_or(RenderPassErrorInner::MissingAttachments)?, depth: 1, }, + _phantom: PhantomData, }) } fn finish( mut self, texture_guard: &Storage, id::TextureId>, - ) -> Result<(TrackerSet, UsedSwapChainInfo), RenderPassErrorInner> { + ) -> Result<(TrackerSet, Option>), RenderPassErrorInner> { for ra in self.render_attachments { let texture = &texture_guard[ra.texture_id.value]; check_texture_usage(texture.usage, TextureUsage::RENDER_ATTACHMENT)?; @@ -1072,7 +1049,7 @@ impl<'a, B: GfxBackend> RenderPassInfo<'a, B> { .unwrap(); } } - Ok((self.trackers, self.used_swapchain_with_framebuffer)) + Ok((self.trackers, self.used_swap_chain)) } } @@ -1108,7 +1085,7 @@ impl Global { let (device_guard, mut token) = hub.devices.read(&mut token); - let (cmd_buf_raw, trackers, used_swapchain_with_framebuffer) = { + let (cmd_buf_raw, trackers, used_swapchain) = { // read-only lock guard let (cmb_guard, mut token) = hub.command_buffers.read(&mut token); @@ -1866,9 +1843,8 @@ impl Global { raw.end_render_pass(); } - let (trackers, used_swapchain_with_framebuffer) = - info.finish(&*texture_guard).map_pass_err(scope)?; - (raw, trackers, used_swapchain_with_framebuffer) + let (trackers, used_swapchain) = info.finish(&*texture_guard).map_pass_err(scope)?; + (raw, trackers, used_swapchain) }; let (mut cmb_guard, mut token) = hub.command_buffers.write(&mut token); @@ -1877,9 +1853,7 @@ impl Global { let cmd_buf = CommandBuffer::get_encoder_mut(&mut *cmb_guard, encoder_id).map_pass_err(scope)?; cmd_buf.has_labels |= base.label.is_some(); - cmd_buf - .used_swap_chains - .extend(used_swapchain_with_framebuffer); + cmd_buf.used_swap_chains.extend(used_swapchain); #[cfg(feature = "trace")] if let Some(ref mut list) = cmd_buf.commands { diff --git a/wgpu-core/src/device/life.rs b/wgpu-core/src/device/life.rs index 015ebeb4d..594ea4eda 100644 --- a/wgpu-core/src/device/life.rs +++ b/wgpu-core/src/device/life.rs @@ -14,7 +14,7 @@ use crate::{ hub::{GfxBackend, GlobalIdentityHandlerFactory, Hub, Token}, id, resource, track::TrackerSet, - FastHashMap, RefCount, Stored, SubmissionIndex, + RefCount, Stored, SubmissionIndex, }; use copyless::VecHelper as _; @@ -636,74 +636,6 @@ impl LifetimeTracker { } } - pub(crate) fn triage_framebuffers( - &mut self, - hub: &Hub, - framebuffers: &mut FastHashMap, - token: &mut Token>, - ) { - let (texture_view_guard, _) = hub.texture_views.read(token); - let remove_list = framebuffers - .keys() - .filter_map(|key| { - let mut last_submit = None; - let mut needs_cleanup = false; - - // A framebuffer needs to be scheduled for cleanup, if there's at least one - // attachment is no longer valid. - - for &at in key.all() { - // If this attachment is still registered, it's still valid - if texture_view_guard.contains(at.0) { - continue; - } - - // This attachment is no longer registered, this framebuffer needs cleanup - needs_cleanup = true; - - // Check if there's any active submissions that are still referring to this - // attachment, if there are we need to get the greatest submission index, as - // that's the last time this attachment is still valid - let mut attachment_last_submit = None; - for a in &self.active { - if a.last_resources.image_views.iter().any(|&(id, _)| id == at) { - let max = attachment_last_submit.unwrap_or(0).max(a.index); - attachment_last_submit = Some(max); - } - } - - // Between all attachments, we need the smallest index, because that's the last - // time this framebuffer is still valid - if let Some(attachment_last_submit) = attachment_last_submit { - let min = last_submit - .unwrap_or(std::usize::MAX) - .min(attachment_last_submit); - last_submit = Some(min); - } - } - - if needs_cleanup { - Some((key.clone(), last_submit.unwrap_or(0))) - } else { - None - } - }) - .collect::>(); - - if !remove_list.is_empty() { - tracing::debug!("Free framebuffers {:?}", remove_list); - for (ref key, submit_index) in remove_list { - let framebuffer = framebuffers.remove(key).unwrap(); - self.active - .iter_mut() - .find(|a| a.index == submit_index) - .map_or(&mut self.free_resources, |a| &mut a.last_resources) - .framebuffers - .push(framebuffer); - } - } - } - pub(crate) fn handle_mapping( &mut self, hub: &Hub, diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 6ff734940..7b977bfe6 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -103,12 +103,20 @@ impl AttachmentData { .chain(&self.resolves) .chain(&self.depth_stencil) } + + pub(crate) fn map U>(&self, fun: F) -> AttachmentData { + AttachmentData { + colors: self.colors.iter().map(&fun).collect(), + resolves: self.resolves.iter().map(&fun).collect(), + depth_stencil: self.depth_stencil.as_ref().map(&fun), + } + } } pub(crate) type AttachmentDataVec = ArrayVec<[T; MAX_COLOR_TARGETS + MAX_COLOR_TARGETS + 1]>; pub(crate) type RenderPassKey = AttachmentData<(hal::pass::Attachment, hal::image::Layout)>; -pub(crate) type FramebufferKey = AttachmentData>; +pub(crate) type FramebufferKey = AttachmentData; #[derive(Clone, Debug, Hash, PartialEq)] #[cfg_attr(feature = "serial-pass", derive(serde::Deserialize, serde::Serialize))] @@ -211,11 +219,17 @@ fn fire_map_callbacks>(callback } } +#[derive(Debug)] +pub(crate) struct RenderPassLock { + pub(crate) render_passes: FastHashMap, + pub(crate) framebuffers: FastHashMap, +} + /// Structure describing a logical device. Some members are internally mutable, /// stored behind mutexes. /// TODO: establish clear order of locking for these: /// `mem_allocator`, `desc_allocator`, `life_tracke`, `trackers`, -/// `render_passes`, `framebuffers`, `pending_writes`, `trace`. +/// `render_passes`, `pending_writes`, `trace`. /// /// Currently, the rules are: /// 1. `life_tracker` is locked after `hub.devices`, enforced by the type system @@ -234,8 +248,7 @@ pub struct Device { pub(crate) active_submission_index: SubmissionIndex, /// Has to be locked temporarily only (locked last) pub(crate) trackers: Mutex, - pub(crate) render_passes: Mutex>, - pub(crate) framebuffers: Mutex>, + pub(crate) render_passes: Mutex>, // Life tracker should be locked right after the device and before anything else. life_tracker: Mutex>, temp_suspected: life::SuspectedResources, @@ -297,8 +310,10 @@ impl Device { life_guard: LifeGuard::new(""), active_submission_index: 0, trackers: Mutex::new(TrackerSet::new(B::VARIANT)), - render_passes: Mutex::new(FastHashMap::default()), - framebuffers: Mutex::new(FastHashMap::default()), + render_passes: Mutex::new(RenderPassLock { + render_passes: FastHashMap::default(), + framebuffers: FastHashMap::default(), + }), life_tracker: Mutex::new(life::LifetimeTracker::new()), temp_suspected: life::SuspectedResources::default(), #[cfg(feature = "trace")] @@ -359,7 +374,6 @@ impl Device { token, ); life_tracker.triage_mapped(hub, token); - life_tracker.triage_framebuffers(hub, &mut *self.framebuffers.lock(), token); let last_done = life_tracker.triage_submissions(&self.raw, force_wait)?; let callbacks = life_tracker.handle_mapping(hub, &self.raw, &self.trackers, token); life_tracker.cleanup(&self.raw, &self.mem_allocator, &self.desc_allocator); @@ -591,12 +605,11 @@ impl Device { mip_level_count, )); } - let mut view_capabilities = hal::image::ViewCapabilities::empty(); - + let mut view_caps = hal::image::ViewCapabilities::empty(); // 2D textures with array layer counts that are multiples of 6 could be cubemaps // Following gpuweb/gpuweb#68 always add the hint in that case if desc.dimension == TextureDimension::D2 && desc.size.depth % 6 == 0 { - view_capabilities |= hal::image::ViewCapabilities::KIND_CUBE; + view_caps |= hal::image::ViewCapabilities::KIND_CUBE; }; // TODO: 2D arrays, cubemap arrays @@ -610,7 +623,7 @@ impl Device { format, hal::image::Tiling::Optimal, usage, - view_capabilities, + view_caps, ) .map_err(|err| match err { hal::image::CreationError::OutOfMemory(_) => DeviceError::OutOfMemory, @@ -642,6 +655,11 @@ impl Device { kind, format: desc.format, format_features, + framebuffer_attachment: hal::image::FramebufferAttachment { + usage, + format, + view_caps, + }, full_range: TextureSelector { levels: 0..desc.mip_level_count as hal::image::Level, layers: 0..kind.num_layers(), @@ -801,6 +819,7 @@ impl Device { format_features: texture.format_features, extent: texture.kind.extent().at_level(desc.base_mip_level as _), samples: texture.kind.num_samples(), + framebuffer_attachment: texture.framebuffer_attachment.clone(), selector, life_guard: LifeGuard::new(desc.label.borrow_or_default()), }) @@ -2172,7 +2191,7 @@ impl Device { .get(pipeline_layout_id) .map_err(|_| pipeline::CreateRenderPipelineError::InvalidLayout)?; - let mut render_pass_cache = self.render_passes.lock(); + let mut rp_lock = self.render_passes.lock(); let pipeline_desc = hal::pso::GraphicsPipelineDesc { label: desc.label.as_ref().map(AsRef::as_ref), primitive_assembler, @@ -2185,7 +2204,7 @@ impl Device { layout: &layout.raw, subpass: hal::pass::Subpass { index: 0, - main_pass: match render_pass_cache.entry(rp_key) { + main_pass: match rp_lock.render_passes.entry(rp_key) { Entry::Occupied(e) => e.into_mut(), Entry::Vacant(e) => { let pass = self @@ -2312,10 +2331,11 @@ impl Device { unsafe { desc_alloc.cleanup(&self.raw); mem_alloc.clear(&self.raw); - for (_, rp) in self.render_passes.lock().drain() { + let rps = self.render_passes.into_inner(); + for (_, rp) in rps.render_passes { self.raw.destroy_render_pass(rp); } - for (_, fbo) in self.framebuffers.lock().drain() { + for (_, fbo) in rps.framebuffers { self.raw.destroy_framebuffer(fbo); } } @@ -3987,6 +4007,7 @@ impl Global { } } validate_swap_chain_descriptor(&mut config, &caps)?; + let framebuffer_attachment = config.framebuffer_attachment(); unsafe { B::get_surface_mut(surface) @@ -4027,8 +4048,8 @@ impl Global { .create_semaphore() .or(Err(DeviceError::OutOfMemory))?, acquired_view_id: None, - acquired_framebuffers: Vec::new(), active_submission_index: 0, + framebuffer_attachment, }; swap_chain_guard.insert(sc_id, swap_chain); Ok(sc_id) diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index 208b4278a..355caa9cf 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -514,19 +514,17 @@ impl Global { )); } - for (sc_id, fbo) in cmdbuf.used_swap_chains.drain(..) { + for sc_id in cmdbuf.used_swap_chains.drain(..) { let sc = &mut swap_chain_guard[sc_id.value]; - sc.active_submission_index = submit_index; if sc.acquired_view_id.is_none() { return Err(QueueSubmitError::SwapChainOutputDropped); } - // For each swapchain, we only want to have at most 1 signaled semaphore. - if sc.acquired_framebuffers.is_empty() { + if sc.active_submission_index != submit_index { + sc.active_submission_index = submit_index; // Only add a signal if this is the first time for this swapchain // to be used in the submission. signal_swapchain_semaphores.push(sc_id.value); } - sc.acquired_framebuffers.push(fbo); } // optimize the tracked states diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index c4ecf7161..de9f7a58f 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -206,6 +206,7 @@ pub struct Texture { pub(crate) kind: hal::image::Kind, pub(crate) format: wgt::TextureFormat, pub(crate) format_features: wgt::TextureFormatFeatures, + pub(crate) framebuffer_attachment: hal::image::FramebufferAttachment, pub(crate) full_range: TextureSelector, pub(crate) life_guard: LifeGuard, } @@ -309,6 +310,7 @@ pub struct TextureView { pub(crate) format_features: wgt::TextureFormatFeatures, pub(crate) extent: hal::image::Extent, pub(crate) samples: hal::image::NumSamples, + pub(crate) framebuffer_attachment: hal::image::FramebufferAttachment, pub(crate) selector: TextureSelector, pub(crate) life_guard: LifeGuard, } diff --git a/wgpu-core/src/swap_chain.rs b/wgpu-core/src/swap_chain.rs index 58bfdee38..89532b9b3 100644 --- a/wgpu-core/src/swap_chain.rs +++ b/wgpu-core/src/swap_chain.rs @@ -44,7 +44,7 @@ use crate::{ LifeGuard, PrivateFeatures, Stored, SubmissionIndex, }; -use hal::{self, device::Device as _, queue::CommandQueue as _, window::PresentationSurface as _}; +use hal::{queue::CommandQueue as _, window::PresentationSurface as _}; use thiserror::Error; use wgt::{SwapChainDescriptor, SwapChainStatus}; @@ -59,8 +59,8 @@ pub struct SwapChain { pub(crate) num_frames: hal::window::SwapImageIndex, pub(crate) semaphore: B::Semaphore, pub(crate) acquired_view_id: Option>, - pub(crate) acquired_framebuffers: Vec, pub(crate) active_submission_index: SubmissionIndex, + pub(crate) framebuffer_attachment: hal::image::FramebufferAttachment, } impl crate::hub::Resource for SwapChain { @@ -194,6 +194,7 @@ impl Global { depth: 1, }, samples: 1, + framebuffer_attachment: sc.framebuffer_attachment.clone(), selector: TextureSelector { layers: 0..1, levels: 0..1, @@ -282,12 +283,6 @@ impl Global { tracing::debug!(trace = true, "Presented. End of Frame"); - for fbo in sc.acquired_framebuffers.drain(..) { - unsafe { - device.raw.destroy_framebuffer(fbo); - } - } - match result { Ok(None) => Ok(SwapChainStatus::Good), Ok(Some(_)) => Ok(SwapChainStatus::Suboptimal),