From ff2a3e84fc1fed17783c50cfc94de3675959a453 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Tue, 8 Jun 2021 01:19:18 -0400 Subject: [PATCH] update synchronization, fix last errors in wgc --- Cargo.lock | 1 + wgpu-core/src/command/clear.rs | 2 +- wgpu-core/src/command/render.rs | 31 ++-- wgpu-core/src/command/transfer.rs | 2 - wgpu-core/src/conv.rs | 40 ----- wgpu-core/src/device/life.rs | 55 +------ wgpu-core/src/device/mod.rs | 245 +++++++++++++++++------------- wgpu-core/src/device/queue.rs | 48 +++--- wgpu-core/src/hub.rs | 8 +- wgpu-core/src/instance.rs | 15 +- wgpu-core/src/lib.rs | 17 ++- wgpu-core/src/swap_chain.rs | 18 ++- wgpu-core/src/track/mod.rs | 2 +- wgpu-hal/Cargo.toml | 1 + wgpu-hal/src/empty.rs | 15 +- wgpu-hal/src/lib.rs | 8 + 16 files changed, 253 insertions(+), 255 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5d4b71e568..c7fd6d6346 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1891,6 +1891,7 @@ version = "0.1.0" dependencies = [ "bitflags", "naga", + "raw-window-handle", "smallvec", "thiserror", "wgpu-types", diff --git a/wgpu-core/src/command/clear.rs b/wgpu-core/src/command/clear.rs index 4b79d63b0a..6a50ac708b 100644 --- a/wgpu-core/src/command/clear.rs +++ b/wgpu-core/src/command/clear.rs @@ -236,7 +236,7 @@ impl Global { hal::TextureUse::COPY_DST, ) .map_err(ClearError::InvalidTexture)?; - let dst_raw = dst_texture + let _dst_raw = dst_texture .raw .as_ref() .ok_or(ClearError::InvalidTexture(dst))?; diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index c628b88643..67f8f2b0e4 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -10,7 +10,7 @@ use crate::{ PassErrorScope, QueryResetMap, QueryUseError, RenderCommand, RenderCommandError, StateChange, }, - device::{AttachmentData, Device, RenderPassCompatibilityError, RenderPassContext}, + device::{AttachmentData, RenderPassCompatibilityError, RenderPassContext}, hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token}, id, memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction}, @@ -524,7 +524,6 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { color_attachments: &[RenderPassColorAttachment], depth_stencil_attachment: Option<&RenderPassDepthStencilAttachment>, cmd_buf: &mut CommandBuffer, - device: &Device, view_guard: &'a Storage, id::TextureViewId>, ) -> Result { profiling::scope!("start", "RenderPassInfo"); @@ -539,7 +538,6 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { let mut attachment_type_name = ""; let mut extent = None; let mut sample_count = 0; - let mut depth_stencil_aspects = hal::FormatAspect::empty(); let mut used_swap_chain = None::>; let mut add_view = |view: &TextureView, type_name| { @@ -576,8 +574,8 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { .map_err(|_| RenderPassErrorInner::InvalidAttachment(at.view))?; add_view(view, "depth")?; - depth_stencil_aspects = view.desc.aspects(); - if depth_stencil_aspects.contains(hal::FormatAspect::COLOR) { + let ds_aspects = view.desc.aspects(); + if ds_aspects.contains(hal::FormatAspect::COLOR) { return Err(RenderPassErrorInner::InvalidDepthStencilAttachmentFormat( view.desc.format, )); @@ -595,7 +593,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { .trackers .textures .query(source_id.value, view.selector.clone()); - let new_use = if at.is_read_only(depth_stencil_aspects)? { + let new_use = if at.is_read_only(ds_aspects)? { is_ds_read_only = true; hal::TextureUse::DEPTH_STENCIL_READ | hal::TextureUse::SAMPLED } else { @@ -672,18 +670,18 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { .views .use_extend(&*view_guard, resolve_target, (), ()) .map_err(|_| RenderPassErrorInner::InvalidAttachment(resolve_target))?; - if extent != Some(resolve_view.extent) { + if color_view.extent != resolve_view.extent { return Err(RenderPassErrorInner::AttachmentsDimensionMismatch { previous: (attachment_type_name, extent.unwrap_or_default()), mismatch: ("resolve", resolve_view.extent), }); } + if color_view.samples == 1 { + return Err(RenderPassErrorInner::InvalidResolveSourceSampleCount); + } if resolve_view.samples != 1 { return Err(RenderPassErrorInner::InvalidResolveTargetSampleCount); } - if sample_count == 1 { - return Err(RenderPassErrorInner::InvalidResolveSourceSampleCount); - } let boundary_usage = match resolve_view.source { TextureViewSource::Native(ref source_id) => { @@ -702,7 +700,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { let old_use = previous_use.unwrap_or(new_use); old_use..new_use } - TextureViewSource::SwapChain(source_id) => { + TextureViewSource::SwapChain(ref source_id) => { assert!(used_swap_chain.is_none()); used_swap_chain = Some(source_id.clone()); hal::TextureUse::UNINITIALIZED..hal::TextureUse::empty() @@ -867,10 +865,12 @@ impl Global { } let device = &device_guard[cmd_buf.device_id.value]; - let mut raw = device - .raw - .create_command_buffer(&hal::CommandBufferDescriptor { label: base.label }) - .unwrap(); //TODO: handle this better + let mut raw = unsafe { + device + .raw + .create_command_buffer(&hal::CommandBufferDescriptor { label: base.label }) + .unwrap() //TODO: handle this better + }; let (bundle_guard, mut token) = hub.render_bundles.read(&mut token); let (pipeline_layout_guard, mut token) = hub.pipeline_layouts.read(&mut token); @@ -892,7 +892,6 @@ impl Global { color_attachments, depth_stencil_attachment, cmd_buf, - device, &*view_guard, ) .map_pass_err(scope)?; diff --git a/wgpu-core/src/command/transfer.rs b/wgpu-core/src/command/transfer.rs index 79031f1d56..b16fc13889 100644 --- a/wgpu-core/src/command/transfer.rs +++ b/wgpu-core/src/command/transfer.rs @@ -538,7 +538,6 @@ impl Global { }), ); - let (block_width, _) = format_desc.block_dimensions; if !conv::is_valid_copy_dst_texture_format(dst_texture.desc.format) { return Err( TransferError::CopyToForbiddenTextureFormat(dst_texture.desc.format).into(), @@ -653,7 +652,6 @@ impl Global { true, )?; - let (block_width, _) = format_desc.block_dimensions; if !conv::is_valid_copy_src_texture_format(src_texture.desc.format) { return Err( TransferError::CopyFromForbiddenTextureFormat(src_texture.desc.format).into(), diff --git a/wgpu-core/src/conv.rs b/wgpu-core/src/conv.rs index 9a8014d743..4b9336db40 100644 --- a/wgpu-core/src/conv.rs +++ b/wgpu-core/src/conv.rs @@ -106,10 +106,8 @@ pub fn check_texture_dimension_size( limits: &wgt::Limits, ) -> Result<(), resource::TextureDimensionError> { use resource::{TextureDimensionError as Tde, TextureErrorDimension as Ted}; - use std::convert::TryInto; use wgt::TextureDimension::*; - let layers = depth_or_array_layers.try_into().unwrap_or(!0); let (extent_limits, sample_limit) = match dimension { D1 => ( [ @@ -155,41 +153,3 @@ pub fn check_texture_dimension_size( Ok(()) } - -pub fn map_color_f32(color: &wgt::Color) -> [f32; 4] { - [ - color.r as f32, - color.g as f32, - color.b as f32, - color.a as f32, - ] -} -pub fn map_color_i32(color: &wgt::Color) -> [i32; 4] { - [ - color.r as i32, - color.g as i32, - color.b as i32, - color.a as i32, - ] -} -pub fn map_color_u32(color: &wgt::Color) -> [u32; 4] { - [ - color.r as u32, - color.g as u32, - color.b as u32, - color.a as u32, - ] -} - -/// Take `value` and round it up to the nearest alignment `alignment`. -/// -/// ```text -/// (0, 3) -> 0 -/// (1, 3) -> 3 -/// (2, 3) -> 3 -/// (3, 3) -> 3 -/// (4, 3) -> 6 -/// ... -pub fn align_up(value: u32, alignment: u32) -> u32 { - ((value + alignment - 1) / alignment) * alignment -} diff --git a/wgpu-core/src/device/life.rs b/wgpu-core/src/device/life.rs index 23b2b2b008..02c95277cf 100644 --- a/wgpu-core/src/device/life.rs +++ b/wgpu-core/src/device/life.rs @@ -19,8 +19,6 @@ use thiserror::Error; use std::sync::atomic::Ordering; -const CLEANUP_WAIT_MS: u32 = 5000; - /// A struct that keeps lists of resources that are no longer needed by the user. #[derive(Debug, Default)] pub(super) struct SuspectedResources { @@ -165,7 +163,6 @@ impl NonReferencedResources { struct ActiveSubmission { index: SubmissionIndex, - fence: A::Fence, last_resources: NonReferencedResources, mapped: Vec>, } @@ -222,7 +219,6 @@ impl LifetimeTracker { pub fn track_submission( &mut self, index: SubmissionIndex, - fence: A::Fence, new_suspects: &SuspectedResources, temp_resources: impl Iterator>, ) { @@ -248,7 +244,6 @@ impl LifetimeTracker { self.active.alloc().init(ActiveSubmission { index, - fence, last_resources, mapped: Vec::new(), }); @@ -258,65 +253,23 @@ impl LifetimeTracker { self.mapped.push(Stored { value, ref_count }); } - fn wait_idle(&self, device: &A::Device) -> Result<(), WaitIdleError> { - if !self.active.is_empty() { - log::debug!("Waiting for IDLE..."); - let mut status = true; - //TODO: change this to wait for the last fence value only - for a in self.active.iter() { - status &= unsafe { - device - .wait( - &a.fence, - a.index as u64, //TODO: check this - CLEANUP_WAIT_MS, - ) - .map_err(DeviceError::from)? - }; - } - log::debug!("...Done"); - if !status { - // We timed out while waiting for the fences - return Err(WaitIdleError::StuckGpu); - } - } - Ok(()) - } - /// Returns the last submission index that is done. - pub fn triage_submissions( - &mut self, - device: &A::Device, - force_wait: bool, - ) -> Result { + pub fn triage_submissions(&mut self, last_done: SubmissionIndex) { profiling::scope!("triage_submissions"); - /* TODO: better sync - if force_wait { - self.wait_idle(device)?; - } + //TODO: enable when `is_sorted_by_key` is stable //debug_assert!(self.active.is_sorted_by_key(|a| a.index)); let done_count = self .active .iter() - .position(|a| unsafe { device.get_fence_value(&a.fence).unwrap() }) + .position(|a| a.index > last_done) .unwrap_or_else(|| self.active.len()); - let last_done = match done_count.checked_sub(1) { - Some(i) => self.active[i].index, - None => return Ok(0), - }; for a in self.active.drain(..done_count) { log::trace!("Active submission {} is done", a.index); self.free_resources.extend(a.last_resources); self.ready_to_map.extend(a.mapped); - unsafe { - device.destroy_fence(a.fence); - } - }*/ - let last_done = 0; - - Ok(last_done) + } } pub fn cleanup(&mut self, device: &A::Device) { diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 2991f9ffa5..e509b7c2b6 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -11,7 +11,8 @@ use crate::{ pipeline, resource, swap_chain, track::{BufferState, TextureSelector, TextureState, TrackerSet, UsageConflict}, validation::{self, check_buffer_usage, check_texture_usage}, - FastHashMap, Label, LabelHelpers, LifeGuard, MultiRefCount, Stored, SubmissionIndex, + CowHelpers as _, FastHashMap, Label, LabelHelpers as _, LifeGuard, MultiRefCount, Stored, + SubmissionIndex, }; use arrayvec::ArrayVec; @@ -31,6 +32,7 @@ pub mod trace; use smallvec::SmallVec; pub const SHADER_STAGE_COUNT: usize = 3; +const CLEANUP_WAIT_MS: u32 = 5000; const IMPLICIT_FAILURE: &str = "failed implicit"; @@ -54,13 +56,6 @@ pub(crate) struct AttachmentData { } impl Eq for AttachmentData {} impl AttachmentData { - pub(crate) fn all(&self) -> impl Iterator { - self.colors - .iter() - .chain(&self.resolves) - .chain(&self.depth_stencil) - } - pub(crate) fn map U>(&self, fun: F) -> AttachmentData { AttachmentData { colors: self.colors.iter().map(&fun).collect(), @@ -128,18 +123,19 @@ fn map_buffer( size: BufferAddress, kind: HostMap, ) -> Result, resource::BufferAccessError> { - let ptr = raw - .map_buffer(buffer.raw.as_ref().unwrap(), offset..offset + size) - .map_err(DeviceError::from)?; + let ptr = unsafe { + raw.map_buffer(buffer.raw.as_ref().unwrap(), offset..offset + size) + .map_err(DeviceError::from)? + }; buffer.sync_mapped_writes = match kind { - HostMap::Read if !buffer.is_coherent => { + HostMap::Read if !buffer.is_coherent => unsafe { raw.invalidate_mapped_ranges( buffer.raw.as_ref().unwrap(), iter::once(offset..offset + size), ); None - } + }, HostMap::Write if !buffer.is_coherent => Some(offset..offset + size), _ => None, }; @@ -163,10 +159,12 @@ fn map_buffer( ) }; if zero_init_needs_flush_now { - raw.flush_mapped_ranges( - buffer.raw.as_ref().unwrap(), - iter::once(uninitialized_range.start..uninitialized_range.start + num_bytes), - ); + unsafe { + raw.flush_mapped_ranges( + buffer.raw.as_ref().unwrap(), + iter::once(uninitialized_range.start..uninitialized_range.start + num_bytes), + ) + }; } } @@ -201,6 +199,7 @@ pub struct Device { //Note: The submission index here corresponds to the last submission that is done. pub(crate) life_guard: LifeGuard, pub(crate) active_submission_index: SubmissionIndex, + fence: A::Fence, /// Has to be locked temporarily only (locked last) pub(crate) trackers: Mutex, // Life tracker should be locked right after the device and before anything else. @@ -226,7 +225,7 @@ pub enum CreateDeviceError { impl Device { #[allow(clippy::too_many_arguments)] pub(crate) fn new( - device: hal::OpenDevice, + open: hal::OpenDevice, adapter_id: Stored, alignments: hal::Alignments, downlevel: wgt::DownlevelCapabilities, @@ -237,13 +236,16 @@ impl Device { if let Some(_) = trace_path { log::error!("Feature 'trace' is not enabled"); } + let fence = + unsafe { open.device.create_fence() }.map_err(|_| CreateDeviceError::OutOfMemory)?; Ok(Self { - raw: device.device, + raw: open.device, adapter_id, - queue: device.queue, + queue: open.queue, life_guard: LifeGuard::new(""), active_submission_index: 0, + fence, trackers: Mutex::new(TrackerSet::new(A::VARIANT)), life_tracker: Mutex::new(life::LifetimeTracker::new()), temp_suspected: life::SuspectedResources::default(), @@ -277,10 +279,6 @@ impl Device { } } - pub(crate) fn last_completed_submission_index(&self) -> SubmissionIndex { - self.life_guard.submission_index.load(Ordering::Acquire) - } - fn lock_life_internal<'this, 'token: 'this>( tracker: &'this Mutex>, _token: &mut Token<'token, Self>, @@ -313,13 +311,27 @@ impl Device { token, ); life_tracker.triage_mapped(hub, token); - let last_done = life_tracker.triage_submissions(&self.raw, force_wait)?; + + let last_done_index = if force_wait { + let current_index = self.active_submission_index; + unsafe { + self.raw + .wait(&self.fence, current_index, CLEANUP_WAIT_MS) + .map_err(DeviceError::from)? + }; + current_index + } else { + unsafe { + self.raw + .get_fence_value(&self.fence) + .map_err(DeviceError::from)? + } + }; + + life_tracker.triage_submissions(last_done_index); let callbacks = life_tracker.handle_mapping(hub, &self.raw, &self.trackers, token); life_tracker.cleanup(&self.raw); - self.life_guard - .submission_index - .store(last_done, Ordering::Release); Ok(callbacks) } @@ -416,11 +428,14 @@ impl Device { usage |= hal::BufferUse::COPY_DST; } + let mut memory_flags = hal::MemoryFlag::empty(); + memory_flags.set(hal::MemoryFlag::TRANSIENT, transient); + let hal_desc = hal::BufferDescriptor { - label: desc.label.map(|cow| cow.as_ref()), + label: desc.label.borrow_option(), size: desc.size, usage, - memory_flags: hal::MemoryFlag::empty(), + memory_flags, }; let buffer = unsafe { self.raw.create_buffer(&hal_desc) }.map_err(DeviceError::from)?; @@ -508,7 +523,7 @@ impl Device { usage: conv::map_texture_usage(desc.usage, desc.format.into()), memory_flags: hal::MemoryFlag::empty(), }; - let mut raw = unsafe { + let raw = unsafe { self.raw .create_texture(&hal_desc) .map_err(DeviceError::from)? @@ -900,8 +915,7 @@ impl Device { } => (Some(wgt::Features::BUFFER_BINDING_ARRAY), false), Bt::Buffer { ty: wgt::BufferBindingType::Storage { read_only }, - has_dynamic_offset, - min_binding_size: _, + .. } => (Some(wgt::Features::BUFFER_BINDING_ARRAY), !read_only), Bt::Sampler { .. } => (None, false), Bt::Texture { .. } => (Some(wgt::Features::SAMPLED_TEXTURE_BINDING_ARRAY), false), @@ -920,7 +934,7 @@ impl Device { }; // Validate the count parameter - if let Some(count) = entry.count { + if entry.count.is_some() { required_features |= array_feature .ok_or(binding_model::BindGroupLayoutEntryError::ArrayUnsupported) .map_err(|error| binding_model::CreateBindGroupLayoutError::Entry { @@ -1515,7 +1529,7 @@ impl Device { .iter() .map(|&id| &bgl_guard.get(id).unwrap().raw) .collect(), - push_constant_ranges: desc.push_constant_ranges, + push_constant_ranges: desc.push_constant_ranges.reborrow(), }; let raw = unsafe { @@ -1631,28 +1645,30 @@ impl Device { .get(desc.stage.module) .map_err(|_| validation::StageError::InvalidModule)?; - let flag = wgt::ShaderStage::COMPUTE; - let provided_layouts = match desc.layout { - Some(pipeline_layout_id) => Some(Device::get_introspection_bind_group_layouts( - pipeline_layout_guard - .get(pipeline_layout_id) - .map_err(|_| pipeline::CreateComputePipelineError::InvalidLayout)?, - &*bgl_guard, - )), - None => { - for _ in 0..self.limits.max_bind_groups { - derived_group_layouts.push(binding_model::BindEntryMap::default()); + { + let flag = wgt::ShaderStage::COMPUTE; + let provided_layouts = match desc.layout { + Some(pipeline_layout_id) => Some(Device::get_introspection_bind_group_layouts( + pipeline_layout_guard + .get(pipeline_layout_id) + .map_err(|_| pipeline::CreateComputePipelineError::InvalidLayout)?, + &*bgl_guard, + )), + None => { + for _ in 0..self.limits.max_bind_groups { + derived_group_layouts.push(binding_model::BindEntryMap::default()); + } + None } - None - } - }; - let _ = shader_module.interface.check_stage( - provided_layouts.as_ref().map(|p| p.as_slice()), - &mut derived_group_layouts, - &desc.stage.entry_point, - flag, - io, - )?; + }; + let _ = shader_module.interface.check_stage( + provided_layouts.as_ref().map(|p| p.as_slice()), + &mut derived_group_layouts, + &desc.stage.entry_point, + flag, + io, + )?; + } let pipeline_layout_id = match desc.layout { Some(id) => id, @@ -1672,7 +1688,7 @@ impl Device { label: desc.label.borrow_option(), layout: &layout.raw, stage: hal::ProgrammableStage { - entry_point: desc.stage.entry_point, + entry_point: desc.stage.entry_point.reborrow(), module: &shader_module.raw, }, }; @@ -1944,7 +1960,7 @@ impl Device { hal::ProgrammableStage { module: &shader_module.raw, - entry_point: stage.entry_point, + entry_point: stage.entry_point.reborrow(), } }; @@ -1989,7 +2005,7 @@ impl Device { Some(hal::ProgrammableStage { module: &shader_module.raw, - entry_point: fragment.stage.entry_point, + entry_point: fragment.stage.entry_point.reborrow(), }) } None => None, @@ -2050,7 +2066,7 @@ impl Device { vertex_buffers: vertex_buffers.into(), vertex_stage, primitive: desc.primitive, - depth_stencil: desc.depth_stencil, + depth_stencil: desc.depth_stencil.clone(), multisample: desc.multisample, fragment_stage, color_targets: Cow::Borrowed(color_targets), @@ -2117,14 +2133,21 @@ impl Device { submission_index: SubmissionIndex, token: &mut Token, ) -> Result<(), WaitIdleError> { - if self.last_completed_submission_index() <= submission_index { + let last_done_index = unsafe { + self.raw + .get_fence_value(&self.fence) + .map_err(DeviceError::from)? + }; + if last_done_index < submission_index { log::info!("Waiting for submission {:?}", submission_index); - self.lock_life(token) - .triage_submissions(&self.raw, true) - .map(|_| ()) - } else { - Ok(()) + unsafe { + self.raw + .wait(&self.fence, submission_index, !0) + .map_err(DeviceError::from)? + }; + self.lock_life(token).triage_submissions(submission_index); } + Ok(()) } fn create_query_set( @@ -2186,13 +2209,18 @@ impl Device { /// Wait for idle and remove resources that we can, before we die. pub(crate) fn prepare_to_die(&mut self) { let mut life_tracker = self.life_tracker.lock(); - if let Err(error) = life_tracker.triage_submissions(&self.raw, true) { - log::error!("failed to triage submissions: {}", error); + let current_index = self.active_submission_index; + if let Err(error) = unsafe { self.raw.wait(&self.fence, current_index, CLEANUP_WAIT_MS) } { + log::error!("failed to wait for the device: {:?}", error); } + life_tracker.triage_submissions(current_index); life_tracker.cleanup(&self.raw); } pub(crate) fn dispose(self) { + unsafe { + self.raw.destroy_fence(self.fence); + } self.pending_writes.dispose(&self.raw); } } @@ -2391,7 +2419,7 @@ impl Global { } }; let stage_buffer = stage.raw.unwrap(); - let ptr = match device.raw.map_buffer(&stage_buffer, 0..stage.size) { + let ptr = match unsafe { device.raw.map_buffer(&stage_buffer, 0..stage.size) } { Ok(ptr) => ptr, Err(e) => { let raw = buffer.raw.unwrap(); @@ -2496,19 +2524,21 @@ impl Global { } let raw_buf = buffer.raw.as_ref().unwrap(); - let ptr = device - .raw - .map_buffer(raw_buf, 0..data.len() as u64) - .map_err(DeviceError::from)?; - ptr::copy_nonoverlapping( - data.as_ptr(), - ptr.as_ptr().offset(offset as isize), - data.len(), - ); - device - .raw - .unmap_buffer(raw_buf) - .map_err(DeviceError::from)?; + unsafe { + let ptr = device + .raw + .map_buffer(raw_buf, 0..data.len() as u64) + .map_err(DeviceError::from)?; + ptr::copy_nonoverlapping( + data.as_ptr(), + ptr.as_ptr().offset(offset as isize), + data.len(), + ); + device + .raw + .unmap_buffer(raw_buf) + .map_err(DeviceError::from)?; + } //TODO: flush Ok(()) @@ -2540,19 +2570,21 @@ impl Global { //TODO: invalidate let raw_buf = buffer.raw.as_ref().unwrap(); - let ptr = device - .raw - .map_buffer(raw_buf, 0..data.len() as u64) - .map_err(DeviceError::from)?; - ptr::copy_nonoverlapping( - ptr.as_ptr().offset(offset as isize), - data.as_mut_ptr(), - data.len(), - ); - device - .raw - .unmap_buffer(raw_buf) - .map_err(DeviceError::from)?; + unsafe { + let ptr = device + .raw + .map_buffer(raw_buf, 0..data.len() as u64) + .map_err(DeviceError::from)?; + ptr::copy_nonoverlapping( + ptr.as_ptr().offset(offset as isize), + data.as_mut_ptr(), + data.len(), + ); + device + .raw + .unmap_buffer(raw_buf) + .map_err(DeviceError::from)?; + } Ok(()) } @@ -3375,7 +3407,7 @@ impl Global { label: desc.label.borrow_option(), }) }; - let mut raw = match cmd_buf_result { + let raw = match cmd_buf_result { Ok(raw) => raw, Err(error) => break DeviceError::from(error), }; @@ -3901,7 +3933,7 @@ impl Global { if !caps.formats.contains(&config.format) { return Err(swap_chain::CreateSwapChainError::UnsupportedFormat { requested: config.format, - available: caps.formats, + available: caps.formats.clone(), }); } if !caps.usage.contains(config.usage) { @@ -3940,7 +3972,7 @@ impl Global { Err(_) => break swap_chain::CreateSwapChainError::InvalidSurface, }; - let caps = { + let caps = unsafe { let surface = A::get_surface_mut(surface); let adapter = &adapter_guard[device.adapter_id.value]; match adapter.raw.adapter.surface_capabilities(surface) { @@ -4303,6 +4335,13 @@ impl Global { }); } let _ = ptr; + if needs_flush { + unsafe { + device + .raw + .flush_mapped_ranges(&stage_buffer, iter::once(0..buffer.size)); + } + } let raw_buf = buffer .raw @@ -4361,10 +4400,12 @@ impl Global { } let _ = (ptr, range); } - device - .raw - .unmap_buffer(buffer.raw.as_ref().unwrap()) - .map_err(DeviceError::from)?; + unsafe { + device + .raw + .unmap_buffer(buffer.raw.as_ref().unwrap()) + .map_err(DeviceError::from)? + }; } } Ok(None) diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index 4d9fdf7bd5..6a99e63d6c 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -168,7 +168,7 @@ impl super::Device { usage: hal::BufferUse::MAP_WRITE | hal::BufferUse::COPY_SRC, memory_flags: hal::MemoryFlag::TRANSIENT, }; - let mut buffer = unsafe { self.raw.create_buffer(&stage_desc)? }; + let buffer = unsafe { self.raw.create_buffer(&stage_desc)? }; let cmdbuf = match self.pending_writes.command_buffer.take() { Some(cmdbuf) => cmdbuf, @@ -501,14 +501,16 @@ impl Global { } } } - device - .raw - .unmap_buffer(&stage.buffer) - .map_err(DeviceError::from)?; - if !stage.is_coherent { + unsafe { device .raw - .flush_mapped_ranges(&stage.buffer, iter::once(0..stage_size)); + .unmap_buffer(&stage.buffer) + .map_err(DeviceError::from)?; + if !stage.is_coherent { + device + .raw + .flush_mapped_ranges(&stage.buffer, iter::once(0..stage_size)); + } } // WebGPU uses the physical size of the texture for copies whereas vulkan uses @@ -572,7 +574,7 @@ impl Global { device.active_submission_index += 1; let submit_index = device.active_submission_index; - let fence = { + { let mut signal_swapchain_semaphores = SmallVec::<[_; 1]>::new(); let (mut swap_chain_guard, mut token) = hub.swap_chains.write(&mut token); let (mut command_buffer_guard, mut token) = hub.command_buffers.write(&mut token); @@ -701,12 +703,14 @@ impl Global { cmdbuf.raw.last_mut().unwrap().finish(); } // execute resource transitions - let mut transit = device - .raw - .create_command_buffer(&hal::CommandBufferDescriptor { - label: Some("_Transit"), - }) - .map_err(DeviceError::from)?; + let mut transit = unsafe { + device + .raw + .create_command_buffer(&hal::CommandBufferDescriptor { + label: Some("_Transit"), + }) + .map_err(DeviceError::from)? + }; log::trace!("Stitching command buffer {:?} before submission", cmb_id); trackers.merge_extend_stateless(&cmdbuf.trackers); CommandBuffer::insert_barriers( @@ -731,13 +735,11 @@ impl Global { } } - // now prepare the GPU submission - let mut fence = device.raw.create_fence().map_err(DeviceError::from)?; //Note: we could technically avoid the heap Vec here let mut command_buffers = Vec::new(); command_buffers.extend(pending_write_command_buffer); for &cmd_buf_id in command_buffer_ids.iter() { - match command_buffer_guard.get(cmd_buf_id) { + match command_buffer_guard.get_mut(cmd_buf_id) { Ok(cmd_buf) if cmd_buf.is_finished() => { command_buffers.extend(cmd_buf.raw.drain(..)); } @@ -745,14 +747,13 @@ impl Global { } } - let fence_value = 1; //TODO unsafe { - device - .queue - .submit(command_buffers.into_iter(), Some((&mut fence, fence_value))); + device.queue.submit( + command_buffers.into_iter(), + Some((&mut device.fence, submit_index)), + ); } - fence - }; + } let callbacks = match device.maintain(&hub, false, &mut token) { Ok(callbacks) => callbacks, @@ -763,7 +764,6 @@ impl Global { profiling::scope!("cleanup"); super::Device::lock_life_internal(&device.life_tracker, &mut token).track_submission( submit_index, - fence, &device.temp_suspected, device.pending_writes.temp_resources.drain(..), ); diff --git a/wgpu-core/src/hub.rs b/wgpu-core/src/hub.rs index 03b7b597b3..970aa24415 100644 --- a/wgpu-core/src/hub.rs +++ b/wgpu-core/src/hub.rs @@ -627,14 +627,18 @@ impl Hub { if let Element::Occupied(command_buffer, _) = element { let device = &devices[command_buffer.device_id.value]; for raw in command_buffer.raw { - device.raw.destroy_command_buffer(raw); + unsafe { + device.raw.destroy_command_buffer(raw); + } } } } for element in self.bind_groups.data.write().map.drain(..) { if let Element::Occupied(bind_group, _) = element { let device = &devices[bind_group.device_id.value]; - device.raw.destroy_bind_group(bind_group.raw); + unsafe { + device.raw.destroy_bind_group(bind_group.raw); + } } } diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index dd5125bb84..e127018f1c 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -140,11 +140,12 @@ impl Adapter { wgt::TextureFormat::Rgba8Unorm, ]; - let caps = self - .raw - .adapter - .surface_capabilities(A::get_surface_mut(surface)) - .ok_or(GetSwapChainPreferredFormatError::UnsupportedQueueFamily)?; + let caps = unsafe { + self.raw + .adapter + .surface_capabilities(A::get_surface_mut(surface)) + .ok_or(GetSwapChainPreferredFormatError::UnsupportedQueueFamily)? + }; preferred_formats .iter() @@ -157,7 +158,7 @@ impl Adapter { &self, format: wgt::TextureFormat, ) -> wgt::TextureFormatFeatures { - let caps = self.raw.adapter.texture_format_capabilities(format); + let caps = unsafe { self.raw.adapter.texture_format_capabilities(format) }; let mut allowed_usages = format.describe().guaranteed_format_features.allowed_usages; allowed_usages.set( @@ -351,6 +352,7 @@ impl Global { }; Surface { + /* #[cfg(vulkan)] vulkan: map(&self.instance.vulkan), #[cfg(metal)] @@ -361,6 +363,7 @@ impl Global { dx11: map(&self.instance.dx11), #[cfg(gl)] gl: map(&self.instance.gl), + */ } } }; diff --git a/wgpu-core/src/lib.rs b/wgpu-core/src/lib.rs index b797a970c9..0af3c812a4 100644 --- a/wgpu-core/src/lib.rs +++ b/wgpu-core/src/lib.rs @@ -66,11 +66,11 @@ use loom::sync::atomic; #[cfg(not(test))] use std::sync::atomic; -use atomic::{AtomicUsize, Ordering}; +use atomic::{AtomicU64, AtomicUsize, Ordering}; use std::{borrow::Cow, os::raw::c_char, ptr}; -type SubmissionIndex = usize; +type SubmissionIndex = hal::FenceValue; type Index = u32; type Epoch = u32; @@ -90,6 +90,15 @@ impl<'a> LabelHelpers<'a> for Label<'a> { } } +trait CowHelpers<'a> { + fn reborrow(&'a self) -> Self; +} +impl<'a, T: ToOwned + ?Sized> CowHelpers<'a> for Cow<'a, T> { + fn reborrow(&'a self) -> Self { + Cow::Borrowed(self.as_ref()) + } +} + /// Reference count object that is 1:1 with each reference. #[derive(Debug)] struct RefCount(ptr::NonNull); @@ -197,7 +206,7 @@ impl Drop for MultiRefCount { #[derive(Debug)] pub struct LifeGuard { ref_count: Option, - submission_index: AtomicUsize, + submission_index: AtomicU64, #[cfg(debug_assertions)] pub(crate) label: String, } @@ -208,7 +217,7 @@ impl LifeGuard { let bx = Box::new(AtomicUsize::new(1)); Self { ref_count: ptr::NonNull::new(Box::into_raw(bx)).map(RefCount), - submission_index: AtomicUsize::new(0), + submission_index: AtomicU64::new(0), #[cfg(debug_assertions)] label: label.to_string(), } diff --git a/wgpu-core/src/swap_chain.rs b/wgpu-core/src/swap_chain.rs index eeb8f00faa..69b0d8bcb1 100644 --- a/wgpu-core/src/swap_chain.rs +++ b/wgpu-core/src/swap_chain.rs @@ -162,6 +162,10 @@ impl Global { return Err(DeviceError::from(err).into()); } hal::SurfaceError::Outdated => Status::Outdated, + hal::SurfaceError::Other(msg) => { + log::error!("acquire error: {}", msg); + Status::Lost + } }, ), }; @@ -175,10 +179,12 @@ impl Global { let view_id = match texture { Some(suf_texture) => { - let raw = device - .raw - .create_texture_view(suf_texture.borrow(), &hal_desc) - .map_err(DeviceError::from)?; + let raw = unsafe { + device + .raw + .create_texture_view(suf_texture.borrow(), &hal_desc) + .map_err(DeviceError::from)? + }; let view = resource::TextureView { raw, source: resource::TextureViewSource::SwapChain(Stored { @@ -284,6 +290,10 @@ impl Global { hal::SurfaceError::Lost => Ok(Status::Lost), hal::SurfaceError::Device(err) => Err(SwapChainError::from(DeviceError::from(err))), hal::SurfaceError::Outdated => Ok(Status::Outdated), + hal::SurfaceError::Other(msg) => { + log::error!("acquire error: {}", msg); + Err(SwapChainError::InvalidSurface) + } }, } } diff --git a/wgpu-core/src/track/mod.rs b/wgpu-core/src/track/mod.rs index 500e036602..3fe3825d19 100644 --- a/wgpu-core/src/track/mod.rs +++ b/wgpu-core/src/track/mod.rs @@ -599,7 +599,7 @@ impl TrackerSet { } /// Clear all the trackers. - pub fn clear(&mut self) { + pub fn _clear(&mut self) { self.buffers.clear(); self.textures.clear(); self.views.clear(); diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 1da7c57998..d605a9d875 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -15,6 +15,7 @@ license = "MPL-2.0" [dependencies] bitflags = "1.0" +raw-window-handle = "0.3" smallvec = "1" thiserror = "1" wgt = { package = "wgpu-types", path = "../wgpu-types" } diff --git a/wgpu-hal/src/empty.rs b/wgpu-hal/src/empty.rs index 3abe0c0872..bbb44fde9e 100644 --- a/wgpu-hal/src/empty.rs +++ b/wgpu-hal/src/empty.rs @@ -37,6 +37,12 @@ impl crate::Api for Api { } impl crate::Instance for Context { + unsafe fn create_surface( + &self, + rwh: &impl raw_window_handle::HasRawWindowHandle, + ) -> Result { + Ok(Context) + } unsafe fn enumerate_adapters(&self) -> Vec> { Vec::new() } @@ -266,10 +272,10 @@ impl crate::CommandBuffer for Encoder { ) { } + // render + unsafe fn begin_render_pass(&mut self, desc: &crate::RenderPassDescriptor) {} unsafe fn end_render_pass(&mut self) {} - unsafe fn begin_compute_pass(&mut self) {} - unsafe fn end_compute_pass(&mut self) {} unsafe fn set_bind_group( &mut self, @@ -357,6 +363,11 @@ impl crate::CommandBuffer for Encoder { ) { } + // compute + + unsafe fn begin_compute_pass(&mut self) {} + unsafe fn end_compute_pass(&mut self) {} + unsafe fn set_compute_pipeline(&mut self, pipeline: &Resource) {} unsafe fn dispatch(&mut self, count: [u32; 3]) {} diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 74e0d61b5e..58d145cc3e 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -96,6 +96,10 @@ pub enum SurfaceError { Other(&'static str), } +#[derive(Clone, Debug, PartialEq, Error)] +#[error("Window handle is not supported")] +pub struct UnsupportedWindow; + pub trait Api: Clone + Sized { type Instance: Instance; type Surface: Surface; @@ -121,6 +125,10 @@ pub trait Api: Clone + Sized { } pub trait Instance { + unsafe fn create_surface( + &self, + rwh: &impl raw_window_handle::HasRawWindowHandle, + ) -> Result; unsafe fn enumerate_adapters(&self) -> Vec>; }