Update render pass and framebuffers logic to the latest gfx-hal

This commit is contained in:
Dzmitry Malyshau 2021-01-13 02:31:40 -05:00
parent 4ce449c89f
commit 012569845d
10 changed files with 166 additions and 245 deletions

25
Cargo.lock generated
View File

@ -441,7 +441,7 @@ dependencies = [
[[package]] [[package]]
name = "gfx-auxil" name = "gfx-auxil"
version = "0.5.0" 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 = [ dependencies = [
"fxhash", "fxhash",
"gfx-hal", "gfx-hal",
@ -451,7 +451,7 @@ dependencies = [
[[package]] [[package]]
name = "gfx-backend-dx11" name = "gfx-backend-dx11"
version = "0.6.0" 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 = [ dependencies = [
"arrayvec", "arrayvec",
"bitflags", "bitflags",
@ -472,7 +472,7 @@ dependencies = [
[[package]] [[package]]
name = "gfx-backend-dx12" name = "gfx-backend-dx12"
version = "0.6.2" 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 = [ dependencies = [
"arrayvec", "arrayvec",
"bit-set", "bit-set",
@ -492,7 +492,7 @@ dependencies = [
[[package]] [[package]]
name = "gfx-backend-empty" name = "gfx-backend-empty"
version = "0.6.0" 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 = [ dependencies = [
"gfx-hal", "gfx-hal",
"log", "log",
@ -502,7 +502,7 @@ dependencies = [
[[package]] [[package]]
name = "gfx-backend-gl" name = "gfx-backend-gl"
version = "0.6.0" 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 = [ dependencies = [
"arrayvec", "arrayvec",
"bitflags", "bitflags",
@ -525,7 +525,7 @@ dependencies = [
[[package]] [[package]]
name = "gfx-backend-metal" name = "gfx-backend-metal"
version = "0.6.0" 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 = [ dependencies = [
"arrayvec", "arrayvec",
"bitflags", "bitflags",
@ -535,7 +535,6 @@ dependencies = [
"foreign-types", "foreign-types",
"gfx-auxil", "gfx-auxil",
"gfx-hal", "gfx-hal",
"lazy_static",
"log", "log",
"metal", "metal",
"naga", "naga",
@ -550,7 +549,7 @@ dependencies = [
[[package]] [[package]]
name = "gfx-backend-vulkan" name = "gfx-backend-vulkan"
version = "0.6.5" 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 = [ dependencies = [
"arrayvec", "arrayvec",
"ash", "ash",
@ -558,10 +557,10 @@ dependencies = [
"core-graphics-types", "core-graphics-types",
"gfx-hal", "gfx-hal",
"inplace_it", "inplace_it",
"lazy_static",
"log", "log",
"naga", "naga",
"objc", "objc",
"parking_lot 0.11.0",
"raw-window-handle", "raw-window-handle",
"smallvec", "smallvec",
"winapi 0.3.9", "winapi 0.3.9",
@ -570,7 +569,7 @@ dependencies = [
[[package]] [[package]]
name = "gfx-hal" name = "gfx-hal"
version = "0.6.0" 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 = [ dependencies = [
"bitflags", "bitflags",
"naga", "naga",
@ -580,9 +579,9 @@ dependencies = [
[[package]] [[package]]
name = "glow" name = "glow"
version = "0.6.1" version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1625b792e2f9267116dd41eb7d325e0ea2572ceba5069451906745e04f852f33" checksum = "3eac04632dc8c047fb70d658f8479583e1bb084859f67a150227769a10fc161f"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"slotmap", "slotmap",
@ -1209,7 +1208,7 @@ dependencies = [
[[package]] [[package]]
name = "range-alloc" name = "range-alloc"
version = "0.1.1" 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]] [[package]]
name = "raw-window-handle" name = "raw-window-handle"

View File

@ -6,7 +6,7 @@ members = [
"wgpu-types", "wgpu-types",
] ]
#[patch."https://github.com/gfx-rs/gfx"] [patch."https://github.com/gfx-rs/gfx"]
#hal = { package = "gfx-hal", path = "../gfx/src/hal" } #hal = { package = "gfx-hal", path = "../gfx/src/hal" }
#gfx-backend-vulkan = { path = "../gfx/src/backend/vulkan", features = ["naga"] } #gfx-backend-vulkan = { path = "../gfx/src/backend/vulkan", features = ["naga"] }
#gfx-backend-metal = { path = "../gfx/src/backend/metal", 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-dx11 = { path = "../gfx/src/backend/dx11" }
#gfx-backend-empty = { path = "../gfx/src/backend/empty" } #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" } #naga = { path = "../naga" }

View File

@ -36,24 +36,24 @@ thiserror = "1"
gpu-alloc = { git = "https://github.com/zakarumych/gpu-alloc", rev = "29e761f24edc50e28d238e723503b146d55d222e", features = ["tracing"] } 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"] } 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" } hal = { package = "gfx-hal", git = "https://github.com/gfx-rs/gfx", rev = "006f0c00782d5f602b4afa8e1fa9ffc2085af997" }
gfx-backend-empty = { git = "https://github.com/gfx-rs/gfx", rev = "6b3a1e36939473f0062232baf11e1deacd6605f4" } 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] [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-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "006f0c00782d5f602b4afa8e1fa9ffc2085af997", features = ["naga"] }
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"] }
[target.'cfg(all(not(target_arch = "wasm32"), any(target_os = "ios", target_os = "macos")))'.dependencies] [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-metal = { git = "https://github.com/gfx-rs/gfx", rev = "006f0c00782d5f602b4afa8e1fa9ffc2085af997", features = ["naga"] }
gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "6b3a1e36939473f0062232baf11e1deacd6605f4", optional = true } gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "006f0c00782d5f602b4afa8e1fa9ffc2085af997", optional = true }
[target.'cfg(all(not(target_arch = "wasm32"), windows))'.dependencies] [target.'cfg(all(not(target_arch = "wasm32"), windows))'.dependencies]
gfx-backend-dx12 = { git = "https://github.com/gfx-rs/gfx", rev = "6b3a1e36939473f0062232baf11e1deacd6605f4" } gfx-backend-dx12 = { git = "https://github.com/gfx-rs/gfx", rev = "006f0c00782d5f602b4afa8e1fa9ffc2085af997" }
gfx-backend-dx11 = { git = "https://github.com/gfx-rs/gfx", rev = "6b3a1e36939473f0062232baf11e1deacd6605f4" } gfx-backend-dx11 = { git = "https://github.com/gfx-rs/gfx", rev = "006f0c00782d5f602b4afa8e1fa9ffc2085af997" }
gfx-backend-vulkan = { 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"] }
[target.'cfg(target_arch = "wasm32")'.dependencies] [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] [dependencies.naga]
git = "https://github.com/gfx-rs/naga" git = "https://github.com/gfx-rs/naga"

View File

@ -43,7 +43,7 @@ pub struct CommandBuffer<B: hal::Backend> {
recorded_thread_id: ThreadId, recorded_thread_id: ThreadId,
pub(crate) device_id: Stored<id::DeviceId>, pub(crate) device_id: Stored<id::DeviceId>,
pub(crate) trackers: TrackerSet, pub(crate) trackers: TrackerSet,
pub(crate) used_swap_chains: SmallVec<[(Stored<id::SwapChainId>, B::Framebuffer); 1]>, pub(crate) used_swap_chains: SmallVec<[Stored<id::SwapChainId>; 1]>,
limits: wgt::Limits, limits: wgt::Limits,
private_features: PrivateFeatures, private_features: PrivateFeatures,
has_labels: bool, has_labels: bool,
@ -217,7 +217,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
Ok(cmd_buf) => { Ok(cmd_buf) => {
cmd_buf.is_recording = false; cmd_buf.is_recording = false;
// stop tracking the swapchain image, if used // 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] let view_id = swap_chain_guard[sc_id.value]
.acquired_view_id .acquired_view_id
.as_ref() .as_ref()

View File

@ -11,8 +11,8 @@ use crate::{
}, },
conv, conv,
device::{ device::{
AttachmentData, AttachmentDataVec, Device, FramebufferKey, RenderPassCompatibilityError, AttachmentData, AttachmentDataVec, Device, RenderPassCompatibilityError, RenderPassContext,
RenderPassContext, RenderPassKey, MAX_COLOR_TARGETS, MAX_VERTEX_BUFFERS, RenderPassKey, RenderPassLock, MAX_COLOR_TARGETS, MAX_VERTEX_BUFFERS,
}, },
hub::{GfxBackend, Global, GlobalIdentityHandlerFactory, Storage, Token}, hub::{GfxBackend, Global, GlobalIdentityHandlerFactory, Storage, Token},
id, id,
@ -42,6 +42,7 @@ use std::{
borrow::{Borrow, Cow}, borrow::{Borrow, Cow},
collections::hash_map::Entry, collections::hash_map::Entry,
fmt, iter, fmt, iter,
marker::PhantomData,
num::NonZeroU32, num::NonZeroU32,
ops::Range, ops::Range,
str, str,
@ -503,15 +504,14 @@ struct RenderAttachment<'a> {
new_use: TextureUse, new_use: TextureUse,
} }
type UsedSwapChainInfo<F> = Option<(Stored<id::SwapChainId>, F)>;
struct RenderPassInfo<'a, B: hal::Backend> { struct RenderPassInfo<'a, B: hal::Backend> {
context: RenderPassContext, context: RenderPassContext,
trackers: TrackerSet, trackers: TrackerSet,
render_attachments: AttachmentDataVec<RenderAttachment<'a>>, render_attachments: AttachmentDataVec<RenderAttachment<'a>>,
used_swapchain_with_framebuffer: UsedSwapChainInfo<B::Framebuffer>, used_swap_chain: Option<Stored<id::SwapChainId>>,
is_ds_read_only: bool, is_ds_read_only: bool,
extent: wgt::Extent3d, extent: wgt::Extent3d,
_phantom: PhantomData<B>,
} }
impl<'a, B: GfxBackend> RenderPassInfo<'a, B> { 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 depth_stencil_aspects = hal::format::Aspects::empty();
let mut used_swap_chain = None::<Stored<id::SwapChainId>>; let mut used_swap_chain = None::<Stored<id::SwapChainId>>;
let mut trackers = TrackerSet::new(B::VARIANT); let mut trackers = TrackerSet::new(B::VARIANT);
let mut used_swapchain_with_framebuffer = None;
let mut add_view = |view: &TextureView<B>| { let mut add_view = |view: &TextureView<B>| {
if let Some(ex) = extent { if let Some(ex) = extent {
@ -809,8 +808,11 @@ impl<'a, B: GfxBackend> RenderPassInfo<'a, B> {
return Err(RenderPassErrorInner::InvalidSampleCount(sample_count)); return Err(RenderPassErrorInner::InvalidSampleCount(sample_count));
} }
let mut render_pass_cache = device.render_passes.lock(); let RenderPassLock {
let render_pass = match render_pass_cache.entry(rp_key.clone()) { 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::Occupied(e) => e.into_mut(),
Entry::Vacant(entry) => { Entry::Vacant(entry) => {
let color_ids: [hal::pass::AttachmentRef; MAX_COLOR_TARGETS] = [ let color_ids: [hal::pass::AttachmentRef; MAX_COLOR_TARGETS] = [
@ -871,83 +873,41 @@ impl<'a, B: GfxBackend> RenderPassInfo<'a, B> {
} }
}; };
let mut framebuffer_cache; let view_data = AttachmentData {
let fb_key = FramebufferKey {
colors: color_attachments colors: color_attachments
.iter() .iter()
.map(|at| id::Valid(at.attachment)) .map(|at| view_guard.get(at.attachment).unwrap())
.collect(), .collect(),
resolves: color_attachments resolves: color_attachments
.iter() .iter()
.filter_map(|at| at.resolve_target) .filter_map(|at| at.resolve_target)
.map(id::Valid) .map(|attachment| view_guard.get(attachment).unwrap())
.collect(), .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 { let context = RenderPassContext {
attachments: AttachmentData { attachments: view_data.map(|view| view.format),
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),
},
sample_count, 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::<AttachmentDataVec<_>>();
let framebuffer = unsafe {
device
.raw
.create_framebuffer(&render_pass, attachments, 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. // Cache framebuffers by the device.
framebuffer_cache = device.framebuffers.lock(); let framebuffer = match framebuffers.entry(fb_key) {
match framebuffer_cache.entry(fb_key) {
Entry::Occupied(e) => e.into_mut(), Entry::Occupied(e) => e.into_mut(),
Entry::Vacant(e) => { Entry::Vacant(e) => {
let fb = { let fb = unsafe {
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::<AttachmentDataVec<_>>();
unsafe {
device device
.raw .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))? .or(Err(RenderPassErrorInner::OutOfMemory))?
}
}; };
e.insert(fb) e.insert(fb)
} }
}
}
}; };
let rect = { let rect = {
@ -959,13 +919,20 @@ impl<'a, B: GfxBackend> RenderPassInfo<'a, B> {
h: ex.height as _, 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() .iter()
.zip(&rp_key.colors) .zip(&rp_key.colors)
.flat_map(|(at, (rat, _layout))| { .zip(raw_views.colors)
match at.channel.load_op { .map(
LoadOp::Load => None, |((at, (rat, _layout)), image_view)| hal::command::RenderAttachmentInfo {
image_view,
clear_value: match at.channel.load_op {
LoadOp::Load => Default::default(),
LoadOp::Clear => { LoadOp::Clear => {
use hal::format::ChannelType; use hal::format::ChannelType;
//TODO: validate sign/unsign and normalized ranges of the color values //TODO: validate sign/unsign and normalized ranges of the color values
@ -986,32 +953,41 @@ impl<'a, B: GfxBackend> RenderPassInfo<'a, B> {
uint32: conv::map_color_u32(&at.channel.clear_value), uint32: conv::map_color_u32(&at.channel.clear_value),
}, },
}; };
Some(hal::command::ClearValue { color: value }) hal::command::ClearValue { color: value }
} }
},
},
)
.chain(raw_views.resolves.into_iter().map(|image_view| {
hal::command::RenderAttachmentInfo {
image_view,
clear_value: Default::default(),
} }
}) }))
.chain(depth_stencil_attachment.and_then(|at| { .chain(depth_stencil_attachment.zip(raw_views.depth_stencil).map(
match (at.depth.load_op, at.stencil.load_op) { |(at, image_view)| hal::command::RenderAttachmentInfo {
(LoadOp::Load, LoadOp::Load) => None, image_view,
clear_value: match (at.depth.load_op, at.stencil.load_op) {
(LoadOp::Load, LoadOp::Load) => Default::default(),
(LoadOp::Clear, _) | (_, LoadOp::Clear) => { (LoadOp::Clear, _) | (_, LoadOp::Clear) => {
let value = hal::command::ClearDepthStencil { let value = hal::command::ClearDepthStencil {
depth: at.depth.clear_value, depth: at.depth.clear_value,
stencil: at.stencil.clear_value, stencil: at.stencil.clear_value,
}; };
Some(hal::command::ClearValue { hal::command::ClearValue {
depth_stencil: value, depth_stencil: value,
})
} }
} }
})) },
.collect::<ArrayVec<[_; MAX_COLOR_TARGETS + 1]>>(); },
));
unsafe { unsafe {
raw.begin_render_pass( raw.begin_render_pass(
render_pass, render_pass,
framebuffer, framebuffer,
rect, rect,
clear_values, attachments,
hal::command::SubpassContents::Inline, hal::command::SubpassContents::Inline,
); );
raw.set_scissors(0, iter::once(&rect)); raw.set_scissors(0, iter::once(&rect));
@ -1028,20 +1004,21 @@ impl<'a, B: GfxBackend> RenderPassInfo<'a, B> {
context, context,
trackers, trackers,
render_attachments, render_attachments,
used_swapchain_with_framebuffer, used_swap_chain,
is_ds_read_only, is_ds_read_only,
extent: wgt::Extent3d { extent: wgt::Extent3d {
width: attachment_width.ok_or(RenderPassErrorInner::MissingAttachments)?, width: attachment_width.ok_or(RenderPassErrorInner::MissingAttachments)?,
height: attachment_height.ok_or(RenderPassErrorInner::MissingAttachments)?, height: attachment_height.ok_or(RenderPassErrorInner::MissingAttachments)?,
depth: 1, depth: 1,
}, },
_phantom: PhantomData,
}) })
} }
fn finish( fn finish(
mut self, mut self,
texture_guard: &Storage<Texture<B>, id::TextureId>, texture_guard: &Storage<Texture<B>, id::TextureId>,
) -> Result<(TrackerSet, UsedSwapChainInfo<B::Framebuffer>), RenderPassErrorInner> { ) -> Result<(TrackerSet, Option<Stored<id::SwapChainId>>), RenderPassErrorInner> {
for ra in self.render_attachments { for ra in self.render_attachments {
let texture = &texture_guard[ra.texture_id.value]; let texture = &texture_guard[ra.texture_id.value];
check_texture_usage(texture.usage, TextureUsage::RENDER_ATTACHMENT)?; check_texture_usage(texture.usage, TextureUsage::RENDER_ATTACHMENT)?;
@ -1072,7 +1049,7 @@ impl<'a, B: GfxBackend> RenderPassInfo<'a, B> {
.unwrap(); .unwrap();
} }
} }
Ok((self.trackers, self.used_swapchain_with_framebuffer)) Ok((self.trackers, self.used_swap_chain))
} }
} }
@ -1108,7 +1085,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let (device_guard, mut token) = hub.devices.read(&mut token); 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 // read-only lock guard
let (cmb_guard, mut token) = hub.command_buffers.read(&mut token); let (cmb_guard, mut token) = hub.command_buffers.read(&mut token);
@ -1866,9 +1843,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
raw.end_render_pass(); raw.end_render_pass();
} }
let (trackers, used_swapchain_with_framebuffer) = let (trackers, used_swapchain) = info.finish(&*texture_guard).map_pass_err(scope)?;
info.finish(&*texture_guard).map_pass_err(scope)?; (raw, trackers, used_swapchain)
(raw, trackers, used_swapchain_with_framebuffer)
}; };
let (mut cmb_guard, mut token) = hub.command_buffers.write(&mut token); let (mut cmb_guard, mut token) = hub.command_buffers.write(&mut token);
@ -1877,9 +1853,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let cmd_buf = let cmd_buf =
CommandBuffer::get_encoder_mut(&mut *cmb_guard, encoder_id).map_pass_err(scope)?; CommandBuffer::get_encoder_mut(&mut *cmb_guard, encoder_id).map_pass_err(scope)?;
cmd_buf.has_labels |= base.label.is_some(); cmd_buf.has_labels |= base.label.is_some();
cmd_buf cmd_buf.used_swap_chains.extend(used_swapchain);
.used_swap_chains
.extend(used_swapchain_with_framebuffer);
#[cfg(feature = "trace")] #[cfg(feature = "trace")]
if let Some(ref mut list) = cmd_buf.commands { if let Some(ref mut list) = cmd_buf.commands {

View File

@ -14,7 +14,7 @@ use crate::{
hub::{GfxBackend, GlobalIdentityHandlerFactory, Hub, Token}, hub::{GfxBackend, GlobalIdentityHandlerFactory, Hub, Token},
id, resource, id, resource,
track::TrackerSet, track::TrackerSet,
FastHashMap, RefCount, Stored, SubmissionIndex, RefCount, Stored, SubmissionIndex,
}; };
use copyless::VecHelper as _; use copyless::VecHelper as _;
@ -636,74 +636,6 @@ impl<B: GfxBackend> LifetimeTracker<B> {
} }
} }
pub(crate) fn triage_framebuffers<G: GlobalIdentityHandlerFactory>(
&mut self,
hub: &Hub<B, G>,
framebuffers: &mut FastHashMap<super::FramebufferKey, B::Framebuffer>,
token: &mut Token<super::Device<B>>,
) {
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::<FastHashMap<_, _>>();
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<G: GlobalIdentityHandlerFactory>( pub(crate) fn handle_mapping<G: GlobalIdentityHandlerFactory>(
&mut self, &mut self,
hub: &Hub<B, G>, hub: &Hub<B, G>,

View File

@ -103,12 +103,20 @@ impl<T> AttachmentData<T> {
.chain(&self.resolves) .chain(&self.resolves)
.chain(&self.depth_stencil) .chain(&self.depth_stencil)
} }
pub(crate) fn map<U, F: Fn(&T) -> U>(&self, fun: F) -> AttachmentData<U> {
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<T> = ArrayVec<[T; MAX_COLOR_TARGETS + MAX_COLOR_TARGETS + 1]>; pub(crate) type AttachmentDataVec<T> = ArrayVec<[T; MAX_COLOR_TARGETS + MAX_COLOR_TARGETS + 1]>;
pub(crate) type RenderPassKey = AttachmentData<(hal::pass::Attachment, hal::image::Layout)>; pub(crate) type RenderPassKey = AttachmentData<(hal::pass::Attachment, hal::image::Layout)>;
pub(crate) type FramebufferKey = AttachmentData<id::Valid<id::TextureViewId>>; pub(crate) type FramebufferKey = AttachmentData<hal::image::FramebufferAttachment>;
#[derive(Clone, Debug, Hash, PartialEq)] #[derive(Clone, Debug, Hash, PartialEq)]
#[cfg_attr(feature = "serial-pass", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serial-pass", derive(serde::Deserialize, serde::Serialize))]
@ -211,11 +219,17 @@ fn fire_map_callbacks<I: IntoIterator<Item = BufferMapPendingCallback>>(callback
} }
} }
#[derive(Debug)]
pub(crate) struct RenderPassLock<B: hal::Backend> {
pub(crate) render_passes: FastHashMap<RenderPassKey, B::RenderPass>,
pub(crate) framebuffers: FastHashMap<FramebufferKey, B::Framebuffer>,
}
/// Structure describing a logical device. Some members are internally mutable, /// Structure describing a logical device. Some members are internally mutable,
/// stored behind mutexes. /// stored behind mutexes.
/// TODO: establish clear order of locking for these: /// TODO: establish clear order of locking for these:
/// `mem_allocator`, `desc_allocator`, `life_tracke`, `trackers`, /// `mem_allocator`, `desc_allocator`, `life_tracke`, `trackers`,
/// `render_passes`, `framebuffers`, `pending_writes`, `trace`. /// `render_passes`, `pending_writes`, `trace`.
/// ///
/// Currently, the rules are: /// Currently, the rules are:
/// 1. `life_tracker` is locked after `hub.devices`, enforced by the type system /// 1. `life_tracker` is locked after `hub.devices`, enforced by the type system
@ -234,8 +248,7 @@ pub struct Device<B: hal::Backend> {
pub(crate) active_submission_index: SubmissionIndex, pub(crate) active_submission_index: SubmissionIndex,
/// Has to be locked temporarily only (locked last) /// Has to be locked temporarily only (locked last)
pub(crate) trackers: Mutex<TrackerSet>, pub(crate) trackers: Mutex<TrackerSet>,
pub(crate) render_passes: Mutex<FastHashMap<RenderPassKey, B::RenderPass>>, pub(crate) render_passes: Mutex<RenderPassLock<B>>,
pub(crate) framebuffers: Mutex<FastHashMap<FramebufferKey, B::Framebuffer>>,
// Life tracker should be locked right after the device and before anything else. // Life tracker should be locked right after the device and before anything else.
life_tracker: Mutex<life::LifetimeTracker<B>>, life_tracker: Mutex<life::LifetimeTracker<B>>,
temp_suspected: life::SuspectedResources, temp_suspected: life::SuspectedResources,
@ -297,8 +310,10 @@ impl<B: GfxBackend> Device<B> {
life_guard: LifeGuard::new("<device>"), life_guard: LifeGuard::new("<device>"),
active_submission_index: 0, active_submission_index: 0,
trackers: Mutex::new(TrackerSet::new(B::VARIANT)), trackers: Mutex::new(TrackerSet::new(B::VARIANT)),
render_passes: Mutex::new(FastHashMap::default()), render_passes: Mutex::new(RenderPassLock {
framebuffers: Mutex::new(FastHashMap::default()), render_passes: FastHashMap::default(),
framebuffers: FastHashMap::default(),
}),
life_tracker: Mutex::new(life::LifetimeTracker::new()), life_tracker: Mutex::new(life::LifetimeTracker::new()),
temp_suspected: life::SuspectedResources::default(), temp_suspected: life::SuspectedResources::default(),
#[cfg(feature = "trace")] #[cfg(feature = "trace")]
@ -359,7 +374,6 @@ impl<B: GfxBackend> Device<B> {
token, token,
); );
life_tracker.triage_mapped(hub, 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 last_done = life_tracker.triage_submissions(&self.raw, force_wait)?;
let callbacks = life_tracker.handle_mapping(hub, &self.raw, &self.trackers, token); let callbacks = life_tracker.handle_mapping(hub, &self.raw, &self.trackers, token);
life_tracker.cleanup(&self.raw, &self.mem_allocator, &self.desc_allocator); life_tracker.cleanup(&self.raw, &self.mem_allocator, &self.desc_allocator);
@ -591,12 +605,11 @@ impl<B: GfxBackend> Device<B> {
mip_level_count, 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 // 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 // Following gpuweb/gpuweb#68 always add the hint in that case
if desc.dimension == TextureDimension::D2 && desc.size.depth % 6 == 0 { 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 // TODO: 2D arrays, cubemap arrays
@ -610,7 +623,7 @@ impl<B: GfxBackend> Device<B> {
format, format,
hal::image::Tiling::Optimal, hal::image::Tiling::Optimal,
usage, usage,
view_capabilities, view_caps,
) )
.map_err(|err| match err { .map_err(|err| match err {
hal::image::CreationError::OutOfMemory(_) => DeviceError::OutOfMemory, hal::image::CreationError::OutOfMemory(_) => DeviceError::OutOfMemory,
@ -642,6 +655,11 @@ impl<B: GfxBackend> Device<B> {
kind, kind,
format: desc.format, format: desc.format,
format_features, format_features,
framebuffer_attachment: hal::image::FramebufferAttachment {
usage,
format,
view_caps,
},
full_range: TextureSelector { full_range: TextureSelector {
levels: 0..desc.mip_level_count as hal::image::Level, levels: 0..desc.mip_level_count as hal::image::Level,
layers: 0..kind.num_layers(), layers: 0..kind.num_layers(),
@ -801,6 +819,7 @@ impl<B: GfxBackend> Device<B> {
format_features: texture.format_features, format_features: texture.format_features,
extent: texture.kind.extent().at_level(desc.base_mip_level as _), extent: texture.kind.extent().at_level(desc.base_mip_level as _),
samples: texture.kind.num_samples(), samples: texture.kind.num_samples(),
framebuffer_attachment: texture.framebuffer_attachment.clone(),
selector, selector,
life_guard: LifeGuard::new(desc.label.borrow_or_default()), life_guard: LifeGuard::new(desc.label.borrow_or_default()),
}) })
@ -2172,7 +2191,7 @@ impl<B: GfxBackend> Device<B> {
.get(pipeline_layout_id) .get(pipeline_layout_id)
.map_err(|_| pipeline::CreateRenderPipelineError::InvalidLayout)?; .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 { let pipeline_desc = hal::pso::GraphicsPipelineDesc {
label: desc.label.as_ref().map(AsRef::as_ref), label: desc.label.as_ref().map(AsRef::as_ref),
primitive_assembler, primitive_assembler,
@ -2185,7 +2204,7 @@ impl<B: GfxBackend> Device<B> {
layout: &layout.raw, layout: &layout.raw,
subpass: hal::pass::Subpass { subpass: hal::pass::Subpass {
index: 0, 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::Occupied(e) => e.into_mut(),
Entry::Vacant(e) => { Entry::Vacant(e) => {
let pass = self let pass = self
@ -2312,10 +2331,11 @@ impl<B: hal::Backend> Device<B> {
unsafe { unsafe {
desc_alloc.cleanup(&self.raw); desc_alloc.cleanup(&self.raw);
mem_alloc.clear(&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); self.raw.destroy_render_pass(rp);
} }
for (_, fbo) in self.framebuffers.lock().drain() { for (_, fbo) in rps.framebuffers {
self.raw.destroy_framebuffer(fbo); self.raw.destroy_framebuffer(fbo);
} }
} }
@ -3987,6 +4007,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
} }
} }
validate_swap_chain_descriptor(&mut config, &caps)?; validate_swap_chain_descriptor(&mut config, &caps)?;
let framebuffer_attachment = config.framebuffer_attachment();
unsafe { unsafe {
B::get_surface_mut(surface) B::get_surface_mut(surface)
@ -4027,8 +4048,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.create_semaphore() .create_semaphore()
.or(Err(DeviceError::OutOfMemory))?, .or(Err(DeviceError::OutOfMemory))?,
acquired_view_id: None, acquired_view_id: None,
acquired_framebuffers: Vec::new(),
active_submission_index: 0, active_submission_index: 0,
framebuffer_attachment,
}; };
swap_chain_guard.insert(sc_id, swap_chain); swap_chain_guard.insert(sc_id, swap_chain);
Ok(sc_id) Ok(sc_id)

View File

@ -514,19 +514,17 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
)); ));
} }
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]; let sc = &mut swap_chain_guard[sc_id.value];
sc.active_submission_index = submit_index;
if sc.acquired_view_id.is_none() { if sc.acquired_view_id.is_none() {
return Err(QueueSubmitError::SwapChainOutputDropped); return Err(QueueSubmitError::SwapChainOutputDropped);
} }
// For each swapchain, we only want to have at most 1 signaled semaphore. if sc.active_submission_index != submit_index {
if sc.acquired_framebuffers.is_empty() { sc.active_submission_index = submit_index;
// Only add a signal if this is the first time for this swapchain // Only add a signal if this is the first time for this swapchain
// to be used in the submission. // to be used in the submission.
signal_swapchain_semaphores.push(sc_id.value); signal_swapchain_semaphores.push(sc_id.value);
} }
sc.acquired_framebuffers.push(fbo);
} }
// optimize the tracked states // optimize the tracked states

View File

@ -206,6 +206,7 @@ pub struct Texture<B: hal::Backend> {
pub(crate) kind: hal::image::Kind, pub(crate) kind: hal::image::Kind,
pub(crate) format: wgt::TextureFormat, pub(crate) format: wgt::TextureFormat,
pub(crate) format_features: wgt::TextureFormatFeatures, pub(crate) format_features: wgt::TextureFormatFeatures,
pub(crate) framebuffer_attachment: hal::image::FramebufferAttachment,
pub(crate) full_range: TextureSelector, pub(crate) full_range: TextureSelector,
pub(crate) life_guard: LifeGuard, pub(crate) life_guard: LifeGuard,
} }
@ -309,6 +310,7 @@ pub struct TextureView<B: hal::Backend> {
pub(crate) format_features: wgt::TextureFormatFeatures, pub(crate) format_features: wgt::TextureFormatFeatures,
pub(crate) extent: hal::image::Extent, pub(crate) extent: hal::image::Extent,
pub(crate) samples: hal::image::NumSamples, pub(crate) samples: hal::image::NumSamples,
pub(crate) framebuffer_attachment: hal::image::FramebufferAttachment,
pub(crate) selector: TextureSelector, pub(crate) selector: TextureSelector,
pub(crate) life_guard: LifeGuard, pub(crate) life_guard: LifeGuard,
} }

View File

@ -44,7 +44,7 @@ use crate::{
LifeGuard, PrivateFeatures, Stored, SubmissionIndex, 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 thiserror::Error;
use wgt::{SwapChainDescriptor, SwapChainStatus}; use wgt::{SwapChainDescriptor, SwapChainStatus};
@ -59,8 +59,8 @@ pub struct SwapChain<B: hal::Backend> {
pub(crate) num_frames: hal::window::SwapImageIndex, pub(crate) num_frames: hal::window::SwapImageIndex,
pub(crate) semaphore: B::Semaphore, pub(crate) semaphore: B::Semaphore,
pub(crate) acquired_view_id: Option<Stored<TextureViewId>>, pub(crate) acquired_view_id: Option<Stored<TextureViewId>>,
pub(crate) acquired_framebuffers: Vec<B::Framebuffer>,
pub(crate) active_submission_index: SubmissionIndex, pub(crate) active_submission_index: SubmissionIndex,
pub(crate) framebuffer_attachment: hal::image::FramebufferAttachment,
} }
impl<B: hal::Backend> crate::hub::Resource for SwapChain<B> { impl<B: hal::Backend> crate::hub::Resource for SwapChain<B> {
@ -194,6 +194,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
depth: 1, depth: 1,
}, },
samples: 1, samples: 1,
framebuffer_attachment: sc.framebuffer_attachment.clone(),
selector: TextureSelector { selector: TextureSelector {
layers: 0..1, layers: 0..1,
levels: 0..1, levels: 0..1,
@ -282,12 +283,6 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
tracing::debug!(trace = true, "Presented. End of Frame"); tracing::debug!(trace = true, "Presented. End of Frame");
for fbo in sc.acquired_framebuffers.drain(..) {
unsafe {
device.raw.destroy_framebuffer(fbo);
}
}
match result { match result {
Ok(None) => Ok(SwapChainStatus::Good), Ok(None) => Ok(SwapChainStatus::Good),
Ok(Some(_)) => Ok(SwapChainStatus::Suboptimal), Ok(Some(_)) => Ok(SwapChainStatus::Suboptimal),