Refactor usage tracking to be truly sparse

This commit is contained in:
Dzmitry Malyshau 2020-01-06 21:20:35 -05:00
parent ba0acc94a1
commit 017a54ff97
9 changed files with 322 additions and 351 deletions

View File

@ -174,12 +174,7 @@ impl<F> Global<F> {
); );
assert!(src_buffer.usage.contains(BufferUsage::INDIRECT)); assert!(src_buffer.usage.contains(BufferUsage::INDIRECT));
let barriers = src_pending.map(|pending| hal::memory::Barrier::Buffer { let barriers = src_pending.map(|pending| pending.into_hal(src_buffer));
states: pending.to_states(),
target: &src_buffer.raw,
families: None,
range: None .. None,
});
unsafe { unsafe {
pass.raw.pipeline_barrier( pass.raw.pipeline_barrier(

View File

@ -44,7 +44,15 @@ use crate::{
use arrayvec::ArrayVec; use arrayvec::ArrayVec;
use hal::{adapter::PhysicalDevice as _, command::CommandBuffer as _, device::Device as _}; 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> { pub struct RenderBundle<B: hal::Backend> {
@ -128,25 +136,15 @@ impl<B: GfxBackend> CommandBuffer<B> {
.buffers .buffers
.merge_replace(&head.buffers) .merge_replace(&head.buffers)
.map(|pending| { .map(|pending| {
log::trace!("\tbuffer -> {:?}", pending); let buf = &buffer_guard[pending.id];
hal::memory::Barrier::Buffer { pending.into_hal(buf)
states: pending.to_states(),
target: &buffer_guard[pending.id].raw,
range: None .. None,
families: None,
}
}); });
let texture_barriers = base let texture_barriers = base
.textures .textures
.merge_replace(&head.textures) .merge_replace(&head.textures)
.map(|pending| { .map(|pending| {
log::trace!("\ttexture -> {:?}", pending); let tex = &texture_guard[pending.id];
hal::memory::Barrier::Image { pending.into_hal(tex)
states: pending.to_states(),
target: &texture_guard[pending.id].raw,
range: pending.selector,
families: None,
}
}); });
base.views.merge_extend(&head.views).unwrap(); base.views.merge_extend(&head.views).unwrap();
base.bind_groups.merge_extend(&head.bind_groups).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( let first_use = cmb.trackers.views.init(
at.attachment, at.attachment,
view.life_guard.add_ref(), view.life_guard.add_ref(),
&(), PhantomData,
).is_some(); ).is_some();
let layouts = match view.inner { let layouts = match view.inner {
@ -388,7 +386,7 @@ impl<F: IdentityFilter<RenderPassId>> Global<F> {
let first_use = cmb.trackers.views.init( let first_use = cmb.trackers.views.init(
resolve_target, resolve_target,
view.life_guard.add_ref(), view.life_guard.add_ref(),
&(), PhantomData,
).is_some(); ).is_some();
let layouts = match view.inner { let layouts = match view.inner {
@ -451,15 +449,13 @@ impl<F: IdentityFilter<RenderPassId>> Global<F> {
assert!(texture.usage.contains(TextureUsage::OUTPUT_ATTACHMENT)); assert!(texture.usage.contains(TextureUsage::OUTPUT_ATTACHMENT));
let usage = consistent_usage.unwrap_or(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.value,
source_id.ref_count.clone(), &source_id.ref_count,
&texture.full_range, view_range.clone(),
) { usage,
Some(mut init) => init.set(view_range.clone(), usage), );
None => panic!("Your texture {:?} is in the another attachment!", source_id.value),
};
if consistent_usage.is_some() { if consistent_usage.is_some() {
// If we expect the texture to be transited to a new state by the // If we expect the texture to be transited to a new state by the
// render pass configuration, make the tracker aware of that. // render pass configuration, make the tracker aware of that.
@ -468,7 +464,6 @@ impl<F: IdentityFilter<RenderPassId>> Global<F> {
&source_id.ref_count, &source_id.ref_count,
view_range.clone(), view_range.clone(),
TextureUsage::OUTPUT_ATTACHMENT, TextureUsage::OUTPUT_ATTACHMENT,
&texture.full_range,
); );
}; };
} }

View File

@ -85,13 +85,7 @@ impl<F> Global<F> {
.buffers .buffers
.use_replace(&*buffer_guard, source, (), BufferUsage::COPY_SRC); .use_replace(&*buffer_guard, source, (), BufferUsage::COPY_SRC);
assert!(src_buffer.usage.contains(BufferUsage::COPY_SRC)); assert!(src_buffer.usage.contains(BufferUsage::COPY_SRC));
barriers.extend(src_pending.map(|pending| pending.into_hal(src_buffer)));
barriers.extend(src_pending.map(|pending| hal::memory::Barrier::Buffer {
states: pending.to_states(),
target: &src_buffer.raw,
families: None,
range: None .. None,
}));
let (dst_buffer, dst_pending) = cmb.trackers.buffers.use_replace( let (dst_buffer, dst_pending) = cmb.trackers.buffers.use_replace(
&*buffer_guard, &*buffer_guard,
@ -100,13 +94,7 @@ impl<F> Global<F> {
BufferUsage::COPY_DST, BufferUsage::COPY_DST,
); );
assert!(dst_buffer.usage.contains(BufferUsage::COPY_DST)); assert!(dst_buffer.usage.contains(BufferUsage::COPY_DST));
barriers.extend(dst_pending.map(|pending| pending.into_hal(dst_buffer)));
barriers.extend(dst_pending.map(|pending| hal::memory::Barrier::Buffer {
states: pending.to_states(),
target: &dst_buffer.raw,
families: None,
range: None .. None,
}));
let region = hal::command::BufferCopy { let region = hal::command::BufferCopy {
src: source_offset, src: source_offset,
@ -146,13 +134,7 @@ impl<F> Global<F> {
BufferUsage::COPY_SRC, BufferUsage::COPY_SRC,
); );
assert!(src_buffer.usage.contains(BufferUsage::COPY_SRC)); assert!(src_buffer.usage.contains(BufferUsage::COPY_SRC));
let src_barriers = src_pending.map(|pending| pending.into_hal(src_buffer));
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 (dst_texture, dst_pending) = cmb.trackers.textures.use_replace( let (dst_texture, dst_pending) = cmb.trackers.textures.use_replace(
&*texture_guard, &*texture_guard,
@ -161,13 +143,7 @@ impl<F> Global<F> {
TextureUsage::COPY_DST, TextureUsage::COPY_DST,
); );
assert!(dst_texture.usage.contains(TextureUsage::COPY_DST)); assert!(dst_texture.usage.contains(TextureUsage::COPY_DST));
let dst_barriers = dst_pending.map(|pending| pending.into_hal(dst_texture));
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 bytes_per_texel = conv::map_texture_format(dst_texture.format, cmb.features) let bytes_per_texel = conv::map_texture_format(dst_texture.format, cmb.features)
.surface_desc() .surface_desc()
@ -222,13 +198,7 @@ impl<F> Global<F> {
TextureUsage::COPY_SRC, TextureUsage::COPY_SRC,
); );
assert!(src_texture.usage.contains(TextureUsage::COPY_SRC)); assert!(src_texture.usage.contains(TextureUsage::COPY_SRC));
let src_barriers = src_pending.map(|pending| pending.into_hal(src_texture));
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 (dst_buffer, dst_barriers) = cmb.trackers.buffers.use_replace( let (dst_buffer, dst_barriers) = cmb.trackers.buffers.use_replace(
&*buffer_guard, &*buffer_guard,
@ -237,13 +207,7 @@ impl<F> Global<F> {
BufferUsage::COPY_DST, BufferUsage::COPY_DST,
); );
assert!(dst_buffer.usage.contains(BufferUsage::COPY_DST)); assert!(dst_buffer.usage.contains(BufferUsage::COPY_DST));
let dst_barrier = dst_barriers.map(|pending| pending.into_hal(dst_buffer));
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 bytes_per_texel = conv::map_texture_format(src_texture.format, cmb.features) let bytes_per_texel = conv::map_texture_format(src_texture.format, cmb.features)
.surface_desc() .surface_desc()
@ -303,13 +267,7 @@ impl<F> Global<F> {
TextureUsage::COPY_SRC, TextureUsage::COPY_SRC,
); );
assert!(src_texture.usage.contains(TextureUsage::COPY_SRC)); assert!(src_texture.usage.contains(TextureUsage::COPY_SRC));
barriers.extend(src_pending.map(|pending| pending.into_hal(src_texture)));
barriers.extend(src_pending.map(|pending| hal::memory::Barrier::Image {
states: pending.to_states(),
target: &src_texture.raw,
families: None,
range: pending.selector,
}));
let (dst_texture, dst_pending) = cmb.trackers.textures.use_replace( let (dst_texture, dst_pending) = cmb.trackers.textures.use_replace(
&*texture_guard, &*texture_guard,
@ -318,13 +276,7 @@ impl<F> Global<F> {
TextureUsage::COPY_DST, TextureUsage::COPY_DST,
); );
assert!(dst_texture.usage.contains(TextureUsage::COPY_DST)); assert!(dst_texture.usage.contains(TextureUsage::COPY_DST));
barriers.extend(dst_pending.map(|pending| pending.into_hal(dst_texture)));
barriers.extend(dst_pending.map(|pending| hal::memory::Barrier::Image {
states: pending.to_states(),
target: &dst_texture.raw,
families: None,
range: pending.selector,
}));
let region = hal::command::ImageCopy { let region = hal::command::ImageCopy {
src_subresource: source.to_sub_layers(aspects), src_subresource: source.to_sub_layers(aspects),

View File

@ -11,7 +11,7 @@ use crate::{
pipeline, pipeline,
resource, resource,
swap_chain, swap_chain,
track::{SEPARATE_DEPTH_STENCIL_STATES, TrackerSet}, track::{BufferState, TextureState, TrackerSet},
BufferAddress, BufferAddress,
FastHashMap, FastHashMap,
Features, Features,
@ -36,6 +36,7 @@ use std::{
collections::hash_map::Entry, collections::hash_map::Entry,
ffi, ffi,
iter, iter,
marker::PhantomData,
ops, ops,
ptr, ptr,
slice, slice,
@ -473,13 +474,18 @@ impl<F: IdentityFilter<id::BufferId>> Global<F> {
let device = &device_guard[device_id]; let device = &device_guard[device_id];
let buffer = device.create_buffer(device_id, desc); let buffer = device.create_buffer(device_id, desc);
let ref_count = buffer.life_guard.add_ref(); let ref_count = buffer.life_guard.add_ref();
let range = buffer.full_range;
let id = hub.buffers.register_identity(id_in, buffer, &mut token); let id = hub.buffers.register_identity(id_in, buffer, &mut token);
device device
.trackers .trackers
.lock() .lock()
.buffers .buffers
.init(id, ref_count, &()) .init(
id,
ref_count,
BufferState::from_selector(&range),
)
.unwrap(); .unwrap();
id id
} }
@ -499,6 +505,7 @@ impl<F: IdentityFilter<id::BufferId>> Global<F> {
let device = &device_guard[device_id]; let device = &device_guard[device_id];
let mut buffer = device.create_buffer(device_id, &desc); let mut buffer = device.create_buffer(device_id, &desc);
let ref_count = buffer.life_guard.add_ref(); 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) { let pointer = match map_buffer(&device.raw, &mut buffer, 0 .. desc.size, HostMap::Write) {
Ok(ptr) => ptr, Ok(ptr) => ptr,
@ -514,7 +521,7 @@ impl<F: IdentityFilter<id::BufferId>> Global<F> {
.buffers.init( .buffers.init(
id, id,
ref_count, ref_count,
&(), BufferState::from_selector(&range),
) )
.unwrap() .unwrap()
.set((), resource::BufferUsage::MAP_WRITE); .set((), resource::BufferUsage::MAP_WRITE);
@ -632,7 +639,7 @@ impl<F: IdentityFilter<id::TextureId>> Global<F> {
.textures.init( .textures.init(
id, id,
ref_count, ref_count,
&range, TextureState::from_selector(&range),
) )
.unwrap() .unwrap()
.set(range, resource::TextureUsage::UNINITIALIZED); .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 (desc.base_array_layer + desc.array_layer_count) as u16
}; };
let range = hal::image::SubresourceRange { let range = hal::image::SubresourceRange {
aspects: if SEPARATE_DEPTH_STENCIL_STATES { aspects: texture.full_range.aspects,
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
},
levels: desc.base_mip_level as u8 .. end_level, levels: desc.base_mip_level as u8 .. end_level,
layers: desc.base_array_layer as u16 .. end_layer, 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); let id = hub.texture_views.register_identity(id_in, view, &mut token);
device.trackers device.trackers
.lock() .lock()
.views.init(id, ref_count, &()) .views.init(id, ref_count, PhantomData)
.unwrap(); .unwrap();
id id
} }
@ -822,7 +821,7 @@ impl<F: IdentityFilter<id::SamplerId>> Global<F> {
let id = hub.samplers.register_identity(id_in, sampler, &mut token); let id = hub.samplers.register_identity(id_in, sampler, &mut token);
device.trackers device.trackers
.lock() .lock()
.samplers.init(id, ref_count, &()) .samplers.init(id, ref_count, PhantomData)
.unwrap(); .unwrap();
id id
} }
@ -1080,7 +1079,6 @@ impl<F: IdentityFilter<id::BindGroupId>> Global<F> {
&source_id.ref_count, &source_id.ref_count,
view.range.clone(), view.range.clone(),
usage, usage,
&texture.full_range,
) )
.unwrap(); .unwrap();
assert!(texture.usage.contains(usage)); assert!(texture.usage.contains(usage));
@ -1130,7 +1128,7 @@ impl<F: IdentityFilter<id::BindGroupId>> Global<F> {
.trackers .trackers
.lock() .lock()
.bind_groups .bind_groups
.init(id, ref_count, &()) .init(id, ref_count, PhantomData)
.unwrap(); .unwrap();
id id
} }
@ -1886,7 +1884,7 @@ impl<F> Global<F> {
let mut token = Token::root(); let mut token = Token::root();
let (device_guard, mut token) = hub.devices.read(&mut token); 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 (mut buffer_guard, _) = hub.buffers.write(&mut token);
let buffer = &mut buffer_guard[buffer_id]; let buffer = &mut buffer_guard[buffer_id];
@ -1906,13 +1904,9 @@ impl<F> Global<F> {
buffer.pending_mapping = Some(resource::BufferPendingMapping { buffer.pending_mapping = Some(resource::BufferPendingMapping {
range, range,
op: operation, 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.device_id.value,
buffer.life_guard.add_ref(),
buffer.full_range,
)
}; };
let device = &device_guard[device_id]; let device = &device_guard[device_id];
@ -1921,7 +1915,7 @@ impl<F> Global<F> {
.trackers .trackers
.lock() .lock()
.buffers .buffers
.change_replace(buffer_id, &ref_count, (), usage, &full_range); .change_replace(buffer_id, &ref_count, (), usage);
device device
.lock_life(&mut token) .lock_life(&mut token)

View File

@ -3,18 +3,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use super::{PendingTransition, ResourceState, Unit}; use super::{PendingTransition, ResourceState, Unit};
use crate::{conv, id::BufferId, resource::BufferUsage}; use crate::{id::BufferId, resource::BufferUsage};
use std::ops::Range;
//TODO: store `hal::buffer::State` here to avoid extra conversions //TODO: store `hal::buffer::State` here to avoid extra conversions
pub type BufferState = Unit<BufferUsage>; pub type BufferState = Unit<BufferUsage>;
impl PendingTransition<BufferState> { 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> { fn collapse(self) -> Result<BufferUsage, Self> {
if self.usage.start.is_empty() if self.usage.start.is_empty()
|| self.usage.start == self.usage.end || self.usage.start == self.usage.end
@ -27,17 +21,25 @@ impl PendingTransition<BufferState> {
} }
} }
impl ResourceState for BufferState { impl Default for BufferState {
type Id = BufferId; fn default() -> Self {
type Selector = ();
type Usage = BufferUsage;
fn new(_full_selector: &Self::Selector) -> Self {
BufferState { BufferState {
first: None, first: None,
last: BufferUsage::empty(), 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> { fn query(&self, _selector: Self::Selector) -> Option<Self::Usage> {
Some(self.last) Some(self.last)

View File

@ -7,8 +7,10 @@ mod range;
mod texture; mod texture;
use crate::{ use crate::{
conv,
hub::Storage, hub::Storage,
id::{BindGroupId, SamplerId, TextureViewId, TypedId}, id::{BindGroupId, SamplerId, TextureViewId, TypedId},
resource,
Backend, Backend,
Epoch, Epoch,
FastHashMap, FastHashMap,
@ -21,16 +23,14 @@ use std::{
collections::hash_map::Entry, collections::hash_map::Entry,
fmt, fmt,
marker::PhantomData, marker::PhantomData,
ops::Range, ops,
vec::Drain, vec::Drain,
}; };
use buffer::BufferState; pub use buffer::BufferState;
use texture::TextureState; pub use texture::TextureState;
pub const SEPARATE_DEPTH_STENCIL_STATES: bool = false;
/// A single unit of state tracking. It keeps an initial /// A single unit of state tracking. It keeps an initial
/// usage as well as the last/current one, similar to `Range`. /// usage as well as the last/current one, similar to `Range`.
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
@ -56,7 +56,7 @@ impl<U: Copy> Unit<U> {
/// The main trait that abstracts away the tracking logic of /// The main trait that abstracts away the tracking logic of
/// a particular resource type, like a buffer or a texture. /// a particular resource type, like a buffer or a texture.
pub trait ResourceState: Clone { pub trait ResourceState: Clone + Default {
/// Corresponding `HUB` identifier. /// Corresponding `HUB` identifier.
type Id: Copy + fmt::Debug + TypedId; type Id: Copy + fmt::Debug + TypedId;
/// A type specifying the sub-resources. /// A type specifying the sub-resources.
@ -64,9 +64,6 @@ pub trait ResourceState: Clone {
/// Usage type for a `Unit` of a sub-resource. /// Usage type for a `Unit` of a sub-resource.
type Usage: fmt::Debug; 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 /// Check if all the selected sub-resources have the same
/// usage, and return it. /// usage, and return it.
/// ///
@ -129,7 +126,44 @@ struct Resource<S> {
pub struct PendingTransition<S: ResourceState> { pub struct PendingTransition<S: ResourceState> {
pub id: S::Id, pub id: S::Id,
pub selector: S::Selector, 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 /// Helper initialization structure that allows setting the usage on
@ -238,7 +272,7 @@ impl<S: ResourceState> ResourceTracker<S> {
&mut self, &mut self,
id: S::Id, id: S::Id,
ref_count: RefCount, ref_count: RefCount,
full_selector: &S::Selector, state: S,
) -> Option<Initializer<S>> { ) -> Option<Initializer<S>> {
let (index, epoch, backend) = id.unzip(); let (index, epoch, backend) = id.unzip();
debug_assert_eq!(backend, self.backend); debug_assert_eq!(backend, self.backend);
@ -246,7 +280,7 @@ impl<S: ResourceState> ResourceTracker<S> {
Entry::Vacant(e) => { Entry::Vacant(e) => {
let res = e.insert(Resource { let res = e.insert(Resource {
ref_count, ref_count,
state: S::new(full_selector), state,
epoch, epoch,
}); });
Some(Initializer { Some(Initializer {
@ -277,14 +311,13 @@ impl<S: ResourceState> ResourceTracker<S> {
map: &'a mut FastHashMap<Index, Resource<S>>, map: &'a mut FastHashMap<Index, Resource<S>>,
id: S::Id, id: S::Id,
ref_count: &RefCount, ref_count: &RefCount,
full_selector: &S::Selector,
) -> &'a mut Resource<S> { ) -> &'a mut Resource<S> {
let (index, epoch, backend) = id.unzip(); let (index, epoch, backend) = id.unzip();
debug_assert_eq!(self_backend, backend); debug_assert_eq!(self_backend, backend);
match map.entry(index) { match map.entry(index) {
Entry::Vacant(e) => e.insert(Resource { Entry::Vacant(e) => e.insert(Resource {
ref_count: ref_count.clone(), ref_count: ref_count.clone(),
state: S::new(full_selector), state: S::default(),
epoch, epoch,
}), }),
Entry::Occupied(e) => { Entry::Occupied(e) => {
@ -303,9 +336,8 @@ impl<S: ResourceState> ResourceTracker<S> {
ref_count: &RefCount, ref_count: &RefCount,
selector: S::Selector, selector: S::Selector,
usage: S::Usage, usage: S::Usage,
full_selector: &S::Selector,
) -> Result<(), PendingTransition<S>> { ) -> 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 .state
.change(id, selector, usage, None) .change(id, selector, usage, None)
} }
@ -317,9 +349,8 @@ impl<S: ResourceState> ResourceTracker<S> {
ref_count: &RefCount, ref_count: &RefCount,
selector: S::Selector, selector: S::Selector,
usage: S::Usage, usage: S::Usage,
full_selector: &S::Selector,
) -> Drain<PendingTransition<S>> { ) -> 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 res.state
.change(id, selector, usage, Some(&mut self.temp)) .change(id, selector, usage, Some(&mut self.temp))
.ok(); //TODO: unwrap? .ok(); //TODO: unwrap?
@ -376,7 +407,7 @@ impl<S: ResourceState> ResourceTracker<S> {
/// the last read-only usage, if possible. /// the last read-only usage, if possible.
/// ///
/// Returns the old usage as an error if there is a conflict. /// 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, &mut self,
storage: &'a Storage<T, S::Id>, storage: &'a Storage<T, S::Id>,
id: S::Id, id: S::Id,
@ -384,7 +415,7 @@ impl<S: ResourceState> ResourceTracker<S> {
usage: S::Usage, usage: S::Usage,
) -> Result<&'a T, S::Usage> { ) -> Result<&'a T, S::Usage> {
let item = &storage[id]; 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(|()| item)
.map_err(|pending| pending.usage.start) .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 /// Combines storage access by 'Id' with the transition that replaces
/// the last usage with a new one, returning an iterator over these /// the last usage with a new one, returning an iterator over these
/// transitions. /// transitions.
pub fn use_replace<'a, T: 'a + Borrow<RefCount> + Borrow<S::Selector>>( pub fn use_replace<'a, T: 'a + Borrow<RefCount>>(
&mut self, &mut self,
storage: &'a Storage<T, S::Id>, storage: &'a Storage<T, S::Id>,
id: S::Id, id: S::Id,
@ -401,7 +432,7 @@ impl<S: ResourceState> ResourceTracker<S> {
usage: S::Usage, usage: S::Usage,
) -> (&'a T, Drain<PendingTransition<S>>) { ) -> (&'a T, Drain<PendingTransition<S>>) {
let item = &storage[id]; 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) (item, drain)
} }
} }
@ -412,10 +443,6 @@ impl<I: Copy + fmt::Debug + TypedId> ResourceState for PhantomData<I> {
type Selector = (); type Selector = ();
type Usage = (); type Usage = ();
fn new(_full_selector: &Self::Selector) -> Self {
PhantomData
}
fn query(&self, _selector: Self::Selector) -> Option<Self::Usage> { fn query(&self, _selector: Self::Selector) -> Option<Self::Usage> {
Some(()) Some(())
} }

View File

@ -2,7 +2,15 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * 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, /// Structure that keeps track of a I -> T mapping,
/// optimized for a case where keys of the same values /// 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> { pub struct RangedStates<I, T> {
/// List of ranges, each associated with a singe value. /// List of ranges, each associated with a singe value.
/// Ranges of keys have to be non-intersecting and ordered. /// Ranges of keys have to be non-intersecting and ordered.
ranges: Vec<(Range<I>, T)>, ranges: SmallVec<[(Range<I>, T); 1]>,
}
impl<I, T> Default for RangedStates<I, T> {
fn default() -> Self {
RangedStates { ranges: Vec::new() }
}
} }
impl<I: Copy + PartialOrd, T: Copy + PartialEq> RangedStates<I, T> { 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. /// Construct a new instance from a slice of ranges.
#[cfg(test)] #[cfg(test)]
pub fn new(values: &[(Range<I>, T)]) -> Self { pub fn from_slice(values: &[(Range<I>, T)]) -> Self {
RangedStates { 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)] #[derive(Debug)]
pub struct Merge<'a, I, T> { pub struct Merge<'a, I, T> {
base: I, base: I,
sa: Peekable<Iter<'a, (Range<I>, T)>>, sa: iter::Peekable<Iter<'a, (Range<I>, T)>>,
sb: 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> { 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}; use std::{fmt::Debug, ops::Range};
fn easy_merge<T: PartialEq + Copy + Debug>( fn easy_merge<T: PartialEq + Copy + Debug>(
ra: Vec<(Range<usize>, T)>, ra: &[(Range<usize>, T)],
rb: Vec<(Range<usize>, T)>, rb: &[(Range<usize>, T)],
) -> Vec<(Range<usize>, Range<Option<T>>)> { ) -> Vec<(Range<usize>, Range<Option<T>>)> {
RangedStates { ranges: ra } RangedStates::from_slice(ra)
.merge(&RangedStates { ranges: rb }, 0) .merge(&RangedStates::from_slice(rb), 0)
.collect() .collect()
} }
#[test] #[test]
fn sane_good() { fn sane_good() {
let rs = RangedStates { let rs = RangedStates::from_slice(
ranges: vec![(1 .. 4, 9u8), (4 .. 5, 9)], &[(1 .. 4, 9u8), (4 .. 5, 9)],
}; );
rs.check_sanity(); rs.check_sanity();
} }
#[test] #[test]
#[should_panic] #[should_panic]
fn sane_empty() { fn sane_empty() {
let rs = RangedStates { let rs = RangedStates::from_slice(
ranges: vec![(1 .. 4, 9u8), (5 .. 5, 9)], &[(1 .. 4, 9u8), (5 .. 5, 9)],
}; );
rs.check_sanity(); rs.check_sanity();
} }
#[test] #[test]
#[should_panic] #[should_panic]
fn sane_intersect() { fn sane_intersect() {
let rs = RangedStates { let rs = RangedStates::from_slice(
ranges: vec![(1 .. 4, 9u8), (3 .. 5, 9)], &[(1 .. 4, 9u8), (3 .. 5, 9)],
}; );
rs.check_sanity(); rs.check_sanity();
} }
#[test] #[test]
fn coalesce() { fn coalesce() {
let mut rs = RangedStates { let mut rs = RangedStates::from_slice(
ranges: vec![(1 .. 4, 9u8), (4 .. 5, 9), (5 .. 7, 1), (8 .. 9, 1)], &[(1 .. 4, 9u8), (4 .. 5, 9), (5 .. 7, 1), (8 .. 9, 1)],
}; );
rs.coalesce(); rs.coalesce();
rs.check_sanity(); 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] #[test]
fn query() { fn query() {
let rs = RangedStates { let rs = RangedStates::from_slice(
ranges: vec![(1 .. 4, 1u8), (5 .. 7, 2)], &[(1 .. 4, 1u8), (5 .. 7, 2)],
}; );
assert_eq!(rs.query(&(0 .. 1), |v| *v), None); 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 .. 3), |v| *v), Some(Ok(1)));
assert_eq!(rs.query(&(1 .. 6), |v| *v), Some(Err(()))); assert_eq!(rs.query(&(1 .. 6), |v| *v), Some(Err(())));
@ -324,9 +341,9 @@ mod test {
#[test] #[test]
fn isolate() { fn isolate() {
let rs = RangedStates { let rs = RangedStates::from_slice(
ranges: vec![(1 .. 4, 9u8), (4 .. 5, 9), (5 .. 7, 1), (8 .. 9, 1)], &[(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(4 .. 5, 0), &[(4 .. 5, 9u8),]);
assert_eq!( assert_eq!(
&rs.sanely_isolated(0 .. 6, 0), &rs.sanely_isolated(0 .. 6, 0),
@ -345,28 +362,31 @@ mod test {
#[test] #[test]
fn merge_same() { fn merge_same() {
assert_eq!( assert_eq!(
easy_merge(vec![(1 .. 4, 0u8),], vec![(1 .. 4, 2u8),],), &easy_merge(&[(1 .. 4, 0u8),], &[(1 .. 4, 2u8),],),
vec![(1 .. 4, Some(0) .. Some(2)),] &[(1 .. 4, Some(0) .. Some(2)),]
); );
} }
#[test] #[test]
fn merge_empty() { fn merge_empty() {
assert_eq!( assert_eq!(
easy_merge(vec![(1 .. 2, 0u8),], vec![],), &easy_merge(&[(1 .. 2, 0u8),], &[],),
vec![(1 .. 2, Some(0) .. None),] &[(1 .. 2, Some(0) .. None),]
); );
assert_eq!( assert_eq!(
easy_merge(vec![], vec![(3 .. 4, 1u8),],), &easy_merge(&[], &[(3 .. 4, 1u8),],),
vec![(3 .. 4, None .. Some(1)),] &[(3 .. 4, None .. Some(1)),]
); );
} }
#[test] #[test]
fn merge_separate() { fn merge_separate() {
assert_eq!( assert_eq!(
easy_merge(vec![(1 .. 2, 0u8), (5 .. 6, 1u8),], vec![(2 .. 4, 2u8),],), &easy_merge(
vec![ &[(1 .. 2, 0u8), (5 .. 6, 1u8),],
&[(2 .. 4, 2u8),],
),
&[
(1 .. 2, Some(0) .. None), (1 .. 2, Some(0) .. None),
(2 .. 4, None .. Some(2)), (2 .. 4, None .. Some(2)),
(5 .. 6, Some(1) .. None), (5 .. 6, Some(1) .. None),
@ -377,27 +397,30 @@ mod test {
#[test] #[test]
fn merge_subset() { fn merge_subset() {
assert_eq!( assert_eq!(
easy_merge(vec![(1 .. 6, 0u8),], vec![(2 .. 4, 2u8),],), &easy_merge(
vec![ &[(1 .. 6, 0u8),],
&[(2 .. 4, 2u8),],
),
&[
(1 .. 2, Some(0) .. None), (1 .. 2, Some(0) .. None),
(2 .. 4, Some(0) .. Some(2)), (2 .. 4, Some(0) .. Some(2)),
(4 .. 6, Some(0) .. None), (4 .. 6, Some(0) .. None),
] ]
); );
assert_eq!( assert_eq!(
easy_merge(vec![(2 .. 4, 0u8),], vec![(1 .. 4, 2u8),],), &easy_merge(&[(2 .. 4, 0u8),], &[(1 .. 4, 2u8),],),
vec![(1 .. 2, None .. Some(2)), (2 .. 4, Some(0) .. Some(2)),] &[(1 .. 2, None .. Some(2)), (2 .. 4, Some(0) .. Some(2)),]
); );
} }
#[test] #[test]
fn merge_all() { fn merge_all() {
assert_eq!( assert_eq!(
easy_merge( &easy_merge(
vec![(1 .. 4, 0u8), (5 .. 8, 1u8),], &[(1 .. 4, 0u8), (5 .. 8, 1u8),],
vec![(2 .. 6, 2u8), (7 .. 9, 3u8),], &[(2 .. 6, 2u8), (7 .. 9, 3u8),],
), ),
vec![ &[
(1 .. 2, Some(0) .. None), (1 .. 2, Some(0) .. None),
(2 .. 4, Some(0) .. Some(2)), (2 .. 4, Some(0) .. Some(2)),
(4 .. 5, None .. Some(2)), (4 .. 5, None .. Some(2)),

View File

@ -2,30 +2,25 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use super::{SEPARATE_DEPTH_STENCIL_STATES, range::RangedStates, PendingTransition, ResourceState, Unit}; use super::{range::RangedStates, PendingTransition, ResourceState, Unit};
use crate::{conv, device::MAX_MIP_LEVELS, id::TextureId, resource::TextureUsage}; use crate::{device::MAX_MIP_LEVELS, id::TextureId, resource::TextureUsage};
use arrayvec::ArrayVec; use arrayvec::ArrayVec;
use std::ops::Range; use std::{iter, ops::Range};
//TODO: store `hal::image::State` here to avoid extra conversions //TODO: store `hal::image::State` here to avoid extra conversions
type PlaneStates = RangedStates<hal::image::Layer, Unit<TextureUsage>>; 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 { 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> { 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> { fn collapse(self) -> Result<TextureUsage, Self> {
if self.usage.start.is_empty() if self.usage.start.is_empty()
|| self.usage.start == self.usage.end || 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 { impl ResourceState for TextureState {
type Id = TextureId; type Id = TextureId;
type Selector = hal::image::SubresourceRange; type Selector = hal::image::SubresourceRange;
type Usage = TextureUsage; 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> { fn query(&self, selector: Self::Selector) -> Option<Self::Usage> {
let mut result = None; 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(); 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_start = num_levels.min(selector.levels.start as usize);
let mip_end = num_levels.min(selector.levels.end as usize); let mip_end = num_levels.min(selector.levels.end as usize);
for mip in self.mips[mip_start .. mip_end].iter() { for mip in self.mips[mip_start .. mip_end].iter() {
for &(aspects, ref plane_states) in mip { match mip.query(&selector.layers, |unit| unit.last) {
if !selector.aspects.intersects(aspects) { None => {}
continue; Some(Ok(usage)) if result == Some(usage) => {}
} Some(Ok(usage)) if result.is_none() => {
match plane_states.query(&selector.layers, |unit| unit.last) { result = Some(usage);
None => {}
Some(Ok(usage)) if result == Some(usage) => {}
Some(Ok(usage)) if result.is_none() => {
result = Some(usage);
}
Some(Ok(_)) | Some(Err(())) => return None,
} }
Some(Ok(_)) | Some(Err(())) => return None,
} }
} }
result result
@ -91,44 +88,44 @@ impl ResourceState for TextureState {
usage: Self::Usage, usage: Self::Usage,
mut output: Option<&mut Vec<PendingTransition<Self>>>, mut output: Option<&mut Vec<PendingTransition<Self>>>,
) -> Result<(), 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 for (mip_id, mip) in self.mips
[selector.levels.start as usize .. selector.levels.end as usize] [selector.levels.start as usize .. selector.levels.end as usize]
.iter_mut() .iter_mut()
.enumerate() .enumerate()
{ {
let level = selector.levels.start + mip_id as hal::image::Level; let level = selector.levels.start + mip_id as hal::image::Level;
for &mut (mip_aspects, ref mut plane_states) in mip { let layers = mip.isolate(&selector.layers, Unit::new(usage));
let aspects = selector.aspects & mip_aspects; for &mut (ref range, ref mut unit) in layers {
if aspects.is_empty() { if unit.last == usage && TextureUsage::ORDERED.contains(usage) {
continue; continue;
} }
debug_assert_eq!(aspects, mip_aspects); let pending = PendingTransition {
let layers = plane_states.isolate(&selector.layers, Unit::new(usage)); id,
for &mut (ref range, ref mut unit) in layers { selector: hal::image::SubresourceRange {
if unit.last == usage && TextureUsage::ORDERED.contains(usage) { aspects: hal::format::Aspects::empty(),
continue; levels: level .. level + 1,
} layers: range.clone(),
let pending = PendingTransition { },
id, usage: unit.last .. usage,
selector: hal::image::SubresourceRange { };
aspects,
levels: level .. level + 1,
layers: range.clone(),
},
usage: unit.last .. usage,
};
unit.last = match output { unit.last = match output {
None => pending.collapse()?, None => pending.collapse()?,
Some(ref mut out) => { Some(ref mut out) => {
out.push(pending); out.push(pending);
if unit.first.is_none() { if unit.first.is_none() {
unit.first = Some(unit.last); unit.first = Some(unit.last);
}
usage
} }
}; usage
} }
};
} }
} }
Ok(()) Ok(())
@ -141,74 +138,75 @@ impl ResourceState for TextureState {
mut output: Option<&mut Vec<PendingTransition<Self>>>, mut output: Option<&mut Vec<PendingTransition<Self>>>,
) -> Result<(), PendingTransition<Self>> { ) -> Result<(), PendingTransition<Self>> {
let mut temp = Vec::new(); let mut temp = Vec::new();
while self.mips.len() < other.mips.len() as usize { if self.full {
self.mips.push(MipState::default()); 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() { for (mip_id, (mip_self, mip_other)) in self.mips.iter_mut().zip(&other.mips).enumerate() {
let level = mip_id as hal::image::Level; 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) { temp.extend(mip_self.merge(mip_other, 0));
debug_assert_eq!(aspects, aspects_other); mip_self.clear();
temp.extend(planes_self.merge(planes_other, 0));
planes_self.clear();
for (layers, states) in temp.drain(..) { for (layers, states) in temp.drain(..) {
let unit = match states { let unit = match states {
Range { Range {
start: None, start: None,
end: None, end: None,
} => unreachable!(), } => unreachable!(),
Range { Range {
start: Some(start), start: Some(start),
end: None, end: None,
} => start, } => start,
Range { Range {
start: None, start: None,
end: Some(end), end: Some(end),
} => end, } => end,
Range { Range {
start: Some(start), start: Some(start),
end: Some(end), end: Some(end),
} => { } => {
let to_usage = end.port(); let to_usage = end.port();
if start.last == to_usage if start.last == to_usage
&& TextureUsage::ORDERED.contains(to_usage) && TextureUsage::ORDERED.contains(to_usage)
{ {
Unit { Unit {
first: start.first, first: start.first,
last: end.last, last: end.last,
} }
} else { } else {
let pending = PendingTransition { let pending = PendingTransition {
id, id,
selector: hal::image::SubresourceRange { selector: hal::image::SubresourceRange {
aspects, aspects: hal::format::Aspects::empty(),
levels: level .. level+1, levels: level .. level+1,
layers: layers.clone(), layers: layers.clone(),
}, },
usage: start.last .. to_usage, usage: start.last .. to_usage,
}; };
match output { match output {
None => { None => {
Unit { Unit {
first: start.first, first: start.first,
last: pending.collapse()?, last: pending.collapse()?,
}
} }
Some(ref mut out) => { }
out.push(pending); Some(ref mut out) => {
Unit { out.push(pending);
first: Some(start.last), Unit {
last: end.last, 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) { fn optimize(&mut self) {
for mip in self.mips.iter_mut() { for mip in self.mips.iter_mut() {
for &mut (_, ref mut planes) in mip.iter_mut() { mip.coalesce();
planes.coalesce();
}
} }
} }
} }
@ -234,16 +230,14 @@ mod test {
#[test] #[test]
fn query() { fn query() {
let mut ts = TextureState::new(&SubresourceRange { let mut ts = TextureState::default();
aspects: Aspects::COLOR, ts.mips.push(PlaneStates::empty());
levels: 0 .. 2, ts.mips.push(PlaneStates::from_slice(&[
layers: 0 .. 10,
});
ts.mips[1][0].1 = PlaneStates::new(&[
(1 .. 3, Unit::new(TextureUsage::SAMPLED)), (1 .. 3, Unit::new(TextureUsage::SAMPLED)),
(3 .. 5, Unit::new(TextureUsage::SAMPLED)), (3 .. 5, Unit::new(TextureUsage::SAMPLED)),
(5 .. 6, Unit::new(TextureUsage::STORAGE)), (5 .. 6, Unit::new(TextureUsage::STORAGE)),
]); ]));
assert_eq!( assert_eq!(
ts.query(SubresourceRange { ts.query(SubresourceRange {
aspects: Aspects::COLOR, aspects: Aspects::COLOR,
@ -253,15 +247,6 @@ mod test {
// level 1 matches // level 1 matches
Some(TextureUsage::SAMPLED), Some(TextureUsage::SAMPLED),
); );
assert_eq!(
ts.query(SubresourceRange {
aspects: Aspects::DEPTH,
levels: 1 .. 2,
layers: 2 .. 5,
}),
// no depth found
None,
);
assert_eq!( assert_eq!(
ts.query(SubresourceRange { ts.query(SubresourceRange {
aspects: Aspects::COLOR, aspects: Aspects::COLOR,

View File

@ -8,8 +8,6 @@ use core::{gfx_select, hub::Token, id};
use std::{marker::PhantomData, slice}; use std::{marker::PhantomData, slice};
use libc::{c_ulong};
pub type RequestAdapterCallback = pub type RequestAdapterCallback =
unsafe extern "C" fn(id: id::AdapterId, userdata: *mut std::ffi::c_void); unsafe extern "C" fn(id: id::AdapterId, userdata: *mut std::ffi::c_void);
pub type BufferMapReadCallback = pub type BufferMapReadCallback =
@ -80,7 +78,7 @@ pub fn wgpu_create_surface(raw_handle: raw_window_handle::RawWindowHandle) -> id
#[no_mangle] #[no_mangle]
pub extern "C" fn wgpu_create_surface_from_xlib( pub extern "C" fn wgpu_create_surface_from_xlib(
display: *mut *const std::ffi::c_void, display: *mut *const std::ffi::c_void,
window: c_ulong, window: libc::c_ulong,
) -> id::SurfaceId { ) -> id::SurfaceId {
use raw_window_handle::unix::XlibHandle; use raw_window_handle::unix::XlibHandle;
wgpu_create_surface(raw_window_handle::RawWindowHandle::Xlib(XlibHandle { wgpu_create_surface(raw_window_handle::RawWindowHandle::Xlib(XlibHandle {