mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Merge #127
127: Track async mapping properly r=grovesNL,swiftcoder a=kvark Fixes #117, fixes #95, fixes #132 The change can be logically split into 3 parts: 1. when `ActiveSubmission` is retired, we now move the mapped buffers into the "ready to map" vector. This was the missing bit that caused mapping to not work previously. 2. mapping callbacks in Rust wrapper are refactored and they `unmap()` automatically now on users behalf 3. we wait for idle before destroying the device, which allows us to process all the pending callbacks. This fix gets rid of the dummy submission our compute example used to do. Co-authored-by: Dzmitry Malyshau <dmalyshau@mozilla.com> Co-authored-by: Dzmitry Malyshau <kvarkus@gmail.com>
This commit is contained in:
@@ -17,18 +17,18 @@ matrix:
|
||||
- env: MACOSX_DEPLOYMENT_TARGET=10.9
|
||||
os: osx
|
||||
rust: stable
|
||||
osx_image: xcode9
|
||||
osx_image: xcode9.4
|
||||
compiler: clang
|
||||
#- env: MACOSX_DEPLOYMENT_TARGET=10.9
|
||||
# os: osx
|
||||
# rust: nightly
|
||||
# osx_image: xcode9
|
||||
# osx_image: xcode9.4
|
||||
# compiler: clang
|
||||
|
||||
# iPhoneOS 64bit
|
||||
#- env: TARGET=aarch64-apple-ios
|
||||
# os: osx
|
||||
# osx_image: xcode9
|
||||
# osx_image: xcode9.4
|
||||
# rust: nightly
|
||||
|
||||
branches:
|
||||
|
||||
@@ -20,7 +20,7 @@ fn main() {
|
||||
|
||||
let instance = wgpu::Instance::new();
|
||||
let adapter = instance.get_adapter(&wgpu::AdapterDescriptor {
|
||||
power_preference: wgpu::PowerPreference::LowPower,
|
||||
power_preference: wgpu::PowerPreference::Default,
|
||||
});
|
||||
let mut device = adapter.create_device(&wgpu::DeviceDescriptor {
|
||||
extensions: wgpu::Extensions {
|
||||
@@ -91,13 +91,8 @@ fn main() {
|
||||
device.get_queue().submit(&[encoder.finish()]);
|
||||
|
||||
staging_buffer.map_read_async(0, size, |result: wgpu::BufferMapAsyncResult<&[u32]>| {
|
||||
if let wgpu::BufferMapAsyncResult::Success(data) = result {
|
||||
println!("Times: {:?}", data);
|
||||
if let Ok(mapping) = result {
|
||||
println!("Times: {:?}", mapping.data);
|
||||
}
|
||||
});
|
||||
|
||||
let encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
|
||||
device.get_queue().submit(&[encoder.finish()]);
|
||||
|
||||
staging_buffer.unmap(); // TODO: staging_buffer can't be referenced from the callback
|
||||
}
|
||||
|
||||
@@ -754,10 +754,12 @@ WGPUSwapChainId wgpu_device_create_swap_chain(WGPUDeviceId device_id,
|
||||
|
||||
WGPUTextureId wgpu_device_create_texture(WGPUDeviceId device_id, const WGPUTextureDescriptor *desc);
|
||||
|
||||
void wgpu_device_destroy(WGPUBufferId device_id);
|
||||
void wgpu_device_destroy(WGPUDeviceId device_id);
|
||||
|
||||
WGPUQueueId wgpu_device_get_queue(WGPUDeviceId device_id);
|
||||
|
||||
void wgpu_device_poll(WGPUDeviceId device_id, bool force_wait);
|
||||
|
||||
WGPUSurfaceId wgpu_instance_create_surface_from_macos_layer(WGPUInstanceId instance_id,
|
||||
void *layer);
|
||||
|
||||
|
||||
@@ -131,4 +131,17 @@ impl<B: hal::Backend> CommandAllocator<B> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn destroy(self, device: &B::Device) {
|
||||
let mut inner = self.inner.lock();
|
||||
while let Some(cmd_buf) = inner.pending.pop() {
|
||||
inner.recycle(cmd_buf);
|
||||
}
|
||||
for (_, mut pool) in inner.pools.drain() {
|
||||
unsafe {
|
||||
pool.raw.free(pool.available);
|
||||
device.destroy_command_pool(pool.raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
binding_model, command, conv, pipeline, resource, swap_chain,
|
||||
hub::HUB,
|
||||
track::{DummyUsage, Stitch, TrackPermit, TrackerSet},
|
||||
track::{DummyUsage, Stitch, Tracktion, TrackPermit, TrackerSet},
|
||||
AdapterId, BindGroupId, BufferId, CommandBufferId, DeviceId, QueueId, SurfaceId, TextureId,
|
||||
TextureViewId,
|
||||
BufferMapAsyncStatus, BufferMapOperation, LifeGuard, RefCount, Stored, SubmissionIndex,
|
||||
@@ -100,7 +100,16 @@ struct ActiveSubmission<B: hal::Backend> {
|
||||
mapped: Vec<BufferId>,
|
||||
}
|
||||
|
||||
struct DestroyedResources<B: hal::Backend> {
|
||||
/// A struct responsible for tracking resource lifetimes.
|
||||
///
|
||||
/// Here is how host mapping is handled:
|
||||
/// 1. When mapping is requested we add the buffer to the pending list of `mapped` buffers.
|
||||
/// 2. When `triage_referenced` is called, it checks the last submission index associated with each of the mapped buffer,
|
||||
/// and register the buffer with either a submission in flight, or straight into `ready_to_map` vector.
|
||||
/// 3. when `ActiveSubmission` is retired, the mapped buffers associated with it are moved to `ready_to_map` vector.
|
||||
/// 4. Finally, `handle_mapping` issues all the callbacks.
|
||||
|
||||
struct PendingResources<B: hal::Backend> {
|
||||
/// Resources that the user has requested be mapped, but are still in use.
|
||||
mapped: Vec<Stored<BufferId>>,
|
||||
/// Resources that are destroyed by the user but still referenced by
|
||||
@@ -115,10 +124,10 @@ struct DestroyedResources<B: hal::Backend> {
|
||||
ready_to_map: Vec<BufferId>,
|
||||
}
|
||||
|
||||
unsafe impl<B: hal::Backend> Send for DestroyedResources<B> {}
|
||||
unsafe impl<B: hal::Backend> Sync for DestroyedResources<B> {}
|
||||
unsafe impl<B: hal::Backend> Send for PendingResources<B> {}
|
||||
unsafe impl<B: hal::Backend> Sync for PendingResources<B> {}
|
||||
|
||||
impl<B: hal::Backend> DestroyedResources<B> {
|
||||
impl<B: hal::Backend> PendingResources<B> {
|
||||
fn destroy(&mut self, resource_id: ResourceId, ref_count: RefCount) {
|
||||
debug_assert!(!self.referenced.iter().any(|r| r.0 == resource_id));
|
||||
self.referenced.push((resource_id, ref_count));
|
||||
@@ -132,15 +141,28 @@ impl<B: hal::Backend> DestroyedResources<B> {
|
||||
}
|
||||
|
||||
/// Returns the last submission index that is done.
|
||||
fn cleanup(&mut self, device: &B::Device) -> SubmissionIndex {
|
||||
fn cleanup(&mut self, device: &B::Device, force_wait: bool) -> SubmissionIndex {
|
||||
let mut last_done = 0;
|
||||
|
||||
if force_wait {
|
||||
unsafe {
|
||||
device.wait_for_fences(
|
||||
self.active.iter().map(|a| &a.fence),
|
||||
hal::device::WaitFor::All,
|
||||
!0,
|
||||
)
|
||||
}.unwrap();
|
||||
}
|
||||
|
||||
for i in (0..self.active.len()).rev() {
|
||||
if unsafe { device.get_fence_status(&self.active[i].fence).unwrap() } {
|
||||
if force_wait || unsafe {
|
||||
device.get_fence_status(&self.active[i].fence).unwrap()
|
||||
} {
|
||||
let a = self.active.swap_remove(i);
|
||||
trace!("Active submission {} is done", a.index);
|
||||
last_done = last_done.max(a.index);
|
||||
self.free.extend(a.resources.into_iter().map(|(_, r)| r));
|
||||
self.ready_to_map.extend(a.mapped);
|
||||
unsafe {
|
||||
device.destroy_fence(a.fence);
|
||||
}
|
||||
@@ -170,7 +192,7 @@ impl<B: hal::Backend> DestroyedResources<B> {
|
||||
}
|
||||
}
|
||||
|
||||
impl DestroyedResources<back::Backend> {
|
||||
impl PendingResources<back::Backend> {
|
||||
fn triage_referenced(&mut self, trackers: &mut TrackerSet) {
|
||||
for i in (0..self.referenced.len()).rev() {
|
||||
let num_refs = self.referenced[i].1.load();
|
||||
@@ -221,21 +243,15 @@ impl DestroyedResources<back::Backend> {
|
||||
|
||||
let buffer_guard = HUB.buffers.read();
|
||||
|
||||
for i in (0..self.mapped.len()).rev() {
|
||||
let resource_id = self.mapped.swap_remove(i).value;
|
||||
for stored in self.mapped.drain(..) {
|
||||
let resource_id = stored.value;
|
||||
let buf = &buffer_guard[resource_id];
|
||||
|
||||
let usage = match buf.pending_map_operation {
|
||||
Some(BufferMapOperation::Read(..)) => resource::BufferUsageFlags::MAP_READ,
|
||||
Some(BufferMapOperation::Write(..)) => resource::BufferUsageFlags::MAP_WRITE,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
trackers
|
||||
.buffers
|
||||
.get_with_replaced_usage(&buffer_guard, resource_id, usage)
|
||||
.unwrap();
|
||||
|
||||
let submit_index = buf.life_guard.submission_index.load(Ordering::Acquire);
|
||||
trace!("Mapping of {:?} at submission {:?} gets assigned to active {:?}",
|
||||
resource_id, submit_index,
|
||||
self.active.iter().position(|a| a.index == submit_index));
|
||||
|
||||
self.active
|
||||
.iter_mut()
|
||||
.find(|a| a.index == submit_index)
|
||||
@@ -371,7 +387,7 @@ pub struct Device<B: hal::Backend> {
|
||||
pub(crate) render_passes: Mutex<FastHashMap<RenderPassKey, B::RenderPass>>,
|
||||
pub(crate) framebuffers: Mutex<FastHashMap<FramebufferKey, B::Framebuffer>>,
|
||||
desc_pool: Mutex<B::DescriptorPool>,
|
||||
destroyed: Mutex<DestroyedResources<B>>,
|
||||
pending: Mutex<PendingResources<B>>,
|
||||
}
|
||||
|
||||
impl<B: hal::Backend> Device<B> {
|
||||
@@ -448,7 +464,7 @@ impl<B: hal::Backend> Device<B> {
|
||||
render_passes: Mutex::new(FastHashMap::default()),
|
||||
framebuffers: Mutex::new(FastHashMap::default()),
|
||||
desc_pool,
|
||||
destroyed: Mutex::new(DestroyedResources {
|
||||
pending: Mutex::new(PendingResources {
|
||||
mapped: Vec::new(),
|
||||
referenced: Vec::new(),
|
||||
active: Vec::new(),
|
||||
@@ -459,6 +475,22 @@ impl<B: hal::Backend> Device<B> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Device<back::Backend> {
|
||||
fn maintain(&self, force_wait: bool) {
|
||||
let mut pending = self.pending.lock();
|
||||
let mut trackers = self.trackers.lock();
|
||||
|
||||
pending.triage_referenced(&mut *trackers);
|
||||
pending.triage_framebuffers(&mut *self.framebuffers.lock());
|
||||
let last_done = pending.cleanup(&self.raw, force_wait);
|
||||
pending.handle_mapping(&self.raw, &self.limits);
|
||||
|
||||
if last_done != 0 {
|
||||
self.com_allocator.maintain(last_done);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ShaderModule<B: hal::Backend> {
|
||||
pub(crate) raw: B::ShaderModule,
|
||||
}
|
||||
@@ -485,10 +517,20 @@ pub fn device_create_buffer(
|
||||
.unwrap()
|
||||
.into();
|
||||
// TODO: allocate with rendy
|
||||
|
||||
// if the memory is mapped but not coherent, round up to the atom size
|
||||
let mut mem_size = requirements.size;
|
||||
if memory_properties.contains(hal::memory::Properties::CPU_VISIBLE) &&
|
||||
!memory_properties.contains(hal::memory::Properties::COHERENT)
|
||||
{
|
||||
let mask = device.limits.non_coherent_atom_size as u64 - 1;
|
||||
mem_size = ((mem_size - 1 ) | mask) + 1;
|
||||
}
|
||||
|
||||
let memory = unsafe {
|
||||
device
|
||||
.raw
|
||||
.allocate_memory(device_type, requirements.size)
|
||||
.allocate_memory(device_type, mem_size)
|
||||
.unwrap()
|
||||
};
|
||||
unsafe {
|
||||
@@ -587,7 +629,7 @@ pub extern "C" fn wgpu_buffer_destroy(buffer_id: BufferId) {
|
||||
let buffer_guard = HUB.buffers.read();
|
||||
let buffer = &buffer_guard[buffer_id];
|
||||
HUB.devices.read()[buffer.device_id.value]
|
||||
.destroyed
|
||||
.pending
|
||||
.lock()
|
||||
.destroy(
|
||||
ResourceId::Buffer(buffer_id),
|
||||
@@ -785,7 +827,7 @@ pub extern "C" fn wgpu_texture_destroy(texture_id: TextureId) {
|
||||
let texture_guard = HUB.textures.read();
|
||||
let texture = &texture_guard[texture_id];
|
||||
HUB.devices.read()[texture.device_id.value]
|
||||
.destroyed
|
||||
.pending
|
||||
.lock()
|
||||
.destroy(
|
||||
ResourceId::Texture(texture_id),
|
||||
@@ -798,7 +840,7 @@ pub extern "C" fn wgpu_texture_view_destroy(texture_view_id: TextureViewId) {
|
||||
let texture_view_guard = HUB.texture_views.read();
|
||||
let view = &texture_view_guard[texture_view_id];
|
||||
let device_id = HUB.textures.read()[view.texture_id.value].device_id.value;
|
||||
HUB.devices.read()[device_id].destroyed.lock().destroy(
|
||||
HUB.devices.read()[device_id].pending.lock().destroy(
|
||||
ResourceId::TextureView(texture_view_id),
|
||||
view.life_guard.ref_count.clone(),
|
||||
);
|
||||
@@ -1094,13 +1136,8 @@ pub extern "C" fn wgpu_queue_submit(
|
||||
let (submit_index, fence) = {
|
||||
let mut device_guard = HUB.devices.write();
|
||||
let device = &mut device_guard[queue_id];
|
||||
|
||||
let mut swap_chain_links = Vec::new();
|
||||
|
||||
let mut trackers = device.trackers.lock();
|
||||
let mut destroyed = device.destroyed.lock();
|
||||
destroyed.triage_referenced(&mut *trackers);
|
||||
destroyed.triage_framebuffers(&mut *device.framebuffers.lock());
|
||||
let mut swap_chain_links = Vec::new();
|
||||
|
||||
let submit_index = 1 + device
|
||||
.life_guard
|
||||
@@ -1123,7 +1160,9 @@ pub extern "C" fn wgpu_queue_submit(
|
||||
|
||||
// update submission IDs
|
||||
for id in comb.trackers.buffers.used() {
|
||||
buffer_guard[id]
|
||||
let buffer = &buffer_guard[id];
|
||||
assert!(buffer.pending_map_operation.is_none());
|
||||
buffer
|
||||
.life_guard
|
||||
.submission_index
|
||||
.store(submit_index, Ordering::Release);
|
||||
@@ -1213,24 +1252,13 @@ pub extern "C" fn wgpu_queue_submit(
|
||||
let device_guard = HUB.devices.read();
|
||||
let device = &device_guard[queue_id];
|
||||
|
||||
let last_done = {
|
||||
let mut destroyed = device.destroyed.lock();
|
||||
let last_done = destroyed.cleanup(&device.raw);
|
||||
destroyed.handle_mapping(&device.raw, &device.limits);
|
||||
|
||||
destroyed.active.alloc().init(ActiveSubmission {
|
||||
index: submit_index,
|
||||
fence,
|
||||
resources: Vec::new(),
|
||||
mapped: Vec::new(),
|
||||
});
|
||||
|
||||
last_done
|
||||
};
|
||||
|
||||
if last_done != 0 {
|
||||
device.com_allocator.maintain(last_done);
|
||||
}
|
||||
device.maintain(false);
|
||||
device.pending.lock().active.alloc().init(ActiveSubmission {
|
||||
index: submit_index,
|
||||
fence,
|
||||
resources: Vec::new(),
|
||||
mapped: Vec::new(),
|
||||
});
|
||||
|
||||
// finally, return the command buffers to the allocator
|
||||
for &cmb_id in command_buffer_ids {
|
||||
@@ -1572,14 +1600,14 @@ pub fn device_create_swap_chain(
|
||||
Some(mut old) => {
|
||||
//TODO: remove this once gfx-rs stops destroying the old swapchain
|
||||
device.raw.wait_idle().unwrap();
|
||||
let mut destroyed = device.destroyed.lock();
|
||||
let mut pending = device.pending.lock();
|
||||
assert_eq!(old.device_id.value, device_id);
|
||||
for frame in old.frames {
|
||||
destroyed.destroy(
|
||||
pending.destroy(
|
||||
ResourceId::Texture(frame.texture_id.value),
|
||||
frame.texture_id.ref_count,
|
||||
);
|
||||
destroyed.destroy(
|
||||
pending.destroy(
|
||||
ResourceId::TextureView(frame.view_id.value),
|
||||
frame.view_id.ref_count,
|
||||
);
|
||||
@@ -1801,8 +1829,15 @@ pub extern "C" fn wgpu_buffer_set_sub_data(
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wgpu_device_destroy(device_id: BufferId) {
|
||||
HUB.devices.unregister(device_id);
|
||||
pub extern "C" fn wgpu_device_poll(device_id: DeviceId, force_wait: bool) {
|
||||
HUB.devices.read()[device_id].maintain(force_wait);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wgpu_device_destroy(device_id: DeviceId) {
|
||||
let device = HUB.devices.unregister(device_id);
|
||||
device.maintain(true);
|
||||
device.com_allocator.destroy(&device.raw);
|
||||
}
|
||||
|
||||
pub type BufferMapReadCallback =
|
||||
@@ -1818,22 +1853,36 @@ pub extern "C" fn wgpu_buffer_map_read_async(
|
||||
callback: BufferMapReadCallback,
|
||||
userdata: *mut u8,
|
||||
) {
|
||||
let mut buffer_guard = HUB.buffers.write();
|
||||
let buffer = &mut buffer_guard[buffer_id];
|
||||
let (device_id, ref_count) = {
|
||||
let mut buffer_guard = HUB.buffers.write();
|
||||
let buffer = &mut buffer_guard[buffer_id];
|
||||
|
||||
if buffer.pending_map_operation.is_some() {
|
||||
log::error!("wgpu_buffer_map_read_async failed: buffer mapping is pending");
|
||||
callback(BufferMapAsyncStatus::Error, std::ptr::null_mut(), userdata);
|
||||
return;
|
||||
if buffer.pending_map_operation.is_some() {
|
||||
log::error!("wgpu_buffer_map_read_async failed: buffer mapping is pending");
|
||||
callback(BufferMapAsyncStatus::Error, std::ptr::null_mut(), userdata);
|
||||
return;
|
||||
}
|
||||
|
||||
let range = start as u64..(start + size) as u64;
|
||||
buffer.pending_map_operation = Some(BufferMapOperation::Read(range, callback, userdata));
|
||||
(buffer.device_id.value, buffer.life_guard.ref_count.clone())
|
||||
};
|
||||
|
||||
let device_guard = HUB.devices.read();
|
||||
let device = &device_guard[device_id];
|
||||
|
||||
let usage = resource::BufferUsageFlags::MAP_READ;
|
||||
match device.trackers.lock().buffers.transit(buffer_id, &ref_count, usage, TrackPermit::REPLACE) {
|
||||
Ok(Tracktion::Keep) => {}
|
||||
Ok(Tracktion::Replace { .. }) => {
|
||||
//TODO: launch a memory barrier into `HOST_READ` access?
|
||||
}
|
||||
other => panic!("Invalid mapping transition {:?}", other),
|
||||
}
|
||||
|
||||
let range = start as u64..(start + size) as u64;
|
||||
buffer.pending_map_operation = Some(BufferMapOperation::Read(range, callback, userdata));
|
||||
|
||||
HUB.devices.read()[buffer.device_id.value]
|
||||
.destroyed
|
||||
device.pending
|
||||
.lock()
|
||||
.map(buffer_id, buffer.life_guard.ref_count.clone());
|
||||
.map(buffer_id, ref_count);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -1844,22 +1893,36 @@ pub extern "C" fn wgpu_buffer_map_write_async(
|
||||
callback: BufferMapWriteCallback,
|
||||
userdata: *mut u8,
|
||||
) {
|
||||
let mut buffer_guard = HUB.buffers.write();
|
||||
let buffer = &mut buffer_guard[buffer_id];
|
||||
let (device_id, ref_count) = {
|
||||
let mut buffer_guard = HUB.buffers.write();
|
||||
let buffer = &mut buffer_guard[buffer_id];
|
||||
|
||||
if buffer.pending_map_operation.is_some() {
|
||||
log::error!("wgpu_buffer_map_write_async failed: buffer mapping is pending");
|
||||
callback(BufferMapAsyncStatus::Error, std::ptr::null_mut(), userdata);
|
||||
return;
|
||||
if buffer.pending_map_operation.is_some() {
|
||||
log::error!("wgpu_buffer_map_write_async failed: buffer mapping is pending");
|
||||
callback(BufferMapAsyncStatus::Error, std::ptr::null_mut(), userdata);
|
||||
return;
|
||||
}
|
||||
|
||||
let range = start as u64..(start + size) as u64;
|
||||
buffer.pending_map_operation = Some(BufferMapOperation::Write(range, callback, userdata));
|
||||
(buffer.device_id.value, buffer.life_guard.ref_count.clone())
|
||||
};
|
||||
|
||||
let device_guard = HUB.devices.read();
|
||||
let device = &device_guard[device_id];
|
||||
|
||||
let usage = resource::BufferUsageFlags::MAP_WRITE;
|
||||
match device.trackers.lock().buffers.transit(buffer_id, &ref_count, usage, TrackPermit::REPLACE) {
|
||||
Ok(Tracktion::Keep) => {}
|
||||
Ok(Tracktion::Replace { .. }) => {
|
||||
//TODO: launch a memory barrier into `HOST_WRITE` access?
|
||||
}
|
||||
other => panic!("Invalid mapping transition {:?}", other),
|
||||
}
|
||||
|
||||
let range = start as u64..(start + size) as u64;
|
||||
buffer.pending_map_operation = Some(BufferMapOperation::Write(range, callback, userdata));
|
||||
|
||||
HUB.devices.read()[buffer.device_id.value]
|
||||
.destroyed
|
||||
device.pending
|
||||
.lock()
|
||||
.map(buffer_id, buffer.life_guard.ref_count.clone());
|
||||
.map(buffer_id, ref_count);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
||||
@@ -5,6 +5,8 @@ use crate::{
|
||||
#[cfg(feature = "local")]
|
||||
use crate::{DeviceId, SurfaceId};
|
||||
|
||||
#[cfg(feature = "local")]
|
||||
use log::info;
|
||||
#[cfg(feature = "remote")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -168,6 +170,7 @@ pub extern "C" fn wgpu_instance_get_adapter(
|
||||
desc: &AdapterDescriptor,
|
||||
) -> AdapterId {
|
||||
let adapter = instance_get_adapter(instance_id, desc);
|
||||
info!("Adapter {:?}", adapter.info);
|
||||
HUB.adapters.register_local(adapter)
|
||||
}
|
||||
|
||||
|
||||
@@ -285,6 +285,11 @@ impl Adapter {
|
||||
}
|
||||
|
||||
impl Device {
|
||||
/// Check for resource cleanups and mapping callbacks.
|
||||
pub fn poll(&self, force_wait: bool) {
|
||||
wgn::wgpu_device_poll(self.id, force_wait);
|
||||
}
|
||||
|
||||
pub fn create_shader_module(&self, spv: &[u8]) -> ShaderModule {
|
||||
let desc = wgn::ShaderModuleDescriptor {
|
||||
code: wgn::ByteArray {
|
||||
@@ -493,15 +498,24 @@ impl Device {
|
||||
|
||||
impl Drop for Device {
|
||||
fn drop(&mut self) {
|
||||
wgn::wgpu_device_poll(self.id, true);
|
||||
//TODO: make this work in general
|
||||
#[cfg(feature = "metal-auto-capture")]
|
||||
wgn::wgpu_device_destroy(self.id);
|
||||
}
|
||||
}
|
||||
|
||||
pub enum BufferMapAsyncResult<T> {
|
||||
Success(T),
|
||||
Error,
|
||||
pub struct BufferAsyncMapping<T> {
|
||||
pub data: T,
|
||||
buffer_id: wgn::BufferId,
|
||||
}
|
||||
//TODO: proper error type
|
||||
pub type BufferMapAsyncResult<T> = Result<BufferAsyncMapping<T>, ()>;
|
||||
|
||||
impl<T> Drop for BufferAsyncMapping<T> {
|
||||
fn drop(&mut self) {
|
||||
wgn::wgpu_buffer_unmap(self.buffer_id);
|
||||
}
|
||||
}
|
||||
|
||||
struct BufferMapReadAsyncUserData<T, F>
|
||||
@@ -510,6 +524,7 @@ where
|
||||
{
|
||||
size: u32,
|
||||
callback: F,
|
||||
buffer_id: wgn::BufferId,
|
||||
phantom: std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
@@ -519,6 +534,7 @@ where
|
||||
{
|
||||
size: u32,
|
||||
callback: F,
|
||||
buffer_id: wgn::BufferId,
|
||||
phantom: std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
@@ -539,28 +555,32 @@ impl Buffer {
|
||||
extern "C" fn buffer_map_read_callback_wrapper<T, F>(
|
||||
status: wgn::BufferMapAsyncStatus,
|
||||
data: *const u8,
|
||||
userdata: *mut u8,
|
||||
user_data: *mut u8,
|
||||
) where
|
||||
F: FnOnce(BufferMapAsyncResult<&[T]>),
|
||||
{
|
||||
let userdata =
|
||||
unsafe { Box::from_raw(userdata as *mut BufferMapReadAsyncUserData<T, F>) };
|
||||
let user_data =
|
||||
unsafe { Box::from_raw(user_data as *mut BufferMapReadAsyncUserData<T, F>) };
|
||||
let data = unsafe {
|
||||
slice::from_raw_parts(
|
||||
data as *const T,
|
||||
userdata.size as usize / std::mem::size_of::<T>(),
|
||||
user_data.size as usize / std::mem::size_of::<T>(),
|
||||
)
|
||||
};
|
||||
if let wgn::BufferMapAsyncStatus::Success = status {
|
||||
(userdata.callback)(BufferMapAsyncResult::Success::<&[T]>(data));
|
||||
(user_data.callback)(Ok(BufferAsyncMapping {
|
||||
data,
|
||||
buffer_id: user_data.buffer_id,
|
||||
}));
|
||||
} else {
|
||||
(userdata.callback)(BufferMapAsyncResult::Error);
|
||||
(user_data.callback)(Err(()))
|
||||
}
|
||||
}
|
||||
|
||||
let userdata = Box::new(BufferMapReadAsyncUserData {
|
||||
let user_data = Box::new(BufferMapReadAsyncUserData {
|
||||
size,
|
||||
callback,
|
||||
buffer_id: self.id,
|
||||
phantom: std::marker::PhantomData,
|
||||
});
|
||||
wgn::wgpu_buffer_map_read_async(
|
||||
@@ -568,7 +588,7 @@ impl Buffer {
|
||||
start,
|
||||
size,
|
||||
buffer_map_read_callback_wrapper::<T, F>,
|
||||
Box::into_raw(userdata) as *mut u8,
|
||||
Box::into_raw(user_data) as *mut u8,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -584,28 +604,32 @@ impl Buffer {
|
||||
extern "C" fn buffer_map_write_callback_wrapper<T, F>(
|
||||
status: wgn::BufferMapAsyncStatus,
|
||||
data: *mut u8,
|
||||
userdata: *mut u8,
|
||||
user_data: *mut u8,
|
||||
) where
|
||||
F: FnOnce(BufferMapAsyncResult<&mut [T]>),
|
||||
{
|
||||
let userdata =
|
||||
unsafe { Box::from_raw(userdata as *mut BufferMapWriteAsyncUserData<T, F>) };
|
||||
let user_data =
|
||||
unsafe { Box::from_raw(user_data as *mut BufferMapWriteAsyncUserData<T, F>) };
|
||||
let data = unsafe {
|
||||
slice::from_raw_parts_mut(
|
||||
data as *mut T,
|
||||
userdata.size as usize / std::mem::size_of::<T>(),
|
||||
user_data.size as usize / std::mem::size_of::<T>(),
|
||||
)
|
||||
};
|
||||
if let wgn::BufferMapAsyncStatus::Success = status {
|
||||
(userdata.callback)(BufferMapAsyncResult::Success::<&mut [T]>(data));
|
||||
(user_data.callback)(Ok(BufferAsyncMapping {
|
||||
data,
|
||||
buffer_id: user_data.buffer_id,
|
||||
}));
|
||||
} else {
|
||||
(userdata.callback)(BufferMapAsyncResult::Error);
|
||||
(user_data.callback)(Err(()))
|
||||
}
|
||||
}
|
||||
|
||||
let userdata = Box::new(BufferMapWriteAsyncUserData {
|
||||
let user_data = Box::new(BufferMapWriteAsyncUserData {
|
||||
size,
|
||||
callback,
|
||||
buffer_id: self.id,
|
||||
phantom: std::marker::PhantomData,
|
||||
});
|
||||
wgn::wgpu_buffer_map_write_async(
|
||||
@@ -613,7 +637,7 @@ impl Buffer {
|
||||
start,
|
||||
size,
|
||||
buffer_map_write_callback_wrapper::<T, F>,
|
||||
Box::into_raw(userdata) as *mut u8,
|
||||
Box::into_raw(user_data) as *mut u8,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user