mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Merge #1147
1147: Update render pass and framebuffers logic to the latest gfx-hal r=cwfitzgerald a=kvark **Connections** Updates gfx-hal with the latest major changes of https://github.com/gfx-rs/gfx/pull/3571 **Description** There is no need to track framebuffers at all any more! Since they don't contain images, we can keep them permanently. There is no need to create and delete framebuffers for the swapchain either. Lots of non-trivial code is gone 🎉 The PR also removes one of the mutexes that the device holds. **Testing** Will be tested on wgpu-rs Co-authored-by: Dzmitry Malyshau <kvarkus@gmail.com>
This commit is contained in:
537
Cargo.lock
generated
537
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -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" }
|
||||
|
||||
@@ -15,12 +15,12 @@ publish = false
|
||||
[features]
|
||||
|
||||
[dependencies]
|
||||
env_logger = "0.7"
|
||||
env_logger = "0.8"
|
||||
log = "0.4"
|
||||
raw-window-handle = "0.3"
|
||||
renderdoc = { version = "0.8", optional = true, default_features = false }
|
||||
renderdoc = { version = "0.10", optional = true, default_features = false }
|
||||
ron = "0.6"
|
||||
winit = { version = "0.22", optional = true }
|
||||
winit = { version = "0.24", optional = true }
|
||||
|
||||
[dependencies.wgt]
|
||||
path = "../wgpu-types"
|
||||
|
||||
@@ -33,27 +33,27 @@ smallvec = "1"
|
||||
tracing = { version = "0.1", default-features = false, features = ["std"] }
|
||||
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"] }
|
||||
gpu-alloc = { git = "https://github.com/zakarumych/gpu-alloc", rev = "15f4fe2cebbd0bf9ab446757a8e370e0adf4c502", features = ["tracing"] }
|
||||
gpu-descriptor = { git = "https://github.com/zakarumych/gpu-descriptor", rev = "aa092613889f03f8254d6f7278d08c655324c7c7", 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 = "7dc99d525cc7ad04161f227993181f36c68fe86e" }
|
||||
gfx-backend-empty = { git = "https://github.com/gfx-rs/gfx", rev = "7dc99d525cc7ad04161f227993181f36c68fe86e" }
|
||||
|
||||
[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 = "7dc99d525cc7ad04161f227993181f36c68fe86e", features = ["naga"] }
|
||||
gfx-backend-gl = { git = "https://github.com/gfx-rs/gfx", rev = "7dc99d525cc7ad04161f227993181f36c68fe86e", 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 = "7dc99d525cc7ad04161f227993181f36c68fe86e", features = ["naga"] }
|
||||
gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "7dc99d525cc7ad04161f227993181f36c68fe86e", 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 = "7dc99d525cc7ad04161f227993181f36c68fe86e" }
|
||||
gfx-backend-dx11 = { git = "https://github.com/gfx-rs/gfx", rev = "7dc99d525cc7ad04161f227993181f36c68fe86e" }
|
||||
gfx-backend-vulkan = { git = "https://github.com/gfx-rs/gfx", rev = "7dc99d525cc7ad04161f227993181f36c68fe86e", 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 = "7dc99d525cc7ad04161f227993181f36c68fe86e", features = ["naga"] }
|
||||
|
||||
[dependencies.naga]
|
||||
git = "https://github.com/gfx-rs/naga"
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
@@ -389,15 +390,10 @@ pub enum RenderPassErrorInner {
|
||||
InvalidAttachment(id::TextureViewId),
|
||||
#[error("necessary attachments are missing")]
|
||||
MissingAttachments,
|
||||
#[error("color and/or depth attachments have differing sizes: a {mismatching_attachment_type_name} attachment of size {mismatching_dimensions:?} is not compatible with a {previous_attachment_type_name} attachment's size {previous_dimensions:?}",
|
||||
)]
|
||||
#[error("attachments have differing sizes: {previous:?} is followed by {mismatch:?}")]
|
||||
AttachmentsDimensionMismatch {
|
||||
/// depth or color
|
||||
previous_attachment_type_name: &'static str,
|
||||
/// depth or color
|
||||
mismatching_attachment_type_name: &'static str,
|
||||
previous_dimensions: (u32, u32),
|
||||
mismatching_dimensions: (u32, u32),
|
||||
previous: (&'static str, wgt::Extent3d),
|
||||
mismatch: (&'static str, wgt::Extent3d),
|
||||
},
|
||||
#[error("attachment's sample count {0} is invalid")]
|
||||
InvalidSampleCount(u8),
|
||||
@@ -407,11 +403,6 @@ pub enum RenderPassErrorInner {
|
||||
InvalidResolveTargetSampleCount,
|
||||
#[error("not enough memory left")]
|
||||
OutOfMemory,
|
||||
#[error("extent state {state_extent:?} must match extent from view {view_extent:?}")]
|
||||
ExtentStateMismatch {
|
||||
state_extent: hal::image::Extent,
|
||||
view_extent: hal::image::Extent,
|
||||
},
|
||||
#[error("attempted to use a swap chain image as a depth/stencil attachment")]
|
||||
SwapChainImageAsDepthStencil,
|
||||
#[error("unable to clear non-present/read-only depth")]
|
||||
@@ -503,15 +494,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> {
|
||||
@@ -532,25 +522,19 @@ impl<'a, B: GfxBackend> RenderPassInfo<'a, B> {
|
||||
|
||||
let mut render_attachments = AttachmentDataVec::<RenderAttachment>::new();
|
||||
|
||||
let mut attachment_width = None;
|
||||
let mut attachment_height = None;
|
||||
let mut attachment_type_name = "";
|
||||
|
||||
let mut mismatching_dimensions = None;
|
||||
|
||||
let mut extent = None;
|
||||
let mut sample_count = 0;
|
||||
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>| {
|
||||
let mut add_view = |view: &TextureView<B>, type_name| {
|
||||
if let Some(ex) = extent {
|
||||
if ex != view.extent {
|
||||
return Err(RenderPassErrorInner::ExtentStateMismatch {
|
||||
state_extent: ex,
|
||||
view_extent: view.extent,
|
||||
return Err(RenderPassErrorInner::AttachmentsDimensionMismatch {
|
||||
previous: (attachment_type_name, ex),
|
||||
mismatch: (type_name, view.extent),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@@ -564,6 +548,7 @@ impl<'a, B: GfxBackend> RenderPassInfo<'a, B> {
|
||||
expected: sample_count,
|
||||
});
|
||||
}
|
||||
attachment_type_name = type_name;
|
||||
Ok(())
|
||||
};
|
||||
|
||||
@@ -574,25 +559,7 @@ impl<'a, B: GfxBackend> RenderPassInfo<'a, B> {
|
||||
.views
|
||||
.use_extend(&*view_guard, at.attachment, (), ())
|
||||
.map_err(|_| RenderPassErrorInner::InvalidAttachment(at.attachment))?;
|
||||
add_view(view)?;
|
||||
|
||||
// get the width and height set by another attachment, then check if it matches
|
||||
let (previous_width, previous_height) = (
|
||||
*attachment_width.get_or_insert(view.extent.width),
|
||||
*attachment_height.get_or_insert(view.extent.height),
|
||||
);
|
||||
|
||||
if previous_width != view.extent.width || previous_height != view.extent.height
|
||||
{
|
||||
mismatching_dimensions = Some((
|
||||
"depth",
|
||||
(view.extent.width, view.extent.height),
|
||||
(previous_width, previous_height),
|
||||
));
|
||||
} else {
|
||||
// this attachment's size was successfully inserted into `attachment_width` and `attachment_height`
|
||||
attachment_type_name = "depth";
|
||||
}
|
||||
add_view(view, "depth")?;
|
||||
|
||||
depth_stencil_aspects = view.aspects;
|
||||
|
||||
@@ -650,24 +617,7 @@ impl<'a, B: GfxBackend> RenderPassInfo<'a, B> {
|
||||
.views
|
||||
.use_extend(&*view_guard, at.attachment, (), ())
|
||||
.map_err(|_| RenderPassErrorInner::InvalidAttachment(at.attachment))?;
|
||||
add_view(view)?;
|
||||
|
||||
// get the width and height set by another attachment, then check if it matches
|
||||
let (previous_width, previous_height) = (
|
||||
*attachment_width.get_or_insert(view.extent.width),
|
||||
*attachment_height.get_or_insert(view.extent.height),
|
||||
);
|
||||
|
||||
if previous_width != view.extent.width || previous_height != view.extent.height {
|
||||
mismatching_dimensions = Some((
|
||||
"color",
|
||||
(view.extent.width, view.extent.height),
|
||||
(previous_width, previous_height),
|
||||
));
|
||||
} else {
|
||||
// this attachment's size was successfully inserted into `attachment_width` and `attachment_height`
|
||||
attachment_type_name = "color";
|
||||
}
|
||||
add_view(view, "color")?;
|
||||
|
||||
let layouts = match view.inner {
|
||||
TextureViewInner::Native { ref source_id, .. } => {
|
||||
@@ -719,29 +669,15 @@ impl<'a, B: GfxBackend> RenderPassInfo<'a, B> {
|
||||
colors.push((color_at, hal::image::Layout::ColorAttachmentOptimal));
|
||||
}
|
||||
|
||||
if let Some((
|
||||
mismatching_attachment_type_name,
|
||||
previous_dimensions,
|
||||
mismatching_dimensions,
|
||||
)) = mismatching_dimensions
|
||||
{
|
||||
return Err(RenderPassErrorInner::AttachmentsDimensionMismatch {
|
||||
previous_attachment_type_name: attachment_type_name,
|
||||
mismatching_attachment_type_name,
|
||||
previous_dimensions,
|
||||
mismatching_dimensions,
|
||||
});
|
||||
}
|
||||
|
||||
for resolve_target in color_attachments.iter().flat_map(|at| at.resolve_target) {
|
||||
let view = trackers
|
||||
.views
|
||||
.use_extend(&*view_guard, resolve_target, (), ())
|
||||
.map_err(|_| RenderPassErrorInner::InvalidAttachment(resolve_target))?;
|
||||
if extent != Some(view.extent) {
|
||||
return Err(RenderPassErrorInner::ExtentStateMismatch {
|
||||
state_extent: extent.unwrap_or_default(),
|
||||
view_extent: view.extent,
|
||||
return Err(RenderPassErrorInner::AttachmentsDimensionMismatch {
|
||||
previous: (attachment_type_name, extent.unwrap_or_default()),
|
||||
mismatch: ("resolve", view.extent),
|
||||
});
|
||||
}
|
||||
if view.samples != 1 {
|
||||
@@ -809,8 +745,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,147 +810,122 @@ 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 extent = extent.ok_or(RenderPassErrorInner::MissingAttachments)?;
|
||||
let fb_key = (
|
||||
view_data.map(|view| view.framebuffer_attachment.clone()),
|
||||
extent,
|
||||
);
|
||||
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().0.all().map(|fat| fat.clone()),
|
||||
conv::map_extent(&extent, wgt::TextureDimension::D3),
|
||||
)
|
||||
.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)
|
||||
}
|
||||
};
|
||||
|
||||
let rect = {
|
||||
let ex = extent.unwrap();
|
||||
hal::pso::Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: ex.width as _,
|
||||
h: ex.height as _,
|
||||
}
|
||||
let rect = hal::pso::Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: extent.width as _,
|
||||
h: extent.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 +942,17 @@ 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,
|
||||
},
|
||||
extent,
|
||||
_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 +983,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 +1019,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 +1777,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 +1787,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 {
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -103,12 +103,23 @@ 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>,
|
||||
wgt::Extent3d,
|
||||
);
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq)]
|
||||
#[cfg_attr(feature = "serial-pass", derive(serde::Deserialize, serde::Serialize))]
|
||||
@@ -211,11 +222,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 +251,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 +313,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 +377,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 +608,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 +626,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 +658,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(),
|
||||
@@ -775,6 +796,7 @@ impl<B: GfxBackend> Device<B> {
|
||||
layer_start: desc.base_array_layer as _,
|
||||
layer_count: desc.array_layer_count.map(|v| v.get() as _),
|
||||
};
|
||||
let hal_extent = texture.kind.extent().at_level(desc.base_mip_level as _);
|
||||
|
||||
let raw = unsafe {
|
||||
self.raw
|
||||
@@ -799,8 +821,13 @@ impl<B: GfxBackend> Device<B> {
|
||||
aspects,
|
||||
format: texture.format,
|
||||
format_features: texture.format_features,
|
||||
extent: texture.kind.extent().at_level(desc.base_mip_level as _),
|
||||
extent: wgt::Extent3d {
|
||||
width: hal_extent.width,
|
||||
height: hal_extent.height,
|
||||
depth: view_layer_count,
|
||||
},
|
||||
samples: texture.kind.num_samples(),
|
||||
framebuffer_attachment: texture.framebuffer_attachment.clone(),
|
||||
selector,
|
||||
life_guard: LifeGuard::new(desc.label.borrow_or_default()),
|
||||
})
|
||||
@@ -2172,7 +2199,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 +2212,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 +2339,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 +4015,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 +4056,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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
@@ -307,8 +308,9 @@ pub struct TextureView<B: hal::Backend> {
|
||||
pub(crate) aspects: hal::format::Aspects,
|
||||
pub(crate) format: wgt::TextureFormat,
|
||||
pub(crate) format_features: wgt::TextureFormatFeatures,
|
||||
pub(crate) extent: hal::image::Extent,
|
||||
pub(crate) extent: wgt::Extent3d,
|
||||
pub(crate) samples: hal::image::NumSamples,
|
||||
pub(crate) framebuffer_attachment: hal::image::FramebufferAttachment,
|
||||
pub(crate) selector: TextureSelector,
|
||||
pub(crate) life_guard: LifeGuard,
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
@@ -188,12 +188,13 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
allowed_usages: wgt::TextureUsage::RENDER_ATTACHMENT,
|
||||
flags: wgt::TextureFormatFeatureFlags::empty(),
|
||||
},
|
||||
extent: hal::image::Extent {
|
||||
extent: wgt::Extent3d {
|
||||
width: sc.desc.width,
|
||||
height: sc.desc.height,
|
||||
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),
|
||||
|
||||
Reference in New Issue
Block a user