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));
|
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(
|
||||||
|
@ -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,
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
@ -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)),
|
||||||
|
@ -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,
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user