mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
Add reference counting to objects
This commit is contained in:
parent
c1eb437b25
commit
39186c9c7b
@ -1,5 +1,5 @@
|
||||
use super::CommandBuffer;
|
||||
use {DeviceId, Stored};
|
||||
use {DeviceId, LifeGuard, Stored};
|
||||
use track::{Tracker};
|
||||
|
||||
use hal::command::RawCommandBuffer;
|
||||
@ -61,8 +61,8 @@ impl<B: hal::Backend> CommandAllocator<B> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn allocate(
|
||||
&self, device_id: DeviceId, device: &B::Device
|
||||
pub(crate) fn allocate(
|
||||
&self, device_id: Stored<DeviceId>, device: &B::Device
|
||||
) -> CommandBuffer<B> {
|
||||
let thread_id = thread::current().id();
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
@ -90,7 +90,8 @@ impl<B: hal::Backend> CommandAllocator<B> {
|
||||
raw: vec![init],
|
||||
fence,
|
||||
recorded_thread_id: thread_id,
|
||||
device_id: Stored(device_id),
|
||||
device_id,
|
||||
life_guard: LifeGuard::new(),
|
||||
buffer_tracker: Tracker::new(),
|
||||
texture_tracker: Tracker::new(),
|
||||
}
|
||||
|
||||
@ -16,10 +16,10 @@ pub struct ComputePass<B: hal::Backend> {
|
||||
}
|
||||
|
||||
impl<B: hal::Backend> ComputePass<B> {
|
||||
pub fn new(raw: B::CommandBuffer, cmb_id: CommandBufferId) -> Self {
|
||||
pub(crate) fn new(raw: B::CommandBuffer, cmb_id: Stored<CommandBufferId>) -> Self {
|
||||
ComputePass {
|
||||
raw,
|
||||
cmb_id: Stored(cmb_id),
|
||||
cmb_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -34,10 +34,10 @@ pub extern "C" fn wgpu_compute_pass_end_pass(
|
||||
|
||||
HUB.command_buffers
|
||||
.lock()
|
||||
.get_mut(pass.cmb_id.0)
|
||||
.get_mut(pass.cmb_id.value)
|
||||
.raw
|
||||
.push(pass.raw);
|
||||
pass.cmb_id.0
|
||||
pass.cmb_id.value
|
||||
}
|
||||
|
||||
pub extern "C" fn wgpu_compute_pass_set_bind_group(
|
||||
|
||||
@ -2,7 +2,7 @@ mod allocator;
|
||||
mod compute;
|
||||
mod render;
|
||||
|
||||
pub use self::allocator::CommandAllocator;
|
||||
pub(crate) use self::allocator::CommandAllocator;
|
||||
pub use self::compute::*;
|
||||
pub use self::render::*;
|
||||
|
||||
@ -10,7 +10,7 @@ use hal::{self, Device};
|
||||
use hal::command::RawCommandBuffer;
|
||||
|
||||
use {
|
||||
B, Color, Origin3d, Stored, BufferUsageFlags, TextureUsageFlags,
|
||||
B, Color, LifeGuard, Origin3d, Stored, BufferUsageFlags, TextureUsageFlags, WeaklyStored,
|
||||
BufferId, CommandBufferId, ComputePassId, DeviceId, RenderPassId, TextureId, TextureViewId,
|
||||
};
|
||||
use conv;
|
||||
@ -83,6 +83,7 @@ pub struct CommandBuffer<B: hal::Backend> {
|
||||
fence: B::Fence,
|
||||
recorded_thread_id: ThreadId,
|
||||
device_id: Stored<DeviceId>,
|
||||
life_guard: LifeGuard,
|
||||
pub(crate) buffer_tracker: BufferTracker,
|
||||
pub(crate) texture_tracker: TextureTracker,
|
||||
}
|
||||
@ -139,7 +140,7 @@ pub extern "C" fn wgpu_command_buffer_begin_render_pass(
|
||||
let mut cmb_guard = HUB.command_buffers.lock();
|
||||
let cmb = cmb_guard.get_mut(command_buffer_id);
|
||||
let device_guard = HUB.devices.lock();
|
||||
let device = device_guard.get(cmb.device_id.0);
|
||||
let device = device_guard.get(cmb.device_id.value);
|
||||
let view_guard = HUB.texture_views.lock();
|
||||
|
||||
let mut current_comb = device.com_allocator.extend(cmb);
|
||||
@ -160,7 +161,7 @@ pub extern "C" fn wgpu_command_buffer_begin_render_pass(
|
||||
} else {
|
||||
extent = Some(view.extent);
|
||||
}
|
||||
let query = tracker.query(view.texture_id.0, TextureUsageFlags::empty());
|
||||
let query = tracker.query(&view.texture_id, TextureUsageFlags::empty());
|
||||
let (_, layout) = conv::map_texture_state(
|
||||
query.usage,
|
||||
hal::format::Aspects::DEPTH | hal::format::Aspects::STENCIL,
|
||||
@ -185,7 +186,7 @@ pub extern "C" fn wgpu_command_buffer_begin_render_pass(
|
||||
} else {
|
||||
extent = Some(view.extent);
|
||||
}
|
||||
let query = tracker.query(view.texture_id.0, TextureUsageFlags::empty());
|
||||
let query = tracker.query(&view.texture_id, TextureUsageFlags::empty());
|
||||
let (_, layout) = conv::map_texture_state(query.usage, hal::format::Aspects::COLOR);
|
||||
hal::pass::Attachment {
|
||||
format: Some(conv::map_texture_format(view.format)),
|
||||
@ -234,8 +235,8 @@ pub extern "C" fn wgpu_command_buffer_begin_render_pass(
|
||||
let fb_key = FramebufferKey {
|
||||
attachments: desc.color_attachments
|
||||
.iter()
|
||||
.map(|at| Stored(at.attachment))
|
||||
.chain(desc.depth_stencil_attachment.as_ref().map(|at| Stored(at.attachment)))
|
||||
.map(|at| WeaklyStored(at.attachment))
|
||||
.chain(desc.depth_stencil_attachment.as_ref().map(|at| WeaklyStored(at.attachment)))
|
||||
.collect(),
|
||||
};
|
||||
let framebuffer = match framebuffer_cache.entry(fb_key) {
|
||||
@ -246,7 +247,7 @@ pub extern "C" fn wgpu_command_buffer_begin_render_pass(
|
||||
.key()
|
||||
.attachments
|
||||
.iter()
|
||||
.map(|&Stored(id)| &view_guard.get(id).raw);
|
||||
.map(|&WeaklyStored(id)| &view_guard.get(id).raw);
|
||||
|
||||
device.raw
|
||||
.create_framebuffer(&render_pass, attachments, extent.unwrap())
|
||||
@ -289,7 +290,10 @@ pub extern "C" fn wgpu_command_buffer_begin_render_pass(
|
||||
.lock()
|
||||
.register(RenderPass::new(
|
||||
current_comb,
|
||||
command_buffer_id,
|
||||
Stored {
|
||||
value: command_buffer_id,
|
||||
ref_count: cmb.life_guard.ref_count.clone(),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
@ -301,8 +305,12 @@ pub extern "C" fn wgpu_command_buffer_begin_compute_pass(
|
||||
let cmb = cmb_guard.get_mut(command_buffer_id);
|
||||
|
||||
let raw = cmb.raw.pop().unwrap();
|
||||
let stored = Stored {
|
||||
value: command_buffer_id,
|
||||
ref_count: cmb.life_guard.ref_count.clone(),
|
||||
};
|
||||
|
||||
HUB.compute_passes
|
||||
.lock()
|
||||
.register(ComputePass::new(raw, command_buffer_id))
|
||||
.register(ComputePass::new(raw, stored))
|
||||
}
|
||||
|
||||
@ -17,13 +17,13 @@ pub struct RenderPass<B: hal::Backend> {
|
||||
}
|
||||
|
||||
impl<B: hal::Backend> RenderPass<B> {
|
||||
pub fn new(
|
||||
pub(crate) fn new(
|
||||
raw: B::CommandBuffer,
|
||||
cmb_id: CommandBufferId,
|
||||
cmb_id: Stored<CommandBufferId>,
|
||||
) -> Self {
|
||||
RenderPass {
|
||||
raw,
|
||||
cmb_id: Stored(cmb_id),
|
||||
cmb_id,
|
||||
buffer_tracker: BufferTracker::new(),
|
||||
texture_tracker: TextureTracker::new(),
|
||||
}
|
||||
@ -40,7 +40,7 @@ pub extern "C" fn wgpu_render_pass_end_pass(
|
||||
pass.raw.end_render_pass();
|
||||
|
||||
let mut cmb_guard = HUB.command_buffers.lock();
|
||||
let cmb = cmb_guard.get_mut(pass.cmb_id.0);
|
||||
let cmb = cmb_guard.get_mut(pass.cmb_id.value);
|
||||
|
||||
if let Some(ref mut last) = cmb.raw.last_mut() {
|
||||
CommandBuffer::insert_barriers(
|
||||
@ -52,5 +52,5 @@ pub extern "C" fn wgpu_render_pass_end_pass(
|
||||
}
|
||||
|
||||
cmb.raw.push(pass.raw);
|
||||
pass.cmb_id.0
|
||||
pass.cmb_id.value
|
||||
}
|
||||
|
||||
@ -2,8 +2,9 @@ use {back, binding_model, command, conv, pipeline, resource};
|
||||
use registry::{HUB, Items, Registry};
|
||||
use track::{BufferTracker, TextureTracker};
|
||||
use {
|
||||
CommandBuffer, Stored, TextureUsageFlags,
|
||||
BindGroupLayoutId, BlendStateId, CommandBufferId, DepthStencilStateId,
|
||||
CommandBuffer, LifeGuard, RefCount, Stored, SubmissionIndex, WeaklyStored,
|
||||
TextureUsageFlags,
|
||||
BindGroupLayoutId, BlendStateId, BufferId, CommandBufferId, DepthStencilStateId,
|
||||
DeviceId, PipelineLayoutId, QueueId, RenderPipelineId, ShaderModuleId,
|
||||
TextureId, TextureViewId,
|
||||
};
|
||||
@ -16,6 +17,7 @@ use rendy_memory::{allocator, Config, Heaps};
|
||||
use std::{ffi, slice};
|
||||
use std::collections::hash_map::{Entry, HashMap};
|
||||
use std::sync::Mutex;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
|
||||
#[derive(Hash, PartialEq)]
|
||||
@ -26,21 +28,67 @@ impl Eq for RenderPassKey {}
|
||||
|
||||
#[derive(Hash, PartialEq)]
|
||||
pub(crate) struct FramebufferKey {
|
||||
pub attachments: Vec<Stored<TextureViewId>>,
|
||||
pub attachments: Vec<WeaklyStored<TextureViewId>>,
|
||||
}
|
||||
impl Eq for FramebufferKey {}
|
||||
|
||||
enum Resource {
|
||||
Buffer(BufferId),
|
||||
Texture(TextureId),
|
||||
}
|
||||
|
||||
struct ActiveFrame<B: hal::Backend> {
|
||||
submission_index: SubmissionIndex,
|
||||
fence: B::Fence,
|
||||
resources: Vec<Resource>,
|
||||
}
|
||||
|
||||
struct DestroyedResources<B: hal::Backend> {
|
||||
/// Resources that are destroyed by the user but still referenced by
|
||||
/// other objects or command buffers.
|
||||
referenced: Vec<(Resource, RefCount)>,
|
||||
/// Resources that are not referenced any more but still used by GPU.
|
||||
/// Grouped by frames associated with a fence and a submission index.
|
||||
active: Vec<ActiveFrame<B>>,
|
||||
/// Resources that are neither referenced or used, just pending
|
||||
/// actual deletion.
|
||||
free: Vec<Resource>,
|
||||
}
|
||||
|
||||
unsafe impl<B: hal::Backend> Send for DestroyedResources<B> {}
|
||||
unsafe impl<B: hal::Backend> Sync for DestroyedResources<B> {}
|
||||
|
||||
impl<B: hal::Backend> DestroyedResources<B> {
|
||||
fn add(&mut self, resource: Resource, life_guard: &LifeGuard) {
|
||||
if life_guard.ref_count.load() == 1 {
|
||||
let sub_index = life_guard.submission_index.load(Ordering::Acquire);
|
||||
match self.active.iter_mut().find(|af| af.submission_index == sub_index) {
|
||||
Some(frame) => {
|
||||
frame.resources.push(resource);
|
||||
}
|
||||
None => {
|
||||
self.free.push(resource);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.referenced.push((resource, life_guard.ref_count.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Device<B: hal::Backend> {
|
||||
pub(crate) raw: B::Device,
|
||||
queue_group: hal::QueueGroup<B, hal::General>,
|
||||
mem_allocator: Heaps<B::Memory>,
|
||||
pub(crate) com_allocator: command::CommandAllocator<B>,
|
||||
life_guard: LifeGuard,
|
||||
buffer_tracker: Mutex<BufferTracker>,
|
||||
texture_tracker: Mutex<TextureTracker>,
|
||||
mem_props: hal::MemoryProperties,
|
||||
pub(crate) render_passes: Mutex<HashMap<RenderPassKey, B::RenderPass>>,
|
||||
pub(crate) framebuffers: Mutex<HashMap<FramebufferKey, B::Framebuffer>>,
|
||||
last_submission_index: SubmissionIndex,
|
||||
destroyed: Mutex<DestroyedResources<B>>,
|
||||
}
|
||||
|
||||
impl<B: hal::Backend> Device<B> {
|
||||
@ -75,11 +123,18 @@ impl<B: hal::Backend> Device<B> {
|
||||
mem_allocator,
|
||||
com_allocator: command::CommandAllocator::new(queue_group.family()),
|
||||
queue_group,
|
||||
life_guard: LifeGuard::new(),
|
||||
buffer_tracker: Mutex::new(BufferTracker::new()),
|
||||
texture_tracker: Mutex::new(TextureTracker::new()),
|
||||
mem_props,
|
||||
render_passes: Mutex::new(HashMap::new()),
|
||||
framebuffers: Mutex::new(HashMap::new()),
|
||||
last_submission_index: 0,
|
||||
destroyed: Mutex::new(DestroyedResources {
|
||||
referenced: Vec::new(),
|
||||
active: Vec::new(),
|
||||
free: Vec::new(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -136,19 +191,28 @@ pub extern "C" fn wgpu_device_create_texture(
|
||||
layers: 0 .. 1, //TODO
|
||||
};
|
||||
|
||||
let life_guard = LifeGuard::new();
|
||||
let ref_count = life_guard.ref_count.clone();
|
||||
let id = HUB.textures
|
||||
.lock()
|
||||
.register(resource::Texture {
|
||||
raw: bound_image,
|
||||
device_id: Stored(device_id),
|
||||
device_id: Stored {
|
||||
value: device_id,
|
||||
ref_count: device.life_guard.ref_count.clone(),
|
||||
},
|
||||
kind,
|
||||
format: desc.format,
|
||||
full_range,
|
||||
life_guard,
|
||||
});
|
||||
let query = device.texture_tracker
|
||||
.lock()
|
||||
.unwrap()
|
||||
.query(id, TextureUsageFlags::WRITE_ALL);
|
||||
.query(
|
||||
&Stored { value: id, ref_count },
|
||||
TextureUsageFlags::WRITE_ALL,
|
||||
);
|
||||
assert!(query.initialized);
|
||||
|
||||
id
|
||||
@ -164,7 +228,7 @@ pub extern "C" fn wgpu_texture_create_texture_view(
|
||||
|
||||
let raw = HUB.devices
|
||||
.lock()
|
||||
.get(texture.device_id.0)
|
||||
.get(texture.device_id.value)
|
||||
.raw
|
||||
.create_image_view(
|
||||
&texture.raw,
|
||||
@ -183,10 +247,14 @@ pub extern "C" fn wgpu_texture_create_texture_view(
|
||||
.lock()
|
||||
.register(resource::TextureView {
|
||||
raw,
|
||||
texture_id: Stored(texture_id),
|
||||
texture_id: Stored {
|
||||
value: texture_id,
|
||||
ref_count: texture.life_guard.ref_count.clone(),
|
||||
},
|
||||
format: texture.format,
|
||||
extent: texture.kind.extent(),
|
||||
samples: texture.kind.num_samples(),
|
||||
life_guard: LifeGuard::new(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -205,7 +273,7 @@ pub extern "C" fn wgpu_texture_create_default_texture_view(
|
||||
|
||||
let raw = HUB.devices
|
||||
.lock()
|
||||
.get(texture.device_id.0)
|
||||
.get(texture.device_id.value)
|
||||
.raw
|
||||
.create_image_view(
|
||||
&texture.raw,
|
||||
@ -220,13 +288,38 @@ pub extern "C" fn wgpu_texture_create_default_texture_view(
|
||||
.lock()
|
||||
.register(resource::TextureView {
|
||||
raw,
|
||||
texture_id: Stored(texture_id),
|
||||
texture_id: Stored {
|
||||
value: texture_id,
|
||||
ref_count: texture.life_guard.ref_count.clone(),
|
||||
},
|
||||
format: texture.format,
|
||||
extent: texture.kind.extent(),
|
||||
samples: texture.kind.num_samples(),
|
||||
life_guard: LifeGuard::new(),
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wgpu_texture_destroy(
|
||||
texture_id: DeviceId,
|
||||
) {
|
||||
let texture_guard = HUB.textures.lock();
|
||||
let texture = texture_guard.get(texture_id);
|
||||
let device_guard = HUB.devices.lock();
|
||||
device_guard
|
||||
.get(texture.device_id.value)
|
||||
.destroyed
|
||||
.lock()
|
||||
.unwrap()
|
||||
.add(Resource::Texture(texture_id), &texture.life_guard);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wgpu_texture_view_destroy(
|
||||
_texture_view_id: TextureViewId,
|
||||
) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wgpu_device_create_bind_group_layout(
|
||||
@ -338,7 +431,11 @@ pub extern "C" fn wgpu_device_create_command_buffer(
|
||||
let device_guard = HUB.devices.lock();
|
||||
let device = device_guard.get(device_id);
|
||||
|
||||
let mut cmd_buf = device.com_allocator.allocate(device_id, &device.raw);
|
||||
let dev_stored = Stored {
|
||||
value: device_id,
|
||||
ref_count: device.life_guard.ref_count.clone(),
|
||||
};
|
||||
let mut cmd_buf = device.com_allocator.allocate(dev_stored, &device.raw);
|
||||
cmd_buf.raw.last_mut().unwrap().begin(
|
||||
hal::command::CommandBufferFlags::ONE_TIME_SUBMIT,
|
||||
hal::command::CommandBufferInheritanceInfo::default(),
|
||||
|
||||
@ -43,12 +43,78 @@ pub use self::resource::*;
|
||||
use back::Backend as B;
|
||||
use registry::Id;
|
||||
|
||||
#[derive(Debug, Hash, PartialEq, Eq)]
|
||||
struct Stored<T>(T);
|
||||
#[cfg(not(feature = "remote"))]
|
||||
unsafe impl<T> Sync for Stored<T> {}
|
||||
#[cfg(not(feature = "remote"))]
|
||||
use std::ptr;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
|
||||
//#[cfg(not(feature = "remote"))]
|
||||
//unsafe impl<T> Sync for Stored<T> {}
|
||||
//#[cfg(not(feature = "remote"))]
|
||||
//unsafe impl<T> Send for Stored<T> {}
|
||||
|
||||
type SubmissionIndex = usize;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct RefCount(ptr::NonNull<AtomicUsize>);
|
||||
|
||||
impl RefCount {
|
||||
const MAX: usize = 1 << 24;
|
||||
|
||||
fn load(&self) -> usize {
|
||||
unsafe { self.0.as_ref() }.load(Ordering::Acquire)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for RefCount {
|
||||
fn clone(&self) -> Self {
|
||||
let old_size = unsafe { self.0.as_ref() }.fetch_add(1, Ordering::Relaxed);
|
||||
assert!(old_size < Self::MAX);
|
||||
RefCount(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RefCount {
|
||||
fn drop(&mut self) {
|
||||
if unsafe { self.0.as_ref() }.fetch_sub(1, Ordering::Relaxed) == 1 {
|
||||
let _ = unsafe { Box::from_raw(self.0.as_ptr()) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LifeGuard {
|
||||
ref_count: RefCount,
|
||||
submission_index: AtomicUsize,
|
||||
}
|
||||
|
||||
//TODO: reconsider this
|
||||
unsafe impl Send for LifeGuard {}
|
||||
unsafe impl Sync for LifeGuard {}
|
||||
|
||||
impl LifeGuard {
|
||||
fn new() -> Self {
|
||||
let bx = Box::new(AtomicUsize::new(1));
|
||||
LifeGuard {
|
||||
ref_count: RefCount(ptr::NonNull::new(Box::into_raw(bx)).unwrap()),
|
||||
submission_index: AtomicUsize::new(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Stored<T> {
|
||||
value: T,
|
||||
ref_count: RefCount,
|
||||
}
|
||||
|
||||
unsafe impl<T> Send for Stored<T> {}
|
||||
unsafe impl<T> Sync for Stored<T> {}
|
||||
|
||||
#[derive(Debug, Hash, PartialEq, Eq)]
|
||||
struct WeaklyStored<T>(T);
|
||||
|
||||
unsafe impl<T> Send for WeaklyStored<T> {}
|
||||
unsafe impl<T> Sync for WeaklyStored<T> {}
|
||||
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use {
|
||||
Extent3d, Stored,
|
||||
Extent3d, LifeGuard, Stored,
|
||||
DeviceId, TextureId,
|
||||
};
|
||||
|
||||
@ -32,6 +32,7 @@ pub(crate) struct Buffer<B: hal::Backend> {
|
||||
//pub raw: B::UnboundBuffer,
|
||||
pub raw: B::Buffer,
|
||||
pub memory_properties: hal::memory::Properties,
|
||||
pub life_guard: LifeGuard,
|
||||
// TODO: mapping, unmap()
|
||||
}
|
||||
|
||||
@ -82,6 +83,7 @@ pub(crate) struct Texture<B: hal::Backend> {
|
||||
pub kind: hal::image::Kind,
|
||||
pub format: TextureFormat,
|
||||
pub full_range: hal::image::SubresourceRange,
|
||||
pub life_guard: LifeGuard,
|
||||
}
|
||||
|
||||
|
||||
@ -122,6 +124,7 @@ pub(crate) struct TextureView<B: hal::Backend> {
|
||||
pub format: TextureFormat,
|
||||
pub extent: hal::image::Extent,
|
||||
pub samples: hal::image::NumSamples,
|
||||
pub life_guard: LifeGuard,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use {Stored, BufferId, TextureId};
|
||||
use {RefCount, Stored, WeaklyStored, BufferId, TextureId};
|
||||
use resource::{BufferUsageFlags, TextureUsageFlags};
|
||||
|
||||
use std::collections::hash_map::{Entry, HashMap};
|
||||
@ -42,10 +42,18 @@ impl GenericUsage for TextureUsageFlags {
|
||||
}
|
||||
}
|
||||
|
||||
struct Track<U> {
|
||||
ref_count: RefCount,
|
||||
init: U,
|
||||
last: U,
|
||||
}
|
||||
|
||||
unsafe impl<U> Send for Track<U> {}
|
||||
unsafe impl<U> Sync for Track<U> {}
|
||||
|
||||
//TODO: consider having `I` as an associated type of `U`?
|
||||
pub struct Tracker<I, U> {
|
||||
map: HashMap<Stored<I>, Range<U>>,
|
||||
map: HashMap<WeaklyStored<I>, Track<U>>,
|
||||
}
|
||||
pub type BufferTracker = Tracker<BufferId, BufferUsageFlags>;
|
||||
pub type TextureTracker = Tracker<TextureId, TextureUsageFlags>;
|
||||
@ -54,16 +62,22 @@ impl<
|
||||
I: Clone + Hash + Eq,
|
||||
U: Copy + GenericUsage + BitOr<Output = U> + PartialEq,
|
||||
> Tracker<I, U> {
|
||||
pub fn new() -> Self {
|
||||
pub(crate) fn new() -> Self {
|
||||
Tracker {
|
||||
map: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn query(&mut self, id: I, default: U) -> Query<U> {
|
||||
match self.map.entry(Stored(id)) {
|
||||
pub(crate) fn query(
|
||||
&mut self, stored: &Stored<I>, default: U
|
||||
) -> Query<U> {
|
||||
match self.map.entry(WeaklyStored(stored.value.clone())) {
|
||||
Entry::Vacant(e) => {
|
||||
e.insert(default .. default);
|
||||
e.insert(Track {
|
||||
ref_count: stored.ref_count.clone(),
|
||||
init: default,
|
||||
last: default,
|
||||
});
|
||||
Query {
|
||||
usage: default,
|
||||
initialized: true,
|
||||
@ -71,28 +85,34 @@ impl<
|
||||
}
|
||||
Entry::Occupied(e) => {
|
||||
Query {
|
||||
usage: e.get().end,
|
||||
usage: e.get().last,
|
||||
initialized: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transit(&mut self, id: I, usage: U, permit: TrackPermit) -> Result<Tracktion<U>, U> {
|
||||
match self.map.entry(Stored(id)) {
|
||||
pub(crate) fn transit(
|
||||
&mut self, id: I, ref_count: &RefCount, usage: U, permit: TrackPermit
|
||||
) -> Result<Tracktion<U>, U> {
|
||||
match self.map.entry(WeaklyStored(id)) {
|
||||
Entry::Vacant(e) => {
|
||||
e.insert(usage .. usage);
|
||||
e.insert(Track {
|
||||
ref_count: ref_count.clone(),
|
||||
init: usage,
|
||||
last: usage,
|
||||
});
|
||||
Ok(Tracktion::Init)
|
||||
}
|
||||
Entry::Occupied(mut e) => {
|
||||
let old = e.get().end;
|
||||
let old = e.get().last;
|
||||
if usage == old {
|
||||
Ok(Tracktion::Keep)
|
||||
} else if permit.contains(TrackPermit::EXTEND) && !(old | usage).is_exclusive() {
|
||||
e.get_mut().end = old | usage;
|
||||
e.get_mut().last = old | usage;
|
||||
Ok(Tracktion::Extend { old })
|
||||
} else if permit.contains(TrackPermit::REPLACE) {
|
||||
e.get_mut().end = usage;
|
||||
e.get_mut().last = usage;
|
||||
Ok(Tracktion::Replace { old })
|
||||
} else {
|
||||
Err(old)
|
||||
@ -101,13 +121,15 @@ impl<
|
||||
}
|
||||
}
|
||||
|
||||
pub fn consume<'a>(&'a mut self, other: &'a Self) -> impl 'a + Iterator<Item = (I, Range<U>)> {
|
||||
pub fn consume<'a>(
|
||||
&'a mut self, other: &'a Self
|
||||
) -> impl 'a + Iterator<Item = (I, Range<U>)> {
|
||||
other.map
|
||||
.iter()
|
||||
.flat_map(move |(id, new)| match self.transit(id.0.clone(), new.end, TrackPermit::REPLACE) {
|
||||
.flat_map(move |(id, new)| match self.transit(id.0.clone(), &new.ref_count, new.last, TrackPermit::REPLACE) {
|
||||
Ok(Tracktion::Init) |
|
||||
Ok(Tracktion::Keep) => None,
|
||||
Ok(Tracktion::Replace { old }) => Some((id.0.clone(), old .. new.end)),
|
||||
Ok(Tracktion::Replace { old }) => Some((id.0.clone(), old .. new.last)),
|
||||
Ok(Tracktion::Extend { .. }) |
|
||||
Err(_) => panic!("Unable to consume a resource transition!"),
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user