mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-22 14:55:05 +00:00
Refactor usage tracking to be truly sparse
This commit is contained in:
parent
ba0acc94a1
commit
017a54ff97
@ -174,12 +174,7 @@ impl<F> Global<F> {
|
||||
);
|
||||
assert!(src_buffer.usage.contains(BufferUsage::INDIRECT));
|
||||
|
||||
let barriers = src_pending.map(|pending| hal::memory::Barrier::Buffer {
|
||||
states: pending.to_states(),
|
||||
target: &src_buffer.raw,
|
||||
families: None,
|
||||
range: None .. None,
|
||||
});
|
||||
let barriers = src_pending.map(|pending| pending.into_hal(src_buffer));
|
||||
|
||||
unsafe {
|
||||
pass.raw.pipeline_barrier(
|
||||
|
@ -44,7 +44,15 @@ use crate::{
|
||||
use arrayvec::ArrayVec;
|
||||
use hal::{adapter::PhysicalDevice as _, command::CommandBuffer as _, device::Device as _};
|
||||
|
||||
use std::{borrow::Borrow, collections::hash_map::Entry, iter, mem, slice, thread::ThreadId};
|
||||
use std::{
|
||||
borrow::Borrow,
|
||||
collections::hash_map::Entry,
|
||||
iter,
|
||||
marker::PhantomData,
|
||||
mem,
|
||||
slice,
|
||||
thread::ThreadId,
|
||||
};
|
||||
|
||||
|
||||
pub struct RenderBundle<B: hal::Backend> {
|
||||
@ -128,25 +136,15 @@ impl<B: GfxBackend> CommandBuffer<B> {
|
||||
.buffers
|
||||
.merge_replace(&head.buffers)
|
||||
.map(|pending| {
|
||||
log::trace!("\tbuffer -> {:?}", pending);
|
||||
hal::memory::Barrier::Buffer {
|
||||
states: pending.to_states(),
|
||||
target: &buffer_guard[pending.id].raw,
|
||||
range: None .. None,
|
||||
families: None,
|
||||
}
|
||||
let buf = &buffer_guard[pending.id];
|
||||
pending.into_hal(buf)
|
||||
});
|
||||
let texture_barriers = base
|
||||
.textures
|
||||
.merge_replace(&head.textures)
|
||||
.map(|pending| {
|
||||
log::trace!("\ttexture -> {:?}", pending);
|
||||
hal::memory::Barrier::Image {
|
||||
states: pending.to_states(),
|
||||
target: &texture_guard[pending.id].raw,
|
||||
range: pending.selector,
|
||||
families: None,
|
||||
}
|
||||
let tex = &texture_guard[pending.id];
|
||||
pending.into_hal(tex)
|
||||
});
|
||||
base.views.merge_extend(&head.views).unwrap();
|
||||
base.bind_groups.merge_extend(&head.bind_groups).unwrap();
|
||||
@ -328,7 +326,7 @@ impl<F: IdentityFilter<RenderPassId>> Global<F> {
|
||||
let first_use = cmb.trackers.views.init(
|
||||
at.attachment,
|
||||
view.life_guard.add_ref(),
|
||||
&(),
|
||||
PhantomData,
|
||||
).is_some();
|
||||
|
||||
let layouts = match view.inner {
|
||||
@ -388,7 +386,7 @@ impl<F: IdentityFilter<RenderPassId>> Global<F> {
|
||||
let first_use = cmb.trackers.views.init(
|
||||
resolve_target,
|
||||
view.life_guard.add_ref(),
|
||||
&(),
|
||||
PhantomData,
|
||||
).is_some();
|
||||
|
||||
let layouts = match view.inner {
|
||||
@ -451,15 +449,13 @@ impl<F: IdentityFilter<RenderPassId>> Global<F> {
|
||||
assert!(texture.usage.contains(TextureUsage::OUTPUT_ATTACHMENT));
|
||||
|
||||
let usage = consistent_usage.unwrap_or(TextureUsage::OUTPUT_ATTACHMENT);
|
||||
match trackers.textures.init(
|
||||
// this is important to record the `first` state.
|
||||
let _ = trackers.textures.change_replace(
|
||||
source_id.value,
|
||||
source_id.ref_count.clone(),
|
||||
&texture.full_range,
|
||||
) {
|
||||
Some(mut init) => init.set(view_range.clone(), usage),
|
||||
None => panic!("Your texture {:?} is in the another attachment!", source_id.value),
|
||||
};
|
||||
|
||||
&source_id.ref_count,
|
||||
view_range.clone(),
|
||||
usage,
|
||||
);
|
||||
if consistent_usage.is_some() {
|
||||
// If we expect the texture to be transited to a new state by the
|
||||
// render pass configuration, make the tracker aware of that.
|
||||
@ -468,7 +464,6 @@ impl<F: IdentityFilter<RenderPassId>> Global<F> {
|
||||
&source_id.ref_count,
|
||||
view_range.clone(),
|
||||
TextureUsage::OUTPUT_ATTACHMENT,
|
||||
&texture.full_range,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
@ -85,13 +85,7 @@ impl<F> Global<F> {
|
||||
.buffers
|
||||
.use_replace(&*buffer_guard, source, (), BufferUsage::COPY_SRC);
|
||||
assert!(src_buffer.usage.contains(BufferUsage::COPY_SRC));
|
||||
|
||||
barriers.extend(src_pending.map(|pending| hal::memory::Barrier::Buffer {
|
||||
states: pending.to_states(),
|
||||
target: &src_buffer.raw,
|
||||
families: None,
|
||||
range: None .. None,
|
||||
}));
|
||||
barriers.extend(src_pending.map(|pending| pending.into_hal(src_buffer)));
|
||||
|
||||
let (dst_buffer, dst_pending) = cmb.trackers.buffers.use_replace(
|
||||
&*buffer_guard,
|
||||
@ -100,13 +94,7 @@ impl<F> Global<F> {
|
||||
BufferUsage::COPY_DST,
|
||||
);
|
||||
assert!(dst_buffer.usage.contains(BufferUsage::COPY_DST));
|
||||
|
||||
barriers.extend(dst_pending.map(|pending| hal::memory::Barrier::Buffer {
|
||||
states: pending.to_states(),
|
||||
target: &dst_buffer.raw,
|
||||
families: None,
|
||||
range: None .. None,
|
||||
}));
|
||||
barriers.extend(dst_pending.map(|pending| pending.into_hal(dst_buffer)));
|
||||
|
||||
let region = hal::command::BufferCopy {
|
||||
src: source_offset,
|
||||
@ -146,13 +134,7 @@ impl<F> Global<F> {
|
||||
BufferUsage::COPY_SRC,
|
||||
);
|
||||
assert!(src_buffer.usage.contains(BufferUsage::COPY_SRC));
|
||||
|
||||
let src_barriers = src_pending.map(|pending| hal::memory::Barrier::Buffer {
|
||||
states: pending.to_states(),
|
||||
target: &src_buffer.raw,
|
||||
families: None,
|
||||
range: None .. None,
|
||||
});
|
||||
let src_barriers = src_pending.map(|pending| pending.into_hal(src_buffer));
|
||||
|
||||
let (dst_texture, dst_pending) = cmb.trackers.textures.use_replace(
|
||||
&*texture_guard,
|
||||
@ -161,13 +143,7 @@ impl<F> Global<F> {
|
||||
TextureUsage::COPY_DST,
|
||||
);
|
||||
assert!(dst_texture.usage.contains(TextureUsage::COPY_DST));
|
||||
|
||||
let dst_barriers = dst_pending.map(|pending| hal::memory::Barrier::Image {
|
||||
states: pending.to_states(),
|
||||
target: &dst_texture.raw,
|
||||
families: None,
|
||||
range: pending.selector,
|
||||
});
|
||||
let dst_barriers = dst_pending.map(|pending| pending.into_hal(dst_texture));
|
||||
|
||||
let bytes_per_texel = conv::map_texture_format(dst_texture.format, cmb.features)
|
||||
.surface_desc()
|
||||
@ -222,13 +198,7 @@ impl<F> Global<F> {
|
||||
TextureUsage::COPY_SRC,
|
||||
);
|
||||
assert!(src_texture.usage.contains(TextureUsage::COPY_SRC));
|
||||
|
||||
let src_barriers = src_pending.map(|pending| hal::memory::Barrier::Image {
|
||||
states: pending.to_states(),
|
||||
target: &src_texture.raw,
|
||||
families: None,
|
||||
range: pending.selector,
|
||||
});
|
||||
let src_barriers = src_pending.map(|pending| pending.into_hal(src_texture));
|
||||
|
||||
let (dst_buffer, dst_barriers) = cmb.trackers.buffers.use_replace(
|
||||
&*buffer_guard,
|
||||
@ -237,13 +207,7 @@ impl<F> Global<F> {
|
||||
BufferUsage::COPY_DST,
|
||||
);
|
||||
assert!(dst_buffer.usage.contains(BufferUsage::COPY_DST));
|
||||
|
||||
let dst_barrier = dst_barriers.map(|pending| hal::memory::Barrier::Buffer {
|
||||
states: pending.to_states(),
|
||||
target: &dst_buffer.raw,
|
||||
families: None,
|
||||
range: None .. None,
|
||||
});
|
||||
let dst_barrier = dst_barriers.map(|pending| pending.into_hal(dst_buffer));
|
||||
|
||||
let bytes_per_texel = conv::map_texture_format(src_texture.format, cmb.features)
|
||||
.surface_desc()
|
||||
@ -303,13 +267,7 @@ impl<F> Global<F> {
|
||||
TextureUsage::COPY_SRC,
|
||||
);
|
||||
assert!(src_texture.usage.contains(TextureUsage::COPY_SRC));
|
||||
|
||||
barriers.extend(src_pending.map(|pending| hal::memory::Barrier::Image {
|
||||
states: pending.to_states(),
|
||||
target: &src_texture.raw,
|
||||
families: None,
|
||||
range: pending.selector,
|
||||
}));
|
||||
barriers.extend(src_pending.map(|pending| pending.into_hal(src_texture)));
|
||||
|
||||
let (dst_texture, dst_pending) = cmb.trackers.textures.use_replace(
|
||||
&*texture_guard,
|
||||
@ -318,13 +276,7 @@ impl<F> Global<F> {
|
||||
TextureUsage::COPY_DST,
|
||||
);
|
||||
assert!(dst_texture.usage.contains(TextureUsage::COPY_DST));
|
||||
|
||||
barriers.extend(dst_pending.map(|pending| hal::memory::Barrier::Image {
|
||||
states: pending.to_states(),
|
||||
target: &dst_texture.raw,
|
||||
families: None,
|
||||
range: pending.selector,
|
||||
}));
|
||||
barriers.extend(dst_pending.map(|pending| pending.into_hal(dst_texture)));
|
||||
|
||||
let region = hal::command::ImageCopy {
|
||||
src_subresource: source.to_sub_layers(aspects),
|
||||
|
@ -11,7 +11,7 @@ use crate::{
|
||||
pipeline,
|
||||
resource,
|
||||
swap_chain,
|
||||
track::{SEPARATE_DEPTH_STENCIL_STATES, TrackerSet},
|
||||
track::{BufferState, TextureState, TrackerSet},
|
||||
BufferAddress,
|
||||
FastHashMap,
|
||||
Features,
|
||||
@ -36,6 +36,7 @@ use std::{
|
||||
collections::hash_map::Entry,
|
||||
ffi,
|
||||
iter,
|
||||
marker::PhantomData,
|
||||
ops,
|
||||
ptr,
|
||||
slice,
|
||||
@ -473,13 +474,18 @@ impl<F: IdentityFilter<id::BufferId>> Global<F> {
|
||||
let device = &device_guard[device_id];
|
||||
let buffer = device.create_buffer(device_id, desc);
|
||||
let ref_count = buffer.life_guard.add_ref();
|
||||
let range = buffer.full_range;
|
||||
|
||||
let id = hub.buffers.register_identity(id_in, buffer, &mut token);
|
||||
device
|
||||
.trackers
|
||||
.lock()
|
||||
.buffers
|
||||
.init(id, ref_count, &())
|
||||
.init(
|
||||
id,
|
||||
ref_count,
|
||||
BufferState::from_selector(&range),
|
||||
)
|
||||
.unwrap();
|
||||
id
|
||||
}
|
||||
@ -499,6 +505,7 @@ impl<F: IdentityFilter<id::BufferId>> Global<F> {
|
||||
let device = &device_guard[device_id];
|
||||
let mut buffer = device.create_buffer(device_id, &desc);
|
||||
let ref_count = buffer.life_guard.add_ref();
|
||||
let range = buffer.full_range;
|
||||
|
||||
let pointer = match map_buffer(&device.raw, &mut buffer, 0 .. desc.size, HostMap::Write) {
|
||||
Ok(ptr) => ptr,
|
||||
@ -514,7 +521,7 @@ impl<F: IdentityFilter<id::BufferId>> Global<F> {
|
||||
.buffers.init(
|
||||
id,
|
||||
ref_count,
|
||||
&(),
|
||||
BufferState::from_selector(&range),
|
||||
)
|
||||
.unwrap()
|
||||
.set((), resource::BufferUsage::MAP_WRITE);
|
||||
@ -632,7 +639,7 @@ impl<F: IdentityFilter<id::TextureId>> Global<F> {
|
||||
.textures.init(
|
||||
id,
|
||||
ref_count,
|
||||
&range,
|
||||
TextureState::from_selector(&range),
|
||||
)
|
||||
.unwrap()
|
||||
.set(range, resource::TextureUsage::UNINITIALIZED);
|
||||
@ -686,15 +693,7 @@ impl<F: IdentityFilter<id::TextureViewId>> Global<F> {
|
||||
(desc.base_array_layer + desc.array_layer_count) as u16
|
||||
};
|
||||
let range = hal::image::SubresourceRange {
|
||||
aspects: if SEPARATE_DEPTH_STENCIL_STATES {
|
||||
match desc.aspect {
|
||||
resource::TextureAspect::All => texture.full_range.aspects,
|
||||
resource::TextureAspect::DepthOnly => hal::format::Aspects::DEPTH,
|
||||
resource::TextureAspect::StencilOnly => hal::format::Aspects::STENCIL,
|
||||
}
|
||||
} else {
|
||||
texture.full_range.aspects
|
||||
},
|
||||
aspects: texture.full_range.aspects,
|
||||
levels: desc.base_mip_level as u8 .. end_level,
|
||||
layers: desc.base_array_layer as u16 .. end_layer,
|
||||
};
|
||||
@ -744,7 +743,7 @@ impl<F: IdentityFilter<id::TextureViewId>> Global<F> {
|
||||
let id = hub.texture_views.register_identity(id_in, view, &mut token);
|
||||
device.trackers
|
||||
.lock()
|
||||
.views.init(id, ref_count, &())
|
||||
.views.init(id, ref_count, PhantomData)
|
||||
.unwrap();
|
||||
id
|
||||
}
|
||||
@ -822,7 +821,7 @@ impl<F: IdentityFilter<id::SamplerId>> Global<F> {
|
||||
let id = hub.samplers.register_identity(id_in, sampler, &mut token);
|
||||
device.trackers
|
||||
.lock()
|
||||
.samplers.init(id, ref_count, &())
|
||||
.samplers.init(id, ref_count, PhantomData)
|
||||
.unwrap();
|
||||
id
|
||||
}
|
||||
@ -1080,7 +1079,6 @@ impl<F: IdentityFilter<id::BindGroupId>> Global<F> {
|
||||
&source_id.ref_count,
|
||||
view.range.clone(),
|
||||
usage,
|
||||
&texture.full_range,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(texture.usage.contains(usage));
|
||||
@ -1130,7 +1128,7 @@ impl<F: IdentityFilter<id::BindGroupId>> Global<F> {
|
||||
.trackers
|
||||
.lock()
|
||||
.bind_groups
|
||||
.init(id, ref_count, &())
|
||||
.init(id, ref_count, PhantomData)
|
||||
.unwrap();
|
||||
id
|
||||
}
|
||||
@ -1886,7 +1884,7 @@ impl<F> Global<F> {
|
||||
let mut token = Token::root();
|
||||
let (device_guard, mut token) = hub.devices.read(&mut token);
|
||||
|
||||
let (device_id, ref_count, full_range) = {
|
||||
let (device_id, ref_count) = {
|
||||
let (mut buffer_guard, _) = hub.buffers.write(&mut token);
|
||||
let buffer = &mut buffer_guard[buffer_id];
|
||||
|
||||
@ -1906,13 +1904,9 @@ impl<F> Global<F> {
|
||||
buffer.pending_mapping = Some(resource::BufferPendingMapping {
|
||||
range,
|
||||
op: operation,
|
||||
parent_ref_count: buffer.life_guard.add_ref()
|
||||
parent_ref_count: buffer.life_guard.add_ref(),
|
||||
});
|
||||
(
|
||||
buffer.device_id.value,
|
||||
buffer.life_guard.add_ref(),
|
||||
buffer.full_range,
|
||||
)
|
||||
(buffer.device_id.value, buffer.life_guard.add_ref())
|
||||
};
|
||||
|
||||
let device = &device_guard[device_id];
|
||||
@ -1921,7 +1915,7 @@ impl<F> Global<F> {
|
||||
.trackers
|
||||
.lock()
|
||||
.buffers
|
||||
.change_replace(buffer_id, &ref_count, (), usage, &full_range);
|
||||
.change_replace(buffer_id, &ref_count, (), usage);
|
||||
|
||||
device
|
||||
.lock_life(&mut token)
|
||||
|
@ -3,18 +3,12 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use super::{PendingTransition, ResourceState, Unit};
|
||||
use crate::{conv, id::BufferId, resource::BufferUsage};
|
||||
use std::ops::Range;
|
||||
use crate::{id::BufferId, resource::BufferUsage};
|
||||
|
||||
//TODO: store `hal::buffer::State` here to avoid extra conversions
|
||||
pub type BufferState = Unit<BufferUsage>;
|
||||
|
||||
impl PendingTransition<BufferState> {
|
||||
/// Produce the gfx-hal buffer states corresponding to the transition.
|
||||
pub fn to_states(&self) -> Range<hal::buffer::State> {
|
||||
conv::map_buffer_state(self.usage.start) .. conv::map_buffer_state(self.usage.end)
|
||||
}
|
||||
|
||||
fn collapse(self) -> Result<BufferUsage, Self> {
|
||||
if self.usage.start.is_empty()
|
||||
|| self.usage.start == self.usage.end
|
||||
@ -27,17 +21,25 @@ impl PendingTransition<BufferState> {
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceState for BufferState {
|
||||
type Id = BufferId;
|
||||
type Selector = ();
|
||||
type Usage = BufferUsage;
|
||||
|
||||
fn new(_full_selector: &Self::Selector) -> Self {
|
||||
impl Default for BufferState {
|
||||
fn default() -> Self {
|
||||
BufferState {
|
||||
first: None,
|
||||
last: BufferUsage::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BufferState {
|
||||
pub fn from_selector(_full_selector: &()) -> Self {
|
||||
BufferState::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceState for BufferState {
|
||||
type Id = BufferId;
|
||||
type Selector = ();
|
||||
type Usage = BufferUsage;
|
||||
|
||||
fn query(&self, _selector: Self::Selector) -> Option<Self::Usage> {
|
||||
Some(self.last)
|
||||
|
@ -7,8 +7,10 @@ mod range;
|
||||
mod texture;
|
||||
|
||||
use crate::{
|
||||
conv,
|
||||
hub::Storage,
|
||||
id::{BindGroupId, SamplerId, TextureViewId, TypedId},
|
||||
resource,
|
||||
Backend,
|
||||
Epoch,
|
||||
FastHashMap,
|
||||
@ -21,16 +23,14 @@ use std::{
|
||||
collections::hash_map::Entry,
|
||||
fmt,
|
||||
marker::PhantomData,
|
||||
ops::Range,
|
||||
ops,
|
||||
vec::Drain,
|
||||
};
|
||||
|
||||
use buffer::BufferState;
|
||||
use texture::TextureState;
|
||||
pub use buffer::BufferState;
|
||||
pub use texture::TextureState;
|
||||
|
||||
|
||||
pub const SEPARATE_DEPTH_STENCIL_STATES: bool = false;
|
||||
|
||||
/// A single unit of state tracking. It keeps an initial
|
||||
/// usage as well as the last/current one, similar to `Range`.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
@ -56,7 +56,7 @@ impl<U: Copy> Unit<U> {
|
||||
|
||||
/// The main trait that abstracts away the tracking logic of
|
||||
/// a particular resource type, like a buffer or a texture.
|
||||
pub trait ResourceState: Clone {
|
||||
pub trait ResourceState: Clone + Default {
|
||||
/// Corresponding `HUB` identifier.
|
||||
type Id: Copy + fmt::Debug + TypedId;
|
||||
/// A type specifying the sub-resources.
|
||||
@ -64,9 +64,6 @@ pub trait ResourceState: Clone {
|
||||
/// Usage type for a `Unit` of a sub-resource.
|
||||
type Usage: fmt::Debug;
|
||||
|
||||
/// Create a new resource state to track the specified subresources.
|
||||
fn new(full_selector: &Self::Selector) -> Self;
|
||||
|
||||
/// Check if all the selected sub-resources have the same
|
||||
/// usage, and return it.
|
||||
///
|
||||
@ -129,7 +126,44 @@ struct Resource<S> {
|
||||
pub struct PendingTransition<S: ResourceState> {
|
||||
pub id: S::Id,
|
||||
pub selector: S::Selector,
|
||||
pub usage: Range<S::Usage>,
|
||||
pub usage: ops::Range<S::Usage>,
|
||||
}
|
||||
|
||||
impl PendingTransition<BufferState> {
|
||||
/// Produce the gfx-hal barrier corresponding to the transition.
|
||||
pub fn into_hal<'a, B: hal::Backend>(
|
||||
self,
|
||||
buf: &'a resource::Buffer<B>,
|
||||
) -> hal::memory::Barrier<'a, B> {
|
||||
log::trace!("\tbuffer -> {:?}", self);
|
||||
hal::memory::Barrier::Buffer {
|
||||
states: conv::map_buffer_state(self.usage.start) .. conv::map_buffer_state(self.usage.end),
|
||||
target: &buf.raw,
|
||||
range: None .. None,
|
||||
families: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PendingTransition<TextureState> {
|
||||
/// Produce the gfx-hal barrier corresponding to the transition.
|
||||
pub fn into_hal<'a, B: hal::Backend>(
|
||||
self,
|
||||
tex: &'a resource::Texture<B>,
|
||||
) -> hal::memory::Barrier<'a, B> {
|
||||
log::trace!("\ttexture -> {:?}", self);
|
||||
let aspects = tex.full_range.aspects;
|
||||
hal::memory::Barrier::Image {
|
||||
states: conv::map_texture_state(self.usage.start, aspects)
|
||||
.. conv::map_texture_state(self.usage.end, aspects),
|
||||
target: &tex.raw,
|
||||
range: hal::image::SubresourceRange {
|
||||
aspects,
|
||||
.. self.selector
|
||||
},
|
||||
families: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper initialization structure that allows setting the usage on
|
||||
@ -238,7 +272,7 @@ impl<S: ResourceState> ResourceTracker<S> {
|
||||
&mut self,
|
||||
id: S::Id,
|
||||
ref_count: RefCount,
|
||||
full_selector: &S::Selector,
|
||||
state: S,
|
||||
) -> Option<Initializer<S>> {
|
||||
let (index, epoch, backend) = id.unzip();
|
||||
debug_assert_eq!(backend, self.backend);
|
||||
@ -246,7 +280,7 @@ impl<S: ResourceState> ResourceTracker<S> {
|
||||
Entry::Vacant(e) => {
|
||||
let res = e.insert(Resource {
|
||||
ref_count,
|
||||
state: S::new(full_selector),
|
||||
state,
|
||||
epoch,
|
||||
});
|
||||
Some(Initializer {
|
||||
@ -277,14 +311,13 @@ impl<S: ResourceState> ResourceTracker<S> {
|
||||
map: &'a mut FastHashMap<Index, Resource<S>>,
|
||||
id: S::Id,
|
||||
ref_count: &RefCount,
|
||||
full_selector: &S::Selector,
|
||||
) -> &'a mut Resource<S> {
|
||||
let (index, epoch, backend) = id.unzip();
|
||||
debug_assert_eq!(self_backend, backend);
|
||||
match map.entry(index) {
|
||||
Entry::Vacant(e) => e.insert(Resource {
|
||||
ref_count: ref_count.clone(),
|
||||
state: S::new(full_selector),
|
||||
state: S::default(),
|
||||
epoch,
|
||||
}),
|
||||
Entry::Occupied(e) => {
|
||||
@ -303,9 +336,8 @@ impl<S: ResourceState> ResourceTracker<S> {
|
||||
ref_count: &RefCount,
|
||||
selector: S::Selector,
|
||||
usage: S::Usage,
|
||||
full_selector: &S::Selector,
|
||||
) -> Result<(), PendingTransition<S>> {
|
||||
Self::get_or_insert(self.backend, &mut self.map, id, ref_count, full_selector)
|
||||
Self::get_or_insert(self.backend, &mut self.map, id, ref_count)
|
||||
.state
|
||||
.change(id, selector, usage, None)
|
||||
}
|
||||
@ -317,9 +349,8 @@ impl<S: ResourceState> ResourceTracker<S> {
|
||||
ref_count: &RefCount,
|
||||
selector: S::Selector,
|
||||
usage: S::Usage,
|
||||
full_selector: &S::Selector,
|
||||
) -> Drain<PendingTransition<S>> {
|
||||
let res = Self::get_or_insert(self.backend, &mut self.map, id, ref_count, full_selector);
|
||||
let res = Self::get_or_insert(self.backend, &mut self.map, id, ref_count);
|
||||
res.state
|
||||
.change(id, selector, usage, Some(&mut self.temp))
|
||||
.ok(); //TODO: unwrap?
|
||||
@ -376,7 +407,7 @@ impl<S: ResourceState> ResourceTracker<S> {
|
||||
/// the last read-only usage, if possible.
|
||||
///
|
||||
/// Returns the old usage as an error if there is a conflict.
|
||||
pub fn use_extend<'a, T: 'a + Borrow<RefCount> + Borrow<S::Selector>>(
|
||||
pub fn use_extend<'a, T: 'a + Borrow<RefCount>>(
|
||||
&mut self,
|
||||
storage: &'a Storage<T, S::Id>,
|
||||
id: S::Id,
|
||||
@ -384,7 +415,7 @@ impl<S: ResourceState> ResourceTracker<S> {
|
||||
usage: S::Usage,
|
||||
) -> Result<&'a T, S::Usage> {
|
||||
let item = &storage[id];
|
||||
self.change_extend(id, item.borrow(), selector, usage, item.borrow())
|
||||
self.change_extend(id, item.borrow(), selector, usage)
|
||||
.map(|()| item)
|
||||
.map_err(|pending| pending.usage.start)
|
||||
}
|
||||
@ -393,7 +424,7 @@ impl<S: ResourceState> ResourceTracker<S> {
|
||||
/// Combines storage access by 'Id' with the transition that replaces
|
||||
/// the last usage with a new one, returning an iterator over these
|
||||
/// transitions.
|
||||
pub fn use_replace<'a, T: 'a + Borrow<RefCount> + Borrow<S::Selector>>(
|
||||
pub fn use_replace<'a, T: 'a + Borrow<RefCount>>(
|
||||
&mut self,
|
||||
storage: &'a Storage<T, S::Id>,
|
||||
id: S::Id,
|
||||
@ -401,7 +432,7 @@ impl<S: ResourceState> ResourceTracker<S> {
|
||||
usage: S::Usage,
|
||||
) -> (&'a T, Drain<PendingTransition<S>>) {
|
||||
let item = &storage[id];
|
||||
let drain = self.change_replace(id, item.borrow(), selector, usage, item.borrow());
|
||||
let drain = self.change_replace(id, item.borrow(), selector, usage);
|
||||
(item, drain)
|
||||
}
|
||||
}
|
||||
@ -412,10 +443,6 @@ impl<I: Copy + fmt::Debug + TypedId> ResourceState for PhantomData<I> {
|
||||
type Selector = ();
|
||||
type Usage = ();
|
||||
|
||||
fn new(_full_selector: &Self::Selector) -> Self {
|
||||
PhantomData
|
||||
}
|
||||
|
||||
fn query(&self, _selector: Self::Selector) -> Option<Self::Usage> {
|
||||
Some(())
|
||||
}
|
||||
|
@ -2,7 +2,15 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::{cmp::Ordering, fmt::Debug, iter::Peekable, ops::Range, slice::Iter};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
fmt::Debug,
|
||||
iter,
|
||||
ops::Range,
|
||||
slice::Iter,
|
||||
};
|
||||
|
||||
/// Structure that keeps track of a I -> T mapping,
|
||||
/// optimized for a case where keys of the same values
|
||||
@ -11,21 +19,27 @@ use std::{cmp::Ordering, fmt::Debug, iter::Peekable, ops::Range, slice::Iter};
|
||||
pub struct RangedStates<I, T> {
|
||||
/// List of ranges, each associated with a singe value.
|
||||
/// Ranges of keys have to be non-intersecting and ordered.
|
||||
ranges: Vec<(Range<I>, T)>,
|
||||
}
|
||||
|
||||
impl<I, T> Default for RangedStates<I, T> {
|
||||
fn default() -> Self {
|
||||
RangedStates { ranges: Vec::new() }
|
||||
}
|
||||
ranges: SmallVec<[(Range<I>, T); 1]>,
|
||||
}
|
||||
|
||||
impl<I: Copy + PartialOrd, T: Copy + PartialEq> RangedStates<I, T> {
|
||||
pub fn empty() -> Self {
|
||||
RangedStates {
|
||||
ranges: SmallVec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_range(range: Range<I>, value: T) -> Self {
|
||||
RangedStates {
|
||||
ranges: iter::once((range, value)).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a new instance from a slice of ranges.
|
||||
#[cfg(test)]
|
||||
pub fn new(values: &[(Range<I>, T)]) -> Self {
|
||||
pub fn from_slice(values: &[(Range<I>, T)]) -> Self {
|
||||
RangedStates {
|
||||
ranges: values.to_vec(),
|
||||
ranges: values.iter().cloned().collect(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,8 +203,8 @@ impl<I: Copy + PartialOrd, T: Copy + PartialEq> RangedStates<I, T> {
|
||||
#[derive(Debug)]
|
||||
pub struct Merge<'a, I, T> {
|
||||
base: I,
|
||||
sa: Peekable<Iter<'a, (Range<I>, T)>>,
|
||||
sb: Peekable<Iter<'a, (Range<I>, T)>>,
|
||||
sa: iter::Peekable<Iter<'a, (Range<I>, T)>>,
|
||||
sb: iter::Peekable<Iter<'a, (Range<I>, T)>>,
|
||||
}
|
||||
|
||||
impl<'a, I: Copy + Debug + Ord, T: Copy + Debug> Iterator for Merge<'a, I, T> {
|
||||
@ -268,55 +282,58 @@ mod test {
|
||||
use std::{fmt::Debug, ops::Range};
|
||||
|
||||
fn easy_merge<T: PartialEq + Copy + Debug>(
|
||||
ra: Vec<(Range<usize>, T)>,
|
||||
rb: Vec<(Range<usize>, T)>,
|
||||
ra: &[(Range<usize>, T)],
|
||||
rb: &[(Range<usize>, T)],
|
||||
) -> Vec<(Range<usize>, Range<Option<T>>)> {
|
||||
RangedStates { ranges: ra }
|
||||
.merge(&RangedStates { ranges: rb }, 0)
|
||||
RangedStates::from_slice(ra)
|
||||
.merge(&RangedStates::from_slice(rb), 0)
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sane_good() {
|
||||
let rs = RangedStates {
|
||||
ranges: vec![(1 .. 4, 9u8), (4 .. 5, 9)],
|
||||
};
|
||||
let rs = RangedStates::from_slice(
|
||||
&[(1 .. 4, 9u8), (4 .. 5, 9)],
|
||||
);
|
||||
rs.check_sanity();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn sane_empty() {
|
||||
let rs = RangedStates {
|
||||
ranges: vec![(1 .. 4, 9u8), (5 .. 5, 9)],
|
||||
};
|
||||
let rs = RangedStates::from_slice(
|
||||
&[(1 .. 4, 9u8), (5 .. 5, 9)],
|
||||
);
|
||||
rs.check_sanity();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn sane_intersect() {
|
||||
let rs = RangedStates {
|
||||
ranges: vec![(1 .. 4, 9u8), (3 .. 5, 9)],
|
||||
};
|
||||
let rs = RangedStates::from_slice(
|
||||
&[(1 .. 4, 9u8), (3 .. 5, 9)],
|
||||
);
|
||||
rs.check_sanity();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn coalesce() {
|
||||
let mut rs = RangedStates {
|
||||
ranges: vec![(1 .. 4, 9u8), (4 .. 5, 9), (5 .. 7, 1), (8 .. 9, 1)],
|
||||
};
|
||||
let mut rs = RangedStates::from_slice(
|
||||
&[(1 .. 4, 9u8), (4 .. 5, 9), (5 .. 7, 1), (8 .. 9, 1)],
|
||||
);
|
||||
rs.coalesce();
|
||||
rs.check_sanity();
|
||||
assert_eq!(rs.ranges, vec![(1 .. 5, 9), (5 .. 7, 1), (8 .. 9, 1),]);
|
||||
assert_eq!(
|
||||
rs.ranges.as_slice(),
|
||||
&[(1 .. 5, 9), (5 .. 7, 1), (8 .. 9, 1),]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn query() {
|
||||
let rs = RangedStates {
|
||||
ranges: vec![(1 .. 4, 1u8), (5 .. 7, 2)],
|
||||
};
|
||||
let rs = RangedStates::from_slice(
|
||||
&[(1 .. 4, 1u8), (5 .. 7, 2)],
|
||||
);
|
||||
assert_eq!(rs.query(&(0 .. 1), |v| *v), None);
|
||||
assert_eq!(rs.query(&(1 .. 3), |v| *v), Some(Ok(1)));
|
||||
assert_eq!(rs.query(&(1 .. 6), |v| *v), Some(Err(())));
|
||||
@ -324,9 +341,9 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn isolate() {
|
||||
let rs = RangedStates {
|
||||
ranges: vec![(1 .. 4, 9u8), (4 .. 5, 9), (5 .. 7, 1), (8 .. 9, 1)],
|
||||
};
|
||||
let rs = RangedStates::from_slice(
|
||||
&[(1 .. 4, 9u8), (4 .. 5, 9), (5 .. 7, 1), (8 .. 9, 1)],
|
||||
);
|
||||
assert_eq!(&rs.sanely_isolated(4 .. 5, 0), &[(4 .. 5, 9u8),]);
|
||||
assert_eq!(
|
||||
&rs.sanely_isolated(0 .. 6, 0),
|
||||
@ -345,28 +362,31 @@ mod test {
|
||||
#[test]
|
||||
fn merge_same() {
|
||||
assert_eq!(
|
||||
easy_merge(vec![(1 .. 4, 0u8),], vec![(1 .. 4, 2u8),],),
|
||||
vec![(1 .. 4, Some(0) .. Some(2)),]
|
||||
&easy_merge(&[(1 .. 4, 0u8),], &[(1 .. 4, 2u8),],),
|
||||
&[(1 .. 4, Some(0) .. Some(2)),]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_empty() {
|
||||
assert_eq!(
|
||||
easy_merge(vec![(1 .. 2, 0u8),], vec![],),
|
||||
vec![(1 .. 2, Some(0) .. None),]
|
||||
&easy_merge(&[(1 .. 2, 0u8),], &[],),
|
||||
&[(1 .. 2, Some(0) .. None),]
|
||||
);
|
||||
assert_eq!(
|
||||
easy_merge(vec![], vec![(3 .. 4, 1u8),],),
|
||||
vec![(3 .. 4, None .. Some(1)),]
|
||||
&easy_merge(&[], &[(3 .. 4, 1u8),],),
|
||||
&[(3 .. 4, None .. Some(1)),]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_separate() {
|
||||
assert_eq!(
|
||||
easy_merge(vec![(1 .. 2, 0u8), (5 .. 6, 1u8),], vec![(2 .. 4, 2u8),],),
|
||||
vec![
|
||||
&easy_merge(
|
||||
&[(1 .. 2, 0u8), (5 .. 6, 1u8),],
|
||||
&[(2 .. 4, 2u8),],
|
||||
),
|
||||
&[
|
||||
(1 .. 2, Some(0) .. None),
|
||||
(2 .. 4, None .. Some(2)),
|
||||
(5 .. 6, Some(1) .. None),
|
||||
@ -377,27 +397,30 @@ mod test {
|
||||
#[test]
|
||||
fn merge_subset() {
|
||||
assert_eq!(
|
||||
easy_merge(vec![(1 .. 6, 0u8),], vec![(2 .. 4, 2u8),],),
|
||||
vec![
|
||||
&easy_merge(
|
||||
&[(1 .. 6, 0u8),],
|
||||
&[(2 .. 4, 2u8),],
|
||||
),
|
||||
&[
|
||||
(1 .. 2, Some(0) .. None),
|
||||
(2 .. 4, Some(0) .. Some(2)),
|
||||
(4 .. 6, Some(0) .. None),
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
easy_merge(vec![(2 .. 4, 0u8),], vec![(1 .. 4, 2u8),],),
|
||||
vec![(1 .. 2, None .. Some(2)), (2 .. 4, Some(0) .. Some(2)),]
|
||||
&easy_merge(&[(2 .. 4, 0u8),], &[(1 .. 4, 2u8),],),
|
||||
&[(1 .. 2, None .. Some(2)), (2 .. 4, Some(0) .. Some(2)),]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_all() {
|
||||
assert_eq!(
|
||||
easy_merge(
|
||||
vec![(1 .. 4, 0u8), (5 .. 8, 1u8),],
|
||||
vec![(2 .. 6, 2u8), (7 .. 9, 3u8),],
|
||||
&easy_merge(
|
||||
&[(1 .. 4, 0u8), (5 .. 8, 1u8),],
|
||||
&[(2 .. 6, 2u8), (7 .. 9, 3u8),],
|
||||
),
|
||||
vec![
|
||||
&[
|
||||
(1 .. 2, Some(0) .. None),
|
||||
(2 .. 4, Some(0) .. Some(2)),
|
||||
(4 .. 5, None .. Some(2)),
|
||||
|
@ -2,30 +2,25 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use super::{SEPARATE_DEPTH_STENCIL_STATES, range::RangedStates, PendingTransition, ResourceState, Unit};
|
||||
use crate::{conv, device::MAX_MIP_LEVELS, id::TextureId, resource::TextureUsage};
|
||||
use super::{range::RangedStates, PendingTransition, ResourceState, Unit};
|
||||
use crate::{device::MAX_MIP_LEVELS, id::TextureId, resource::TextureUsage};
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
|
||||
use std::ops::Range;
|
||||
use std::{iter, ops::Range};
|
||||
|
||||
|
||||
//TODO: store `hal::image::State` here to avoid extra conversions
|
||||
type PlaneStates = RangedStates<hal::image::Layer, Unit<TextureUsage>>;
|
||||
type MipState = ArrayVec<[(hal::format::Aspects, PlaneStates); 2]>;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct TextureState {
|
||||
mips: ArrayVec<[MipState; MAX_MIP_LEVELS]>,
|
||||
mips: ArrayVec<[PlaneStates; MAX_MIP_LEVELS]>,
|
||||
/// True if we have the information about all the subresources here
|
||||
full: bool,
|
||||
}
|
||||
|
||||
impl PendingTransition<TextureState> {
|
||||
/// Produce the gfx-hal image states corresponding to the transition.
|
||||
pub fn to_states(&self) -> Range<hal::image::State> {
|
||||
conv::map_texture_state(self.usage.start, self.selector.aspects)
|
||||
.. conv::map_texture_state(self.usage.end, self.selector.aspects)
|
||||
}
|
||||
|
||||
fn collapse(self) -> Result<TextureUsage, Self> {
|
||||
if self.usage.start.is_empty()
|
||||
|| self.usage.start == self.usage.end
|
||||
@ -38,47 +33,49 @@ impl PendingTransition<TextureState> {
|
||||
}
|
||||
}
|
||||
|
||||
impl TextureState {
|
||||
pub fn from_selector(full_selector: &hal::image::SubresourceRange) -> Self {
|
||||
debug_assert_eq!(full_selector.layers.start, 0);
|
||||
debug_assert_eq!(full_selector.levels.start, 0);
|
||||
TextureState {
|
||||
mips: iter::repeat_with(|| {
|
||||
PlaneStates::from_range(
|
||||
0 .. full_selector.layers.end,
|
||||
Unit::new(TextureUsage::UNINITIALIZED),
|
||||
)
|
||||
})
|
||||
.take(full_selector.levels.end as usize)
|
||||
.collect(),
|
||||
full: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceState for TextureState {
|
||||
type Id = TextureId;
|
||||
type Selector = hal::image::SubresourceRange;
|
||||
type Usage = TextureUsage;
|
||||
|
||||
fn new(full_selector: &Self::Selector) -> Self {
|
||||
TextureState {
|
||||
mips: (0 .. full_selector.levels.end)
|
||||
.map(|_| {
|
||||
let mut slices = ArrayVec::new();
|
||||
let aspects_without_stencil = full_selector.aspects & !hal::format::Aspects::STENCIL;
|
||||
if SEPARATE_DEPTH_STENCIL_STATES && full_selector.aspects != aspects_without_stencil {
|
||||
slices.push((aspects_without_stencil, PlaneStates::default()));
|
||||
slices.push((hal::format::Aspects::STENCIL, PlaneStates::default()));
|
||||
} else {
|
||||
slices.push((full_selector.aspects, PlaneStates::default()))
|
||||
}
|
||||
slices
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
fn query(&self, selector: Self::Selector) -> Option<Self::Usage> {
|
||||
let mut result = None;
|
||||
// Note: we only consider the subresources tracked by `self`.
|
||||
// If some are not known to `self`, it means the can assume the
|
||||
// initial state to whatever we need, which we can always make
|
||||
// to be the same as the query result for the known subresources.
|
||||
let num_levels = self.mips.len();
|
||||
if self.full {
|
||||
assert!(num_levels >= selector.levels.end as usize);
|
||||
}
|
||||
let mip_start = num_levels.min(selector.levels.start as usize);
|
||||
let mip_end = num_levels.min(selector.levels.end as usize);
|
||||
for mip in self.mips[mip_start .. mip_end].iter() {
|
||||
for &(aspects, ref plane_states) in mip {
|
||||
if !selector.aspects.intersects(aspects) {
|
||||
continue;
|
||||
}
|
||||
match plane_states.query(&selector.layers, |unit| unit.last) {
|
||||
None => {}
|
||||
Some(Ok(usage)) if result == Some(usage) => {}
|
||||
Some(Ok(usage)) if result.is_none() => {
|
||||
result = Some(usage);
|
||||
}
|
||||
Some(Ok(_)) | Some(Err(())) => return None,
|
||||
match mip.query(&selector.layers, |unit| unit.last) {
|
||||
None => {}
|
||||
Some(Ok(usage)) if result == Some(usage) => {}
|
||||
Some(Ok(usage)) if result.is_none() => {
|
||||
result = Some(usage);
|
||||
}
|
||||
Some(Ok(_)) | Some(Err(())) => return None,
|
||||
}
|
||||
}
|
||||
result
|
||||
@ -91,44 +88,44 @@ impl ResourceState for TextureState {
|
||||
usage: Self::Usage,
|
||||
mut output: Option<&mut Vec<PendingTransition<Self>>>,
|
||||
) -> Result<(), PendingTransition<Self>> {
|
||||
if self.full {
|
||||
assert!(self.mips.len() >= selector.levels.end as usize);
|
||||
} else {
|
||||
while self.mips.len() < selector.levels.end as usize {
|
||||
self.mips.push(PlaneStates::empty());
|
||||
}
|
||||
}
|
||||
for (mip_id, mip) in self.mips
|
||||
[selector.levels.start as usize .. selector.levels.end as usize]
|
||||
.iter_mut()
|
||||
.enumerate()
|
||||
{
|
||||
let level = selector.levels.start + mip_id as hal::image::Level;
|
||||
for &mut (mip_aspects, ref mut plane_states) in mip {
|
||||
let aspects = selector.aspects & mip_aspects;
|
||||
if aspects.is_empty() {
|
||||
let layers = mip.isolate(&selector.layers, Unit::new(usage));
|
||||
for &mut (ref range, ref mut unit) in layers {
|
||||
if unit.last == usage && TextureUsage::ORDERED.contains(usage) {
|
||||
continue;
|
||||
}
|
||||
debug_assert_eq!(aspects, mip_aspects);
|
||||
let layers = plane_states.isolate(&selector.layers, Unit::new(usage));
|
||||
for &mut (ref range, ref mut unit) in layers {
|
||||
if unit.last == usage && TextureUsage::ORDERED.contains(usage) {
|
||||
continue;
|
||||
}
|
||||
let pending = PendingTransition {
|
||||
id,
|
||||
selector: hal::image::SubresourceRange {
|
||||
aspects,
|
||||
levels: level .. level + 1,
|
||||
layers: range.clone(),
|
||||
},
|
||||
usage: unit.last .. usage,
|
||||
};
|
||||
let pending = PendingTransition {
|
||||
id,
|
||||
selector: hal::image::SubresourceRange {
|
||||
aspects: hal::format::Aspects::empty(),
|
||||
levels: level .. level + 1,
|
||||
layers: range.clone(),
|
||||
},
|
||||
usage: unit.last .. usage,
|
||||
};
|
||||
|
||||
unit.last = match output {
|
||||
None => pending.collapse()?,
|
||||
Some(ref mut out) => {
|
||||
out.push(pending);
|
||||
if unit.first.is_none() {
|
||||
unit.first = Some(unit.last);
|
||||
}
|
||||
usage
|
||||
unit.last = match output {
|
||||
None => pending.collapse()?,
|
||||
Some(ref mut out) => {
|
||||
out.push(pending);
|
||||
if unit.first.is_none() {
|
||||
unit.first = Some(unit.last);
|
||||
}
|
||||
};
|
||||
}
|
||||
usage
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@ -141,74 +138,75 @@ impl ResourceState for TextureState {
|
||||
mut output: Option<&mut Vec<PendingTransition<Self>>>,
|
||||
) -> Result<(), PendingTransition<Self>> {
|
||||
let mut temp = Vec::new();
|
||||
while self.mips.len() < other.mips.len() as usize {
|
||||
self.mips.push(MipState::default());
|
||||
if self.full {
|
||||
assert!(self.mips.len() >= other.mips.len());
|
||||
} else {
|
||||
while self.mips.len() < other.mips.len() {
|
||||
self.mips.push(PlaneStates::empty());
|
||||
}
|
||||
}
|
||||
|
||||
for (mip_id, (mip_self, mip_other)) in self.mips.iter_mut().zip(&other.mips).enumerate() {
|
||||
let level = mip_id as hal::image::Level;
|
||||
for (&mut (aspects, ref mut planes_self), &(aspects_other, ref planes_other)) in mip_self.iter_mut().zip(mip_other) {
|
||||
debug_assert_eq!(aspects, aspects_other);
|
||||
temp.extend(planes_self.merge(planes_other, 0));
|
||||
planes_self.clear();
|
||||
temp.extend(mip_self.merge(mip_other, 0));
|
||||
mip_self.clear();
|
||||
|
||||
for (layers, states) in temp.drain(..) {
|
||||
let unit = match states {
|
||||
Range {
|
||||
start: None,
|
||||
end: None,
|
||||
} => unreachable!(),
|
||||
Range {
|
||||
start: Some(start),
|
||||
end: None,
|
||||
} => start,
|
||||
Range {
|
||||
start: None,
|
||||
end: Some(end),
|
||||
} => end,
|
||||
Range {
|
||||
start: Some(start),
|
||||
end: Some(end),
|
||||
} => {
|
||||
let to_usage = end.port();
|
||||
if start.last == to_usage
|
||||
&& TextureUsage::ORDERED.contains(to_usage)
|
||||
{
|
||||
Unit {
|
||||
first: start.first,
|
||||
last: end.last,
|
||||
}
|
||||
} else {
|
||||
let pending = PendingTransition {
|
||||
id,
|
||||
selector: hal::image::SubresourceRange {
|
||||
aspects,
|
||||
levels: level .. level+1,
|
||||
layers: layers.clone(),
|
||||
},
|
||||
usage: start.last .. to_usage,
|
||||
};
|
||||
for (layers, states) in temp.drain(..) {
|
||||
let unit = match states {
|
||||
Range {
|
||||
start: None,
|
||||
end: None,
|
||||
} => unreachable!(),
|
||||
Range {
|
||||
start: Some(start),
|
||||
end: None,
|
||||
} => start,
|
||||
Range {
|
||||
start: None,
|
||||
end: Some(end),
|
||||
} => end,
|
||||
Range {
|
||||
start: Some(start),
|
||||
end: Some(end),
|
||||
} => {
|
||||
let to_usage = end.port();
|
||||
if start.last == to_usage
|
||||
&& TextureUsage::ORDERED.contains(to_usage)
|
||||
{
|
||||
Unit {
|
||||
first: start.first,
|
||||
last: end.last,
|
||||
}
|
||||
} else {
|
||||
let pending = PendingTransition {
|
||||
id,
|
||||
selector: hal::image::SubresourceRange {
|
||||
aspects: hal::format::Aspects::empty(),
|
||||
levels: level .. level+1,
|
||||
layers: layers.clone(),
|
||||
},
|
||||
usage: start.last .. to_usage,
|
||||
};
|
||||
|
||||
match output {
|
||||
None => {
|
||||
Unit {
|
||||
first: start.first,
|
||||
last: pending.collapse()?,
|
||||
}
|
||||
match output {
|
||||
None => {
|
||||
Unit {
|
||||
first: start.first,
|
||||
last: pending.collapse()?,
|
||||
}
|
||||
Some(ref mut out) => {
|
||||
out.push(pending);
|
||||
Unit {
|
||||
first: Some(start.last),
|
||||
last: end.last,
|
||||
}
|
||||
}
|
||||
Some(ref mut out) => {
|
||||
out.push(pending);
|
||||
Unit {
|
||||
first: Some(start.last),
|
||||
last: end.last,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
planes_self.append(layers, unit);
|
||||
}
|
||||
}
|
||||
};
|
||||
mip_self.append(layers, unit);
|
||||
}
|
||||
}
|
||||
|
||||
@ -217,9 +215,7 @@ impl ResourceState for TextureState {
|
||||
|
||||
fn optimize(&mut self) {
|
||||
for mip in self.mips.iter_mut() {
|
||||
for &mut (_, ref mut planes) in mip.iter_mut() {
|
||||
planes.coalesce();
|
||||
}
|
||||
mip.coalesce();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -234,16 +230,14 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn query() {
|
||||
let mut ts = TextureState::new(&SubresourceRange {
|
||||
aspects: Aspects::COLOR,
|
||||
levels: 0 .. 2,
|
||||
layers: 0 .. 10,
|
||||
});
|
||||
ts.mips[1][0].1 = PlaneStates::new(&[
|
||||
let mut ts = TextureState::default();
|
||||
ts.mips.push(PlaneStates::empty());
|
||||
ts.mips.push(PlaneStates::from_slice(&[
|
||||
(1 .. 3, Unit::new(TextureUsage::SAMPLED)),
|
||||
(3 .. 5, Unit::new(TextureUsage::SAMPLED)),
|
||||
(5 .. 6, Unit::new(TextureUsage::STORAGE)),
|
||||
]);
|
||||
]));
|
||||
|
||||
assert_eq!(
|
||||
ts.query(SubresourceRange {
|
||||
aspects: Aspects::COLOR,
|
||||
@ -253,15 +247,6 @@ mod test {
|
||||
// level 1 matches
|
||||
Some(TextureUsage::SAMPLED),
|
||||
);
|
||||
assert_eq!(
|
||||
ts.query(SubresourceRange {
|
||||
aspects: Aspects::DEPTH,
|
||||
levels: 1 .. 2,
|
||||
layers: 2 .. 5,
|
||||
}),
|
||||
// no depth found
|
||||
None,
|
||||
);
|
||||
assert_eq!(
|
||||
ts.query(SubresourceRange {
|
||||
aspects: Aspects::COLOR,
|
||||
|
@ -8,8 +8,6 @@ use core::{gfx_select, hub::Token, id};
|
||||
|
||||
use std::{marker::PhantomData, slice};
|
||||
|
||||
use libc::{c_ulong};
|
||||
|
||||
pub type RequestAdapterCallback =
|
||||
unsafe extern "C" fn(id: id::AdapterId, userdata: *mut std::ffi::c_void);
|
||||
pub type BufferMapReadCallback =
|
||||
@ -80,7 +78,7 @@ pub fn wgpu_create_surface(raw_handle: raw_window_handle::RawWindowHandle) -> id
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wgpu_create_surface_from_xlib(
|
||||
display: *mut *const std::ffi::c_void,
|
||||
window: c_ulong,
|
||||
window: libc::c_ulong,
|
||||
) -> id::SurfaceId {
|
||||
use raw_window_handle::unix::XlibHandle;
|
||||
wgpu_create_surface(raw_window_handle::RawWindowHandle::Xlib(XlibHandle {
|
||||
|
Loading…
Reference in New Issue
Block a user