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]]
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"

View File

@ -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" }

View File

@ -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"

View File

@ -43,7 +43,7 @@ pub struct CommandBuffer<B: hal::Backend> {
recorded_thread_id: ThreadId,
pub(crate) device_id: Stored<id::DeviceId>,
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,
private_features: PrivateFeatures,
has_labels: bool,
@ -217,7 +217,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
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()

View File

@ -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<F> = Option<(Stored<id::SwapChainId>, F)>;
struct RenderPassInfo<'a, B: hal::Backend> {
context: RenderPassContext,
trackers: TrackerSet,
render_attachments: AttachmentDataVec<RenderAttachment<'a>>,
used_swapchain_with_framebuffer: UsedSwapChainInfo<B::Framebuffer>,
used_swap_chain: Option<Stored<id::SwapChainId>>,
is_ds_read_only: bool,
extent: wgt::Extent3d,
_phantom: PhantomData<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 used_swap_chain = None::<Stored<id::SwapChainId>>;
let mut trackers = TrackerSet::new(B::VARIANT);
let mut used_swapchain_with_framebuffer = None;
let mut add_view = |view: &TextureView<B>| {
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::<AttachmentDataVec<_>>();
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::<AttachmentDataVec<_>>();
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::<ArrayVec<[_; MAX_COLOR_TARGETS + 1]>>();
.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<Texture<B>, id::TextureId>,
) -> Result<(TrackerSet, UsedSwapChainInfo<B::Framebuffer>), RenderPassErrorInner> {
) -> Result<(TrackerSet, Option<Stored<id::SwapChainId>>), 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<G: GlobalIdentityHandlerFactory> Global<G> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
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 {

View File

@ -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<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>(
&mut self,
hub: &Hub<B, G>,

View File

@ -103,12 +103,20 @@ impl<T> AttachmentData<T> {
.chain(&self.resolves)
.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 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)]
#[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,
/// 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<B: hal::Backend> {
pub(crate) active_submission_index: SubmissionIndex,
/// Has to be locked temporarily only (locked last)
pub(crate) trackers: Mutex<TrackerSet>,
pub(crate) render_passes: Mutex<FastHashMap<RenderPassKey, B::RenderPass>>,
pub(crate) framebuffers: Mutex<FastHashMap<FramebufferKey, B::Framebuffer>>,
pub(crate) render_passes: Mutex<RenderPassLock<B>>,
// Life tracker should be locked right after the device and before anything else.
life_tracker: Mutex<life::LifetimeTracker<B>>,
temp_suspected: life::SuspectedResources,
@ -297,8 +310,10 @@ impl<B: GfxBackend> Device<B> {
life_guard: LifeGuard::new("<device>"),
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<B: GfxBackend> Device<B> {
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<B: GfxBackend> Device<B> {
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<B: GfxBackend> Device<B> {
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<B: GfxBackend> Device<B> {
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<B: GfxBackend> Device<B> {
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<B: GfxBackend> Device<B> {
.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<B: GfxBackend> Device<B> {
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<B: hal::Backend> Device<B> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
}
}
validate_swap_chain_descriptor(&mut config, &caps)?;
let framebuffer_attachment = config.framebuffer_attachment();
unsafe {
B::get_surface_mut(surface)
@ -4027,8 +4048,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.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)

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];
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

View File

@ -206,6 +206,7 @@ pub struct Texture<B: hal::Backend> {
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<B: hal::Backend> {
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,
}

View File

@ -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<B: hal::Backend> {
pub(crate) num_frames: hal::window::SwapImageIndex,
pub(crate) semaphore: B::Semaphore,
pub(crate) acquired_view_id: Option<Stored<TextureViewId>>,
pub(crate) acquired_framebuffers: Vec<B::Framebuffer>,
pub(crate) active_submission_index: SubmissionIndex,
pub(crate) framebuffer_attachment: hal::image::FramebufferAttachment,
}
impl<B: hal::Backend> crate::hub::Resource for SwapChain<B> {
@ -194,6 +194,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
depth: 1,
},
samples: 1,
framebuffer_attachment: sc.framebuffer_attachment.clone(),
selector: TextureSelector {
layers: 0..1,
levels: 0..1,
@ -282,12 +283,6 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
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),