diff --git a/wgpu-core/Cargo.toml b/wgpu-core/Cargo.toml index cb43a7983b..6a9bd1478e 100644 --- a/wgpu-core/Cargo.toml +++ b/wgpu-core/Cargo.toml @@ -37,7 +37,7 @@ thiserror = "1" [dependencies.naga] git = "https://github.com/gfx-rs/naga" tag = "gfx-25" -features = ["spv-in", "spv-out", "wgsl-in"] +features = ["spv-in", "wgsl-in"] [dependencies.wgt] path = "../wgpu-types" diff --git a/wgpu-core/src/binding_model.rs b/wgpu-core/src/binding_model.rs index 6864e0f123..902227b968 100644 --- a/wgpu-core/src/binding_model.rs +++ b/wgpu-core/src/binding_model.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use crate::{ - device::{descriptor::DescriptorSet, DeviceError, MissingFeatures, SHADER_STAGE_COUNT}, + device::{DeviceError, MissingFeatures, SHADER_STAGE_COUNT}, hub::Resource, id::{BindGroupLayoutId, BufferId, DeviceId, SamplerId, TextureViewId, Valid}, memory_init_tracker::MemoryInitTrackerAction, @@ -633,7 +633,7 @@ pub struct BindGroupDynamicBindingData { #[derive(Debug)] pub struct BindGroup { - pub(crate) raw: DescriptorSet, + pub(crate) raw: A::BindGroup, pub(crate) device_id: Stored, pub(crate) layout_id: Valid, pub(crate) life_guard: LifeGuard, diff --git a/wgpu-core/src/command/bind.rs b/wgpu-core/src/command/bind.rs index 310cd3677c..43d73ce45c 100644 --- a/wgpu-core/src/command/bind.rs +++ b/wgpu-core/src/command/bind.rs @@ -7,7 +7,7 @@ use crate::{ device::SHADER_STAGE_COUNT, hub::{HalApi, Storage}, id::{BindGroupId, BindGroupLayoutId, PipelineLayoutId, Valid}, - Stored, MAX_BIND_GROUPS, + Stored, }; use arrayvec::ArrayVec; @@ -42,7 +42,7 @@ mod compat { #[derive(Debug)] pub struct Manager { - entries: [Entry; crate::MAX_BIND_GROUPS], + entries: [Entry; hal::MAX_BIND_GROUPS], } impl Manager { @@ -145,7 +145,7 @@ pub(super) struct EntryPayload { pub(super) struct Binder { pub(super) pipeline_layout_id: Option>, //TODO: strongly `Stored` manager: compat::Manager>, - payloads: [EntryPayload; MAX_BIND_GROUPS], + payloads: [EntryPayload; hal::MAX_BIND_GROUPS], } impl Binder { diff --git a/wgpu-core/src/command/bundle.rs b/wgpu-core/src/command/bundle.rs index e9b96a43c2..a5d76b76f1 100644 --- a/wgpu-core/src/command/bundle.rs +++ b/wgpu-core/src/command/bundle.rs @@ -43,22 +43,20 @@ use crate::{ StateChange, }, conv, - device::{ - AttachmentData, Device, DeviceError, RenderPassContext, MAX_VERTEX_BUFFERS, - SHADER_STAGE_COUNT, - }, - hal::BufferUse, + device::{AttachmentData, Device, DeviceError, RenderPassContext, SHADER_STAGE_COUNT}, hub::{GlobalIdentityHandlerFactory, HalApi, Hub, Resource, Storage, Token}, id, memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction}, track::{TrackerSet, UsageConflict}, validation::check_buffer_usage, - Label, LabelHelpers, LifeGuard, Stored, MAX_BIND_GROUPS, + Label, LabelHelpers, LifeGuard, Stored, }; use arrayvec::ArrayVec; -use std::{borrow::Cow, iter, mem, ops::Range}; +use std::{borrow::Cow, mem, ops::Range}; use thiserror::Error; +use hal::CommandBuffer as _; + /// Describes a [`RenderBundleEncoder`]. #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] #[cfg_attr(feature = "trace", derive(serde::Serialize))] @@ -105,7 +103,7 @@ impl RenderBundleEncoder { if sc == 0 || sc > 32 || !conv::is_power_of_two(sc) { return Err(CreateRenderBundleError::InvalidSampleCount(sc)); } - sc as u8 + sc }, }, }) @@ -150,10 +148,12 @@ impl RenderBundleEncoder { let mut state = State { trackers: TrackerSet::new(self.parent_id.backend()), index: IndexState::new(), - vertex: (0..MAX_VERTEX_BUFFERS) + vertex: (0..hal::MAX_VERTEX_BUFFERS) .map(|_| VertexState::new()) .collect(), - bind: (0..MAX_BIND_GROUPS).map(|_| BindState::new()).collect(), + bind: (0..hal::MAX_BIND_GROUPS) + .map(|_| BindState::new()) + .collect(), push_constant_ranges: PushConstantState::new(), raw_dynamic_offsets: Vec::new(), flat_dynamic_offsets: Vec::new(), @@ -260,7 +260,7 @@ impl RenderBundleEncoder { let buffer = state .trackers .buffers - .use_extend(&*buffer_guard, buffer_id, (), BufferUse::INDEX) + .use_extend(&*buffer_guard, buffer_id, (), hal::BufferUse::INDEX) .unwrap(); check_buffer_usage(buffer.usage, wgt::BufferUsage::INDEX) .map_pass_err(scope)?; @@ -287,7 +287,7 @@ impl RenderBundleEncoder { let buffer = state .trackers .buffers - .use_extend(&*buffer_guard, buffer_id, (), BufferUse::VERTEX) + .use_extend(&*buffer_guard, buffer_id, (), hal::BufferUse::VERTEX) .unwrap(); check_buffer_usage(buffer.usage, wgt::BufferUsage::VERTEX) .map_pass_err(scope)?; @@ -408,7 +408,7 @@ impl RenderBundleEncoder { let buffer = state .trackers .buffers - .use_extend(&*buffer_guard, buffer_id, (), BufferUse::INDIRECT) + .use_extend(&*buffer_guard, buffer_id, (), hal::BufferUse::INDIRECT) .unwrap(); check_buffer_usage(buffer.usage, wgt::BufferUsage::INDIRECT) .map_pass_err(scope)?; @@ -444,7 +444,7 @@ impl RenderBundleEncoder { let buffer = state .trackers .buffers - .use_extend(&*buffer_guard, buffer_id, (), BufferUse::INDIRECT) + .use_extend(&*buffer_guard, buffer_id, (), hal::BufferUse::INDIRECT) .map_err(|err| RenderCommandError::Buffer(buffer_id, err)) .map_pass_err(scope)?; check_buffer_usage(buffer.usage, wgt::BufferUsage::INDIRECT) @@ -567,7 +567,7 @@ impl RenderBundle { /// The only failure condition is if some of the used buffers are destroyed. pub(crate) unsafe fn execute( &self, - cmd_buf: &mut B::CommandBuffer, + cmd_buf: &mut A::CommandBuffer, pipeline_layout_guard: &Storage< crate::binding_model::PipelineLayout, id::PipelineLayoutId, @@ -576,12 +576,10 @@ impl RenderBundle { pipeline_guard: &Storage, id::RenderPipelineId>, buffer_guard: &Storage, id::BufferId>, ) -> Result<(), ExecutionError> { - use hal::command::CommandBuffer as _; - let mut offsets = self.base.dynamic_offsets.as_slice(); let mut pipeline_layout_id = None::>; if let Some(ref label) = self.base.label { - cmd_buf.begin_debug_marker(label, 0); + cmd_buf.begin_debug_marker(label); } for command in self.base.commands.iter() { @@ -592,17 +590,17 @@ impl RenderBundle { bind_group_id, } => { let bind_group = bind_group_guard.get(bind_group_id).unwrap(); - cmd_buf.bind_graphics_descriptor_sets( + cmd_buf.set_bind_group( &pipeline_layout_guard[pipeline_layout_id.unwrap()].raw, - index as usize, - iter::once(bind_group.raw.raw()), - offsets.iter().take(num_dynamic_offsets as usize).cloned(), + index as u32, + &bind_group.raw, + &offsets[num_dynamic_offsets as usize..], ); offsets = &offsets[num_dynamic_offsets as usize..]; } RenderCommand::SetPipeline(pipeline_id) => { let pipeline = pipeline_guard.get(pipeline_id).unwrap(); - cmd_buf.bind_graphics_pipeline(&pipeline.raw); + cmd_buf.set_render_pipeline(&pipeline.raw); pipeline_layout_id = Some(pipeline.layout_id.value); } @@ -612,19 +610,18 @@ impl RenderBundle { offset, size, } => { - let index_type = conv::map_index_format(index_format); - - let &(ref buffer, _) = buffer_guard + let buffer = buffer_guard .get(buffer_id) .unwrap() .raw .as_ref() .ok_or(ExecutionError::DestroyedBuffer(buffer_id))?; - let range = hal::buffer::SubRange { + let bb = hal::BufferBinding { + buffer, offset, - size: size.map(|s| s.get()), + size, }; - cmd_buf.bind_index_buffer(buffer, range, index_type); + cmd_buf.set_index_buffer(bb, index_format); } RenderCommand::SetVertexBuffer { slot, @@ -632,17 +629,18 @@ impl RenderBundle { offset, size, } => { - let &(ref buffer, _) = buffer_guard + let buffer = buffer_guard .get(buffer_id) .unwrap() .raw .as_ref() .ok_or(ExecutionError::DestroyedBuffer(buffer_id))?; - let range = hal::buffer::SubRange { + let bb = hal::BufferBinding { + buffer, offset, - size: size.map(|s| s.get()), + size, }; - cmd_buf.bind_vertex_buffers(slot, iter::once((buffer, range))); + cmd_buf.set_vertex_buffer(slot, bb); } RenderCommand::SetPushConstant { stages, @@ -659,20 +657,15 @@ impl RenderBundle { let data_slice = &self.base.push_constant_data [(values_offset as usize)..values_end_offset]; - cmd_buf.push_graphics_constants( - &pipeline_layout.raw, - conv::map_shader_stage_flags(stages), - offset, - &data_slice, - ) + cmd_buf.set_push_constants(&pipeline_layout.raw, stages, offset, data_slice) } else { super::push_constant_clear( offset, size_bytes, |clear_offset, clear_data| { - cmd_buf.push_graphics_constants( + cmd_buf.set_push_constants( &pipeline_layout.raw, - conv::map_shader_stage_flags(stages), + stages, clear_offset, clear_data, ); @@ -686,10 +679,7 @@ impl RenderBundle { first_vertex, first_instance, } => { - cmd_buf.draw( - first_vertex..first_vertex + vertex_count, - first_instance..first_instance + instance_count, - ); + cmd_buf.draw(first_vertex, vertex_count, first_instance, instance_count); } RenderCommand::DrawIndexed { index_count, @@ -699,9 +689,11 @@ impl RenderBundle { first_instance, } => { cmd_buf.draw_indexed( - first_index..first_index + index_count, + first_index, + index_count, base_vertex, - first_instance..first_instance + instance_count, + first_instance, + instance_count, ); } RenderCommand::MultiDrawIndirect { @@ -710,13 +702,13 @@ impl RenderBundle { count: None, indexed: false, } => { - let &(ref buffer, _) = buffer_guard + let buffer = buffer_guard .get(buffer_id) .unwrap() .raw .as_ref() .ok_or(ExecutionError::DestroyedBuffer(buffer_id))?; - cmd_buf.draw_indirect(buffer, offset, 1, 0); + cmd_buf.draw_indirect(buffer, offset, 1); } RenderCommand::MultiDrawIndirect { buffer_id, @@ -724,13 +716,13 @@ impl RenderBundle { count: None, indexed: true, } => { - let &(ref buffer, _) = buffer_guard + let buffer = buffer_guard .get(buffer_id) .unwrap() .raw .as_ref() .ok_or(ExecutionError::DestroyedBuffer(buffer_id))?; - cmd_buf.draw_indexed_indirect(buffer, offset, 1, 0); + cmd_buf.draw_indexed_indirect(buffer, offset, 1); } RenderCommand::MultiDrawIndirect { .. } | RenderCommand::MultiDrawIndirectCount { .. } => { @@ -943,8 +935,8 @@ struct VertexLimitState { struct State { trackers: TrackerSet, index: IndexState, - vertex: ArrayVec<[VertexState; MAX_VERTEX_BUFFERS]>, - bind: ArrayVec<[BindState; MAX_BIND_GROUPS]>, + vertex: ArrayVec<[VertexState; hal::MAX_VERTEX_BUFFERS]>, + bind: ArrayVec<[BindState; hal::MAX_BIND_GROUPS]>, push_constant_ranges: PushConstantState, raw_dynamic_offsets: Vec, flat_dynamic_offsets: Vec, diff --git a/wgpu-core/src/command/clear.rs b/wgpu-core/src/command/clear.rs index 032b6b4a30..4b79d63b0a 100644 --- a/wgpu-core/src/command/clear.rs +++ b/wgpu-core/src/command/clear.rs @@ -8,16 +8,13 @@ use std::{num::NonZeroU32, ops::Range}; use crate::device::trace::Command as TraceCommand; use crate::{ command::CommandBuffer, - conv, - device::all_buffer_stages, hub::{Global, GlobalIdentityHandlerFactory, HalApi, Token}, id::{BufferId, CommandEncoderId, TextureId}, memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction}, - resource::{BufferUse, TextureUse}, track::TextureSelector, }; -use hal::command::CommandBuffer as _; +use hal::CommandBuffer as _; use thiserror::Error; use wgt::{ BufferAddress, BufferSize, BufferUsage, ImageSubresourceRange, TextureAspect, TextureUsage, @@ -46,22 +43,22 @@ pub enum ClearError { }, #[error("destination buffer/texture is missing the `COPY_DST` usage flag")] MissingCopyDstUsageFlag(Option, Option), - #[error("texture lacks the aspects that were specified in the image subresource range. Texture has {texture_aspects:?}, specified was {subresource_range_aspects:?}")] + #[error("texture lacks the aspects that were specified in the image subresource range. Texture with format {texture_format:?}, specified was {subresource_range_aspects:?}")] MissingTextureAspect { - texture_aspects: hal::FormatAspect, + texture_format: wgt::TextureFormat, subresource_range_aspects: TextureAspect, }, #[error("image subresource level range is outside of the texture's level range. texture range is {texture_level_range:?}, \ whereas subesource range specified start {subresource_base_mip_level} and count {subresource_mip_level_count:?}")] InvalidTextureLevelRange { - texture_level_range: Range, + texture_level_range: Range, subresource_base_mip_level: u32, subresource_mip_level_count: Option, }, #[error("image subresource layer range is outside of the texture's layer range. texture range is {texture_layer_range:?}, \ whereas subesource range specified start {subresource_base_array_layer} and count {subresource_array_layer_count:?}")] InvalidTextureLayerRange { - texture_layer_range: Range, + texture_layer_range: Range, subresource_base_array_layer: u32, subresource_array_layer_count: Option, }, @@ -96,9 +93,9 @@ impl Global { let (dst_buffer, dst_pending) = cmd_buf .trackers .buffers - .use_replace(&*buffer_guard, dst, (), BufferUse::COPY_DST) + .use_replace(&*buffer_guard, dst, (), hal::BufferUse::COPY_DST) .map_err(ClearError::InvalidBuffer)?; - let &(ref dst_raw, _) = dst_buffer + let dst_raw = dst_buffer .raw .as_ref() .ok_or(ClearError::InvalidBuffer(dst))?; @@ -124,8 +121,11 @@ impl Global { } } - let num_bytes_filled = size.map_or(dst_buffer.size - offset, |s| s.get()); - if num_bytes_filled == 0 { + let end = match size { + Some(size) => offset + size.get(), + None => dst_buffer.size, + }; + if offset == end { log::trace!("Ignoring fill_buffer of size 0"); return Ok(()); } @@ -134,7 +134,7 @@ impl Global { cmd_buf.buffer_memory_init_actions.extend( dst_buffer .initialization_status - .check(offset..(offset + num_bytes_filled)) + .check(offset..end) .map(|range| MemoryInitTrackerAction { id: dst, range, @@ -143,24 +143,11 @@ impl Global { ); // actual hal barrier & operation - let dst_barrier = dst_pending - .map(|pending| pending.into_hal(dst_buffer)) - .next(); + let dst_barrier = dst_pending.map(|pending| pending.into_hal(dst_buffer)); let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap(); unsafe { - cmd_buf_raw.pipeline_barrier( - all_buffer_stages()..hal::pso::PipelineStage::TRANSFER, - hal::memory::Dependencies::empty(), - dst_barrier.into_iter(), - ); - cmd_buf_raw.fill_buffer( - dst_raw, - hal::buffer::SubRange { - offset, - size: size.map(|s| s.get()), - }, - 0, - ); + cmd_buf_raw.transition_buffers(dst_barrier); + cmd_buf_raw.fill_buffer(dst_raw, offset..end, 0); } Ok(()) } @@ -198,24 +185,20 @@ impl Global { .map_err(|_| ClearError::InvalidTexture(dst))?; // Check if subresource aspects are valid. - let aspects = match subresource_range.aspect { - wgt::TextureAspect::All => dst_texture.aspects, - wgt::TextureAspect::DepthOnly => hal::FormatAspect::DEPTH, - wgt::TextureAspect::StencilOnly => hal::FormatAspect::STENCIL, - }; - if !dst_texture.aspects.contains(aspects) { + let requested_aspects = hal::FormatAspect::from(subresource_range.aspect); + let clear_aspects = hal::FormatAspect::from(dst_texture.desc.format) & requested_aspects; + if clear_aspects.is_empty() { return Err(ClearError::MissingTextureAspect { - texture_aspects: dst_texture.aspects, + texture_format: dst_texture.desc.format, subresource_range_aspects: subresource_range.aspect, }); }; // Check if subresource level range is valid - let subresource_level_end = if let Some(count) = subresource_range.mip_level_count { - (subresource_range.base_mip_level + count.get()) as u8 - } else { - dst_texture.full_range.levels.end + let subresource_level_end = match subresource_range.mip_level_count { + Some(count) => subresource_range.base_mip_level + count.get(), + None => dst_texture.full_range.levels.end, }; - if dst_texture.full_range.levels.start > subresource_range.base_mip_level as u8 + if dst_texture.full_range.levels.start > subresource_range.base_mip_level || dst_texture.full_range.levels.end < subresource_level_end { return Err(ClearError::InvalidTextureLevelRange { @@ -225,12 +208,11 @@ impl Global { }); } // Check if subresource layer range is valid - let subresource_layer_end = if let Some(count) = subresource_range.array_layer_count { - (subresource_range.base_array_layer + count.get()) as u16 - } else { - dst_texture.full_range.layers.end + let subresource_layer_end = match subresource_range.array_layer_count { + Some(count) => subresource_range.base_array_layer + count.get(), + None => dst_texture.full_range.layers.end, }; - if dst_texture.full_range.layers.start > subresource_range.base_array_layer as u16 + if dst_texture.full_range.layers.start > subresource_range.base_array_layer || dst_texture.full_range.layers.end < subresource_layer_end { return Err(ClearError::InvalidTextureLayerRange { @@ -248,31 +230,26 @@ impl Global { &*texture_guard, dst, TextureSelector { - levels: subresource_range.base_mip_level as u8..subresource_level_end, - layers: subresource_range.base_array_layer as u16..subresource_layer_end, + levels: subresource_range.base_mip_level..subresource_level_end, + layers: subresource_range.base_array_layer..subresource_layer_end, }, - TextureUse::COPY_DST, + hal::TextureUse::COPY_DST, ) .map_err(ClearError::InvalidTexture)?; - let &(ref dst_raw, _) = dst_texture + let dst_raw = dst_texture .raw .as_ref() .ok_or(ClearError::InvalidTexture(dst))?; - if !dst_texture.usage.contains(TextureUsage::COPY_DST) { + if !dst_texture.desc.usage.contains(TextureUsage::COPY_DST) { return Err(ClearError::MissingCopyDstUsageFlag(None, Some(dst))); } // actual hal barrier & operation - let dst_barrier = dst_pending - .map(|pending| pending.into_hal(dst_texture)) - .next(); + let dst_barrier = dst_pending.map(|pending| pending.into_hal(dst_texture)); let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap(); unsafe { - cmd_buf_raw.pipeline_barrier( - all_buffer_stages()..hal::pso::PipelineStage::TRANSFER, - hal::memory::Dependencies::empty(), - dst_barrier.into_iter(), - ); + cmd_buf_raw.transition_textures(dst_barrier); + /*TODO: image clears cmd_buf_raw.clear_image( dst_raw, hal::image::Layout::TransferDstOptimal, @@ -288,7 +265,7 @@ impl Global { layer_start: subresource_range.base_array_layer as u16, layer_count: subresource_range.array_layer_count.map(|c| c.get() as u16), }), - ); + );*/ } Ok(()) } diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index c0a537be19..e54c085952 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -13,7 +13,7 @@ use crate::{ id, memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction}, resource::{Buffer, Texture}, - track::{StatefulTrackerSubset, TrackerSet, UsageConflict}, + track::{StatefulTrackerSubset, TrackerSet, UsageConflict, UseExtendError}, validation::{check_buffer_usage, MissingBufferUsageError}, Label, DOWNLEVEL_ERROR_WARNING_MESSAGE, }; @@ -22,7 +22,6 @@ use hal::CommandBuffer as _; use thiserror::Error; use wgt::{BufferAddress, BufferUsage, ShaderStage}; -use crate::track::UseExtendError; use std::{fmt, mem, str}; #[doc(hidden)] @@ -293,7 +292,7 @@ impl Global { if let Some(ref label) = base.label { unsafe { - raw.begin_debug_marker(label, 0); + raw.begin_debug_marker(label); } } @@ -377,19 +376,16 @@ impl Global { if !entries.is_empty() { let pipeline_layout = &pipeline_layout_guard[pipeline_layout_id.unwrap()].raw; - let desc_sets = entries.iter().map(|e| { - bind_group_guard[e.group_id.as_ref().unwrap().value] - .raw - .raw() - }); - let offsets = entries.iter().flat_map(|e| &e.dynamic_offsets).cloned(); - unsafe { - raw.bind_compute_descriptor_sets( - pipeline_layout, - index as usize, - desc_sets, - offsets, - ); + for (i, e) in entries.iter().enumerate() { + let raw_bg = &bind_group_guard[e.group_id.as_ref().unwrap().value].raw; + unsafe { + raw.set_bind_group( + pipeline_layout, + index as u32 + i as u32, + raw_bg, + &e.dynamic_offsets, + ); + } } } } @@ -408,7 +404,7 @@ impl Global { .map_pass_err(scope)?; unsafe { - raw.bind_compute_pipeline(&pipeline.raw); + raw.set_compute_pipeline(&pipeline.raw); } // Rebind resources @@ -420,19 +416,17 @@ impl Global { pipeline.layout_id.value, ); if !entries.is_empty() { - let desc_sets = entries.iter().map(|e| { - bind_group_guard[e.group_id.as_ref().unwrap().value] - .raw - .raw() - }); - let offsets = entries.iter().flat_map(|e| &e.dynamic_offsets).cloned(); - unsafe { - raw.bind_compute_descriptor_sets( - &pipeline_layout.raw, - start_index, - desc_sets, - offsets, - ); + for (i, e) in entries.iter().enumerate() { + let raw_bg = + &bind_group_guard[e.group_id.as_ref().unwrap().value].raw; + unsafe { + raw.set_bind_group( + &pipeline_layout.raw, + start_index as u32 + i as u32, + raw_bg, + &e.dynamic_offsets, + ); + } } } @@ -447,8 +441,9 @@ impl Global { offset, size_bytes, |clear_offset, clear_data| unsafe { - raw.push_compute_constants( + raw.set_push_constants( &pipeline_layout.raw, + wgt::ShaderStage::COMPUTE, clear_offset, clear_data, ); @@ -488,7 +483,14 @@ impl Global { ) .map_pass_err(scope)?; - unsafe { raw.push_compute_constants(&pipeline_layout.raw, offset, data_slice) } + unsafe { + raw.set_push_constants( + &pipeline_layout.raw, + wgt::ShaderStage::COMPUTE, + offset, + data_slice, + ); + } } ComputeCommand::Dispatch(groups) => { let scope = PassErrorScope::Dispatch { @@ -537,7 +539,7 @@ impl Global { .map_pass_err(scope); } - let &(ref buf_raw, _) = indirect_buffer + let buf_raw = indirect_buffer .raw .as_ref() .ok_or(ComputePassErrorInner::InvalidIndirectBuffer(buffer_id)) @@ -569,14 +571,14 @@ impl Global { raw.dispatch_indirect(buf_raw, offset); } } - ComputeCommand::PushDebugGroup { color, len } => { + ComputeCommand::PushDebugGroup { color: _, len } => { state.debug_scope_depth += 1; let label = str::from_utf8(&base.string_data[string_offset..string_offset + len]) .unwrap(); string_offset += len; unsafe { - raw.begin_debug_marker(label, color); + raw.begin_debug_marker(label); } } ComputeCommand::PopDebugGroup => { @@ -591,12 +593,12 @@ impl Global { raw.end_debug_marker(); } } - ComputeCommand::InsertDebugMarker { color, len } => { + ComputeCommand::InsertDebugMarker { color: _, len } => { let label = str::from_utf8(&base.string_data[string_offset..string_offset + len]) .unwrap(); string_offset += len; - unsafe { raw.insert_debug_marker(label, color) } + unsafe { raw.insert_debug_marker(label) } } ComputeCommand::WriteTimestamp { query_set_id, diff --git a/wgpu-core/src/command/draw.rs b/wgpu-core/src/command/draw.rs index f86588db9a..8ea2c7b784 100644 --- a/wgpu-core/src/command/draw.rs +++ b/wgpu-core/src/command/draw.rs @@ -7,7 +7,6 @@ use crate::{ binding_model::PushConstantUploadError, - hal::BufferUse, id, track::UseExtendError, validation::{MissingBufferUsageError, MissingTextureUsageError}, @@ -17,7 +16,7 @@ use wgt::{BufferAddress, BufferSize, Color}; use std::num::NonZeroU32; use thiserror::Error; -pub type BufferError = UseExtendError; +pub type BufferError = UseExtendError; /// Error validating a draw call. #[derive(Clone, Debug, Error, PartialEq)] diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index bcf40b297b..c33c862998 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -70,10 +70,11 @@ impl CommandBuffer { #[cfg(feature = "trace")] enable_tracing: bool, #[cfg(debug_assertions)] label: &Label, ) -> Self { + use crate::LabelHelpers as _; CommandBuffer { raw: vec![raw], status: CommandEncoderStatus::Recording, - recorded_thread_id: thread::current.id(), + recorded_thread_id: thread::current().id(), device_id, trackers: TrackerSet::new(A::VARIANT), used_swap_chains: Default::default(), @@ -88,7 +89,7 @@ impl CommandBuffer { None }, #[cfg(debug_assertions)] - label: label.to_string_or_default(), + label: label.borrow_or_default().to_string(), } } @@ -242,8 +243,8 @@ impl Global { cmd_buf.status = CommandEncoderStatus::Finished; // stop tracking the swapchain image, if used for sc_id in cmd_buf.used_swap_chains.iter() { - let view_id = swap_chain_guard[sc_id.value] - .acquired_view_id + let &(ref view_id, _) = swap_chain_guard[sc_id.value] + .acquired_texture .as_ref() .expect("Used swap chain frame has already presented"); cmd_buf.trackers.views.remove(view_id.value); @@ -272,7 +273,7 @@ impl Global { let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap(); unsafe { - cmd_buf_raw.begin_debug_marker(label, 0); + cmd_buf_raw.begin_debug_marker(label); } Ok(()) } @@ -292,7 +293,7 @@ impl Global { let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap(); unsafe { - cmd_buf_raw.insert_debug_marker(label, 0); + cmd_buf_raw.insert_debug_marker(label); } Ok(()) } diff --git a/wgpu-core/src/command/query.rs b/wgpu-core/src/command/query.rs index 01e2d5080a..c2eacff10a 100644 --- a/wgpu-core/src/command/query.rs +++ b/wgpu-core/src/command/query.rs @@ -2,7 +2,7 @@ * 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/. */ -use hal::command::CommandBuffer as _; +use hal::CommandBuffer as _; #[cfg(feature = "trace")] use crate::device::trace::Command as TraceCommand; @@ -10,7 +10,7 @@ use crate::{ command::{CommandBuffer, CommandEncoderError}, hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token}, id::{self, Id, TypedId}, - resource::{BufferUse, QuerySet}, + resource::QuerySet, track::UseExtendError, Epoch, FastHashMap, Index, }; @@ -48,7 +48,7 @@ impl QueryResetMap { pub fn reset_queries( self, - cmd_buf_raw: &mut B::CommandBuffer, + cmd_buf_raw: &mut A::CommandBuffer, query_set_storage: &Storage, id::QuerySetId>, backend: wgt::Backend, ) -> Result<(), id::QuerySetId> { @@ -69,7 +69,7 @@ impl QueryResetMap { // We've hit the end of a run, dispatch a reset (Some(start), false) => { run_start = None; - unsafe { cmd_buf_raw.reset_query_pool(&query_set.raw, start..idx as u32) }; + unsafe { cmd_buf_raw.reset_queries(&query_set.raw, start..idx as u32) }; } // We're starting a run (None, true) => { @@ -167,7 +167,7 @@ impl QuerySet { query_type: SimplifiedQueryType, query_index: u32, reset_state: Option<&mut QueryResetMap>, - ) -> Result, QueryUseError> { + ) -> Result<&A::QuerySet, QueryUseError> { // We need to defer our resets because we are in a renderpass, add the usage to the reset map. if let Some(reset) = reset_state { let used = reset.use_query_set(query_set_id, self, query_index); @@ -191,23 +191,18 @@ impl QuerySet { }); } - let hal_query = hal::query::Query:: { - pool: &self.raw, - id: query_index, - }; - - Ok(hal_query) + Ok(&self.raw) } pub(super) fn validate_and_write_timestamp( &self, - cmd_buf_raw: &mut B::CommandBuffer, + cmd_buf_raw: &mut A::CommandBuffer, query_set_id: id::QuerySetId, query_index: u32, reset_state: Option<&mut QueryResetMap>, ) -> Result<(), QueryUseError> { let needs_reset = reset_state.is_none(); - let hal_query = self.validate_query( + let query_set = self.validate_query( query_set_id, SimplifiedQueryType::Timestamp, query_index, @@ -217,9 +212,9 @@ impl QuerySet { unsafe { // If we don't have a reset state tracker which can defer resets, we must reset now. if needs_reset { - cmd_buf_raw.reset_query_pool(&self.raw, query_index..(query_index + 1)); + cmd_buf_raw.reset_queries(&self.raw, query_index..(query_index + 1)); } - cmd_buf_raw.write_timestamp(hal::pso::PipelineStage::BOTTOM_OF_PIPE, hal_query); + cmd_buf_raw.write_timestamp(query_set, query_index); } Ok(()) @@ -227,14 +222,14 @@ impl QuerySet { pub(super) fn validate_and_begin_pipeline_statistics_query( &self, - cmd_buf_raw: &mut B::CommandBuffer, + cmd_buf_raw: &mut A::CommandBuffer, query_set_id: id::QuerySetId, query_index: u32, reset_state: Option<&mut QueryResetMap>, active_query: &mut Option<(id::QuerySetId, u32)>, ) -> Result<(), QueryUseError> { let needs_reset = reset_state.is_none(); - let hal_query = self.validate_query( + let query_set = self.validate_query( query_set_id, SimplifiedQueryType::PipelineStatistics, query_index, @@ -251,9 +246,9 @@ impl QuerySet { unsafe { // If we don't have a reset state tracker which can defer resets, we must reset now. if needs_reset { - cmd_buf_raw.reset_query_pool(&self.raw, query_index..(query_index + 1)); + cmd_buf_raw.reset_queries(&self.raw, query_index..(query_index + 1)); } - cmd_buf_raw.begin_query(hal_query, hal::query::ControlFlags::empty()); + cmd_buf_raw.begin_query(query_set, query_index); } Ok(()) @@ -261,7 +256,7 @@ impl QuerySet { } pub(super) fn end_pipeline_statistics_query( - cmd_buf_raw: &mut B::CommandBuffer, + cmd_buf_raw: &mut A::CommandBuffer, storage: &Storage, id::QuerySetId>, active_query: &mut Option<(id::QuerySetId, u32)>, ) -> Result<(), QueryUseError> { @@ -269,12 +264,7 @@ pub(super) fn end_pipeline_statistics_query( // We can unwrap here as the validity was validated when the active query was set let query_set = storage.get(query_set_id).unwrap(); - let hal_query = hal::query::Query:: { - pool: &query_set.raw, - id: query_index, - }; - - unsafe { cmd_buf_raw.end_query(hal_query) } + unsafe { cmd_buf_raw.end_query(&query_set.raw, query_index) }; Ok(()) } else { @@ -362,7 +352,7 @@ impl Global { let (dst_buffer, dst_pending) = cmd_buf .trackers .buffers - .use_replace(&*buffer_guard, destination, (), BufferUse::COPY_DST) + .use_replace(&*buffer_guard, destination, (), hal::BufferUse::COPY_DST) .map_err(QueryError::InvalidBuffer)?; let dst_barrier = dst_pending.map(|pending| pending.into_hal(dst_buffer)); @@ -380,9 +370,7 @@ impl Global { .into()); } - let stride = query_set.elements * wgt::QUERY_SIZE; - let bytes_used = (stride * query_count) as BufferAddress; - + let bytes_used = (wgt::QUERY_SIZE * query_count) as BufferAddress; let buffer_start_offset = destination_offset; let buffer_end_offset = buffer_start_offset + bytes_used; @@ -390,7 +378,7 @@ impl Global { return Err(ResolveError::BufferOverrun { start_query, end_query, - stride, + stride: wgt::QUERY_SIZE, buffer_size: dst_buffer.size, buffer_start_offset, buffer_end_offset, @@ -399,18 +387,12 @@ impl Global { } unsafe { - cmd_buf_raw.pipeline_barrier( - all_buffer_stages()..hal::pso::PipelineStage::TRANSFER, - hal::memory::Dependencies::empty(), - dst_barrier, - ); - cmd_buf_raw.copy_query_pool_results( + cmd_buf_raw.transition_buffers(dst_barrier); + cmd_buf_raw.copy_query_results( &query_set.raw, start_query..end_query, - &dst_buffer.raw.as_ref().unwrap().0, + dst_buffer.raw.as_ref().unwrap(), destination_offset, - stride, - hal::query::ResultFlags::WAIT | hal::query::ResultFlags::BITS_64, ); } diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index cdca1aeee0..c628b88643 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -10,16 +10,12 @@ use crate::{ PassErrorScope, QueryResetMap, QueryUseError, RenderCommand, RenderCommandError, StateChange, }, - conv, - device::{ - AttachmentData, AttachmentDataVec, Device, FramebufferKey, RenderPassCompatibilityError, - RenderPassContext, RenderPassKey, RenderPassLock, MAX_COLOR_TARGETS, MAX_VERTEX_BUFFERS, - }, + device::{AttachmentData, Device, RenderPassCompatibilityError, RenderPassContext}, hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token}, id, memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction}, pipeline::PipelineFlags, - resource::{BufferUse, Texture, TextureUse, TextureView, TextureViewInner}, + resource::{Texture, TextureView, TextureViewSource}, track::{StatefulTrackerSubset, TextureSelector, UsageConflict}, validation::{ check_buffer_usage, check_texture_usage, MissingBufferUsageError, MissingTextureUsageError, @@ -28,7 +24,7 @@ use crate::{ }; use arrayvec::ArrayVec; -use hal::{command::CommandBuffer as _, device::Device as _}; +use hal::{CommandBuffer as _, Device as _}; use thiserror::Error; use wgt::{ BufferAddress, BufferSize, BufferUsage, Color, IndexFormat, InputStepMode, TextureUsage, @@ -40,16 +36,7 @@ use serde::Deserialize; use serde::Serialize; use crate::track::UseExtendError; -use std::{ - borrow::{Borrow, Cow}, - collections::hash_map::Entry, - fmt, iter, - marker::PhantomData, - mem, - num::NonZeroU32, - ops::Range, - str, -}; +use std::{borrow::Cow, fmt, iter, marker::PhantomData, mem, num::NonZeroU32, ops::Range, str}; /// Operation to perform to the output attachment at the start of a renderpass. #[repr(C)] @@ -93,6 +80,21 @@ pub struct PassChannel { pub read_only: bool, } +impl PassChannel { + fn hal_ops(&self) -> hal::AttachmentOp { + let mut ops = hal::AttachmentOp::empty(); + match self.load_op { + LoadOp::Load => ops |= hal::AttachmentOp::LOAD, + LoadOp::Clear => (), + }; + match self.store_op { + StoreOp::Store => ops |= hal::AttachmentOp::STORE, + StoreOp::Clear => (), + }; + ops + } +} + /// Describes a color attachment to a render pass. #[repr(C)] #[derive(Clone, Debug, PartialEq)] @@ -153,7 +155,7 @@ pub struct RenderPassDescriptor<'a> { pub struct RenderPass { base: BasePass, parent_id: id::CommandEncoderId, - color_targets: ArrayVec<[RenderPassColorAttachment; MAX_COLOR_TARGETS]>, + color_targets: ArrayVec<[RenderPassColorAttachment; hal::MAX_COLOR_TARGETS]>, depth_stencil_target: Option, } @@ -276,7 +278,7 @@ impl VertexBufferState { #[derive(Debug, Default)] struct VertexState { - inputs: ArrayVec<[VertexBufferState; MAX_VERTEX_BUFFERS]>, + inputs: ArrayVec<[VertexBufferState; hal::MAX_VERTEX_BUFFERS]>, /// Length of the shortest vertex rate vertex buffer vertex_limit: u32, /// Buffer slot which the shortest vertex rate vertex buffer is bound to @@ -404,7 +406,7 @@ pub enum RenderPassErrorInner { mismatch: (&'static str, wgt::Extent3d), }, #[error("attachment's sample count {0} is invalid")] - InvalidSampleCount(u8), + InvalidSampleCount(u32), #[error("attachment with resolve target must be multi-sampled")] InvalidResolveSourceSampleCount, #[error("resolve target must have a sample count of 1")] @@ -418,7 +420,7 @@ pub enum RenderPassErrorInner { #[error("unable to clear non-present/read-only stencil")] InvalidStencilOps, #[error("all attachments must have the same sample count, found {actual} != {expected}")] - SampleCountMismatch { actual: u8, expected: u8 }, + SampleCountMismatch { actual: u32, expected: u32 }, #[error("setting `values_offset` to be `None` is only for internal use in render bundles")] InvalidValuesOffset, #[error("required device features not enabled: {0:?}")] @@ -499,11 +501,11 @@ fn check_device_features( struct RenderAttachment<'a> { texture_id: &'a Stored, selector: &'a TextureSelector, - previous_use: Option, - new_use: TextureUse, + previous_use: Option, + new_use: hal::TextureUse, } -type AttachmentDataVec = ArrayVec<[T; MAX_COLOR_TARGETS + MAX_COLOR_TARGETS + 1]>; +type AttachmentDataVec = ArrayVec<[T; hal::MAX_COLOR_TARGETS + hal::MAX_COLOR_TARGETS + 1]>; struct RenderPassInfo<'a, A: hal::Api> { context: RenderPassContext, @@ -518,6 +520,7 @@ struct RenderPassInfo<'a, A: hal::Api> { impl<'a, A: HalApi> RenderPassInfo<'a, A> { fn start( raw: &mut A::CommandBuffer, + label: Option<&str>, color_attachments: &[RenderPassColorAttachment], depth_stencil_attachment: Option<&RenderPassDepthStencilAttachment>, cmd_buf: &mut CommandBuffer, @@ -525,7 +528,6 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { view_guard: &'a Storage, id::TextureViewId>, ) -> Result { profiling::scope!("start", "RenderPassInfo"); - let sample_count_limit = device.hal_limits.framebuffer_color_sample_counts; // We default to false intentionally, even if depth-stencil isn't used at all. // This allows us to use the primary raw pipeline in `RenderPipeline`, @@ -563,278 +565,173 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { Ok(()) }; - let rp_key = { - let depth_stencil = match depth_stencil_attachment { - Some(at) => { - let view = cmd_buf - .trackers - .views - .use_extend(&*view_guard, at.view, (), ()) - .map_err(|_| RenderPassErrorInner::InvalidAttachment(at.view))?; - add_view(view, "depth")?; - - depth_stencil_aspects = view.aspects; - if view.aspects.contains(hal::FormatAspect::COLOR) { - return Err(RenderPassErrorInner::InvalidDepthStencilAttachmentFormat( - view.format, - )); - } + let mut colors = ArrayVec::<[hal::ColorAttachment; hal::MAX_COLOR_TARGETS]>::new(); + let mut depth_stencil = None; + + if let Some(at) = depth_stencil_attachment { + let view = cmd_buf + .trackers + .views + .use_extend(&*view_guard, at.view, (), ()) + .map_err(|_| RenderPassErrorInner::InvalidAttachment(at.view))?; + add_view(view, "depth")?; + + depth_stencil_aspects = view.desc.aspects(); + if depth_stencil_aspects.contains(hal::FormatAspect::COLOR) { + return Err(RenderPassErrorInner::InvalidDepthStencilAttachmentFormat( + view.desc.format, + )); + } - let source_id = match view.inner { - TextureViewInner::Native { ref source_id, .. } => source_id, - TextureViewInner::SwapChain { .. } => { - return Err(RenderPassErrorInner::SwapChainImageAsDepthStencil); - } - }; + let source_id = match view.source { + TextureViewSource::Native(ref source_id) => source_id, + TextureViewSource::SwapChain(_) => { + return Err(RenderPassErrorInner::SwapChainImageAsDepthStencil); + } + }; + + // Using render pass for transition. + let previous_use = cmd_buf + .trackers + .textures + .query(source_id.value, view.selector.clone()); + let new_use = if at.is_read_only(depth_stencil_aspects)? { + is_ds_read_only = true; + hal::TextureUse::DEPTH_STENCIL_READ | hal::TextureUse::SAMPLED + } else { + hal::TextureUse::DEPTH_STENCIL_WRITE + }; + render_attachments.push(RenderAttachment { + texture_id: source_id, + selector: &view.selector, + previous_use, + new_use, + }); - // Using render pass for transition. + let old_use = previous_use.unwrap_or(new_use); + depth_stencil = Some(hal::DepthStencilAttachment { + target: hal::Attachment { + view: &view.raw, + usage: new_use, + boundary_usage: old_use..new_use, + }, + depth_ops: at.depth.hal_ops(), + stencil_ops: at.stencil.hal_ops(), + clear_value: (at.depth.clear_value, at.stencil.clear_value), + }); + } + + for at in color_attachments { + let color_view = cmd_buf + .trackers + .views + .use_extend(&*view_guard, at.view, (), ()) + .map_err(|_| RenderPassErrorInner::InvalidAttachment(at.view))?; + add_view(color_view, "color")?; + + if !color_view.desc.aspects().contains(hal::FormatAspect::COLOR) { + return Err(RenderPassErrorInner::InvalidColorAttachmentFormat( + color_view.desc.format, + )); + } + + let boundary_usage = match color_view.source { + TextureViewSource::Native(ref source_id) => { let previous_use = cmd_buf .trackers .textures - .query(source_id.value, view.selector.clone()); - let new_use = if at.is_read_only(view.aspects)? { - is_ds_read_only = true; - TextureUse::ATTACHMENT_READ - } else { - TextureUse::ATTACHMENT_WRITE - }; + .query(source_id.value, color_view.selector.clone()); + let new_use = hal::TextureUse::COLOR_TARGET; render_attachments.push(RenderAttachment { texture_id: source_id, - selector: &view.selector, + selector: &color_view.selector, previous_use, new_use, }); - let new_layout = conv::map_texture_state(new_use, view.aspects).1; - let old_layout = match previous_use { - Some(usage) => conv::map_texture_state(usage, view.aspects).1, - None => new_layout, - }; - - let ds_at = hal::pass::Attachment { - format: Some(conv::map_texture_format( - view.format, - device.private_features, - )), - samples: view.samples, - ops: conv::map_load_store_ops(&at.depth), - stencil_ops: conv::map_load_store_ops(&at.stencil), - layouts: old_layout..new_layout, + let old_use = previous_use.unwrap_or(new_use); + old_use..new_use + } + TextureViewSource::SwapChain(ref source_id) => { + assert!(used_swap_chain.is_none()); + used_swap_chain = Some(source_id.clone()); + + let end = hal::TextureUse::empty(); + let start = match at.channel.load_op { + LoadOp::Clear => hal::TextureUse::UNINITIALIZED, + LoadOp::Load => end, }; - Some((ds_at, new_layout)) + start..end } - None => None, }; - let mut colors = ArrayVec::new(); - let mut resolves = ArrayVec::new(); - - for at in color_attachments { - let view = cmd_buf - .trackers - .views - .use_extend(&*view_guard, at.view, (), ()) - .map_err(|_| RenderPassErrorInner::InvalidAttachment(at.view))?; - add_view(view, "color")?; - - if !view.aspects.contains(hal::FormatAspect::COLOR) { - return Err(RenderPassErrorInner::InvalidColorAttachmentFormat( - view.format, - )); - } - - let layouts = match view.inner { - TextureViewInner::Native { ref source_id, .. } => { - let previous_use = cmd_buf - .trackers - .textures - .query(source_id.value, view.selector.clone()); - let new_use = TextureUse::ATTACHMENT_WRITE; - render_attachments.push(RenderAttachment { - texture_id: source_id, - selector: &view.selector, - previous_use, - new_use, - }); - - let new_layout = - conv::map_texture_state(new_use, hal::FormatAspect::COLOR).1; - let old_layout = match previous_use { - Some(usage) => { - conv::map_texture_state(usage, hal::FormatAspect::COLOR).1 - } - None => new_layout, - }; - old_layout..new_layout - } - TextureViewInner::SwapChain { ref source_id, .. } => { - assert!(used_swap_chain.is_none()); - used_swap_chain = Some(source_id.clone()); - - let end = hal::image::Layout::Present; - let start = match at.channel.load_op { - LoadOp::Clear => hal::image::Layout::Undefined, - LoadOp::Load => end, - }; - start..end - } - }; - - let color_at = hal::pass::Attachment { - format: Some(conv::map_texture_format( - view.format, - device.private_features, - )), - samples: view.samples, - ops: conv::map_load_store_ops(&at.channel), - stencil_ops: hal::pass::AttachmentOps::DONT_CARE, - layouts, - }; - colors.push((color_at, hal::image::Layout::ColorAttachmentOptimal)); - } - - for resolve_target in color_attachments.iter().flat_map(|at| at.resolve_target) { - let view = cmd_buf + let mut hal_resolve_target = None; + if let Some(resolve_target) = at.resolve_target { + let resolve_view = cmd_buf .trackers .views .use_extend(&*view_guard, resolve_target, (), ()) .map_err(|_| RenderPassErrorInner::InvalidAttachment(resolve_target))?; - if extent != Some(view.extent) { + if extent != Some(resolve_view.extent) { return Err(RenderPassErrorInner::AttachmentsDimensionMismatch { previous: (attachment_type_name, extent.unwrap_or_default()), - mismatch: ("resolve", view.extent), + mismatch: ("resolve", resolve_view.extent), }); } - if view.samples != 1 { + if resolve_view.samples != 1 { return Err(RenderPassErrorInner::InvalidResolveTargetSampleCount); } if sample_count == 1 { return Err(RenderPassErrorInner::InvalidResolveSourceSampleCount); } - let layouts = match view.inner { - TextureViewInner::Native { ref source_id, .. } => { + let boundary_usage = match resolve_view.source { + TextureViewSource::Native(ref source_id) => { let previous_use = cmd_buf .trackers .textures - .query(source_id.value, view.selector.clone()); - let new_use = TextureUse::ATTACHMENT_WRITE; + .query(source_id.value, resolve_view.selector.clone()); + let new_use = hal::TextureUse::COLOR_TARGET; render_attachments.push(RenderAttachment { texture_id: source_id, - selector: &view.selector, + selector: &resolve_view.selector, previous_use, new_use, }); - let new_layout = - conv::map_texture_state(new_use, hal::FormatAspect::COLOR).1; - let old_layout = match previous_use { - Some(usage) => { - conv::map_texture_state(usage, hal::FormatAspect::COLOR).1 - } - None => new_layout, - }; - old_layout..new_layout + let old_use = previous_use.unwrap_or(new_use); + old_use..new_use } - TextureViewInner::SwapChain { ref source_id, .. } => { + TextureViewSource::SwapChain(source_id) => { assert!(used_swap_chain.is_none()); used_swap_chain = Some(source_id.clone()); - hal::image::Layout::Undefined..hal::image::Layout::Present + hal::TextureUse::UNINITIALIZED..hal::TextureUse::empty() } }; - let resolve_at = hal::pass::Attachment { - format: Some(conv::map_texture_format( - view.format, - device.private_features, - )), - samples: view.samples, - ops: hal::pass::AttachmentOps::new( - hal::pass::AttachmentLoadOp::DontCare, - hal::pass::AttachmentStoreOp::Store, - ), - stencil_ops: hal::pass::AttachmentOps::DONT_CARE, - layouts, - }; - resolves.push((resolve_at, hal::image::Layout::ColorAttachmentOptimal)); + hal_resolve_target = Some(hal::Attachment { + view: &resolve_view.raw, + usage: hal::TextureUse::COLOR_TARGET, + boundary_usage, + }); } - RenderPassKey { - colors, - resolves, - depth_stencil, - } - }; + colors.push(hal::ColorAttachment { + target: hal::Attachment { + view: &color_view.raw, + usage: hal::TextureUse::COLOR_TARGET, + boundary_usage, + }, + resolve_target: hal_resolve_target, + ops: at.channel.hal_ops(), + clear_value: at.channel.clear_value, + }); + } - if sample_count & sample_count_limit == 0 { + if sample_count != 1 && sample_count != 4 { return Err(RenderPassErrorInner::InvalidSampleCount(sample_count)); } - let RenderPassLock { - ref mut render_passes, - ref mut framebuffers, - } = *device.render_passes.lock(); - let render_pass = match render_passes.entry(rp_key.clone()) { - Entry::Occupied(e) => e.into_mut(), - Entry::Vacant(entry) => { - let color_ids: [hal::pass::AttachmentRef; MAX_COLOR_TARGETS] = [ - (0, hal::image::Layout::ColorAttachmentOptimal), - (1, hal::image::Layout::ColorAttachmentOptimal), - (2, hal::image::Layout::ColorAttachmentOptimal), - (3, hal::image::Layout::ColorAttachmentOptimal), - ]; - - let mut resolve_ids = ArrayVec::<[_; MAX_COLOR_TARGETS]>::new(); - let mut attachment_index = color_attachments.len(); - if color_attachments - .iter() - .any(|at| at.resolve_target.is_some()) - { - for ((i, at), &(_, layout)) in color_attachments - .iter() - .enumerate() - .zip(entry.key().resolves.iter()) - { - let real_attachment_index = match at.resolve_target { - Some(_) => attachment_index + i, - None => hal::pass::ATTACHMENT_UNUSED, - }; - resolve_ids.push((real_attachment_index, layout)); - } - attachment_index += color_attachments.len(); - } - - let depth_id = depth_stencil_attachment.map(|_| { - let usage = if is_ds_read_only { - TextureUse::ATTACHMENT_READ - } else { - TextureUse::ATTACHMENT_WRITE - }; - ( - attachment_index, - conv::map_texture_state(usage, depth_stencil_aspects).1, - ) - }); - - let subpass = hal::pass::SubpassDesc { - colors: &color_ids[..color_attachments.len()], - resolves: &resolve_ids, - depth_stencil: depth_id.as_ref(), - inputs: &[], - preserves: &[], - }; - let all = entry.key().all().map(|&(ref at, _)| at.clone()); - - let pass = unsafe { - device - .raw - .create_render_pass(all, iter::once(subpass), iter::empty()) - } - .unwrap(); - entry.insert(pass) - } - }; - let view_data = AttachmentData { colors: color_attachments .iter() @@ -848,121 +745,19 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { depth_stencil: depth_stencil_attachment.map(|at| view_guard.get(at.view).unwrap()), }; let extent = extent.ok_or(RenderPassErrorInner::MissingAttachments)?; - let fb_key = FramebufferKey { - attachments: view_data.map(|view| view.framebuffer_attachment.clone()), - extent, - samples: sample_count, - }; let context = RenderPassContext { - attachments: view_data.map(|view| view.format), + attachments: view_data.map(|view| view.desc.format), sample_count, }; - // Cache framebuffers by the device. - let framebuffer = match framebuffers.entry(fb_key) { - Entry::Occupied(e) => e.into_mut(), - Entry::Vacant(e) => { - let fb = unsafe { - device - .raw - .create_framebuffer( - &render_pass, - e.key().attachments.all().cloned(), - conv::map_extent(&extent, wgt::TextureDimension::D3), - ) - .or(Err(RenderPassErrorInner::OutOfMemory))? - }; - e.insert(fb) - } - }; - - let rect = hal::pso::Rect { - x: 0, - y: 0, - w: extent.width as _, - h: extent.height as _, + let hal_desc = hal::RenderPassDescriptor { + label, + color_attachments: colors.iter().cloned().collect(), + depth_stencil_attachment: depth_stencil, }; - let raw_views = view_data.map(|view| match view.inner { - TextureViewInner::Native { ref raw, .. } => raw, - TextureViewInner::SwapChain { ref image, .. } => Borrow::borrow(image), - }); - - //Note: the order of iteration has to match `AttachmentData::all()` - let attachments = color_attachments - .iter() - .zip(&rp_key.colors) - .zip(raw_views.colors) - .map( - |((at, &(ref rat, _layout)), image_view)| hal::command::RenderAttachmentInfo { - image_view, - clear_value: match at.channel.load_op { - LoadOp::Load => Default::default(), - LoadOp::Clear => { - use hal::format::ChannelType; - //TODO: validate sign/unsign and normalized ranges of the color values - let value = match rat.format.unwrap().base_format().1 { - ChannelType::Unorm - | ChannelType::Snorm - | ChannelType::Ufloat - | ChannelType::Sfloat - | ChannelType::Uscaled - | ChannelType::Sscaled - | ChannelType::Srgb => hal::command::ClearColor { - float32: conv::map_color_f32(&at.channel.clear_value), - }, - ChannelType::Sint => hal::command::ClearColor { - sint32: conv::map_color_i32(&at.channel.clear_value), - }, - ChannelType::Uint => hal::command::ClearColor { - uint32: conv::map_color_u32(&at.channel.clear_value), - }, - }; - hal::command::ClearValue { color: value } - } - }, - }, - ) - .chain(raw_views.resolves.into_iter().map(|image_view| { - hal::command::RenderAttachmentInfo { - image_view, - clear_value: Default::default(), - } - })) - .chain(depth_stencil_attachment.zip(raw_views.depth_stencil).map( - |(at, image_view)| hal::command::RenderAttachmentInfo { - image_view, - clear_value: match (at.depth.load_op, at.stencil.load_op) { - (LoadOp::Load, LoadOp::Load) => Default::default(), - (LoadOp::Clear, _) | (_, LoadOp::Clear) => { - let value = hal::command::ClearDepthStencil { - depth: at.depth.clear_value, - stencil: at.stencil.clear_value, - }; - hal::command::ClearValue { - depth_stencil: value, - } - } - }, - }, - )); - unsafe { - raw.begin_render_pass( - render_pass, - framebuffer, - rect, - attachments, - hal::command::SubpassContents::Inline, - ); - raw.set_scissors(0, iter::once(rect)); - raw.set_viewports( - 0, - iter::once(hal::pso::Viewport { - rect, - depth: 0.0..1.0, - }), - ); - } + raw.begin_render_pass(&hal_desc); + }; Ok(Self { context, @@ -977,6 +772,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { fn finish( mut self, + raw: &mut A::CommandBuffer, texture_guard: &Storage, id::TextureId>, ) -> Result<(StatefulTrackerSubset, Option>), RenderPassErrorInner> { @@ -984,7 +780,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { for ra in self.render_attachments { let texture = &texture_guard[ra.texture_id.value]; - check_texture_usage(texture.usage, TextureUsage::RENDER_ATTACHMENT)?; + check_texture_usage(texture.desc.usage, TextureUsage::RENDER_ATTACHMENT)?; // the tracker set of the pass is always in "extend" mode self.trackers @@ -1012,6 +808,10 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { .unwrap(); } } + + unsafe { + raw.end_render_pass(); + } Ok((self.trackers, self.used_swap_chain)) } } @@ -1056,7 +856,7 @@ impl Global { CommandBuffer::get_encoder_mut(&mut *cmb_guard, encoder_id).map_pass_err(scope)?; // will be reset to true if recording is done without errors cmd_buf.status = CommandEncoderStatus::Error; - cmd_buf.has_labels |= base.label.is_some(); + #[cfg(feature = "trace")] if let Some(ref mut list) = cmd_buf.commands { list.push(crate::device::trace::Command::RunRenderPass { @@ -1067,13 +867,10 @@ impl Global { } let device = &device_guard[cmd_buf.device_id.value]; - let mut raw = device.cmd_allocator.extend(cmd_buf); - unsafe { - if let Some(ref label) = base.label { - device.raw.set_command_buffer_name(&mut raw, label); - } - raw.begin_primary(hal::command::CommandBufferFlags::ONE_TIME_SUBMIT); - } + let mut raw = 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); @@ -1091,6 +888,7 @@ impl Global { let mut info = RenderPassInfo::start( &mut raw, + base.label, color_attachments, depth_stencil_attachment, cmd_buf, @@ -1181,19 +979,18 @@ impl Global { if !entries.is_empty() { let pipeline_layout = &pipeline_layout_guard[pipeline_layout_id.unwrap()].raw; - let desc_sets = entries.iter().map(|e| { - bind_group_guard[e.group_id.as_ref().unwrap().value] - .raw - .raw() - }); - let offsets = entries.iter().flat_map(|e| &e.dynamic_offsets).cloned(); - unsafe { - raw.bind_graphics_descriptor_sets( - pipeline_layout, - index as usize, - desc_sets, - offsets, - ); + for (i, e) in entries.iter().enumerate() { + let raw_bg = + &bind_group_guard[e.group_id.as_ref().unwrap().value].raw; + + unsafe { + raw.set_bind_group( + pipeline_layout, + index as u32 + i as u32, + raw_bg, + &e.dynamic_offsets, + ); + } } } } @@ -1229,15 +1026,12 @@ impl Global { .require(pipeline.flags.contains(PipelineFlags::BLEND_CONSTANT)); unsafe { - raw.bind_graphics_pipeline(&pipeline.raw); + raw.set_render_pipeline(&pipeline.raw); } if pipeline.flags.contains(PipelineFlags::STENCIL_REFERENCE) { unsafe { - raw.set_stencil_reference( - hal::pso::Face::all(), - state.stencil_reference, - ); + raw.set_stencil_reference(state.stencil_reference); } } @@ -1250,20 +1044,18 @@ impl Global { pipeline.layout_id.value, ); if !entries.is_empty() { - let desc_sets = entries.iter().map(|e| { - bind_group_guard[e.group_id.as_ref().unwrap().value] - .raw - .raw() - }); - let offsets = - entries.iter().flat_map(|e| &e.dynamic_offsets).cloned(); - unsafe { - raw.bind_graphics_descriptor_sets( - &pipeline_layout.raw, - start_index, - desc_sets, - offsets, - ); + for (i, e) in entries.iter().enumerate() { + let raw_bg = + &bind_group_guard[e.group_id.as_ref().unwrap().value].raw; + + unsafe { + raw.set_bind_group( + &pipeline_layout.raw, + start_index as u32 + i as u32, + raw_bg, + &e.dynamic_offsets, + ); + } } } @@ -1278,9 +1070,9 @@ impl Global { offset, size_bytes, |clear_offset, clear_data| unsafe { - raw.push_graphics_constants( + raw.set_push_constants( &pipeline_layout.raw, - conv::map_shader_stage_flags(range.stages), + range.stages, clear_offset, clear_data, ); @@ -1321,11 +1113,11 @@ impl Global { let buffer = info .trackers .buffers - .use_extend(&*buffer_guard, buffer_id, (), BufferUse::INDEX) + .use_extend(&*buffer_guard, buffer_id, (), hal::BufferUse::INDEX) .map_err(|e| RenderCommandError::Buffer(buffer_id, e)) .map_pass_err(scope)?; check_buffer_usage(buffer.usage, BufferUsage::INDEX).map_pass_err(scope)?; - let &(ref buf_raw, _) = buffer + let buf_raw = buffer .raw .as_ref() .ok_or(RenderCommandError::DestroyedBuffer(buffer_id)) @@ -1351,13 +1143,13 @@ impl Global { }), ); - let range = hal::buffer::SubRange { + let bb = hal::BufferBinding { + buffer: buf_raw, offset, - size: Some(end - offset), + size, }; - let index_type = conv::map_index_format(index_format); unsafe { - raw.bind_index_buffer(buf_raw, range, index_type); + raw.set_index_buffer(bb, index_format); } } RenderCommand::SetVertexBuffer { @@ -1370,12 +1162,12 @@ impl Global { let buffer = info .trackers .buffers - .use_extend(&*buffer_guard, buffer_id, (), BufferUse::VERTEX) + .use_extend(&*buffer_guard, buffer_id, (), hal::BufferUse::VERTEX) .map_err(|e| RenderCommandError::Buffer(buffer_id, e)) .map_pass_err(scope)?; check_buffer_usage(buffer.usage, BufferUsage::VERTEX) .map_pass_err(scope)?; - let &(ref buf_raw, _) = buffer + let buf_raw = buffer .raw .as_ref() .ok_or(RenderCommandError::DestroyedBuffer(buffer_id)) @@ -1405,19 +1197,20 @@ impl Global { }), ); - let range = hal::buffer::SubRange { + let bb = hal::BufferBinding { + buffer: buf_raw, offset, - size: size.map(|s| s.get()), + size, }; unsafe { - raw.bind_vertex_buffers(slot, iter::once((buf_raw, range))); + raw.set_vertex_buffer(slot, bb); } state.vertex.update_limits(); } RenderCommand::SetBlendConstant(ref color) => { state.blend_constant = OptionalState::Set; unsafe { - raw.set_blend_constants(conv::map_color_f32(color)); + raw.set_blend_constants(color); } } RenderCommand::SetStencilReference(value) => { @@ -1427,7 +1220,7 @@ impl Global { .contains(PipelineFlags::STENCIL_REFERENCE) { unsafe { - raw.set_stencil_reference(hal::pso::Face::all(), value); + raw.set_stencil_reference(value); } } } @@ -1437,7 +1230,6 @@ impl Global { depth_max, } => { let scope = PassErrorScope::SetViewport; - use std::{convert::TryFrom, i16}; if rect.w <= 0.0 || rect.h <= 0.0 || depth_min < 0.0 @@ -1447,20 +1239,14 @@ impl Global { { return Err(RenderCommandError::InvalidViewport).map_pass_err(scope); } - let r = hal::pso::Rect { - x: i16::try_from(rect.x.round() as i64).unwrap_or(0), - y: i16::try_from(rect.y.round() as i64).unwrap_or(0), - w: i16::try_from(rect.w.round() as i64).unwrap_or(i16::MAX), - h: i16::try_from(rect.h.round() as i64).unwrap_or(i16::MAX), + let r = hal::Rect { + x: rect.x, + y: rect.y, + w: rect.w, + h: rect.h, }; unsafe { - raw.set_viewports( - 0, - iter::once(hal::pso::Viewport { - rect: r, - depth: depth_min..depth_max, - }), - ); + raw.set_viewport(&r, depth_min..depth_max); } } RenderCommand::SetPushConstant { @@ -1493,17 +1279,11 @@ impl Global { .map_pass_err(scope)?; unsafe { - raw.push_graphics_constants( - &pipeline_layout.raw, - conv::map_shader_stage_flags(stages), - offset, - data_slice, - ) + raw.set_push_constants(&pipeline_layout.raw, stages, offset, data_slice) } } RenderCommand::SetScissor(ref rect) => { let scope = PassErrorScope::SetScissorRect; - use std::{convert::TryFrom, i16}; if rect.w == 0 || rect.h == 0 || rect.x + rect.w > info.extent.width @@ -1511,14 +1291,14 @@ impl Global { { return Err(RenderCommandError::InvalidScissorRect).map_pass_err(scope); } - let r = hal::pso::Rect { - x: i16::try_from(rect.x).unwrap_or(0), - y: i16::try_from(rect.y).unwrap_or(0), - w: i16::try_from(rect.w).unwrap_or(i16::MAX), - h: i16::try_from(rect.h).unwrap_or(i16::MAX), + let r = hal::Rect { + x: rect.x, + y: rect.y, + w: rect.w, + h: rect.h, }; unsafe { - raw.set_scissors(0, iter::once(r)); + raw.set_scissor_rect(&r); } } RenderCommand::Draw { @@ -1557,10 +1337,7 @@ impl Global { } unsafe { - raw.draw( - first_vertex..first_vertex + vertex_count, - first_instance..first_instance + instance_count, - ); + raw.draw(first_vertex, vertex_count, first_instance, instance_count); } } RenderCommand::DrawIndexed { @@ -1601,9 +1378,11 @@ impl Global { unsafe { raw.draw_indexed( - first_index..first_index + index_count, + first_index, + index_count, base_vertex, - first_instance..first_instance + instance_count, + first_instance, + instance_count, ); } } @@ -1623,7 +1402,7 @@ impl Global { let stride = match indexed { false => mem::size_of::(), true => mem::size_of::(), - } as u64; + }; if count.is_some() { check_device_features( @@ -1636,12 +1415,12 @@ impl Global { let indirect_buffer = info .trackers .buffers - .use_extend(&*buffer_guard, buffer_id, (), BufferUse::INDIRECT) + .use_extend(&*buffer_guard, buffer_id, (), hal::BufferUse::INDIRECT) .map_err(|e| RenderCommandError::Buffer(buffer_id, e)) .map_pass_err(scope)?; check_buffer_usage(indirect_buffer.usage, BufferUsage::INDIRECT) .map_pass_err(scope)?; - let &(ref indirect_raw, _) = indirect_buffer + let indirect_raw = indirect_buffer .raw .as_ref() .ok_or(RenderCommandError::DestroyedBuffer(buffer_id)) @@ -1649,7 +1428,7 @@ impl Global { let actual_count = count.map_or(1, |c| c.get()); - let end_offset = offset + stride * actual_count as u64; + let end_offset = offset + stride as u64 * actual_count as u64; if end_offset > indirect_buffer.size { return Err(RenderPassErrorInner::IndirectBufferOverrun { count, @@ -1673,20 +1452,10 @@ impl Global { match indexed { false => unsafe { - raw.draw_indirect( - indirect_raw, - offset, - actual_count, - stride as u32, - ); + raw.draw_indirect(indirect_raw, offset, actual_count); }, true => unsafe { - raw.draw_indexed_indirect( - indirect_raw, - offset, - actual_count, - stride as u32, - ); + raw.draw_indexed_indirect(indirect_raw, offset, actual_count); }, } } @@ -1719,12 +1488,12 @@ impl Global { let indirect_buffer = info .trackers .buffers - .use_extend(&*buffer_guard, buffer_id, (), BufferUse::INDIRECT) + .use_extend(&*buffer_guard, buffer_id, (), hal::BufferUse::INDIRECT) .map_err(|e| RenderCommandError::Buffer(buffer_id, e)) .map_pass_err(scope)?; check_buffer_usage(indirect_buffer.usage, BufferUsage::INDIRECT) .map_pass_err(scope)?; - let &(ref indirect_raw, _) = indirect_buffer + let indirect_raw = indirect_buffer .raw .as_ref() .ok_or(RenderCommandError::DestroyedBuffer(buffer_id)) @@ -1733,12 +1502,17 @@ impl Global { let count_buffer = info .trackers .buffers - .use_extend(&*buffer_guard, count_buffer_id, (), BufferUse::INDIRECT) + .use_extend( + &*buffer_guard, + count_buffer_id, + (), + hal::BufferUse::INDIRECT, + ) .map_err(|e| RenderCommandError::Buffer(count_buffer_id, e)) .map_pass_err(scope)?; check_buffer_usage(count_buffer.usage, BufferUsage::INDIRECT) .map_pass_err(scope)?; - let &(ref count_raw, _) = count_buffer + let count_raw = count_buffer .raw .as_ref() .ok_or(RenderCommandError::DestroyedBuffer(count_buffer_id)) @@ -1794,7 +1568,6 @@ impl Global { count_raw, count_buffer_offset, max_count, - stride as u32, ); }, true => unsafe { @@ -1804,19 +1577,18 @@ impl Global { count_raw, count_buffer_offset, max_count, - stride as u32, ); }, } } - RenderCommand::PushDebugGroup { color, len } => { + RenderCommand::PushDebugGroup { color: _, len } => { state.debug_scope_depth += 1; let label = str::from_utf8(&base.string_data[string_offset..string_offset + len]) .unwrap(); string_offset += len; unsafe { - raw.begin_debug_marker(label, color); + raw.begin_debug_marker(label); } } RenderCommand::PopDebugGroup => { @@ -1830,13 +1602,13 @@ impl Global { raw.end_debug_marker(); } } - RenderCommand::InsertDebugMarker { color, len } => { + RenderCommand::InsertDebugMarker { color: _, len } => { let label = str::from_utf8(&base.string_data[string_offset..string_offset + len]) .unwrap(); string_offset += len; unsafe { - raw.insert_debug_marker(label, color); + raw.insert_debug_marker(label); } } RenderCommand::WriteTimestamp { @@ -1963,11 +1735,8 @@ impl Global { } log::trace!("Merging {:?} with the render pass", encoder_id); - unsafe { - raw.end_render_pass(); - } - - let (trackers, used_swapchain) = info.finish(&*texture_guard).map_pass_err(scope)?; + let (trackers, used_swapchain) = + info.finish(&mut raw, &*texture_guard).map_pass_err(scope)?; cmd_buf.status = CommandEncoderStatus::Recording; cmd_buf.used_swap_chains.extend(used_swapchain); (raw, trackers, query_reset_state) diff --git a/wgpu-core/src/command/transfer.rs b/wgpu-core/src/command/transfer.rs index c129e517ad..79031f1d56 100644 --- a/wgpu-core/src/command/transfer.rs +++ b/wgpu-core/src/command/transfer.rs @@ -10,14 +10,15 @@ use crate::{ hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token}, id::{BufferId, CommandEncoderId, TextureId}, memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction}, - resource::{Texture, TextureDescriptor, TextureErrorDimension}, + resource::{Texture, TextureErrorDimension}, + track::TextureSelector, }; use hal::CommandBuffer as _; use thiserror::Error; use wgt::{BufferAddress, BufferUsage, Extent3d, TextureUsage}; -use std::{iter, num::NonZeroU32}; +use std::iter; pub type ImageCopyBuffer = wgt::ImageCopyBuffer; pub type ImageCopyTexture = wgt::ImageCopyTexture; @@ -106,42 +107,42 @@ pub enum CopyError { Transfer(#[from] TransferError), } -pub(crate) fn extract_image_range( +pub(crate) fn extract_texture_selector( copy_texture: &ImageCopyTexture, copy_size: &Extent3d, texture_guard: &Storage, TextureId>, -) -> Result<(wgt::ImageSubresourceRange, wgt::TextureFormat), TransferError> { +) -> Result<(TextureSelector, hal::TextureCopyBase, wgt::TextureFormat), TransferError> { let texture = texture_guard .get(copy_texture.texture) - .ok_or(TransferError::InvalidTexture(copy_texture.texture))?; + .map_err(|_| TransferError::InvalidTexture(copy_texture.texture))?; let format = texture.desc.format; let copy_aspect = hal::FormatAspect::from(format) & hal::FormatAspect::from(copy_texture.aspect); if copy_aspect.is_empty() { - return Err(TransferError::MissingTextureAspect { + return Err(TransferError::InvalidTextureAspect { format, aspect: copy_texture.aspect, }); } - let (base_array_layer, array_layer_count) = match texture.desc.dimension { - wgt::TextureDimension::D1 | wgt::TextureDimension::D2 => ( - copy_texture.origin.depth_or_array_layers, - NonZeroU32::new( - copy_texture.origin.depth_or_array_layers + copy_size.depth_or_array_layers, - ), - ), - wgt::TextureDimension::D3 => (0, None), + + let layers = match texture.desc.dimension { + wgt::TextureDimension::D1 | wgt::TextureDimension::D2 => { + copy_texture.origin.z..copy_texture.origin.z + copy_size.depth_or_array_layers + } + wgt::TextureDimension::D3 => 0..1, }; - let range = wgt::ImageSubresourceRange { + let selector = TextureSelector { + levels: copy_texture.mip_level..copy_texture.mip_level + 1, + layers, + }; + let base = hal::TextureCopyBase { + origin: copy_texture.origin, + mip_level: copy_texture.mip_level, aspect: copy_aspect, - base_mip_level: copy_texture.mip_level, - mip_level_count: NonZeroU32::new(1), - base_array_layer, - array_layer_count, }; - Ok((range, format)) + Ok((selector, base, format)) } /// Function copied with some modifications from webgpu standard @@ -242,7 +243,7 @@ pub(crate) fn validate_linear_texture_data( /// Returns the mip level extent. pub(crate) fn validate_texture_copy_range( texture_copy_view: &ImageCopyTexture, - desc: &TextureDescriptor, + desc: &wgt::TextureDescriptor<()>, texture_side: CopySide, copy_size: &Extent3d, ) -> Result { @@ -278,11 +279,11 @@ pub(crate) fn validate_texture_copy_range( }); } let z_copy_max = texture_copy_view.origin.z + copy_size.depth_or_array_layers; - if z_copy_max > extent.depth { + if z_copy_max > extent.depth_or_array_layers { return Err(TransferError::TextureOverrun { start_offset: texture_copy_view.origin.z, end_offset: z_copy_max, - texture_size: extent.depth, + texture_size: extent.depth_or_array_layers, dimension: TextureErrorDimension::Z, side: texture_side, }); @@ -342,7 +343,7 @@ impl Global { .buffers .use_replace(&*buffer_guard, source, (), hal::BufferUse::COPY_SRC) .map_err(TransferError::InvalidBuffer)?; - let &(ref src_raw, _) = src_buffer + let src_raw = src_buffer .raw .as_ref() .ok_or(TransferError::InvalidBuffer(source))?; @@ -359,7 +360,7 @@ impl Global { .buffers .use_replace(&*buffer_guard, destination, (), hal::BufferUse::COPY_DST) .map_err(TransferError::InvalidBuffer)?; - let &(ref dst_raw, _) = dst_buffer + let dst_raw = dst_buffer .raw .as_ref() .ok_or(TransferError::InvalidBuffer(destination))?; @@ -431,12 +432,12 @@ impl Global { let region = hal::BufferCopy { src_offset: source_offset, dst_offset: destination_offset, - size, + size: wgt::BufferSize::new(size).unwrap(), }; let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap(); unsafe { cmd_buf_raw.transition_buffers(src_barrier.into_iter().chain(dst_barrier)); - cmd_buf_raw.copy_buffer(src_raw, dst_raw, iter::once(region)); + cmd_buf_raw.copy_buffer_to_buffer(src_raw, dst_raw, iter::once(region)); } Ok(()) } @@ -471,14 +472,15 @@ impl Global { return Ok(()); } - let (dst_range, _) = extract_image_range(destination, copy_size, &*texture_guard)?; + let (dst_range, dst_base, _) = + extract_texture_selector(destination, copy_size, &*texture_guard)?; let (src_buffer, src_pending) = cmd_buf .trackers .buffers .use_replace(&*buffer_guard, source.buffer, (), hal::BufferUse::COPY_SRC) .map_err(TransferError::InvalidBuffer)?; - let &(ref src_raw, _) = src_buffer + let src_raw = src_buffer .raw .as_ref() .ok_or(TransferError::InvalidBuffer(source.buffer))?; @@ -497,11 +499,11 @@ impl Global { hal::TextureUse::COPY_DST, ) .unwrap(); - let &(ref dst_raw, _) = dst_texture + let dst_raw = dst_texture .raw .as_ref() .ok_or(TransferError::InvalidTexture(destination.texture))?; - if !dst_texture.usage.contains(TextureUsage::COPY_DST) { + if !dst_texture.desc.usage.contains(TextureUsage::COPY_DST) { return Err( TransferError::MissingCopyDstUsageFlag(None, Some(destination.texture)).into(), ); @@ -511,14 +513,13 @@ impl Global { let format_desc = dst_texture.desc.format.describe(); let max_image_extent = validate_texture_copy_range( destination, - dst_texture.format, - dst_texture.kind, + &dst_texture.desc, CopySide::Destination, copy_size, )?; let required_buffer_bytes_in_copy = validate_linear_texture_data( &source.layout, - dst_texture.format, + dst_texture.desc.format, src_buffer.size, CopySide::Source, format_desc.block_size as BufferAddress, @@ -538,8 +539,10 @@ impl Global { ); let (block_width, _) = format_desc.block_dimensions; - if !conv::is_valid_copy_dst_texture_format(dst_texture.format) { - return Err(TransferError::CopyToForbiddenTextureFormat(dst_texture.format).into()); + if !conv::is_valid_copy_dst_texture_format(dst_texture.desc.format) { + return Err( + TransferError::CopyToForbiddenTextureFormat(dst_texture.desc.format).into(), + ); } // WebGPU uses the physical size of the texture for copies whereas vulkan uses @@ -547,9 +550,8 @@ impl Global { // image extent data directly. We want the provided copy size to be no larger than // the virtual size. let region = hal::BufferTextureCopy { - buffer_layout: &source.layout, - texture_mip_level: destination.mip_level, - texture_origin: destination.origin, + buffer_layout: source.layout, + texture_base: dst_base, size: Extent3d { width: copy_size.width.min(max_image_extent.width), height: copy_size.height.min(max_image_extent.height), @@ -595,7 +597,8 @@ impl Global { return Ok(()); } - let (src_range, _) = extract_image_range(source, copy_size, &*texture_guard)?; + let (src_range, src_base, _) = + extract_texture_selector(source, copy_size, &*texture_guard)?; let (src_texture, src_pending) = cmd_buf .trackers @@ -607,16 +610,16 @@ impl Global { hal::TextureUse::COPY_SRC, ) .unwrap(); - let &(ref src_raw, _) = src_texture + let src_raw = src_texture .raw .as_ref() .ok_or(TransferError::InvalidTexture(source.texture))?; - if !src_texture.usage.contains(TextureUsage::COPY_SRC) { + if !src_texture.desc.usage.contains(TextureUsage::COPY_SRC) { return Err(TransferError::MissingCopySrcUsageFlag.into()); } let src_barriers = src_pending.map(|pending| pending.into_hal(src_texture)); - let (dst_buffer, dst_barriers) = cmd_buf + let (dst_buffer, dst_pending) = cmd_buf .trackers .buffers .use_replace( @@ -626,7 +629,7 @@ impl Global { hal::BufferUse::COPY_DST, ) .map_err(TransferError::InvalidBuffer)?; - let &(ref dst_raw, _) = dst_buffer + let dst_raw = dst_buffer .raw .as_ref() .ok_or(TransferError::InvalidBuffer(destination.buffer))?; @@ -635,19 +638,14 @@ impl Global { TransferError::MissingCopyDstUsageFlag(Some(destination.buffer), None).into(), ); } - let dst_barrier = dst_barriers.map(|pending| pending.into_hal(dst_buffer)); + let dst_barriers = dst_pending.map(|pending| pending.into_hal(dst_buffer)); let format_desc = src_texture.desc.format.describe(); - let max_image_extent = validate_texture_copy_range( - source, - src_texture.format, - src_texture.kind, - CopySide::Source, - copy_size, - )?; + let max_image_extent = + validate_texture_copy_range(source, &src_texture.desc, CopySide::Source, copy_size)?; let required_buffer_bytes_in_copy = validate_linear_texture_data( &destination.layout, - src_texture.format, + src_texture.desc.format, dst_buffer.size, CopySide::Destination, format_desc.block_size as BufferAddress, @@ -655,9 +653,11 @@ impl Global { true, )?; - let (block_width, _) = src_texture.format.describe().block_dimensions; - if !conv::is_valid_copy_src_texture_format(src_texture.format) { - return Err(TransferError::CopyFromForbiddenTextureFormat(src_texture.format).into()); + 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(), + ); } cmd_buf.buffer_memory_init_actions.extend( @@ -679,9 +679,8 @@ impl Global { // image extent data directly. We want the provided copy size to be no larger than // the virtual size. let region = hal::BufferTextureCopy { - buffer_layout: &destination.layout, - texture_mip_level: source.mip_level, - texture_origin: source.origin, + buffer_layout: destination.layout, + texture_base: src_base, size: Extent3d { width: copy_size.width.min(max_image_extent.width), height: copy_size.height.min(max_image_extent.height), @@ -733,9 +732,11 @@ impl Global { return Ok(()); } - let (src_range, _) = extract_image_range(source, copy_size, &*texture_guard)?; - let (dst_range, _) = extract_image_range(destination, copy_size, &*texture_guard)?; - if src_range.aspects != dst_range.aspects { + let (src_range, src_base, _) = + extract_texture_selector(source, copy_size, &*texture_guard)?; + let (dst_range, dst_base, _) = + extract_texture_selector(destination, copy_size, &*texture_guard)?; + if src_base.aspect != dst_base.aspect { return Err(TransferError::MismatchedAspects.into()); } @@ -749,11 +750,11 @@ impl Global { hal::TextureUse::COPY_SRC, ) .unwrap(); - let &(ref src_raw, _) = src_texture + let src_raw = src_texture .raw .as_ref() .ok_or(TransferError::InvalidTexture(source.texture))?; - if !src_texture.usage.contains(TextureUsage::COPY_SRC) { + if !src_texture.desc.usage.contains(TextureUsage::COPY_SRC) { return Err(TransferError::MissingCopySrcUsageFlag.into()); } //TODO: try to avoid this the collection. It's needed because both @@ -772,11 +773,11 @@ impl Global { hal::TextureUse::COPY_DST, ) .unwrap(); - let &(ref dst_raw, _) = dst_texture + let dst_raw = dst_texture .raw .as_ref() .ok_or(TransferError::InvalidTexture(destination.texture))?; - if !dst_texture.usage.contains(TextureUsage::COPY_DST) { + if !dst_texture.desc.usage.contains(TextureUsage::COPY_DST) { return Err( TransferError::MissingCopyDstUsageFlag(None, Some(destination.texture)).into(), ); @@ -797,10 +798,8 @@ impl Global { // image extent data directly. We want the provided copy size to be no larger than // the virtual size. let region = hal::TextureCopy { - src_subresource: src_range, - src_origin: source.origin, - dst_subresource: dst_range, - dst_origin: destination.origin, + src_base, + dst_base, size: Extent3d { width: copy_size .width diff --git a/wgpu-core/src/conv.rs b/wgpu-core/src/conv.rs index 4966f92bb9..9a8014d743 100644 --- a/wgpu-core/src/conv.rs +++ b/wgpu-core/src/conv.rs @@ -55,7 +55,7 @@ pub fn map_buffer_usage(usage: wgt::BufferUsage) -> hal::BufferUse { usage.contains(wgt::BufferUsage::UNIFORM), ); u.set( - hal::BufferUse::STORAGE, + hal::BufferUse::STORAGE_LOAD | hal::BufferUse::STORAGE_STORE, usage.contains(wgt::BufferUsage::STORAGE), ); u.set( diff --git a/wgpu-core/src/device/life.rs b/wgpu-core/src/device/life.rs index 20e82c420c..23b2b2b008 100644 --- a/wgpu-core/src/device/life.rs +++ b/wgpu-core/src/device/life.rs @@ -5,12 +5,7 @@ #[cfg(feature = "trace")] use crate::device::trace; use crate::{ - device::{ - alloc, - descriptor::{DescriptorAllocator, DescriptorSet}, - queue::TempResource, - DeviceError, - }, + device::{queue::TempResource, DeviceError}, hub::{GlobalIdentityHandlerFactory, HalApi, Hub, Token}, id, resource, track::TrackerSet, @@ -18,13 +13,13 @@ use crate::{ }; use copyless::VecHelper as _; -use hal::device::Device as _; +use hal::Device as _; use parking_lot::Mutex; use thiserror::Error; use std::sync::atomic::Ordering; -const CLEANUP_WAIT_MS: u64 = 5000; +const CLEANUP_WAIT_MS: u32 = 5000; /// A struct that keeps lists of resources that are no longer needed by the user. #[derive(Debug, Default)] @@ -91,33 +86,31 @@ impl SuspectedResources { /// A struct that keeps lists of resources that are no longer needed. #[derive(Debug)] struct NonReferencedResources { - buffers: Vec<(B::Buffer, alloc::MemoryBlock)>, - images: Vec<(B::Image, alloc::MemoryBlock)>, + buffers: Vec, + textures: Vec, // Note: we keep the associated ID here in order to be able to check // at any point what resources are used in a submission. - image_views: Vec<(id::Valid, B::ImageView)>, - samplers: Vec, - framebuffers: Vec, - desc_sets: Vec>, - compute_pipes: Vec, - graphics_pipes: Vec, - descriptor_set_layouts: Vec, - pipeline_layouts: Vec, - query_sets: Vec, + texture_views: Vec<(id::Valid, A::TextureView)>, + samplers: Vec, + bind_groups: Vec, + compute_pipes: Vec, + render_pipes: Vec, + bind_group_layouts: Vec, + pipeline_layouts: Vec, + query_sets: Vec, } impl NonReferencedResources { fn new() -> Self { Self { buffers: Vec::new(), - images: Vec::new(), - image_views: Vec::new(), + textures: Vec::new(), + texture_views: Vec::new(), samplers: Vec::new(), - framebuffers: Vec::new(), - desc_sets: Vec::new(), + bind_groups: Vec::new(), compute_pipes: Vec::new(), - graphics_pipes: Vec::new(), - descriptor_set_layouts: Vec::new(), + render_pipes: Vec::new(), + bind_group_layouts: Vec::new(), pipeline_layouts: Vec::new(), query_sets: Vec::new(), } @@ -125,76 +118,54 @@ impl NonReferencedResources { fn extend(&mut self, other: Self) { self.buffers.extend(other.buffers); - self.images.extend(other.images); - self.image_views.extend(other.image_views); + self.textures.extend(other.textures); + self.texture_views.extend(other.texture_views); self.samplers.extend(other.samplers); - self.framebuffers.extend(other.framebuffers); - self.desc_sets.extend(other.desc_sets); + self.bind_groups.extend(other.bind_groups); self.compute_pipes.extend(other.compute_pipes); - self.graphics_pipes.extend(other.graphics_pipes); + self.render_pipes.extend(other.render_pipes); self.query_sets.extend(other.query_sets); - assert!(other.descriptor_set_layouts.is_empty()); + assert!(other.bind_group_layouts.is_empty()); assert!(other.pipeline_layouts.is_empty()); } - unsafe fn clean( - &mut self, - device: &B::Device, - memory_allocator_mutex: &Mutex>, - descriptor_allocator_mutex: &Mutex>, - ) { - if !self.buffers.is_empty() || !self.images.is_empty() { - let mut allocator = memory_allocator_mutex.lock(); - for (raw, memory) in self.buffers.drain(..) { - log::trace!("Buffer {:?} is destroyed with memory {:?}", raw, memory); - device.destroy_buffer(raw); - allocator.free(device, memory); - } - for (raw, memory) in self.images.drain(..) { - log::trace!("Image {:?} is destroyed with memory {:?}", raw, memory); - device.destroy_image(raw); - allocator.free(device, memory); - } + unsafe fn clean(&mut self, device: &A::Device) { + for raw in self.buffers.drain(..) { + device.destroy_buffer(raw); } - - for (_, raw) in self.image_views.drain(..) { - device.destroy_image_view(raw); + for raw in self.textures.drain(..) { + device.destroy_texture(raw); + } + for (_, raw) in self.texture_views.drain(..) { + device.destroy_texture_view(raw); } for raw in self.samplers.drain(..) { device.destroy_sampler(raw); } - for raw in self.framebuffers.drain(..) { - device.destroy_framebuffer(raw); - } - - if !self.desc_sets.is_empty() { - descriptor_allocator_mutex - .lock() - .free(device, self.desc_sets.drain(..)); + for raw in self.bind_groups.drain(..) { + device.destroy_bind_group(raw); } - for raw in self.compute_pipes.drain(..) { device.destroy_compute_pipeline(raw); } - for raw in self.graphics_pipes.drain(..) { - device.destroy_graphics_pipeline(raw); + for raw in self.render_pipes.drain(..) { + device.destroy_render_pipeline(raw); } - for raw in self.descriptor_set_layouts.drain(..) { - device.destroy_descriptor_set_layout(raw); + for raw in self.bind_group_layouts.drain(..) { + device.destroy_bind_group_layout(raw); } for raw in self.pipeline_layouts.drain(..) { device.destroy_pipeline_layout(raw); } for raw in self.query_sets.drain(..) { - device.destroy_query_pool(raw); + device.destroy_query_set(raw); } } } -#[derive(Debug)] struct ActiveSubmission { index: SubmissionIndex, - fence: B::Fence, + fence: A::Fence, last_resources: NonReferencedResources, mapped: Vec>, } @@ -215,7 +186,6 @@ pub enum WaitIdleError { /// 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. -#[derive(Debug)] pub(super) struct LifetimeTracker { /// Resources that the user has requested be mapped, but are still in use. mapped: Vec>, @@ -252,15 +222,15 @@ impl LifetimeTracker { pub fn track_submission( &mut self, index: SubmissionIndex, - fence: B::Fence, + fence: A::Fence, new_suspects: &SuspectedResources, - temp_resources: impl Iterator, alloc::MemoryBlock)>, + temp_resources: impl Iterator>, ) { let mut last_resources = NonReferencedResources::new(); - for (res, memory) in temp_resources { + for res in temp_resources { match res { - TempResource::Buffer(raw) => last_resources.buffers.push((raw, memory)), - TempResource::Image(raw) => last_resources.images.push((raw, memory)), + TempResource::Buffer(raw) => last_resources.buffers.push(raw), + TempResource::Texture(raw) => last_resources.textures.push(raw), } } @@ -288,20 +258,23 @@ impl LifetimeTracker { self.mapped.push(Stored { value, ref_count }); } - fn wait_idle(&self, device: &B::Device) -> Result<(), WaitIdleError> { + fn wait_idle(&self, device: &A::Device) -> Result<(), WaitIdleError> { if !self.active.is_empty() { log::debug!("Waiting for IDLE..."); - let status = unsafe { - device - .wait_for_fences( - self.active.iter().map(|a| &a.fence), - hal::device::WaitFor::All, - CLEANUP_WAIT_MS * 1_000_000, - ) - .map_err(DeviceError::from)? - }; + 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); @@ -313,10 +286,11 @@ impl LifetimeTracker { /// Returns the last submission index that is done. pub fn triage_submissions( &mut self, - device: &B::Device, + device: &A::Device, force_wait: bool, ) -> Result { profiling::scope!("triage_submissions"); + /* TODO: better sync if force_wait { self.wait_idle(device)?; } @@ -325,7 +299,7 @@ impl LifetimeTracker { let done_count = self .active .iter() - .position(|a| unsafe { !device.get_fence_status(&a.fence).unwrap_or(false) }) + .position(|a| unsafe { device.get_fence_value(&a.fence).unwrap() }) .unwrap_or_else(|| self.active.len()); let last_done = match done_count.checked_sub(1) { Some(i) => self.active[i].index, @@ -339,29 +313,22 @@ impl LifetimeTracker { unsafe { device.destroy_fence(a.fence); } - } + }*/ + let last_done = 0; Ok(last_done) } - pub fn cleanup( - &mut self, - device: &B::Device, - memory_allocator_mutex: &Mutex>, - descriptor_allocator_mutex: &Mutex>, - ) { + pub fn cleanup(&mut self, device: &A::Device) { profiling::scope!("cleanup"); unsafe { - self.free_resources - .clean(device, memory_allocator_mutex, descriptor_allocator_mutex); - descriptor_allocator_mutex.lock().cleanup(device); + self.free_resources.clean(device); } } pub fn schedule_resource_destruction( &mut self, temp_resource: TempResource, - memory: alloc::MemoryBlock, last_submit_index: SubmissionIndex, ) { let resources = self @@ -370,8 +337,8 @@ impl LifetimeTracker { .find(|a| a.index == last_submit_index) .map_or(&mut self.free_resources, |a| &mut a.last_resources); match temp_resource { - TempResource::Buffer(raw) => resources.buffers.push((raw, memory)), - TempResource::Image(raw) => resources.images.push((raw, memory)), + TempResource::Buffer(raw) => resources.buffers.push(raw), + TempResource::Texture(raw) => resources.textures.push(raw), } } } @@ -423,7 +390,7 @@ impl LifetimeTracker { .iter_mut() .find(|a| a.index == submit_index) .map_or(&mut self.free_resources, |a| &mut a.last_resources) - .desc_sets + .bind_groups .push(res.raw); } } @@ -442,12 +409,11 @@ impl LifetimeTracker { } if let Some(res) = hub.texture_views.unregister_locked(id.0, &mut *guard) { - let raw = match res.inner { - resource::TextureViewInner::Native { raw, source_id } => { + match res.source { + resource::TextureViewSource::Native(source_id) => { self.suspected_resources.textures.push(source_id.value); - raw } - resource::TextureViewInner::SwapChain { .. } => unreachable!(), + resource::TextureViewSource::SwapChain { .. } => unreachable!(), }; let submit_index = res.life_guard.submission_index.load(Ordering::Acquire); @@ -455,8 +421,8 @@ impl LifetimeTracker { .iter_mut() .find(|a| a.index == submit_index) .map_or(&mut self.free_resources, |a| &mut a.last_resources) - .image_views - .push((id, raw)); + .texture_views + .push((id, res.raw)); } } } @@ -479,7 +445,7 @@ impl LifetimeTracker { .iter_mut() .find(|a| a.index == submit_index) .map_or(&mut self.free_resources, |a| &mut a.last_resources) - .images + .textures .extend(res.raw); } } @@ -524,15 +490,8 @@ impl LifetimeTracker { if let Some(res) = hub.buffers.unregister_locked(id.0, &mut *guard) { let submit_index = res.life_guard.submission_index.load(Ordering::Acquire); - if let resource::BufferMapState::Init { - stage_buffer, - stage_memory, - .. - } = res.map_state - { - self.free_resources - .buffers - .push((stage_buffer, stage_memory)); + if let resource::BufferMapState::Init { stage_buffer, .. } = res.map_state { + self.free_resources.buffers.push(stage_buffer); } self.active .iter_mut() @@ -586,7 +545,7 @@ impl LifetimeTracker { .iter_mut() .find(|a| a.index == submit_index) .map_or(&mut self.free_resources, |a| &mut a.last_resources) - .graphics_pipes + .render_pipes .push(res.raw); } } @@ -632,7 +591,7 @@ impl LifetimeTracker { t.lock().add(trace::Action::DestroyBindGroupLayout(id.0)); } if let Some(lay) = hub.bind_group_layouts.unregister_locked(id.0, &mut *guard) { - self.free_resources.descriptor_set_layouts.push(lay.raw); + self.free_resources.bind_group_layouts.push(lay.raw); } } } @@ -693,7 +652,7 @@ impl LifetimeTracker { pub(super) fn handle_mapping( &mut self, hub: &Hub, - raw: &B::Device, + raw: &A::Device, trackers: &Mutex, token: &mut Token>, ) -> Vec { @@ -740,10 +699,7 @@ impl LifetimeTracker { Ok(ptr) => { buffer.map_state = resource::BufferMapState::Active { ptr, - sub_range: hal::buffer::SubRange { - offset: mapping.range.start, - size: Some(size), - }, + range: mapping.range.start..mapping.range.start + size, host, }; resource::BufferMapAsyncStatus::Success diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 2ea0de180b..2991f9ffa5 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -30,9 +30,6 @@ pub mod trace; use smallvec::SmallVec; -pub const MAX_COLOR_TARGETS: usize = 4; -pub const MAX_MIP_LEVELS: u32 = 16; -pub const MAX_VERTEX_BUFFERS: usize = 16; pub const SHADER_STAGE_COUNT: usize = 3; const IMPLICIT_FAILURE: &str = "failed implicit"; @@ -51,8 +48,8 @@ pub enum HostMap { #[derive(Clone, Debug, Hash, PartialEq)] #[cfg_attr(feature = "serial-pass", derive(serde::Deserialize, serde::Serialize))] pub(crate) struct AttachmentData { - pub colors: ArrayVec<[T; MAX_COLOR_TARGETS]>, - pub resolves: ArrayVec<[T; MAX_COLOR_TARGETS]>, + pub colors: ArrayVec<[T; hal::MAX_COLOR_TARGETS]>, + pub resolves: ArrayVec<[T; hal::MAX_COLOR_TARGETS]>, pub depth_stencil: Option, } impl Eq for AttachmentData {} @@ -77,19 +74,19 @@ impl AttachmentData { #[cfg_attr(feature = "serial-pass", derive(serde::Deserialize, serde::Serialize))] pub(crate) struct RenderPassContext { pub attachments: AttachmentData, - pub sample_count: u8, + pub sample_count: u32, } #[derive(Clone, Debug, Error)] pub enum RenderPassCompatibilityError { #[error("Incompatible color attachment: {0:?} != {1:?}")] IncompatibleColorAttachment( - ArrayVec<[TextureFormat; MAX_COLOR_TARGETS]>, - ArrayVec<[TextureFormat; MAX_COLOR_TARGETS]>, + ArrayVec<[TextureFormat; hal::MAX_COLOR_TARGETS]>, + ArrayVec<[TextureFormat; hal::MAX_COLOR_TARGETS]>, ), #[error("Incompatible depth-stencil attachment: {0:?} != {1:?}")] IncompatibleDepthStencilAttachment(Option, Option), #[error("Incompatible sample count: {0:?} != {1:?}")] - IncompatibleSampleCount(u8, u8), + IncompatibleSampleCount(u32, u32), } impl RenderPassContext { @@ -132,12 +129,15 @@ fn map_buffer( kind: HostMap, ) -> Result, resource::BufferAccessError> { let ptr = raw - .map_buffer(&buffer.raw, offset, offset + size) + .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 => { - raw.invalidate_memory_ranges(&buffer.raw, iter::once(offset..offset + size)); + 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), @@ -163,8 +163,8 @@ fn map_buffer( ) }; if zero_init_needs_flush_now { - raw.flush_memory_ranges( - &buffer.raw, + raw.flush_mapped_ranges( + buffer.raw.as_ref().unwrap(), iter::once(uninitialized_range.start..uninitialized_range.start + num_bytes), ); } @@ -191,7 +191,6 @@ fn fire_map_callbacks>(callback /// 1. `life_tracker` is locked after `hub.devices`, enforced by the type system /// 1. `self.trackers` is locked last (unenforced) /// 1. `self.trace` is locked last (unenforced) -#[derive(Debug)] pub struct Device { pub(crate) raw: A::Device, pub(crate) adapter_id: Stored, @@ -211,7 +210,6 @@ pub struct Device { pub(crate) limits: wgt::Limits, pub(crate) features: wgt::Features, pub(crate) downlevel: wgt::DownlevelCapabilities, - spv_options: naga::back::spv::Options, //TODO: move this behind another mutex. This would allow several methods to switch // to borrow Device immutably, such as `write_buffer`, `write_texture`, and `buffer_unmap`. pending_writes: queue::PendingWrites, @@ -240,35 +238,6 @@ impl Device { log::error!("Feature 'trace' is not enabled"); } - let spv_options = { - use naga::back::spv; - let mut flags = spv::WriterFlags::empty(); - flags.set(spv::WriterFlags::DEBUG, cfg!(debug_assertions)); - //Note: we don't adjust the coordinate space, because `NDC_Y_UP` is required. - spv::Options { - lang_version: (1, 0), - //TODO: can be `None` once `spirv` is published - capabilities: Some( - [ - spv::Capability::Shader, - spv::Capability::DerivativeControl, - spv::Capability::InterpolationFunction, - spv::Capability::Matrix, - spv::Capability::ImageQuery, - spv::Capability::Sampled1D, - spv::Capability::Image1D, - spv::Capability::SampledCubeArray, - spv::Capability::ImageCubeArray, - spv::Capability::StorageImageExtendedFormats, - ] - .iter() - .cloned() - .collect(), - ), - flags, - } - }; - Ok(Self { raw: device.device, adapter_id, @@ -296,7 +265,6 @@ impl Device { limits: desc.limits.clone(), features: desc.features, downlevel, - spv_options, pending_writes: queue::PendingWrites::new(), }) } @@ -347,12 +315,11 @@ impl Device { life_tracker.triage_mapped(hub, token); let last_done = life_tracker.triage_submissions(&self.raw, force_wait)?; let callbacks = life_tracker.handle_mapping(hub, &self.raw, &self.trackers, token); - life_tracker.cleanup(&self.raw, &self.mem_allocator, &self.desc_allocator); + life_tracker.cleanup(&self.raw); self.life_guard .submission_index .store(last_done, Ordering::Release); - self.cmd_allocator.maintain(&self.raw, last_done); Ok(callbacks) } @@ -429,29 +396,30 @@ impl Device { transient: bool, ) -> Result, resource::CreateBufferError> { debug_assert_eq!(self_id.backend(), A::VARIANT); - let mut usage = desc.usage; + let mut usage = conv::map_buffer_usage(desc.usage); + + if desc.usage.is_empty() { + return Err(resource::CreateBufferError::EmptyUsage); + } + if desc.mapped_at_creation { if desc.size % wgt::COPY_BUFFER_ALIGNMENT != 0 { return Err(resource::CreateBufferError::UnalignedSize); } if !desc.usage.contains(wgt::BufferUsage::MAP_WRITE) { // we are going to be copying into it, internally - usage |= wgt::BufferUsage::COPY_DST; + usage |= hal::BufferUse::COPY_DST; } } else { // We are required to zero out (initialize) all memory. // This is done on demand using fill_buffer which requires write transfer usage! - usage |= wgt::BufferUsage::TRANSFER_DST; - } - - if desc.usage.is_empty() { - return Err(resource::CreateBufferError::EmptyUsage); + usage |= hal::BufferUse::COPY_DST; } let hal_desc = hal::BufferDescriptor { - label: desc.label, + label: desc.label.map(|cow| cow.as_ref()), size: desc.size, - usage: conv::map_buffer_usage(usage), + usage, memory_flags: hal::MemoryFlag::empty(), }; let buffer = unsafe { self.raw.create_buffer(&hal_desc) }.map_err(DeviceError::from)?; @@ -464,6 +432,7 @@ impl Device { }, usage: desc.usage, size: desc.size, + is_coherent: true, //TODO? initialization_status: MemoryInitTracker::new(desc.size), sync_mapped_writes: None, map_state: resource::BufferMapState::Idle, @@ -525,12 +494,12 @@ impl Device { )?; let mips = desc.mip_level_count; - if mips == 0 || mips > MAX_MIP_LEVELS || mips > desc.extent.max_mips() as u32 { + if mips == 0 || mips > hal::MAX_MIP_LEVELS || mips > desc.size.max_mips() { return Err(resource::CreateTextureError::InvalidMipLevelCount(mips)); } let hal_desc = hal::TextureDescriptor { - label: desc.label, + label: desc.label.borrow_option(), size: desc.size, mip_level_count: desc.mip_level_count, sample_count: desc.sample_count, @@ -554,8 +523,8 @@ impl Device { desc: desc.map_label(|_| ()), format_features, full_range: TextureSelector { - levels: 0..desc.mip_level_count as hal::MipLevel, - layers: 0..desc.array_layer_count as hal::ArrayLayer, + levels: 0..desc.mip_level_count, + layers: 0..desc.array_layer_count(), }, life_guard: LifeGuard::new(desc.label.borrow_or_default()), }) @@ -567,18 +536,18 @@ impl Device { texture_id: id::TextureId, desc: &resource::TextureViewDescriptor, ) -> Result, resource::CreateTextureViewError> { - let &(ref texture_raw, _) = texture + let texture_raw = texture .raw .as_ref() .ok_or(resource::CreateTextureViewError::InvalidTexture)?; let view_dim = match desc.dimension { Some(dim) => { - if texture.dimension != dim.compatible_texture_dimension() { + if texture.desc.dimension != dim.compatible_texture_dimension() { return Err( resource::CreateTextureViewError::InvalidTextureViewDimension { view: dim, - image: texture.dimension, + texture: texture.desc.dimension, }, ); } @@ -587,7 +556,7 @@ impl Device { None => match texture.desc.dimension { wgt::TextureDimension::D1 => wgt::TextureViewDimension::D1, wgt::TextureDimension::D2 - if texture.desc.array_layer_count > 1 + if texture.desc.size.depth_or_array_layers > 1 && desc.range.array_layer_count.is_none() => { wgt::TextureViewDimension::D2Array @@ -603,13 +572,13 @@ impl Device { + desc.range.array_layer_count.map_or(1, |count| count.get()); let level_end = texture.full_range.levels.end; let layer_end = texture.full_range.layers.end; - if required_level_count > level_end as u32 { + if required_level_count > level_end { return Err(resource::CreateTextureViewError::TooManyMipLevels { requested: required_level_count, total: level_end, }); } - if required_layer_count > layer_end as u32 { + if required_layer_count > layer_end { return Err(resource::CreateTextureViewError::TooManyArrayLayers { requested: required_layer_count, total: layer_end, @@ -620,14 +589,14 @@ impl Device { TextureViewDimension::Cube if required_layer_count != 6 => { return Err( resource::CreateTextureViewError::InvalidCubemapTextureDepth { - required_layer_count, + depth: required_layer_count, }, ) } TextureViewDimension::CubeArray if required_layer_count % 6 != 0 => { return Err( resource::CreateTextureViewError::InvalidCubemapArrayTextureDepth { - required_layer_count, + depth: required_layer_count, }, ) } @@ -635,32 +604,28 @@ impl Device { } let full_aspect = hal::FormatAspect::from(texture.desc.format); - let aspect = match desc.range.aspect { - wgt::TextureAspect::All => full_aspect, - wgt::TextureAspect::DepthOnly => hal::FormatAspect::DEPTH, - wgt::TextureAspect::StencilOnly => hal::FormatAspect::STENCIL, - }; - if !full_aspect.contains(aspect) { + let select_aspect = hal::FormatAspect::from(desc.range.aspect); + if (full_aspect & select_aspect).is_empty() { return Err(resource::CreateTextureViewError::InvalidAspect { - requested: aspect, - total: full_aspect, + texture_format: texture.desc.format, + requested_aspect: desc.range.aspect, }); } let end_level = desc .range .mip_level_count - .map_or(level_end, |_| required_level_count as u8); + .map_or(level_end, |_| required_level_count); let end_layer = desc .range .array_layer_count - .map_or(layer_end, |_| required_layer_count as u16); + .map_or(layer_end, |_| required_layer_count); let selector = TextureSelector { - levels: desc.range.base_mip_level as u8..end_level, - layers: desc.range.base_array_layer as u16..end_layer, + levels: desc.range.base_mip_level..end_level, + layers: desc.range.base_array_layer..end_layer, }; - let view_layer_count = (selector.layers.end - selector.layers.start) as u32; + let view_layer_count = selector.layers.end - selector.layers.start; let layer_check_ok = match view_dim { wgt::TextureViewDimension::D1 | wgt::TextureViewDimension::D2 @@ -676,32 +641,40 @@ impl Device { }); } - let mut extent = texture.desc.extent.at_level(desc.range.base_mip_level as _); + let mut extent = texture + .desc + .mip_level_size(desc.range.base_mip_level) + .unwrap(); if view_dim != wgt::TextureViewDimension::D3 { extent.depth_or_array_layers = view_layer_count; } + let format = desc.format.unwrap_or(texture.desc.format); + if format != texture.desc.format { + return Err(resource::CreateTextureViewError::FormatReinterpretation { + texture: texture.desc.format, + view: format, + }); + } let hal_desc = hal::TextureViewDescriptor { - label: desc.label, - format: desc.format.unwrap_or(texture.format), + label: desc.label.borrow_option(), + format, dimension: view_dim, range: desc.range.clone(), }; let raw = unsafe { self.raw - .create_image_view(texture_raw, &hal_desc) - .map_err(DeviceError::from)? + .create_texture_view(texture_raw, &hal_desc) + .map_err(|_| resource::CreateTextureViewError::OutOfMemory)? }; Ok(resource::TextureView { - inner: resource::TextureViewInner::Native { - raw, - source_id: Stored { - value: id::Valid(texture_id), - ref_count: texture.life_guard.add_ref(), - }, - }, + raw, + source: resource::TextureViewSource::Native(Stored { + value: id::Valid(texture_id), + ref_count: texture.life_guard.add_ref(), + }), desc: resource::HalTextureViewDescriptor { format: hal_desc.format, dimension: hal_desc.dimension, @@ -709,9 +682,9 @@ impl Device { }, format_features: texture.format_features, extent, - samples: texture.kind.num_samples(), + samples: texture.desc.sample_count, // once a storage - forever a storage - sampled_internal_use: if texture.usage.contains(wgt::TextureUsage::STORAGE) { + sampled_internal_use: if texture.desc.usage.contains(wgt::TextureUsage::STORAGE) { hal::TextureUse::SAMPLED | hal::TextureUse::STORAGE_LOAD } else { hal::TextureUse::SAMPLED @@ -734,7 +707,7 @@ impl Device { self.require_features(wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER)?; } - let lod_clamp = if desc.lod_min_clamp > 0.0 || desc.load_max_clamp < 32.0 { + let lod_clamp = if desc.lod_min_clamp > 0.0 || desc.lod_max_clamp < 32.0 { Some(desc.lod_min_clamp..desc.lod_max_clamp) } else { None @@ -746,8 +719,12 @@ impl Device { if !valid_clamp { return Err(resource::CreateSamplerError::InvalidClamp(clamp)); } - if self.downlevel.anisotropic_filtering { - Some(clamp) + if self + .downlevel + .flags + .contains(wgt::DownlevelFlags::ANISOTROPIC_FILTERING) + { + std::num::NonZeroU8::new(clamp) } else { None } @@ -756,7 +733,7 @@ impl Device { }; let hal_desc = hal::SamplerDescriptor { - label: desc.label, + label: desc.label.borrow_option(), address_modes: desc.address_modes, mag_filter: desc.mag_filter, min_filter: desc.min_filter, @@ -767,7 +744,11 @@ impl Device { border_color: desc.border_color, }; - let raw = unsafe { self.raw.create_sampler(desc).map_err(DeviceError::from)? }; + let raw = unsafe { + self.raw + .create_sampler(&hal_desc) + .map_err(DeviceError::from)? + }; Ok(resource::Sampler { raw, device_id: Stored { @@ -787,8 +768,7 @@ impl Device { desc: &pipeline::ShaderModuleDescriptor<'a>, source: pipeline::ShaderModuleSource<'a>, ) -> Result, pipeline::CreateShaderModuleError> { - // First, try to produce a Naga module. - let (spv, module) = match source { + let module = match source { pipeline::ShaderModuleSource::SpirV(spv) => { profiling::scope!("naga::spv::parse"); // Parse the given shader code and store its representation. @@ -798,118 +778,77 @@ impl Device { flow_graph_dump_prefix: None, }; let parser = naga::front::spv::Parser::new(spv.iter().cloned(), &options); - let module = match parser.parse() { - Ok(module) => Some(module), + match parser.parse() { + Ok(module) => module, Err(err) => { log::warn!( "Failed to parse shader SPIR-V code for {:?}: {:?}", desc.label, err ); - if desc.flags.contains(wgt::ShaderFlags::VALIDATION) { - return Err(pipeline::CreateShaderModuleError::Parsing); - } - log::warn!("\tProceeding unsafely without validation"); - None + return Err(pipeline::CreateShaderModuleError::Parsing); } - }; - (Some(spv), module) + } } pipeline::ShaderModuleSource::Wgsl(code) => { profiling::scope!("naga::wgsl::parse_str"); // TODO: refactor the corresponding Naga error to be owned, and then // display it instead of unwrapping match naga::front::wgsl::parse_str(&code) { - Ok(module) => (None, Some(module)), + Ok(module) => module, Err(err) => { log::error!("Failed to parse WGSL code for {:?}: {}", desc.label, err); return Err(pipeline::CreateShaderModuleError::Parsing); } } } - pipeline::ShaderModuleSource::Naga(module) => (None, Some(module)), + pipeline::ShaderModuleSource::Naga(module) => module, }; - let (naga_result, interface) = match module { - // If succeeded, then validate it and attempt to give it to gfx-hal directly. - Some(module) if desc.flags.contains(wgt::ShaderFlags::VALIDATION) || spv.is_none() => { - use naga::valid::Capabilities as Caps; - profiling::scope!("naga::validate"); + use naga::valid::Capabilities as Caps; + profiling::scope!("naga::validate"); - let mut caps = Caps::empty(); - caps.set( - Caps::PUSH_CONSTANT, - self.features.contains(wgt::Features::PUSH_CONSTANTS), - ); - caps.set( - Caps::FLOAT64, - self.features.contains(wgt::Features::SHADER_FLOAT64), - ); - let info = naga::valid::Validator::new(naga::valid::ValidationFlags::all(), caps) - .validate(&module)?; - let interface = validation::Interface::new(&module, &info); - let shader = hal::NagaShader { module, info }; - - let naga_result = if desc - .flags - .contains(wgt::ShaderFlags::EXPERIMENTAL_TRANSLATION) - || !cfg!(feature = "cross") - { - let hal_desc = hal::ShaderModuleDescriptor { label: desc.label }; - match unsafe { self.raw.create_shader_module(&hal_desc, shader) } { - Ok(raw) => Ok(raw), - Err((error, shader)) => { - log::warn!("Shader module compilation failed: {}", error); - Err(Some(shader)) - } - } - } else { - Err(Some(shader)) - }; - (naga_result, Some(interface)) - } - _ => (Err(None), None), - }; + let mut caps = Caps::empty(); + caps.set( + Caps::PUSH_CONSTANT, + self.features.contains(wgt::Features::PUSH_CONSTANTS), + ); + caps.set( + Caps::FLOAT64, + self.features.contains(wgt::Features::SHADER_FLOAT64), + ); + let info = naga::valid::Validator::new(naga::valid::ValidationFlags::all(), caps) + .validate(&module)?; + let interface = validation::Interface::new(&module, &info); + let hal_shader = hal::NagaShader { module, info }; - // Otherwise, fall back to SPIR-V. - let spv_result = match naga_result { - Ok(raw) => Ok(raw), - Err(maybe_shader) => { - let spv = match spv { - Some(data) => Ok(data), - None => { - // Produce a SPIR-V from the Naga module - profiling::scope!("naga::wpv::write_vec"); - let shader = maybe_shader.unwrap(); - naga::back::spv::write_vec(&shader.module, &shader.info, &self.spv_options) - .map(Cow::Owned) + let hal_desc = hal::ShaderModuleDescriptor { + label: desc.label.borrow_option(), + }; + let raw = match unsafe { self.raw.create_shader_module(&hal_desc, hal_shader) } { + Ok(raw) => raw, + Err((error, _shader)) => { + return Err(match error { + hal::ShaderError::Device(error) => { + pipeline::CreateShaderModuleError::Device(error.into()) } - }; - match spv { - Ok(data) => unsafe { self.raw.create_shader_module(&data) }, - Err(e) => Err(hal::ShaderError::Compilation(format!("{}", e))), - } + hal::ShaderError::Compilation(ref msg) => { + log::error!("Shader error: {}", msg); + pipeline::CreateShaderModuleError::Generation + } + }) } }; Ok(pipeline::ShaderModule { - raw: match spv_result { - Ok(raw) => raw, - Err(hal::ShaderError::Device(error)) => { - return Err(DeviceError::from(error)); - } - Err(hal::ShaderError::Compilation(ref msg)) => { - log::error!("Shader error: {}", msg); - return Err(pipeline::CreateShaderModuleError::Generation); - } - }, + raw, device_id: Stored { value: id::Valid(self_id), ref_count: self.life_guard.add_ref(), }, interface, #[cfg(debug_assertions)] - label: desc.label.to_string_or_default(), + label: desc.label.borrow_or_default().to_string(), }) } @@ -964,7 +903,7 @@ impl Device { has_dynamic_offset, min_binding_size: _, } => (Some(wgt::Features::BUFFER_BINDING_ARRAY), !read_only), - Bt::Sampler { .. } => (&mut desc_count.sampler, None, false), + Bt::Sampler { .. } => (None, false), Bt::Texture { .. } => (Some(wgt::Features::SAMPLED_TEXTURE_BINDING_ARRAY), false), Bt::StorageTexture { access, .. } => ( None, @@ -1001,14 +940,14 @@ impl Device { })?; } - let hal_bindings = entry_map.values().collect::>(); + let hal_bindings = entry_map.values().cloned().collect::>(); let hal_desc = hal::BindGroupLayoutDescriptor { label, entries: Cow::Owned(hal_bindings), }; let raw = unsafe { self.raw - .create_bind_group_layout(&hal_bindings) + .create_bind_group_layout(&hal_desc) .map_err(DeviceError::from)? }; @@ -1093,7 +1032,7 @@ impl Device { .use_extend(storage, bb.buffer_id, (), internal_use) .map_err(|_| Error::InvalidBuffer(bb.buffer_id))?; check_buffer_usage(buffer.usage, pub_usage)?; - let &(ref raw_buffer, _) = buffer + let raw_buffer = buffer .raw .as_ref() .ok_or(Error::InvalidBuffer(bb.buffer_id))?; @@ -1222,7 +1161,7 @@ impl Device { } let mut hal_bindings = SmallVec::with_capacity(bindings_array.len()); - for bb in bindings_array { + for bb in bindings_array.iter() { let bb = Self::create_buffer_binding( bb, binding, @@ -1281,7 +1220,7 @@ impl Device { .views .use_extend(&*texture_view_guard, id, (), ()) .map_err(|_| Error::InvalidTextureView(id))?; - let format_info = view.format.describe(); + let format_info = view.desc.format.describe(); let (pub_usage, internal_use) = match decl.ty { wgt::BindingType::Texture { sample_type, @@ -1293,7 +1232,7 @@ impl Device { return Err(Error::InvalidTextureMultisample { binding, layout_multisampled: multisampled, - view_samples: view.samples as u32, + view_samples: view.samples, }); } match (sample_type, format_info.sample_type, view.format_features.filterable ) { @@ -1313,15 +1252,15 @@ impl Device { return Err(Error::InvalidTextureSampleType { binding, layout_sample_type: sample_type, - view_format: view.format, + view_format: view.desc.format, }) } } - if view_dimension != view.dimension { + if view_dimension != view.desc.dimension { return Err(Error::InvalidTextureDimension { binding, layout_dimension: view_dimension, - view_dimension: view.dimension, + view_dimension: view.desc.dimension, }); } (wgt::TextureUsage::SAMPLED, view.sampled_internal_use) @@ -1331,18 +1270,18 @@ impl Device { format, view_dimension, } => { - if format != view.format { + if format != view.desc.format { return Err(Error::InvalidStorageTextureFormat { binding, layout_format: format, - view_format: view.format, + view_format: view.desc.format, }); } - if view_dimension != view.dimension { + if view_dimension != view.desc.dimension { return Err(Error::InvalidTextureDimension { binding, layout_dimension: view_dimension, - view_dimension: view.dimension, + view_dimension: view.desc.dimension, }); } let internal_use = match access { @@ -1357,7 +1296,7 @@ impl Device { wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE, ) { return Err(Error::StorageReadWriteNotSupported( - view.format, + view.desc.format, )); } @@ -1374,17 +1313,13 @@ impl Device { }), }; - if view - .aspects + if hal::FormatAspect::from(view.desc.format) .contains(hal::FormatAspect::DEPTH | hal::FormatAspect::STENCIL) { return Err(Error::DepthStencilAspect); } - match view.inner { - resource::TextureViewInner::Native { - ref raw, - ref source_id, - } => { + match view.source { + resource::TextureViewSource::Native(ref source_id) => { // Careful here: the texture may no longer have its own ref count, // if it was deleted by the user. let texture = &texture_guard[source_id.value]; @@ -1396,13 +1331,14 @@ impl Device { internal_use, ) .map_err(UsageConflict::from)?; - check_texture_usage(texture.usage, pub_usage)?; - hal::BindingResource::TextureViews([raw].into(), internal_use) + check_texture_usage(texture.desc.usage, pub_usage)?; } - resource::TextureViewInner::SwapChain { .. } => { + resource::TextureViewSource::SwapChain(_) => { return Err(Error::SwapChainImage); } } + + hal::BindingResource::TextureViews([&view.raw].into(), internal_use) } Br::TextureViewArray(ref bindings_array) => { if let Some(count) = decl.count { @@ -1420,7 +1356,7 @@ impl Device { let mut hal_bindings = SmallVec::with_capacity(bindings_array.len()); let mut common_internal_use = None; - for &id in bindings_array { + for &id in bindings_array.iter() { let view = used .views .use_extend(&*texture_view_guard, id, (), ()) @@ -1439,12 +1375,10 @@ impl Device { }; //TODO: ensure these match across the whole array common_internal_use = Some(internal_use); + hal_bindings.push(&view.raw); - match view.inner { - resource::TextureViewInner::Native { - ref raw, - ref source_id, - } => { + match view.source { + resource::TextureViewSource::Native(ref source_id) => { // Careful here: the texture may no longer have its own ref count, // if it was deleted by the user. let texture = &texture_guard[source_id.value]; @@ -1456,11 +1390,10 @@ impl Device { internal_use, ) .map_err(UsageConflict::from)?; - check_texture_usage(texture.usage, pub_usage)?; - hal_bindings.push(raw); + check_texture_usage(texture.desc.usage, pub_usage)?; } - resource::TextureViewInner::SwapChain { .. } => { - Err(Error::SwapChainImage) + resource::TextureViewSource::SwapChain(_) => { + return Err(Error::SwapChainImage); } } } @@ -1483,7 +1416,8 @@ impl Device { } let hal_desc = hal::BindGroupDescriptor { - name: desc.name, + label: desc.label.borrow_option(), + layout: &layout.raw, entries: hal_entries.into(), }; let raw = unsafe { @@ -1575,13 +1509,13 @@ impl Device { .map_err(Error::TooManyBindings)?; let hal_desc = hal::PipelineLayoutDescriptor { - label: desc.label, + label: desc.label.borrow_option(), bind_group_layouts: desc .bind_group_layouts .iter() .map(|&id| &bgl_guard.get(id).unwrap().raw) .collect(), - push_constant_ranges: desc.push_constant_ranges.as_ref(), + push_constant_ranges: desc.push_constant_ranges, }; let raw = unsafe { @@ -1693,37 +1627,32 @@ impl Device { let io = validation::StageIo::default(); let (shader_module_guard, _) = hub.shader_modules.read(&mut token); - let entry_point_name = &desc.stage.entry_point; let shader_module = shader_module_guard .get(desc.stage.module) .map_err(|_| validation::StageError::InvalidModule)?; let flag = wgt::ShaderStage::COMPUTE; - if let Some(ref interface) = shader_module.interface { - 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 + 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 _ = interface.check_stage( - provided_layouts.as_ref().map(|p| p.as_slice()), - &mut derived_group_layouts, - &entry_point_name, - flag, - io, - )?; - } else if desc.layout.is_none() { - return Err(pipeline::ImplicitLayoutError::ReflectionError(flag).into()); - } + 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 pipeline_layout_id = match desc.layout { Some(id) => id, @@ -1740,10 +1669,10 @@ impl Device { .map_err(|_| pipeline::CreateComputePipelineError::InvalidLayout)?; let pipeline_desc = hal::ComputePipelineDescriptor { - label: desc.label, + label: desc.label.borrow_option(), layout: &layout.raw, stage: hal::ProgrammableStage { - entry: &entry_point_name, + entry_point: desc.stage.entry_point, module: &shader_module.raw, }, }; @@ -1754,7 +1683,7 @@ impl Device { hal::PipelineError::Device(error) => { pipeline::CreateComputePipelineError::Device(error.into()) } - hal::PipelineError::Linkage(msg) => { + hal::PipelineError::Linkage(_stages, msg) => { pipeline::CreateComputePipelineError::Internal(msg) } }, @@ -1832,9 +1761,9 @@ impl Device { }); } vertex_buffers.alloc().init(hal::VertexBufferLayout { - array_stride: vb_state.array_stride as u32, - step_mode: vb_state.state_mode, - attributs: Cow::Borrowed(vb_state.attributes.as_ref()), + array_stride: vb_state.array_stride, + step_mode: vb_state.step_mode, + attributes: Cow::Borrowed(vb_state.attributes.as_ref()), }); for attribute in vb_state.attributes.iter() { @@ -1878,10 +1807,7 @@ impl Device { ); } - if desc.primitive.strip_index_format.is_some() - && desc.primitive.topology != wgt::PrimitiveTopology::LineStrip - && desc.primitive.topology != wgt::PrimitiveTopology::TriangleStrip - { + if desc.primitive.strip_index_format.is_some() && !desc.primitive.topology.is_strip() { return Err( pipeline::CreateRenderPipelineError::StripIndexFormatForNonStripTopology { strip_index_format: desc.primitive.strip_index_format, @@ -1972,7 +1898,7 @@ impl Device { if sc == 0 || sc > 32 || !conv::is_power_of_two(sc) { return Err(pipeline::CreateRenderPipelineError::InvalidSampleCount(sc)); } - sc as u8 + sc }; let (shader_module_guard, _) = hub.shader_modules.read(&mut token); @@ -1988,44 +1914,42 @@ impl Device { } })?; - if let Some(ref interface) = shader_module.interface { - let provided_layouts = match desc.layout { - Some(pipeline_layout_id) => { - let pipeline_layout = pipeline_layout_guard - .get(pipeline_layout_id) - .map_err(|_| pipeline::CreateRenderPipelineError::InvalidLayout)?; - Some(Device::get_introspection_bind_group_layouts( - pipeline_layout, - &*bgl_guard, - )) - } - None => None, - }; + let provided_layouts = match desc.layout { + Some(pipeline_layout_id) => { + let pipeline_layout = pipeline_layout_guard + .get(pipeline_layout_id) + .map_err(|_| pipeline::CreateRenderPipelineError::InvalidLayout)?; + Some(Device::get_introspection_bind_group_layouts( + pipeline_layout, + &*bgl_guard, + )) + } + None => None, + }; - io = interface - .check_stage( - provided_layouts.as_ref().map(|p| p.as_slice()), - &mut derived_group_layouts, - &stage.entry_point, - flag, - io, - ) - .map_err(|error| pipeline::CreateRenderPipelineError::Stage { - stage: flag, - error, - })?; - validated_stages |= flag; - } + io = shader_module + .interface + .check_stage( + provided_layouts.as_ref().map(|p| p.as_slice()), + &mut derived_group_layouts, + &stage.entry_point, + flag, + io, + ) + .map_err(|error| pipeline::CreateRenderPipelineError::Stage { + stage: flag, + error, + })?; + validated_stages |= flag; hal::ProgrammableStage { module: &shader_module.raw, - entry_point: &stage.entry_point, + entry_point: stage.entry_point, } }; let fragment_stage = match desc.fragment { Some(ref fragment) => { - let entry_point_name = &fragment.stage.entry_point; let flag = wgt::ShaderStage::FRAGMENT; let shader_module = @@ -2047,26 +1971,25 @@ impl Device { }; if validated_stages == wgt::ShaderStage::VERTEX { - if let Some(ref interface) = shader_module.interface { - io = interface - .check_stage( - provided_layouts.as_ref().map(|p| p.as_slice()), - &mut derived_group_layouts, - &entry_point_name, - flag, - io, - ) - .map_err(|error| pipeline::CreateRenderPipelineError::Stage { - stage: flag, - error, - })?; - validated_stages |= flag; - } + io = shader_module + .interface + .check_stage( + provided_layouts.as_ref().map(|p| p.as_slice()), + &mut derived_group_layouts, + &fragment.stage.entry_point, + flag, + io, + ) + .map_err(|error| pipeline::CreateRenderPipelineError::Stage { + stage: flag, + error, + })?; + validated_stages |= flag; } Some(hal::ProgrammableStage { module: &shader_module.raw, - entry_point: &entry_point_name, + entry_point: fragment.stage.entry_point, }) } None => None, @@ -2122,14 +2045,15 @@ impl Device { .map_err(|_| pipeline::CreateRenderPipelineError::InvalidLayout)?; let pipeline_desc = hal::RenderPipelineDescriptor { - label: desc.label, + label: desc.label.borrow_option(), layout: &layout.raw, vertex_buffers: vertex_buffers.into(), vertex_stage, - fragment_stage, - color_targets, + primitive: desc.primitive, depth_stencil: desc.depth_stencil, multisample: desc.multisample, + fragment_stage, + color_targets: Cow::Borrowed(color_targets), }; let raw = unsafe { self.raw.create_render_pipeline(&pipeline_desc) }.map_err( @@ -2230,42 +2154,31 @@ impl Device { }); } - let (hal_type, elements) = conv::map_query_type(&desc.ty); - Ok(resource::QuerySet { - raw: unsafe { self.raw.create_query_pool(hal_type, desc.count).unwrap() }, + raw: unsafe { self.raw.create_query_set(desc).unwrap() }, device_id: Stored { value: id::Valid(self_id), ref_count: self.life_guard.add_ref(), }, life_guard: LifeGuard::new(""), desc: desc.clone(), - elements, }) } } impl Device { - pub(crate) fn destroy_bind_group(&self, bind_group: binding_model::BindGroup) { - self.desc_allocator - .lock() - .free(&self.raw, iter::once(bind_group.raw)); - } - pub(crate) fn destroy_buffer(&self, buffer: resource::Buffer) { - if let Some((raw, memory)) = buffer.raw { + if let Some(raw) = buffer.raw { unsafe { - self.mem_allocator.lock().free(&self.raw, memory); self.raw.destroy_buffer(raw); } } } pub(crate) fn destroy_texture(&self, texture: resource::Texture) { - if let Some((raw, memory)) = texture.raw { + if let Some(raw) = texture.raw { unsafe { - self.mem_allocator.lock().free(&self.raw, memory); - self.raw.destroy_image(raw); + self.raw.destroy_texture(raw); } } } @@ -2276,26 +2189,11 @@ impl Device { if let Err(error) = life_tracker.triage_submissions(&self.raw, true) { log::error!("failed to triage submissions: {}", error); } - life_tracker.cleanup(&self.raw, &self.mem_allocator, &self.desc_allocator); + life_tracker.cleanup(&self.raw); } pub(crate) fn dispose(self) { - let mut desc_alloc = self.desc_allocator.into_inner(); - let mut mem_alloc = self.mem_allocator.into_inner(); - self.pending_writes - .dispose(&self.raw, &self.cmd_allocator, &mut mem_alloc); - self.cmd_allocator.destroy(&self.raw); - unsafe { - desc_alloc.cleanup(&self.raw); - mem_alloc.clear(&self.raw); - let rps = self.render_passes.into_inner(); - for (_, rp) in rps.render_passes { - self.raw.destroy_render_pass(rp); - } - for (_, fbo) in rps.framebuffers { - self.raw.destroy_framebuffer(fbo); - } - } + self.pending_writes.dispose(&self.raw); } } @@ -2321,6 +2219,15 @@ pub enum DeviceError { OutOfMemory, } +impl From for DeviceError { + fn from(error: hal::DeviceError) -> Self { + match error { + hal::DeviceError::Lost => DeviceError::Lost, + hal::DeviceError::OutOfMemory => DeviceError::OutOfMemory, + } + } +} + #[derive(Clone, Debug, Error)] #[error("Features {0:?} are required but not enabled on the device")] pub struct MissingFeatures(pub wgt::Features); @@ -2445,19 +2352,17 @@ impl Global { let ref_count = buffer.life_guard.add_ref(); let buffer_use = if !desc.mapped_at_creation { - hal::BufferUse::EMPTY + hal::BufferUse::empty() } else if desc.usage.contains(wgt::BufferUsage::MAP_WRITE) { // buffer is mappable, so we are just doing that at start let map_size = buffer.size; let ptr = match map_buffer(&device.raw, &mut buffer, 0, map_size, HostMap::Write) { Ok(ptr) => ptr, Err(e) => { - let (raw, memory) = buffer.raw.unwrap(); - device.lock_life(&mut token).schedule_resource_destruction( - queue::TempResource::Buffer(raw), - memory, - !0, - ); + let raw = buffer.raw.unwrap(); + device + .lock_life(&mut token) + .schedule_resource_destruction(queue::TempResource::Buffer(raw), !0); break e.into(); } }; @@ -2478,32 +2383,26 @@ impl Global { let mut stage = match device.create_buffer(device_id, &stage_desc, true) { Ok(stage) => stage, Err(e) => { - let (raw, memory) = buffer.raw.unwrap(); - device.lock_life(&mut token).schedule_resource_destruction( - queue::TempResource::Buffer(raw), - memory, - !0, - ); + let raw = buffer.raw.unwrap(); + device + .lock_life(&mut token) + .schedule_resource_destruction(queue::TempResource::Buffer(raw), !0); break e; } }; - let (stage_buffer, mut stage_memory) = stage.raw.unwrap(); - let ptr = match stage_memory.map(&device.raw, 0, stage.size) { + let stage_buffer = stage.raw.unwrap(); + let ptr = match device.raw.map_buffer(&stage_buffer, 0..stage.size) { Ok(ptr) => ptr, Err(e) => { - let (raw, memory) = buffer.raw.unwrap(); + let raw = buffer.raw.unwrap(); let mut life_lock = device.lock_life(&mut token); - life_lock.schedule_resource_destruction( - queue::TempResource::Buffer(raw), - memory, - !0, - ); + life_lock + .schedule_resource_destruction(queue::TempResource::Buffer(raw), !0); life_lock.schedule_resource_destruction( queue::TempResource::Buffer(stage_buffer), - stage_memory, !0, ); - break e.into(); + break DeviceError::from(e).into(); } }; @@ -2515,9 +2414,8 @@ impl Global { buffer.map_state = resource::BufferMapState::Init { ptr, - needs_flush: !stage_memory.is_coherent(), + needs_flush: !stage.is_coherent, stage_buffer, - stage_memory, }; hal::BufferUse::COPY_DST }; @@ -2561,6 +2459,7 @@ impl Global { .wait_for_submit(last_submission, &mut token) } + #[doc(hidden)] pub fn device_set_buffer_sub_data( &self, device_id: id::DeviceId, @@ -2596,16 +2495,26 @@ impl Global { }); } - buffer + 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 - .as_mut() - .unwrap() - .1 - .write_bytes(&device.raw, offset, data)?; + .unmap_buffer(raw_buf) + .map_err(DeviceError::from)?; + //TODO: flush Ok(()) } + #[doc(hidden)] pub fn device_get_buffer_sub_data( &self, device_id: id::DeviceId, @@ -2629,12 +2538,21 @@ impl Global { check_buffer_usage(buffer.usage, wgt::BufferUsage::MAP_READ)?; //assert!(buffer isn't used by the GPU); - buffer + //TODO: invalidate + let raw_buf = buffer.raw.as_ref().unwrap(); + let ptr = device .raw - .as_mut() - .unwrap() - .1 - .read_bytes(&device.raw, offset, data)?; + .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(()) } @@ -2668,22 +2586,20 @@ impl Global { trace.lock().add(trace::Action::FreeBuffer(buffer_id)); } - let (raw, memory) = buffer + let raw = buffer .raw .take() .ok_or(resource::DestroyError::AlreadyDestroyed)?; let temp = queue::TempResource::Buffer(raw); if device.pending_writes.dst_buffers.contains(&buffer_id) { - device.pending_writes.temp_resources.push((temp, memory)); + device.pending_writes.temp_resources.push(temp); } else { let last_submit_index = buffer.life_guard.submission_index.load(Ordering::Acquire); drop(buffer_guard); - device.lock_life(&mut token).schedule_resource_destruction( - temp, - memory, - last_submit_index, - ); + device + .lock_life(&mut token) + .schedule_resource_destruction(temp, last_submit_index); } Ok(()) @@ -2818,22 +2734,20 @@ impl Global { trace.lock().add(trace::Action::FreeTexture(texture_id)); } - let (raw, memory) = texture + let raw = texture .raw .take() .ok_or(resource::DestroyError::AlreadyDestroyed)?; - let temp = queue::TempResource::Image(raw); + let temp = queue::TempResource::Texture(raw); if device.pending_writes.dst_textures.contains(&texture_id) { - device.pending_writes.temp_resources.push((temp, memory)); + device.pending_writes.temp_resources.push(temp); } else { let last_submit_index = texture.life_guard.submission_index.load(Ordering::Acquire); drop(texture_guard); - device.lock_life(&mut token).schedule_resource_destruction( - temp, - memory, - last_submit_index, - ); + device + .lock_life(&mut token) + .schedule_resource_destruction(temp, last_submit_index); } Ok(()) @@ -2960,11 +2874,11 @@ impl Global { let _ref_count = view.life_guard.ref_count.take(); let last_submit_index = view.life_guard.submission_index.load(Ordering::Acquire); - let device_id = match view.inner { - resource::TextureViewInner::Native { ref source_id, .. } => { + let device_id = match view.source { + resource::TextureViewSource::Native(ref source_id) => { texture_guard[source_id.value].device_id.value } - resource::TextureViewInner::SwapChain { .. } => { + resource::TextureViewSource::SwapChain(_) => { return Err(resource::TextureViewDestroyError::SwapChainImage) } }; @@ -3128,7 +3042,7 @@ impl Global { let layout = match device.create_bind_group_layout( device_id, - desc.label.as_ref().map(|cow| cow.as_ref()), + desc.label.borrow_option(), entry_map, ) { Ok(layout) => layout, @@ -3454,22 +3368,27 @@ impl Global { ref_count: device.life_guard.add_ref(), }; - let mut raw = unsafe { - self.raw - .create_command_buffer(&hal::CommandBufferDescriptor { label: desc.label })? + let cmd_buf_result = unsafe { + device + .raw + .create_command_buffer(&hal::CommandBufferDescriptor { + label: desc.label.borrow_option(), + }) + }; + let mut raw = match cmd_buf_result { + Ok(raw) => raw, + Err(error) => break DeviceError::from(error), }; - unsafe { - raw.begin(); - } let command_buffer = command::CommandBuffer::new( raw, - device_id, + dev_stored, device.limits.clone(), device.downlevel, device.features, #[cfg(feature = "trace")] device.trace.is_some(), + &desc.label, ); let id = fid.assign(command_buffer, &mut token); @@ -3497,7 +3416,6 @@ impl Global { if let Some(cmdbuf) = cmdbuf { let device = &mut device_guard[cmdbuf.device_id.value]; device.untrack::(&hub, &cmdbuf.trackers, &mut token); - device.cmd_allocator.discard(cmdbuf); } } @@ -3952,6 +3870,7 @@ impl Global { surface_id: id::SurfaceId, desc: &wgt::SwapChainDescriptor, ) -> (id::SwapChainId, Option) { + use hal::{Adapter as _, Surface as _}; profiling::scope!("create_swap_chain", "Device"); fn validate_swap_chain_descriptor( @@ -3972,13 +3891,21 @@ impl Global { caps.extents ); } - if !caps.vsync_modes.contains(&config.vsync_mode) { + if !caps.present_modes.contains(&config.present_mode) { log::warn!( - "Surface does not support present mode: {:?}, falling back to {:?}", + "Surface does not support present mode: {:?}, falling back to FIFO", config.present_mode, - hal::VsyncMode::FIFO ); - config.vsync_mode = hal::VsyncMode::Fifo; + config.present_mode = wgt::PresentMode::Fifo; + } + if !caps.formats.contains(&config.format) { + return Err(swap_chain::CreateSwapChainError::UnsupportedFormat { + requested: config.format, + available: caps.formats, + }); + } + if !caps.usage.contains(config.usage) { + return Err(swap_chain::CreateSwapChainError::UnsupportedUsage); } if width == 0 || height == 0 { return Err(swap_chain::CreateSwapChainError::ZeroArea); @@ -4013,49 +3940,57 @@ impl Global { Err(_) => break swap_chain::CreateSwapChainError::InvalidSurface, }; - let (caps, formats) = { + let caps = { let surface = A::get_surface_mut(surface); let adapter = &adapter_guard[device.adapter_id.value]; - let queue_family = &adapter.raw.queue_families[0]; - if !surface.supports_queue_family(queue_family) { - break swap_chain::CreateSwapChainError::UnsupportedQueueFamily; + match adapter.raw.adapter.surface_capabilities(surface) { + Some(caps) => caps, + None => break swap_chain::CreateSwapChainError::UnsupportedQueueFamily, } - let formats = surface.supported_formats(&adapter.raw.physical_device); - let caps = surface.capabilities(&adapter.raw.physical_device); - (caps, formats) }; let num_frames = swap_chain::DESIRED_NUM_FRAMES - .max(*caps.image_count.start()) - .min(*caps.image_count.end()); - let mut config = swap_chain::swap_chain_descriptor_to_hal( - &desc, - num_frames, - device.private_features, - ); - if let Some(formats) = formats { - if !formats.contains(&config.format) { - break swap_chain::CreateSwapChainError::UnsupportedFormat { - requested: config.format, - available: formats, - }; - } - } + .max(*caps.swap_chain_sizes.start()) + .min(*caps.swap_chain_sizes.end()); + let mut config = hal::SurfaceConfiguration { + swap_chain_size: num_frames, + present_mode: desc.present_mode, + composite_alpha_mode: hal::CompositeAlphaMode::Opaque, + format: desc.format, + extent: wgt::Extent3d { + width: desc.width, + height: desc.height, + depth_or_array_layers: 1, + }, + usage: conv::map_texture_usage(desc.usage, hal::FormatAspect::COLOR), + }; + if let Err(error) = validate_swap_chain_descriptor(&mut config, &caps) { break error; } - let framebuffer_attachment = config.framebuffer_attachment(); - unsafe { A::get_surface_mut(surface).configure_swapchain(&device.raw, config) } - .map_err(DeviceError::from)?; + match unsafe { A::get_surface_mut(surface).configure(&device.raw, &config) } { + Ok(()) => (), + Err(error) => { + break match error { + hal::SurfaceError::Outdated | hal::SurfaceError::Lost => { + swap_chain::CreateSwapChainError::InvalidSurface + } + hal::SurfaceError::Device(error) => { + swap_chain::CreateSwapChainError::Device(error.into()) + } + hal::SurfaceError::Other(message) => { + log::error!("surface configuration failed: {}", message); + swap_chain::CreateSwapChainError::InvalidSurface + } + } + } + } if let Some(sc) = swap_chain_guard.try_remove(sc_id) { - if sc.acquired_view_id.is_some() { + if sc.acquired_texture.is_some() { break swap_chain::CreateSwapChainError::SwapChainOutputExists; } - unsafe { - device.raw.destroy_semaphore(sc.semaphore); - } } let swap_chain = swap_chain::SwapChain { @@ -4066,13 +4001,9 @@ impl Global { }, desc: desc.clone(), num_frames, - semaphore: match device.raw.create_semaphore() { - Ok(sem) => sem, - Err(_) => break DeviceError::OutOfMemory.into(), - }, - acquired_view_id: None, + acquired_texture: None, active_submission_index: 0, - framebuffer_attachment, + marker: PhantomData, }; swap_chain_guard.insert(sc_id, swap_chain); @@ -4176,7 +4107,7 @@ impl Global { let mut token = Token::root(); let (device_guard, _) = hub.devices.read(&mut token); if let Ok(device) = device_guard.get(id) { - device.raw.start_capture(); + unsafe { device.raw.start_capture() }; } } @@ -4185,7 +4116,7 @@ impl Global { let mut token = Token::root(); let (device_guard, _) = hub.devices.read(&mut token); if let Ok(device) = device_guard.get(id) { - device.raw.stop_capture(); + unsafe { device.raw.stop_capture() }; } } @@ -4314,23 +4245,17 @@ impl Global { } unsafe { Ok((ptr.as_ptr().offset(offset as isize), range_size)) } } - resource::BufferMapState::Active { - ptr, ref sub_range, .. - } => { - if offset < sub_range.offset { + resource::BufferMapState::Active { ptr, ref range, .. } => { + if offset < range.start { return Err(resource::BufferAccessError::OutOfBoundsUnderrun { index: offset, - min: sub_range.offset, + min: range.start, }); } - let range_end_offset = sub_range - .size - .map(|size| size + sub_range.offset) - .unwrap_or(buffer.size); - if offset + range_size > range_end_offset { + if offset + range_size > range.end { return Err(resource::BufferAccessError::OutOfBoundsOverrun { index: offset + range_size - 1, - max: range_end_offset, + max: range.end, }); } unsafe { Ok((ptr.as_ptr().offset(offset as isize), range_size)) } @@ -4362,7 +4287,6 @@ impl Global { resource::BufferMapState::Init { ptr, stage_buffer, - stage_memory, needs_flush, } => { #[cfg(feature = "trace")] @@ -4380,27 +4304,23 @@ impl Global { } let _ = ptr; - if needs_flush { - stage_memory.flush_range(&device.raw, 0, None)?; - } - - let &(ref buf_raw, _) = buffer + let raw_buf = buffer .raw .as_ref() .ok_or(resource::BufferAccessError::Destroyed)?; buffer.life_guard.use_at(device.active_submission_index + 1); - let region = hal::BufferCopy { - src: 0, - dst: 0, - size: buffer.size, - }; + let region = wgt::BufferSize::new(buffer.size).map(|size| hal::BufferCopy { + src_offset: 0, + dst_offset: 0, + size, + }); let transition_src = hal::BufferBarrier { buffer: &stage_buffer, usage: hal::BufferUse::MAP_WRITE..hal::BufferUse::COPY_SRC, }; let transition_dst = hal::BufferBarrier { - buffer: buf_raw, + buffer: raw_buf, usage: hal::BufferUse::empty()..hal::BufferUse::COPY_DST, }; unsafe { @@ -4409,12 +4329,12 @@ impl Global { iter::once(transition_src).chain(iter::once(transition_dst)), ); if buffer.size > 0 { - cmd_buf.copy_buffer_to_buffer(&stage_buffer, buf_raw, iter::once(region)); + cmd_buf.copy_buffer_to_buffer(&stage_buffer, raw_buf, region.into_iter()); } } device .pending_writes - .consume_temp(queue::TempResource::Buffer(stage_buffer), stage_memory); + .consume_temp(queue::TempResource::Buffer(stage_buffer)); device.pending_writes.dst_buffers.insert(buffer_id); } resource::BufferMapState::Idle => { @@ -4423,11 +4343,7 @@ impl Global { resource::BufferMapState::Waiting(pending) => { return Ok(Some((pending.op, resource::BufferMapAsyncStatus::Aborted))); } - resource::BufferMapState::Active { - ptr, - sub_range, - host, - } => { + resource::BufferMapState::Active { ptr, range, host } => { if host == HostMap::Write { #[cfg(feature = "trace")] if let Some(ref trace) = device.trace { @@ -4443,9 +4359,12 @@ impl Global { queued: false, }); } - let _ = (ptr, sub_range); + let _ = (ptr, range); } - device.raw.unmap_buffer(&buffer.raw)?; + 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 c67eb10b9b..4d9fdf7bd5 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -6,7 +6,7 @@ use crate::device::trace::Action; use crate::{ command::{ - extract_image_range, validate_linear_texture_data, validate_texture_copy_range, + extract_texture_selector, validate_linear_texture_data, validate_texture_copy_range, CommandBuffer, CopySide, ImageCopyTexture, TransferError, }, conv, @@ -26,6 +26,21 @@ use thiserror::Error; struct StagingData { buffer: A::Buffer, cmdbuf: A::CommandBuffer, + is_coherent: bool, +} + +impl StagingData { + unsafe fn write( + &self, + device: &A::Device, + offset: wgt::BufferAddress, + data: &[u8], + ) -> Result<(), hal::DeviceError> { + let ptr = device.map_buffer(&self.buffer, offset..offset + data.len() as u64)?; + ptr::copy_nonoverlapping(data.as_ptr(), ptr.as_ptr(), data.len()); + device.unmap_buffer(&self.buffer)?; + Ok(()) + } } #[derive(Debug)] @@ -64,7 +79,7 @@ impl PendingWrites { device.destroy_buffer(buffer); }, TempResource::Texture(texture) => unsafe { - device.destroy_image(texture); + device.destroy_texture(texture); }, } } @@ -91,11 +106,11 @@ impl PendingWrites { fn create_cmd_buf(device: &A::Device) -> A::CommandBuffer { unsafe { - let mut cmd_buf = device.create_command_buffer(&hal::CommandBufferDescriptor { - label: Some("_PendingWrites"), - }); - cmd_buf.begin(); - cmd_buf + device + .create_command_buffer(&hal::CommandBufferDescriptor { + label: Some("_PendingWrites"), + }) + .unwrap() } } @@ -157,9 +172,13 @@ impl super::Device { let cmdbuf = match self.pending_writes.command_buffer.take() { Some(cmdbuf) => cmdbuf, - None => PendingWrites::create_cmd_buf(&self.raw), + None => PendingWrites::::create_cmd_buf(&self.raw), }; - Ok(StagingData { buffer, cmdbuf }) + Ok(StagingData { + buffer, + cmdbuf, + is_coherent: true, //TODO + }) } fn initialize_buffer_memory( @@ -171,7 +190,7 @@ impl super::Device { .dst_buffers .extend(required_buffer_inits.map.keys()); - let cmd_buf = self.pending_writes.borrow_cmd_buf(&self.cmd_allocator); + let cmd_buf = self.pending_writes.borrow_cmd_buf(&self.raw); let mut trackers = self.trackers.lock(); for (buffer_id, mut ranges) in required_buffer_inits.map.drain() { @@ -193,7 +212,7 @@ impl super::Device { hal::BufferUse::COPY_DST, ); let buffer = buffer_guard.get(buffer_id).unwrap(); - let &(ref buffer_raw, _) = buffer + let raw_buf = buffer .raw .as_ref() .ok_or(QueueSubmitError::DestroyedBuffer(buffer_id))?; @@ -202,11 +221,11 @@ impl super::Device { } for range in ranges { - assert!(range.start % 4 == 0, "Buffer {:?} has an uninitialized range with a start not aligned to 4 (start was {})", buffer, range.start); - assert!(range.end % 4 == 0, "Buffer {:?} has an uninitialized range with an end not aligned to 4 (end was {})", buffer, range.end); + assert!(range.start % 4 == 0, "Buffer {:?} has an uninitialized range with a start not aligned to 4 (start was {})", raw_buf, range.start); + assert!(range.end % 4 == 0, "Buffer {:?} has an uninitialized range with an end not aligned to 4 (end was {})", raw_buf, range.end); unsafe { - cmd_buf.fill_buffer(buffer_raw, range, 0); + cmd_buf.fill_buffer(raw_buf, range, 0); } } } @@ -282,14 +301,14 @@ impl Global { } let mut stage = device.prepare_stage(data_size)?; - stage.memory.write_bytes(&device.raw, 0, data)?; + unsafe { stage.write(&device.raw, 0, data) }.map_err(DeviceError::from)?; let mut trackers = device.trackers.lock(); let (dst, transition) = trackers .buffers .use_replace(&*buffer_guard, buffer_id, (), hal::BufferUse::COPY_DST) .map_err(TransferError::InvalidBuffer)?; - let &(ref dst_raw, _) = dst + let dst_raw = dst .raw .as_ref() .ok_or(TransferError::InvalidBuffer(buffer_id))?; @@ -314,11 +333,11 @@ impl Global { .into()); } - let region = hal::BufferCopy { + let region = wgt::BufferSize::new(data.len() as u64).map(|size| hal::BufferCopy { src_offset: 0, dst_offset: buffer_offset, - size: data.len() as _, - }; + size, + }); let barriers = iter::once(hal::BufferBarrier { buffer: &stage.buffer, usage: hal::BufferUse::MAP_WRITE..hal::BufferUse::COPY_SRC, @@ -328,7 +347,7 @@ impl Global { stage.cmdbuf.transition_buffers(barriers); stage .cmdbuf - .copy_buffer_to_buffer(&stage.buffer, dst_raw, iter::once(region)); + .copy_buffer_to_buffer(&stage.buffer, dst_raw, region.into_iter()); } device.pending_writes.consume(stage); @@ -382,8 +401,8 @@ impl Global { } let (texture_guard, _) = hub.textures.read(&mut token); - let (image_range, texture_format) = - extract_image_range(destination, size, &*texture_guard)?; + let (selector, texture_base, texture_format) = + extract_texture_selector(destination, size, &*texture_guard)?; let format_desc = texture_format.describe(); validate_linear_texture_data( data_layout, @@ -414,11 +433,11 @@ impl Global { let block_rows_per_image = texel_rows_per_image / block_height; let bytes_per_row_alignment = get_lowest_common_denom( - device.hal_limits.optimal_buffer_copy_pitch_alignment as u32, - format_desc.block_size, + device.alignments.buffer_copy_pitch.get() as u32, + format_desc.block_size as u32, ); let stage_bytes_per_row = align_to( - format_desc.block_size * width_blocks, + format_desc.block_size as u32 * width_blocks, bytes_per_row_alignment, ); @@ -433,39 +452,34 @@ impl Global { .use_replace( &*texture_guard, destination.texture, - image_range, + selector, hal::TextureUse::COPY_DST, ) .unwrap(); - let &(ref dst_raw, _) = dst + let dst_raw = dst .raw .as_ref() .ok_or(TransferError::InvalidTexture(destination.texture))?; - if !dst.usage.contains(wgt::TextureUsage::COPY_DST) { + if !dst.desc.usage.contains(wgt::TextureUsage::COPY_DST) { return Err( TransferError::MissingCopyDstUsageFlag(None, Some(destination.texture)).into(), ); } - let max_image_extent = validate_texture_copy_range( - destination, - dst.format, - dst.kind, - CopySide::Destination, - size, - )?; + let max_image_extent = + validate_texture_copy_range(destination, &dst.desc, CopySide::Destination, size)?; dst.life_guard.use_at(device.active_submission_index + 1); let bytes_per_row = if let Some(bytes_per_row) = data_layout.bytes_per_row { bytes_per_row.get() } else { - width_blocks * format_desc.block_size + width_blocks * format_desc.block_size as u32 }; - let ptr = stage.memory.map(&device.raw, 0, stage_size)?; + let ptr = unsafe { device.raw.map_buffer(&stage.buffer, 0..stage_size) } + .map_err(DeviceError::from)?; unsafe { profiling::scope!("copy"); - //TODO: https://github.com/zakarumych/gpu-alloc/issues/13 if stage_bytes_per_row == bytes_per_row { // Fast path if the data isalready being aligned optimally. ptr::copy_nonoverlapping(data.as_ptr(), ptr.as_ptr(), stage_size as usize); @@ -487,9 +501,14 @@ impl Global { } } } - stage.memory.unmap(&device.raw); - if !stage.memory.is_coherent() { - stage.memory.flush_range(&device.raw, 0, None)?; + device + .raw + .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 @@ -499,11 +518,10 @@ impl Global { let region = hal::BufferTextureCopy { buffer_layout: wgt::ImageDataLayout { offset: 0, - bytes_per_row: stage_bytes_per_row, - rows_per_image: texel_rows_per_image, + bytes_per_row: NonZeroU32::new(stage_bytes_per_row), + rows_per_image: NonZeroU32::new(texel_rows_per_image), }, - texture_mip_level: destination.mip_level, - texture_origin: destination.origin, + texture_base, size: wgt::Extent3d { width: size.width.min(max_image_extent.width), height: size.height.min(max_image_extent.height), @@ -520,12 +538,9 @@ impl Global { stage .cmdbuf .transition_textures(transition.map(|pending| pending.into_hal(dst))); - stage.cmdbuf.copy_buffer_to_image( - &stage.buffer, - dst_raw, - hal::TextureUse::COPY_DST, - iter::once(region), - ); + stage + .cmdbuf + .copy_buffer_to_texture(&stage.buffer, dst_raw, iter::once(region)); } device.pending_writes.consume(stage); @@ -607,7 +622,7 @@ impl Global { for sc_id in cmdbuf.used_swap_chains.drain(..) { let sc = &mut swap_chain_guard[sc_id.value]; - if sc.acquired_view_id.is_none() { + if sc.acquired_texture.is_none() { return Err(QueueSubmitError::SwapChainOutputDropped); } if sc.active_submission_index != submit_index { @@ -621,13 +636,17 @@ impl Global { // update submission IDs for id in cmdbuf.trackers.buffers.used() { let buffer = &mut buffer_guard[id]; - if buffer.raw.is_none() { - return Err(QueueSubmitError::DestroyedBuffer(id.0)); - } + let raw_buf = match buffer.raw { + Some(ref raw) => raw, + None => { + return Err(QueueSubmitError::DestroyedBuffer(id.0)); + } + }; if !buffer.life_guard.use_at(submit_index) { if let BufferMapState::Active { .. } = buffer.map_state { log::warn!("Dropped buffer has a pending mapping."); - unsafe { device.raw.unmap_buffer(buffer)? }; + unsafe { device.raw.unmap_buffer(raw_buf) } + .map_err(DeviceError::from)?; } device.temp_suspected.buffers.push(id); } else { @@ -677,18 +696,17 @@ impl Global { } } - // execute resource transitions - let mut transit = - device - .raw - .create_command_buffer(&hal::CommandBufferDescriptor { - label: Some("_Transit"), - }); unsafe { // the last buffer was open, closing now - cmdbuf.raw.last_mut().unwrap().end(); - transit.begin(); + 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)?; log::trace!("Stitching command buffer {:?} before submission", cmb_id); trackers.merge_extend_stateless(&cmdbuf.trackers); CommandBuffer::insert_barriers( @@ -700,7 +718,7 @@ impl Global { &*texture_guard, ); unsafe { - transit.end(); + transit.finish(); } cmdbuf.raw.insert(0, transit); } @@ -714,42 +732,28 @@ impl Global { } // now prepare the GPU submission - let mut fence = device - .raw - .create_fence(false) - .or(Err(DeviceError::OutOfMemory))?; - let signal_semaphores = signal_swapchain_semaphores - .into_iter() - .map(|sc_id| &swap_chain_guard[sc_id].semaphore); + 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.as_ref()); + command_buffers.extend(pending_write_command_buffer); for &cmd_buf_id in command_buffer_ids.iter() { match command_buffer_guard.get(cmd_buf_id) { Ok(cmd_buf) if cmd_buf.is_finished() => { - command_buffers.extend(cmd_buf.raw.iter()); + command_buffers.extend(cmd_buf.raw.drain(..)); } _ => {} } } + let fence_value = 1; //TODO unsafe { - device.queue_group.queues[0].submit( - command_buffers.into_iter(), - iter::empty(), - signal_semaphores, - Some(&mut fence), - ); + device + .queue + .submit(command_buffers.into_iter(), Some((&mut fence, fence_value))); } fence }; - if let Some(comb_raw) = pending_write_command_buffer { - device - .cmd_allocator - .after_submit_internal(comb_raw, submit_index); - } - let callbacks = match device.maintain(&hub, false, &mut token) { Ok(callbacks) => callbacks, Err(WaitIdleError::Device(err)) => return Err(QueueSubmitError::Queue(err)), @@ -764,15 +768,6 @@ impl Global { device.pending_writes.temp_resources.drain(..), ); - // finally, return the command buffers to the allocator - for &cmb_id in command_buffer_ids { - if let (Some(cmd_buf), _) = hub.command_buffers.unregister(cmb_id, &mut token) { - device - .cmd_allocator - .after_submit(cmd_buf, &device.raw, submit_index); - } - } - callbacks }; @@ -791,7 +786,7 @@ impl Global { let mut token = Token::root(); let (device_guard, _) = hub.devices.read(&mut token); match device_guard.get(queue_id) { - Ok(device) => Ok(device.queue_group.queues[0].timestamp_period()), + Ok(_device) => Ok(1.0), //TODO? Err(_) => Err(InvalidQueue), } } diff --git a/wgpu-core/src/hub.rs b/wgpu-core/src/hub.rs index e18a815985..03b7b597b3 100644 --- a/wgpu-core/src/hub.rs +++ b/wgpu-core/src/hub.rs @@ -6,14 +6,10 @@ use crate::{ binding_model::{BindGroup, BindGroupLayout, PipelineLayout}, command::{CommandBuffer, RenderBundle}, device::Device, - id::{ - AdapterId, BindGroupId, BindGroupLayoutId, BufferId, CommandBufferId, ComputePipelineId, - DeviceId, PipelineLayoutId, RenderBundleId, RenderPipelineId, SamplerId, ShaderModuleId, - SurfaceId, SwapChainId, TextureId, TextureViewId, TypedId, Valid, - }, + id, instance::{Adapter, Instance, Surface}, pipeline::{ComputePipeline, RenderPipeline, ShaderModule}, - resource::{Buffer, Sampler, Texture, TextureView}, + resource::{Buffer, QuerySet, Sampler, Texture, TextureView}, swap_chain::SwapChain, Epoch, Index, }; @@ -21,8 +17,6 @@ use crate::{ use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard}; use wgt::Backend; -use crate::id::QuerySetId; -use crate::resource::QuerySet; #[cfg(debug_assertions)] use std::cell::Cell; use std::{fmt::Debug, marker::PhantomData, ops}; @@ -51,7 +45,7 @@ impl IdentityManager { } } - pub fn alloc(&mut self, backend: Backend) -> I { + pub fn alloc(&mut self, backend: Backend) -> I { match self.free.pop() { Some(index) => I::zip(index, self.epochs[index as usize], backend), None => { @@ -63,7 +57,7 @@ impl IdentityManager { } } - pub fn free(&mut self, id: I) { + pub fn free(&mut self, id: I) { let (index, epoch, _backend) = id.unzip(); // avoid doing this check in release if cfg!(debug_assertions) { @@ -87,26 +81,26 @@ enum Element { pub(crate) struct InvalidId; #[derive(Debug)] -pub struct Storage { +pub struct Storage { map: Vec>, kind: &'static str, _phantom: PhantomData, } -impl ops::Index> for Storage { +impl ops::Index> for Storage { type Output = T; - fn index(&self, id: Valid) -> &T { + fn index(&self, id: id::Valid) -> &T { self.get(id.0).unwrap() } } -impl ops::IndexMut> for Storage { - fn index_mut(&mut self, id: Valid) -> &mut T { +impl ops::IndexMut> for Storage { + fn index_mut(&mut self, id: id::Valid) -> &mut T { self.get_mut(id.0).unwrap() } } -impl Storage { +impl Storage { pub(crate) fn contains(&self, id: I) -> bool { let (index, epoch, _) = id.unzip(); match self.map[index as usize] { @@ -347,7 +341,7 @@ pub trait IdentityHandler: Debug { fn free(&self, id: I); } -impl IdentityHandler for Mutex { +impl IdentityHandler for Mutex { type Input = PhantomData; fn process(&self, _id: Self::Input, backend: Backend) -> I { self.lock().alloc(backend) @@ -365,7 +359,7 @@ pub trait IdentityHandlerFactory { #[derive(Debug)] pub struct IdentityManagerFactory; -impl IdentityHandlerFactory for IdentityManagerFactory { +impl IdentityHandlerFactory for IdentityManagerFactory { type Filter = Mutex; fn spawn(&self, min_index: Index) -> Self::Filter { Mutex::new(IdentityManager::from_index(min_index)) @@ -373,23 +367,23 @@ impl IdentityHandlerFactory for IdentityManagerFactory { } pub trait GlobalIdentityHandlerFactory: - IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory - + IdentityHandlerFactory + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory + + IdentityHandlerFactory { } @@ -409,13 +403,13 @@ pub trait Resource { } #[derive(Debug)] -pub struct Registry> { +pub struct Registry> { identity: F::Filter, data: RwLock>, backend: Backend, } -impl> Registry { +impl> Registry { fn new(backend: Backend, factory: &F) -> Self { Self { identity: factory.spawn(0), @@ -442,12 +436,12 @@ impl> Registry { } #[must_use] -pub(crate) struct FutureId<'a, I: TypedId, T> { +pub(crate) struct FutureId<'a, I: id::TypedId, T> { id: I, data: &'a RwLock>, } -impl FutureId<'_, I, T> { +impl FutureId<'_, I, T> { #[cfg(feature = "trace")] pub fn id(&self) -> I { self.id @@ -457,9 +451,9 @@ impl FutureId<'_, I, T> { self.id } - pub fn assign<'a, A: Access>(self, value: T, _: &'a mut Token) -> Valid { + pub fn assign<'a, A: Access>(self, value: T, _: &'a mut Token) -> id::Valid { self.data.write().insert(self.id, value); - Valid(self.id) + id::Valid(self.id) } pub fn assign_error<'a, A: Access>(self, label: &str, _: &'a mut Token) -> I { @@ -468,7 +462,7 @@ impl FutureId<'_, I, T> { } } -impl> Registry { +impl> Registry { pub(crate) fn prepare( &self, id_in: >::Input, @@ -535,24 +529,23 @@ impl> Registry { - pub adapters: Registry, AdapterId, F>, - pub devices: Registry, DeviceId, F>, - pub swap_chains: Registry, SwapChainId, F>, - pub pipeline_layouts: Registry, PipelineLayoutId, F>, - pub shader_modules: Registry, ShaderModuleId, F>, - pub bind_group_layouts: Registry, BindGroupLayoutId, F>, - pub bind_groups: Registry, BindGroupId, F>, - pub command_buffers: Registry, CommandBufferId, F>, - pub render_bundles: Registry, - pub render_pipelines: Registry, RenderPipelineId, F>, - pub compute_pipelines: Registry, ComputePipelineId, F>, - pub query_sets: Registry, QuerySetId, F>, - pub buffers: Registry, BufferId, F>, - pub textures: Registry, TextureId, F>, - pub texture_views: Registry, TextureViewId, F>, - pub samplers: Registry, SamplerId, F>, + pub adapters: Registry, id::AdapterId, F>, + pub devices: Registry, id::DeviceId, F>, + pub swap_chains: Registry, id::SwapChainId, F>, + pub pipeline_layouts: Registry, id::PipelineLayoutId, F>, + pub shader_modules: Registry, id::ShaderModuleId, F>, + pub bind_group_layouts: Registry, id::BindGroupLayoutId, F>, + pub bind_groups: Registry, id::BindGroupId, F>, + pub command_buffers: Registry, id::CommandBufferId, F>, + pub render_bundles: Registry, + pub render_pipelines: Registry, id::RenderPipelineId, F>, + pub compute_pipelines: Registry, id::ComputePipelineId, F>, + pub query_sets: Registry, id::QuerySetId, F>, + pub buffers: Registry, id::BufferId, F>, + pub textures: Registry, id::TextureId, F>, + pub texture_views: Registry, id::TextureViewId, F>, + pub samplers: Registry, id::SamplerId, F>, } impl Hub { @@ -582,9 +575,9 @@ impl Hub { //TODO: instead of having a hacky `with_adapters` parameter, // we should have `clear_device(device_id)` that specifically destroys // everything related to a logical device. - fn clear(&self, surface_guard: &mut Storage, with_adapters: bool) { - use crate::resource::TextureViewInner; - use hal::Device as _; + fn clear(&self, surface_guard: &mut Storage, with_adapters: bool) { + use crate::resource::TextureViewSource; + use hal::{Device as _, Surface as _}; let mut devices = self.devices.data.write(); for element in devices.map.iter_mut() { @@ -606,14 +599,14 @@ impl Hub { let textures = self.textures.data.read(); for element in self.texture_views.data.write().map.drain(..) { if let Element::Occupied(texture_view, _) = element { - match texture_view.inner { - TextureViewInner::Native { raw, source_id } => { + match texture_view.source { + TextureViewSource::Native(source_id) => { let device = &devices[textures[source_id.value].device_id.value]; unsafe { - device.raw.destroy_image_view(raw); + device.raw.destroy_texture_view(texture_view.raw); } } - TextureViewInner::SwapChain { .. } => {} //TODO + TextureViewSource::SwapChain(_) => {} //TODO } } } @@ -633,15 +626,15 @@ impl Hub { for element in self.command_buffers.data.write().map.drain(..) { if let Element::Occupied(command_buffer, _) = element { let device = &devices[command_buffer.device_id.value]; - device - .cmd_allocator - .after_submit(command_buffer, &device.raw, 0); + for raw in command_buffer.raw { + 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.destroy_bind_group(bind_group); + device.raw.destroy_bind_group(bind_group.raw); } } @@ -657,7 +650,7 @@ impl Hub { if let Element::Occupied(bgl, _) = element { let device = &devices[bgl.device_id.value]; unsafe { - device.raw.destroy_descriptor_set_layout(bgl.raw); + device.raw.destroy_bind_group_layout(bgl.raw); } } } @@ -681,7 +674,7 @@ impl Hub { if let Element::Occupied(pipeline, _) = element { let device = &devices[pipeline.device_id.value]; unsafe { - device.raw.destroy_graphics_pipeline(pipeline.raw); + device.raw.destroy_render_pipeline(pipeline.raw); } } } @@ -689,16 +682,13 @@ impl Hub { for (index, element) in self.swap_chains.data.write().map.drain(..).enumerate() { if let Element::Occupied(swap_chain, epoch) = element { let device = &devices[swap_chain.device_id.value]; - unsafe { - device.raw.destroy_semaphore(swap_chain.semaphore); - } - let suf_id = TypedId::zip(index as Index, epoch, A::VARIANT); + let suf_id = id::TypedId::zip(index as Index, epoch, A::VARIANT); //TODO: hold the surface alive by the swapchain if surface_guard.contains(suf_id) { let surface = surface_guard.get_mut(suf_id).unwrap(); let suf = A::get_surface_mut(surface); unsafe { - suf.unconfigure_swapchain(&device.raw); + suf.unconfigure(&device.raw); } } } @@ -708,7 +698,7 @@ impl Hub { if let Element::Occupied(query_set, _) = element { let device = &devices[query_set.device_id.value]; unsafe { - device.raw.destroy_query_pool(query_set.raw); + device.raw.destroy_query_set(query_set.raw); } } } @@ -727,16 +717,18 @@ impl Hub { #[derive(Debug)] pub struct Hubs { /* -#[cfg(vulkan)] -vulkan: Hub, -#[cfg(metal)] -metal: Hub, -#[cfg(dx12)] -dx12: Hub, -#[cfg(dx11)] -dx11: Hub, -#[cfg(gl)] -gl: Hub,*/} + #[cfg(vulkan)] + vulkan: Hub, + #[cfg(metal)] + metal: Hub, + #[cfg(dx12)] + dx12: Hub, + #[cfg(dx11)] + dx11: Hub, + #[cfg(gl)] + gl: Hub,*/ + marker: PhantomData, +} impl Hubs { fn new(factory: &F) -> Self { @@ -753,6 +745,7 @@ impl Hubs { #[cfg(gl)] gl: Hub::new(factory), */ + marker: PhantomData, } } } @@ -760,7 +753,7 @@ impl Hubs { #[derive(Debug)] pub struct Global { pub instance: Instance, - pub surfaces: Registry, + pub surfaces: Registry, hubs: Hubs, } diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 722450c0fa..dd5125bb84 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -113,7 +113,6 @@ impl crate::hub::Resource for Surface { } } -#[derive(Debug)] pub struct Adapter { pub(crate) raw: hal::ExposedAdapter, life_guard: LifeGuard, @@ -141,11 +140,16 @@ impl Adapter { wgt::TextureFormat::Rgba8Unorm, ]; - let formats = A::get_surface(surface).supported_formats(&self.raw.adapter); + let caps = self + .raw + .adapter + .surface_capabilities(A::get_surface_mut(surface)) + .ok_or(GetSwapChainPreferredFormatError::UnsupportedQueueFamily)?; + preferred_formats .iter() .cloned() - .find(|preferred| formats.contains(preferred)) + .find(|preferred| caps.formats.contains(preferred)) .ok_or(GetSwapChainPreferredFormatError::NotFound) } @@ -204,7 +208,8 @@ impl Adapter { )); } - if !self.downlevel.is_webgpu_compliant() { + let caps = &self.raw.capabilities; + if !caps.downlevel.is_webgpu_compliant() { log::warn!("{}", DOWNLEVEL_WARNING_MESSAGE); } @@ -218,15 +223,14 @@ impl Adapter { } let gpu = unsafe { self.raw.adapter.open(desc.features) }.map_err(|err| match err { - hal::Error::DeviceLost => RequestDeviceError::DeviceLost, - hal::Error::OutOfMemory => RequestDeviceError::OutOfMemory, + hal::DeviceError::Lost => RequestDeviceError::DeviceLost, + hal::DeviceError::OutOfMemory => RequestDeviceError::OutOfMemory, })?; if let Some(_) = desc.label { //TODO } - let caps = &self.raw.capabilities; assert_eq!( 0, BIND_BUFFER_ALIGNMENT % caps.alignments.storage_buffer_offset, @@ -237,7 +241,7 @@ impl Adapter { BIND_BUFFER_ALIGNMENT % caps.alignments.uniform_buffer_offset, "Adapter uniform buffer offset alignment not compatible with WGPU" ); - if self.raw.limits < desc.limits { + if caps.limits < desc.limits { return Err(RequestDeviceError::LimitsExceeded); } @@ -375,11 +379,12 @@ impl Global { profiling::scope!("create_surface_metal", "Instance"); let surface = Surface { + /* metal: self.instance.metal.as_ref().map(|inst| { // we don't want to link to metal-rs for this #[allow(clippy::transmute_ptr_to_ref)] inst.create_surface_from_layer(unsafe { std::mem::transmute(layer) }) - }), + }),*/ }; let mut token = Token::root(); @@ -630,7 +635,7 @@ impl Global { let (adapter_guard, _) = hub.adapters.read(&mut token); adapter_guard .get(adapter_id) - .map(|adapter| adapter.features) + .map(|adapter| adapter.raw.features) .map_err(|_| InvalidAdapter) } @@ -643,7 +648,7 @@ impl Global { let (adapter_guard, _) = hub.adapters.read(&mut token); adapter_guard .get(adapter_id) - .map(|adapter| adapter.limits.clone()) + .map(|adapter| adapter.raw.capabilities.limits.clone()) .map_err(|_| InvalidAdapter) } @@ -656,7 +661,7 @@ impl Global { let (adapter_guard, _) = hub.adapters.read(&mut token); adapter_guard .get(adapter_id) - .map(|adapter| adapter.raw.downlevel) + .map(|adapter| adapter.raw.capabilities.downlevel) .map_err(|_| InvalidAdapter) } diff --git a/wgpu-core/src/lib.rs b/wgpu-core/src/lib.rs index 5f2c886c1b..b797a970c9 100644 --- a/wgpu-core/src/lib.rs +++ b/wgpu-core/src/lib.rs @@ -78,18 +78,15 @@ pub type RawString = *const c_char; pub type Label<'a> = Option>; trait LabelHelpers<'a> { - fn to_string_or_default(&'a self) -> String; + fn borrow_option(&'a self) -> Option<&'a str>; fn borrow_or_default(&'a self) -> &'a str; } impl<'a> LabelHelpers<'a> for Label<'a> { - fn borrow_or_default(&'a self) -> &'a str { - self.as_ref().map(|cow| cow.as_ref()).unwrap_or("") + fn borrow_option(&'a self) -> Option<&'a str> { + self.as_ref().map(|cow| cow.as_ref()) } - fn to_string_or_default(&'a self) -> String { - self.as_ref() - .map(|cow| cow.as_ref()) - .unwrap_or("") - .to_string() + fn borrow_or_default(&'a self) -> &'a str { + self.borrow_option().unwrap_or_default() } } diff --git a/wgpu-core/src/pipeline.rs b/wgpu-core/src/pipeline.rs index f7ddf6c736..f853ad0c14 100644 --- a/wgpu-core/src/pipeline.rs +++ b/wgpu-core/src/pipeline.rs @@ -15,7 +15,7 @@ use thiserror::Error; pub enum ShaderModuleSource<'a> { SpirV(Cow<'a, [u32]>), Wgsl(Cow<'a, str>), - Naga(&'a naga::Module), + Naga(naga::Module), } #[derive(Clone, Debug)] @@ -23,15 +23,13 @@ pub enum ShaderModuleSource<'a> { #[cfg_attr(feature = "replay", derive(serde::Deserialize))] pub struct ShaderModuleDescriptor<'a> { pub label: Label<'a>, - #[cfg_attr(any(feature = "replay", feature = "trace"), serde(default))] - pub flags: wgt::ShaderFlags, } #[derive(Debug)] pub struct ShaderModule { pub(crate) raw: A::ShaderModule, pub(crate) device_id: Stored, - pub(crate) interface: Option, + pub(crate) interface: validation::Interface, #[cfg(debug_assertions)] pub(crate) label: String, } @@ -53,7 +51,7 @@ impl Resource for ShaderModule { #[derive(Clone, Debug, Error)] pub enum CreateShaderModuleError { - #[error("Failed to parse WGSL")] + #[error("Failed to parse a shader")] Parsing, #[error("Failed to generate the backend-specific code")] Generation, diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index 9e84a7f20b..767cb890b1 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -242,15 +242,9 @@ pub struct TextureViewDescriptor<'a> { } #[derive(Debug)] -pub(crate) enum TextureViewInner { - Native { - raw: A::TextureView, - source_id: Stored, - }, - SwapChain { - raw: A::SurfaceTexture, - source_id: Stored, - }, +pub(crate) enum TextureViewSource { + Native(Stored), + SwapChain(Stored), } #[derive(Debug)] @@ -260,9 +254,16 @@ pub(crate) struct HalTextureViewDescriptor { pub range: wgt::ImageSubresourceRange, } +impl HalTextureViewDescriptor { + pub fn aspects(&self) -> hal::FormatAspect { + hal::FormatAspect::from(self.format) & hal::FormatAspect::from(self.range.aspect) + } +} + #[derive(Debug)] pub struct TextureView { - pub(crate) inner: TextureViewInner, + pub(crate) raw: A::TextureView, + pub(crate) source: TextureViewSource, //TODO: store device_id for quick access? pub(crate) desc: HalTextureViewDescriptor, pub(crate) format_features: wgt::TextureFormatFeatures, @@ -280,30 +281,35 @@ pub enum CreateTextureViewError { InvalidTexture, #[error("not enough memory left")] OutOfMemory, - #[error("Invalid texture view dimension `{view:?}` with texture of dimension `{image:?}`")] + #[error("Invalid texture view dimension `{view:?}` with texture of dimension `{texture:?}`")] InvalidTextureViewDimension { view: wgt::TextureViewDimension, - image: wgt::TextureDimension, + texture: wgt::TextureDimension, }, #[error("Invalid texture depth `{depth}` for texture view of dimension `Cubemap`. Cubemap views must use images of size 6.")] - InvalidCubemapTextureDepth { depth: u16 }, + InvalidCubemapTextureDepth { depth: u32 }, #[error("Invalid texture depth `{depth}` for texture view of dimension `CubemapArray`. Cubemap views must use images with sizes which are a multiple of 6.")] - InvalidCubemapArrayTextureDepth { depth: u16 }, + InvalidCubemapArrayTextureDepth { depth: u32 }, #[error( "TextureView mip level count + base mip level {requested} must be <= Texture mip level count {total}" )] - TooManyMipLevels { requested: u32, total: u8 }, + TooManyMipLevels { requested: u32, total: u32 }, #[error("TextureView array layer count + base array layer {requested} must be <= Texture depth/array layer count {total}")] - TooManyArrayLayers { requested: u32, total: u16 }, + TooManyArrayLayers { requested: u32, total: u32 }, #[error("Requested array layer count {requested} is not valid for the target view dimension {dim:?}")] InvalidArrayLayerCount { requested: u32, dim: wgt::TextureViewDimension, }, - #[error("Aspect {requested:?} is not in the source texture ({total:?})")] + #[error("Aspect {requested_aspect:?} is not in the source texture format {texture_format:?}")] InvalidAspect { - requested: hal::FormatAspect, - total: hal::FormatAspect, + texture_format: wgt::TextureFormat, + requested_aspect: wgt::TextureAspect, + }, + #[error("Unable to view texture {texture:?} as {view:?}")] + FormatReinterpretation { + texture: wgt::TextureFormat, + view: wgt::TextureFormat, }, } @@ -425,10 +431,7 @@ pub struct QuerySet { pub(crate) raw: A::QuerySet, pub(crate) device_id: Stored, pub(crate) life_guard: LifeGuard, - /// Amount of queries in the query set. pub(crate) desc: wgt::QuerySetDescriptor, - /// Amount of numbers in each query (i.e. a pipeline statistics query for two attributes will have this number be two) - pub(crate) elements: u32, } impl Resource for QuerySet { diff --git a/wgpu-core/src/swap_chain.rs b/wgpu-core/src/swap_chain.rs index 7ff69a04d4..eeb8f00faa 100644 --- a/wgpu-core/src/swap_chain.rs +++ b/wgpu-core/src/swap_chain.rs @@ -35,7 +35,6 @@ #[cfg(feature = "trace")] use crate::device::trace::Action; use crate::{ - conv, device::DeviceError, hub::{Global, GlobalIdentityHandlerFactory, HalApi, Input, Token}, id::{DeviceId, SwapChainId, TextureViewId, Valid}, @@ -44,23 +43,23 @@ use crate::{ LifeGuard, Stored, SubmissionIndex, }; -use hal::{Queue as _, Surface as _}; +use hal::{Device as _, Queue as _, Surface as _}; +use std::{borrow::Borrow, marker::PhantomData}; use thiserror::Error; -use wgt::{SwapChainDescriptor, SwapChainStatus}; +use wgt::SwapChainStatus as Status; -const FRAME_TIMEOUT_MS: u64 = 1000; +const FRAME_TIMEOUT_MS: u32 = 1000; pub const DESIRED_NUM_FRAMES: u32 = 3; #[derive(Debug)] pub struct SwapChain { pub(crate) life_guard: LifeGuard, pub(crate) device_id: Stored, - pub(crate) desc: SwapChainDescriptor, - pub(crate) num_frames: hal::window::SwapImageIndex, - pub(crate) semaphore: B::Semaphore, - pub(crate) acquired_view_id: Option>, + pub(crate) desc: wgt::SwapChainDescriptor, + pub(crate) num_frames: u32, + pub(crate) acquired_texture: Option<(Stored, A::SurfaceTexture)>, pub(crate) active_submission_index: SubmissionIndex, - pub(crate) framebuffer_attachment: hal::image::FramebufferAttachment, + pub(crate) marker: PhantomData, } impl crate::hub::Resource for SwapChain { @@ -99,37 +98,17 @@ pub enum CreateSwapChainError { UnsupportedQueueFamily, #[error("requested format {requested:?} is not in list of supported formats: {available:?}")] UnsupportedFormat { - requested: hal::format::Format, - available: Vec, + requested: wgt::TextureFormat, + available: Vec, }, -} - -pub(crate) fn swap_chain_descriptor_to_hal( - desc: &SwapChainDescriptor, - num_frames: u32, - private_features: PrivateFeatures, -) -> hal::window::SwapchainConfig { - let mut config = hal::window::SwapchainConfig::new( - desc.width, - desc.height, - conv::map_texture_format(desc.format, private_features), - num_frames, - ); - //TODO: check for supported - config.image_usage = conv::map_texture_usage(desc.usage, hal::FormatAspect::COLOR); - config.composite_alpha_mode = hal::window::CompositeAlphaMode::OPAQUE; - config.present_mode = match desc.present_mode { - wgt::PresentMode::Immediate => hal::window::PresentMode::IMMEDIATE, - wgt::PresentMode::Mailbox => hal::window::PresentMode::MAILBOX, - wgt::PresentMode::Fifo => hal::window::PresentMode::FIFO, - }; - config + #[error("requested usage is not supported")] + UnsupportedUsage, } #[repr(C)] #[derive(Debug)] pub struct SwapChainOutput { - pub status: SwapChainStatus, + pub status: Status, pub view_id: Option, } @@ -155,7 +134,6 @@ impl Global { .get_mut(swap_chain_id) .map_err(|_| SwapChainError::Invalid)?; - #[allow(unused_variables)] let device = &device_guard[sc.device_id.value]; #[cfg(feature = "trace")] if let Some(ref trace) = device.trace { @@ -165,51 +143,64 @@ impl Global { }); } - let suf = B::get_surface_mut(surface); - let (image, status) = match unsafe { suf.acquire_image(FRAME_TIMEOUT_MS * 1_000_000) } { - Ok((surface_image, None)) => (Some(surface_image), SwapChainStatus::Good), - Ok((surface_image, Some(_))) => (Some(surface_image), SwapChainStatus::Suboptimal), + let suf = A::get_surface_mut(surface); + let (texture, status) = match unsafe { suf.acquire_texture(FRAME_TIMEOUT_MS) } { + Ok(Some(ast)) => { + let status = if ast.suboptimal { + Status::Suboptimal + } else { + Status::Good + }; + (Some(ast.texture), status) + } + Ok(None) => (None, Status::Timeout), Err(err) => ( None, match err { - hal::window::AcquireError::OutOfMemory(_) => { - return Err(DeviceError::OutOfMemory.into()) - } - hal::window::AcquireError::NotReady { .. } => SwapChainStatus::Timeout, - hal::window::AcquireError::OutOfDate(_) => SwapChainStatus::Outdated, - hal::window::AcquireError::SurfaceLost(_) => SwapChainStatus::Lost, - hal::window::AcquireError::DeviceLost(_) => { - return Err(DeviceError::Lost.into()) + hal::SurfaceError::Lost => Status::Lost, + hal::SurfaceError::Device(err) => { + return Err(DeviceError::from(err).into()); } + hal::SurfaceError::Outdated => Status::Outdated, }, ), }; - let view_id = match image { - Some(image) => { + let hal_desc = hal::TextureViewDescriptor { + label: Some("_Frame"), + format: sc.desc.format, + dimension: wgt::TextureViewDimension::D2, + range: wgt::ImageSubresourceRange::default(), + }; + + 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 view = resource::TextureView { - inner: resource::TextureViewInner::SwapChain { - image, - source_id: Stored { - value: Valid(swap_chain_id), - ref_count: sc.life_guard.add_ref(), - }, + raw, + source: resource::TextureViewSource::SwapChain(Stored { + value: Valid(swap_chain_id), + ref_count: sc.life_guard.add_ref(), + }), + desc: resource::HalTextureViewDescriptor { + format: sc.desc.format, + dimension: wgt::TextureViewDimension::D2, + range: wgt::ImageSubresourceRange::default(), }, - aspects: hal::FormatAspect::COLOR, - format: sc.desc.format, format_features: wgt::TextureFormatFeatures { allowed_usages: wgt::TextureUsage::RENDER_ATTACHMENT, flags: wgt::TextureFormatFeatureFlags::empty(), filterable: false, }, - dimension: wgt::TextureViewDimension::D2, extent: wgt::Extent3d { width: sc.desc.width, height: sc.desc.height, depth_or_array_layers: 1, }, samples: 1, - framebuffer_attachment: sc.framebuffer_attachment.clone(), sampled_internal_use: hal::TextureUse::empty(), selector: TextureSelector { layers: 0..1, @@ -221,14 +212,17 @@ impl Global { let ref_count = view.life_guard.add_ref(); let id = fid.assign(view, &mut token); - if sc.acquired_view_id.is_some() { + if sc.acquired_texture.is_some() { return Err(SwapChainError::AlreadyAcquired); } - sc.acquired_view_id = Some(Stored { - value: id, - ref_count, - }); + sc.acquired_texture = Some(( + Stored { + value: id, + ref_count, + }, + suf_texture, + )); Some(id.0) } @@ -241,7 +235,7 @@ impl Global { pub fn swap_chain_present( &self, swap_chain_id: SwapChainId, - ) -> Result { + ) -> Result { profiling::scope!("present", "SwapChain"); let hub = A::hub(self); @@ -263,44 +257,33 @@ impl Global { trace.lock().add(Action::PresentSwapChain(swap_chain_id)); } - let view = { - let view_id = sc - .acquired_view_id + let suf_texture = { + let (view_id, suf_texture) = sc + .acquired_texture .take() .ok_or(SwapChainError::AlreadyAcquired)?; let (view_maybe, _) = hub.texture_views.unregister(view_id.value.0, &mut token); - view_maybe.ok_or(SwapChainError::Invalid)? - }; - if view.life_guard.ref_count.unwrap().load() != 1 { - return Err(SwapChainError::StillReferenced); - } - let image = match view.inner { - resource::TextureViewInner::Native { .. } => unreachable!(), - resource::TextureViewInner::SwapChain { image, .. } => image, + let view = view_maybe.ok_or(SwapChainError::Invalid)?; + if view.life_guard.ref_count.unwrap().load() != 1 { + return Err(SwapChainError::StillReferenced); + } + suf_texture }; - let sem = if sc.active_submission_index > device.last_completed_submission_index() { - Some(&mut sc.semaphore) - } else { - None + let result = unsafe { + device + .queue + .present(A::get_surface_mut(surface), suf_texture) }; - let queue = &mut device.queue_group.queues[0]; - let result = unsafe { queue.present(B::get_surface_mut(surface), image, sem) }; log::debug!("Presented. End of Frame"); match result { - Ok(None) => Ok(SwapChainStatus::Good), - Ok(Some(_)) => Ok(SwapChainStatus::Suboptimal), + Ok(()) => Ok(Status::Good), Err(err) => match err { - hal::window::PresentError::OutOfMemory(_) => { - Err(SwapChainError::Device(DeviceError::OutOfMemory)) - } - hal::window::PresentError::OutOfDate(_) => Ok(SwapChainStatus::Outdated), - hal::window::PresentError::SurfaceLost(_) => Ok(SwapChainStatus::Lost), - hal::window::PresentError::DeviceLost(_) => { - Err(SwapChainError::Device(DeviceError::Lost)) - } + hal::SurfaceError::Lost => Ok(Status::Lost), + hal::SurfaceError::Device(err) => Err(SwapChainError::from(DeviceError::from(err))), + hal::SurfaceError::Outdated => Ok(Status::Outdated), }, } } diff --git a/wgpu-core/src/track/mod.rs b/wgpu-core/src/track/mod.rs index b07ce3866a..500e036602 100644 --- a/wgpu-core/src/track/mod.rs +++ b/wgpu-core/src/track/mod.rs @@ -12,7 +12,9 @@ use crate::{ resource, Epoch, FastHashMap, Index, RefCount, }; -use std::{collections::hash_map::Entry, fmt, marker::PhantomData, ops, vec::Drain}; +use std::{ + collections::hash_map::Entry, fmt, marker::PhantomData, num::NonZeroU32, ops, vec::Drain, +}; use thiserror::Error; pub(crate) use buffer::BufferState; @@ -131,7 +133,7 @@ impl PendingTransition { buf: &'a resource::Buffer, ) -> hal::BufferBarrier<'a, A> { log::trace!("\tbuffer -> {:?}", self); - let &(ref buffer, _) = buf.raw.as_ref().expect("Buffer is destroyed"); + let buffer = buf.raw.as_ref().expect("Buffer is destroyed"); hal::BufferBarrier { buffer, usage: self.usage, @@ -155,10 +157,20 @@ impl PendingTransition { tex: &'a resource::Texture, ) -> hal::TextureBarrier<'a, A> { log::trace!("\ttexture -> {:?}", self); - let &(ref texture, _) = tex.raw.as_ref().expect("Texture is destroyed"); + let texture = tex.raw.as_ref().expect("Texture is destroyed"); hal::TextureBarrier { texture, - subresource: self.selector, + range: wgt::ImageSubresourceRange { + aspect: wgt::TextureAspect::All, + base_mip_level: self.selector.levels.start, + mip_level_count: NonZeroU32::new( + self.selector.levels.end - self.selector.levels.start, + ), + base_array_layer: self.selector.layers.start, + array_layer_count: NonZeroU32::new( + self.selector.layers.end - self.selector.layers.start, + ), + }, usage: self.usage, } } @@ -168,8 +180,8 @@ impl From> for UsageConflict { fn from(e: PendingTransition) -> Self { Self::Texture { id: e.id.0, - mip_levels: e.selector.levels.start as u32..e.selector.levels.end as u32, - array_layers: e.selector.layers.start as u32..e.selector.layers.end as u32, + mip_levels: e.selector.levels.start..e.selector.levels.end, + array_layers: e.selector.layers.start..e.selector.layers.end, combined_use: e.usage.end, } } diff --git a/wgpu-core/src/track/texture.rs b/wgpu-core/src/track/texture.rs index 174a15d0ba..2f01c72a1a 100644 --- a/wgpu-core/src/track/texture.rs +++ b/wgpu-core/src/track/texture.rs @@ -3,28 +3,26 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use super::{range::RangedStates, PendingTransition, ResourceState, Unit}; -use crate::{ - device::MAX_MIP_LEVELS, - id::{TextureId, Valid}, -}; +use crate::id::{TextureId, Valid}; use hal::TextureUse; use arrayvec::ArrayVec; use std::{iter, ops::Range}; -type PlaneStates = RangedStates>; +type PlaneStates = RangedStates>; #[derive(Clone, Debug, PartialEq, Eq)] pub struct TextureSelector { + //TODO: rename to `mip_levels` and `array_layers` for consistency //pub aspects: hal::FormatAspect, - pub levels: Range, - pub layers: Range, + pub levels: Range, + pub layers: Range, } #[derive(Clone, Debug, Default, PartialEq)] pub(crate) struct TextureState { - mips: ArrayVec<[PlaneStates; MAX_MIP_LEVELS as usize]>, + mips: ArrayVec<[PlaneStates; hal::MAX_MIP_LEVELS as usize]>, /// True if we have the information about all the subresources here full: bool, } @@ -43,7 +41,7 @@ impl PendingTransition { } impl TextureState { - pub fn new(mip_level_count: hal::MipLevel, array_layer_count: hal::ArrayLayer) -> Self { + pub fn new(mip_level_count: u32, array_layer_count: u32) -> Self { Self { mips: iter::repeat_with(|| { PlaneStates::from_range(0..array_layer_count, Unit::new(TextureUse::UNINITIALIZED)) @@ -103,7 +101,7 @@ impl ResourceState for TextureState { .iter_mut() .enumerate() { - let level = selector.levels.start + mip_id as hal::MipLevel; + let level = selector.levels.start + mip_id as u32; let layers = mip.isolate(&selector.layers, Unit::new(usage)); for &mut (ref range, ref mut unit) in layers { if unit.last == usage && TextureUse::ORDERED.contains(usage) { @@ -153,7 +151,7 @@ impl ResourceState for TextureState { .iter_mut() .enumerate() { - let level = selector.levels.start + mip_id as hal::MipLevel; + let level = selector.levels.start + mip_id as u32; let layers = mip.isolate(&selector.layers, Unit::new(usage)); for &mut (ref range, ref mut unit) in layers { match unit.first { @@ -192,7 +190,7 @@ impl ResourceState for TextureState { } for (mip_id, (mip_self, mip_other)) in self.mips.iter_mut().zip(&other.mips).enumerate() { - let level = mip_id as hal::MipLevel; + let level = mip_id as u32; temp.extend(mip_self.merge(mip_other, 0)); mip_self.clear(); @@ -374,7 +372,7 @@ mod test { 2..3, Unit { first: Some(TextureUse::COPY_SRC), - last: TextureUse::ATTACHMENT_WRITE, + last: TextureUse::COLOR_TARGET, }, ), ]); @@ -415,7 +413,7 @@ mod test { ts1.mips[0].query(&(2..3), |&v| v), Some(Ok(Unit { first: Some(TextureUse::SAMPLED), - last: TextureUse::ATTACHMENT_WRITE, + last: TextureUse::COLOR_TARGET, })), "wrong final layer 2 state" ); @@ -424,7 +422,7 @@ mod test { ts2.mips[0] = PlaneStates::from_slice(&[( 2..3, Unit { - first: Some(TextureUse::ATTACHMENT_WRITE), + first: Some(TextureUse::COLOR_TARGET), last: TextureUse::COPY_SRC, }, )]); diff --git a/wgpu-hal/src/empty.rs b/wgpu-hal/src/empty.rs index 8e7446539b..3abe0c0872 100644 --- a/wgpu-hal/src/empty.rs +++ b/wgpu-hal/src/empty.rs @@ -1,5 +1,7 @@ #![allow(unused_variables)] +use std::ops::Range; + #[derive(Clone)] pub struct Api; pub struct Context; @@ -17,15 +19,14 @@ impl crate::Api for Api { type Device = Context; type CommandBuffer = Encoder; - type RenderPass = Encoder; - type ComputePass = Encoder; type Buffer = Resource; - type QuerySet = Resource; type Texture = Resource; type SurfaceTexture = Resource; type TextureView = Resource; type Sampler = Resource; + type QuerySet = Resource; + type Fence = Resource; type BindGroupLayout = Resource; type BindGroup = Resource; @@ -55,9 +56,10 @@ impl crate::Surface for Context { unsafe fn acquire_texture( &mut self, timeout_ms: u32, - ) -> Result<(Resource, Option), crate::SurfaceError> { - Ok((Resource, None)) + ) -> Result>, crate::SurfaceError> { + Ok(None) } + unsafe fn discard_texture(&mut self, texture: Resource) {} } impl crate::Adapter for Context { @@ -77,7 +79,19 @@ impl crate::Adapter for Context { } impl crate::Queue for Context { - unsafe fn submit(&mut self, command_buffers: I) {} + unsafe fn submit( + &mut self, + command_buffers: I, + signal_fence: Option<(&Resource, crate::FenceValue)>, + ) { + } + unsafe fn present( + &mut self, + surface: &mut Context, + texture: Resource, + ) -> Result<(), crate::SurfaceError> { + Ok(()) + } } impl crate::Device for Context { @@ -92,7 +106,9 @@ impl crate::Device for Context { ) -> DeviceResult> { Err(crate::DeviceError::Lost) } - unsafe fn unmap_buffer(&self, buffer: &Resource) {} + unsafe fn unmap_buffer(&self, buffer: &Resource) -> DeviceResult<()> { + Ok(()) + } unsafe fn flush_mapped_ranges(&self, buffer: &Resource, ranges: I) {} unsafe fn invalidate_mapped_ranges(&self, buffer: &Resource, ranges: I) {} @@ -165,11 +181,35 @@ impl crate::Device for Context { Ok(Resource) } unsafe fn destroy_compute_pipeline(&self, pipeline: Resource) {} + + unsafe fn create_query_set(&self, desc: &wgt::QuerySetDescriptor) -> DeviceResult { + Ok(Resource) + } + unsafe fn destroy_query_set(&self, set: Resource) {} + unsafe fn create_fence(&self) -> DeviceResult { + Ok(Resource) + } + unsafe fn destroy_fence(&self, fence: Resource) {} + unsafe fn get_fence_value(&self, fence: &Resource) -> DeviceResult { + Ok(0) + } + unsafe fn wait( + &self, + fence: &Resource, + value: crate::FenceValue, + timeout_ms: u32, + ) -> DeviceResult { + Ok(true) + } + + unsafe fn start_capture(&self) -> bool { + false + } + unsafe fn stop_capture(&self) {} } impl crate::CommandBuffer for Encoder { - unsafe fn begin(&mut self) {} - unsafe fn end(&mut self) {} + unsafe fn finish(&mut self) {} unsafe fn transition_buffers<'a, T>(&mut self, barriers: T) where @@ -213,20 +253,46 @@ impl crate::CommandBuffer for Encoder { ) { } - unsafe fn begin_render_pass(&mut self) -> Encoder { - Encoder + unsafe fn begin_query(&mut self, set: &Resource, index: u32) {} + unsafe fn end_query(&mut self, set: &Resource, index: u32) {} + unsafe fn write_timestamp(&mut self, set: &Resource, index: u32) {} + unsafe fn reset_queries(&mut self, set: &Resource, range: Range) {} + unsafe fn copy_query_results( + &mut self, + set: &Resource, + range: Range, + buffer: &Resource, + offset: wgt::BufferAddress, + ) { + } + + 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, + layout: &Resource, + index: u32, + group: &Resource, + dynamic_offsets: &[u32], + ) { } - unsafe fn end_render_pass(&mut self, pass: Encoder) {} - unsafe fn begin_compute_pass(&mut self) -> Encoder { - Encoder + unsafe fn set_push_constants( + &mut self, + layout: &Resource, + stages: wgt::ShaderStage, + offset: u32, + data: &[u32], + ) { } - unsafe fn end_compute_pass(&mut self, pass: Encoder) {} -} -impl crate::RenderPass for Encoder { - unsafe fn set_pipeline(&mut self, pipeline: &Resource) {} + unsafe fn insert_debug_marker(&mut self, label: &str) {} + unsafe fn begin_debug_marker(&mut self, group_label: &str) {} + unsafe fn end_debug_marker(&mut self) {} - unsafe fn set_bind_group(&mut self, layout: &Resource, index: u32, group: &Resource) {} + unsafe fn set_render_pipeline(&mut self, pipeline: &Resource) {} unsafe fn set_index_buffer<'a>( &mut self, @@ -236,10 +302,10 @@ impl crate::RenderPass for Encoder { } unsafe fn set_vertex_buffer<'a>(&mut self, index: u32, binding: crate::BufferBinding<'a, Api>) { } - unsafe fn set_viewport(&mut self, rect: &crate::Rect, depth_range: std::ops::Range) {} - unsafe fn set_scissor_rect(&mut self, rect: &crate::Rect) {} + unsafe fn set_viewport(&mut self, rect: &crate::Rect, depth_range: Range) {} + unsafe fn set_scissor_rect(&mut self, rect: &crate::Rect) {} unsafe fn set_stencil_reference(&mut self, value: u32) {} - unsafe fn set_blend_constants(&mut self, color: wgt::Color) {} + unsafe fn set_blend_constants(&mut self, color: &wgt::Color) {} unsafe fn draw( &mut self, @@ -272,12 +338,26 @@ impl crate::RenderPass for Encoder { draw_count: u32, ) { } -} - -impl crate::ComputePass for Encoder { - unsafe fn set_pipeline(&mut self, pipeline: &Resource) {} + unsafe fn draw_indirect_count( + &mut self, + buffer: &Resource, + offset: wgt::BufferAddress, + count_buffer: &Resource, + count_offset: wgt::BufferAddress, + max_count: u32, + ) { + } + unsafe fn draw_indexed_indirect_count( + &mut self, + buffer: &Resource, + offset: wgt::BufferAddress, + count_buffer: &Resource, + count_offset: wgt::BufferAddress, + max_count: u32, + ) { + } - unsafe fn set_bind_group(&mut self, layout: &Resource, index: u32, group: &Resource) {} + unsafe fn set_compute_pipeline(&mut self, pipeline: &Resource) {} unsafe fn dispatch(&mut self, count: [u32; 3]) {} unsafe fn dispatch_indirect(&mut self, buffer: &Resource, offset: wgt::BufferAddress) {} diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 4afce441c9..74e0d61b5e 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -11,6 +11,8 @@ * - Mapping is persistent, with explicit synchronization. * - Resource transitions are explicit. * - All layouts are explicit. Binding model has compatibility. + * + * General design direction: follow 2/3 major target APIs. */ #![allow( @@ -50,11 +52,13 @@ use thiserror::Error; pub const MAX_ANISOTROPY: u8 = 16; pub const MAX_BIND_GROUPS: usize = 8; +pub const MAX_VERTEX_BUFFERS: usize = 16; +pub const MAX_COLOR_TARGETS: usize = 4; +pub const MAX_MIP_LEVELS: u32 = 16; pub type Label<'a> = Option<&'a str>; pub type MemoryRange = Range; -pub type MipLevel = u8; -pub type ArrayLayer = u16; +pub type FenceValue = u64; #[derive(Clone, Debug, PartialEq, Error)] pub enum DeviceError { @@ -84,35 +88,29 @@ pub enum PipelineError { pub enum SurfaceError { #[error("surface is lost")] Lost, + #[error("surface is outdated, needs to be re-created")] + Outdated, #[error(transparent)] Device(#[from] DeviceError), #[error("other reason: {0}")] Other(&'static str), } -/// Marker value returned if the presentation configuration no longer matches -/// the surface properties exactly, but can still be used to present -/// to the surface successfully. -#[derive(Debug)] -pub struct Suboptimal; - pub trait Api: Clone + Sized { type Instance: Instance; type Surface: Surface; type Adapter: Adapter; type Device: Device; type Queue: Queue; - type CommandBuffer: CommandBuffer; - type RenderPass: RenderPass; - type ComputePass: ComputePass; type Buffer: fmt::Debug + Send + Sync + 'static; - type QuerySet: fmt::Debug + Send + Sync; type Texture: fmt::Debug + Send + Sync + 'static; type SurfaceTexture: fmt::Debug + Send + Sync + Borrow; type TextureView: fmt::Debug + Send + Sync; type Sampler: fmt::Debug + Send + Sync; + type QuerySet: fmt::Debug + Send + Sync; + type Fence: fmt::Debug + Send + Sync; type BindGroupLayout; type BindGroup: fmt::Debug + Send + Sync; @@ -135,10 +133,12 @@ pub trait Surface { unsafe fn unconfigure(&mut self, device: &A::Device); + /// Returns `None` on timing out. unsafe fn acquire_texture( &mut self, timeout_ms: u32, - ) -> Result<(A::SurfaceTexture, Option), SurfaceError>; + ) -> Result>, SurfaceError>; + unsafe fn discard_texture(&mut self, texture: A::SurfaceTexture); } pub trait Adapter { @@ -168,7 +168,7 @@ pub trait Device { buffer: &A::Buffer, range: MemoryRange, ) -> Result, DeviceError>; - unsafe fn unmap_buffer(&self, buffer: &A::Buffer); + unsafe fn unmap_buffer(&self, buffer: &A::Buffer) -> Result<(), DeviceError>; unsafe fn flush_mapped_ranges>( &self, buffer: &A::Buffer, @@ -233,17 +233,43 @@ pub trait Device { desc: &ComputePipelineDescriptor, ) -> Result; unsafe fn destroy_compute_pipeline(&self, pipeline: A::ComputePipeline); + + unsafe fn create_query_set( + &self, + desc: &wgt::QuerySetDescriptor, + ) -> Result; + unsafe fn destroy_query_set(&self, set: A::QuerySet); + unsafe fn create_fence(&self) -> Result; + unsafe fn destroy_fence(&self, fence: A::Fence); + unsafe fn get_fence_value(&self, fence: &A::Fence) -> Result; + unsafe fn wait( + &self, + fence: &A::Fence, + value: FenceValue, + timeout_ms: u32, + ) -> Result; + + unsafe fn start_capture(&self) -> bool; + unsafe fn stop_capture(&self); } pub trait Queue { - unsafe fn submit>(&mut self, command_buffers: I); + unsafe fn submit>( + &mut self, + command_buffers: I, + signal_fence: Option<(&A::Fence, FenceValue)>, + ); + unsafe fn present( + &mut self, + surface: &mut A::Surface, + texture: A::SurfaceTexture, + ) -> Result<(), SurfaceError>; } pub trait SwapChain {} pub trait CommandBuffer { - unsafe fn begin(&mut self); - unsafe fn end(&mut self); + unsafe fn finish(&mut self); unsafe fn transition_buffers<'a, T>(&mut self, barriers: T) where @@ -253,6 +279,8 @@ pub trait CommandBuffer { where T: Iterator>; + // copy operations + unsafe fn fill_buffer(&mut self, buffer: &A::Buffer, range: MemoryRange, value: u8); unsafe fn copy_buffer_to_buffer(&mut self, src: &A::Buffer, dst: &A::Buffer, regions: T) @@ -283,14 +311,7 @@ pub trait CommandBuffer { ) where T: Iterator; - unsafe fn begin_render_pass(&mut self) -> A::RenderPass; - unsafe fn end_render_pass(&mut self, pass: A::RenderPass); - unsafe fn begin_compute_pass(&mut self) -> A::ComputePass; - unsafe fn end_compute_pass(&mut self, pass: A::ComputePass); -} - -pub trait RenderPass { - unsafe fn set_pipeline(&mut self, pipeline: &A::RenderPipeline); + // pass common /// Sets the bind group at `index` to `group`, assuming the layout /// of all the preceeding groups to be taken from `layout`. @@ -299,18 +320,53 @@ pub trait RenderPass { layout: &A::PipelineLayout, index: u32, group: &A::BindGroup, + dynamic_offsets: &[u32], + ); + + unsafe fn set_push_constants( + &mut self, + layout: &A::PipelineLayout, + stages: wgt::ShaderStage, + offset: u32, + data: &[u32], + ); + + unsafe fn insert_debug_marker(&mut self, label: &str); + unsafe fn begin_debug_marker(&mut self, group_label: &str); + unsafe fn end_debug_marker(&mut self); + + // queries + + unsafe fn begin_query(&mut self, set: &A::QuerySet, index: u32); + unsafe fn end_query(&mut self, set: &A::QuerySet, index: u32); + unsafe fn write_timestamp(&mut self, set: &A::QuerySet, index: u32); + unsafe fn reset_queries(&mut self, set: &A::QuerySet, range: Range); + unsafe fn copy_query_results( + &mut self, + set: &A::QuerySet, + range: Range, + buffer: &A::Buffer, + offset: wgt::BufferAddress, ); + // render passes + + // Begins a render pass, clears all active bindings. + unsafe fn begin_render_pass(&mut self, desc: &RenderPassDescriptor); + unsafe fn end_render_pass(&mut self); + + unsafe fn set_render_pipeline(&mut self, pipeline: &A::RenderPipeline); + unsafe fn set_index_buffer<'a>( &mut self, binding: BufferBinding<'a, A>, format: wgt::IndexFormat, ); unsafe fn set_vertex_buffer<'a>(&mut self, index: u32, binding: BufferBinding<'a, A>); - unsafe fn set_viewport(&mut self, rect: &Rect, depth_range: Range); - unsafe fn set_scissor_rect(&mut self, rect: &Rect); + unsafe fn set_viewport(&mut self, rect: &Rect, depth_range: Range); + unsafe fn set_scissor_rect(&mut self, rect: &Rect); unsafe fn set_stencil_reference(&mut self, value: u32); - unsafe fn set_blend_constants(&mut self, color: wgt::Color); + unsafe fn set_blend_constants(&mut self, color: &wgt::Color); unsafe fn draw( &mut self, @@ -339,19 +395,30 @@ pub trait RenderPass { offset: wgt::BufferAddress, draw_count: u32, ); -} - -pub trait ComputePass { - unsafe fn set_pipeline(&mut self, pipeline: &A::ComputePipeline); - - /// Sets the bind group at `index` to `group`, assuming the layout - /// of all the preceeding groups to be taken from `layout`. - unsafe fn set_bind_group( + unsafe fn draw_indirect_count( &mut self, - layout: &A::PipelineLayout, - index: u32, - group: &A::BindGroup, + buffer: &A::Buffer, + offset: wgt::BufferAddress, + count_buffer: &A::Buffer, + count_offset: wgt::BufferAddress, + max_count: u32, ); + unsafe fn draw_indexed_indirect_count( + &mut self, + buffer: &A::Buffer, + offset: wgt::BufferAddress, + count_buffer: &A::Buffer, + count_offset: wgt::BufferAddress, + max_count: u32, + ); + + // compute passes + + // Begins a compute pass, clears all active bindings. + unsafe fn begin_compute_pass(&mut self); + unsafe fn end_compute_pass(&mut self); + + unsafe fn set_compute_pipeline(&mut self, pipeline: &A::ComputePipeline); unsafe fn dispatch(&mut self, count: [u32; 3]); unsafe fn dispatch_indirect(&mut self, buffer: &A::Buffer, offset: wgt::BufferAddress); @@ -423,6 +490,13 @@ bitflags!( } ); +bitflags!( + pub struct AttachmentOp: u8 { + const LOAD = 1; + const STORE = 2; + } +); + bitflags::bitflags! { /// Similar to `wgt::BufferUsage` but for internal use. pub struct BufferUse: u32 { @@ -472,7 +546,7 @@ bitflags::bitflags! { } } -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct Alignments { /// The alignment of the start of the buffer used as a GPU copy source. pub buffer_copy_offset: wgt::BufferSize, @@ -483,7 +557,7 @@ pub struct Alignments { pub uniform_buffer_offset: wgt::BufferSize, } -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct Capabilities { pub limits: wgt::Limits, pub alignments: Alignments, @@ -505,7 +579,7 @@ pub struct SurfaceCapabilities { /// List of supported texture formats. /// /// Must be at least one. - pub texture_formats: Vec, + pub formats: Vec, /// Range for the swap chain sizes. /// @@ -524,12 +598,12 @@ pub struct SurfaceCapabilities { /// Supported texture usage flags. /// /// Must have at least `TextureUse::COLOR_TARGET` - pub texture_uses: TextureUse, + pub usage: TextureUse, /// List of supported V-sync modes. /// /// Must be at least one. - pub vsync_modes: Vec, + pub present_modes: Vec, /// List of supported alpha composition modes. /// @@ -537,6 +611,15 @@ pub struct SurfaceCapabilities { pub composite_alpha_modes: Vec, } +#[derive(Debug)] +pub struct AcquiredSurfaceTexture { + pub texture: A::SurfaceTexture, + /// The presentation configuration no longer matches + /// the surface properties exactly, but can still be used to present + /// to the surface successfully. + pub suboptimal: bool, +} + #[derive(Debug)] pub struct OpenDevice { pub device: A::Device, @@ -721,24 +804,11 @@ pub struct RenderPipelineDescriptor<'a, A: Api> { /// The multi-sampling properties of the pipeline. pub multisample: wgt::MultisampleState, /// The fragment stage for this pipeline. - pub fragment_stage: ProgrammableStage<'a, A>, + pub fragment_stage: Option>, /// The effect of draw calls on the color aspect of the output target. pub color_targets: Cow<'a, [wgt::ColorTargetState]>, } -/// Specifies the mode regulating how a surface presents frames. -#[derive(Debug, Clone)] -pub enum VsyncMode { - /// Don't ever wait for v-sync. - Immediate, - /// Wait for v-sync, overwrite the last rendered frame. - Mailbox, - /// Present frames in the same order they are rendered. - Fifo, - /// Don't wait for the next v-sync if we just missed it. - Relaxed, -} - /// Specifies how the alpha channel of the textures should be handled during (martin mouv i step) /// compositing. #[derive(Debug, Clone)] @@ -766,7 +836,7 @@ pub struct SurfaceConfiguration { /// `SurfaceCapabilities::swap_chain_size` range. pub swap_chain_size: u32, /// Vertical synchronization mode. - pub vsync_mode: VsyncMode, + pub present_mode: wgt::PresentMode, /// Alpha composition mode. pub composite_alpha_mode: CompositeAlphaMode, /// Format of the surface textures. @@ -779,11 +849,11 @@ pub struct SurfaceConfiguration { } #[derive(Debug, Clone)] -pub struct Rect { - pub x: f32, - pub y: f32, - pub w: f32, - pub h: f32, +pub struct Rect { + pub x: T, + pub y: T, + pub w: T, + pub h: T, } #[derive(Debug, Clone)] @@ -795,7 +865,7 @@ pub struct BufferBarrier<'a, A: Api> { #[derive(Debug, Clone)] pub struct TextureBarrier<'a, A: Api> { pub texture: &'a A::Texture, - pub subresource: wgt::ImageSubresourceRange, + pub range: wgt::ImageSubresourceRange, pub usage: Range, } @@ -806,23 +876,85 @@ pub struct BufferCopy { pub size: wgt::BufferSize, } +#[derive(Clone, Debug)] +pub struct TextureCopyBase { + pub origin: wgt::Origin3d, + pub mip_level: u32, + pub aspect: FormatAspect, +} + #[derive(Clone, Debug)] pub struct TextureCopy { - pub src_subresource: wgt::ImageSubresourceRange, - pub src_origin: wgt::Origin3d, - pub dst_subresource: wgt::ImageSubresourceRange, - pub dst_origin: wgt::Origin3d, + pub src_base: TextureCopyBase, + pub dst_base: TextureCopyBase, pub size: wgt::Extent3d, } #[derive(Clone, Debug)] pub struct BufferTextureCopy { pub buffer_layout: wgt::ImageDataLayout, - pub texture_mip_level: u32, - pub texture_origin: wgt::Origin3d, + pub texture_base: TextureCopyBase, pub size: wgt::Extent3d, } +#[derive(Debug)] +pub struct Attachment<'a, A: Api> { + pub view: &'a A::TextureView, + /// Contains either a single mutating usage as a target, or a valid combination + /// of read-only usages. + pub usage: TextureUse, + /// Defines the boundary usages for the attachment. + /// It is expected to begin a render pass with `boundary_usage.start` usage, + /// and will end it with `boundary_usage.end` usage. + pub boundary_usage: Range, +} + +// Rust gets confused about the impl requirements for `A` +impl Clone for Attachment<'_, A> { + fn clone(&self) -> Self { + Self { + view: self.view, + usage: self.usage, + boundary_usage: self.boundary_usage.clone(), + } + } +} + +#[derive(Debug)] +pub struct ColorAttachment<'a, A: Api> { + pub target: Attachment<'a, A>, + pub resolve_target: Option>, + pub ops: AttachmentOp, + pub clear_value: wgt::Color, +} + +// Rust gets confused about the impl requirements for `A` +impl Clone for ColorAttachment<'_, A> { + fn clone(&self) -> Self { + Self { + target: self.target.clone(), + resolve_target: self.resolve_target.clone(), + ops: self.ops, + clear_value: self.clear_value, + } + } +} + +#[derive(Clone, Debug)] +pub struct DepthStencilAttachment<'a, A: Api> { + pub target: Attachment<'a, A>, + pub depth_ops: AttachmentOp, + pub stencil_ops: AttachmentOp, + pub clear_value: (f32, u32), +} + +#[derive(Clone, Debug)] +pub struct RenderPassDescriptor<'a, A: Api> { + pub label: Label<'a>, + pub color_attachments: Cow<'a, [ColorAttachment<'a, A>]>, + pub depth_stencil_attachment: Option>, +} + #[test] fn test_default_limits() { let limits = wgt::Limits::default(); diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 9ad08ae557..3642b24c2f 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -796,26 +796,6 @@ bitflags::bitflags! { } } -bitflags::bitflags! { - /// Flags controlling the shader processing. - /// - /// Note: These flags are internal tweaks, they don't affect the API. - #[repr(transparent)] - #[derive(Default)] - #[cfg_attr(feature = "trace", derive(serde::Serialize))] - #[cfg_attr(feature = "replay", derive(serde::Deserialize))] - pub struct ShaderFlags: u32 { - /// If enabled, `wgpu` will parse the shader with `Naga` - /// and validate it both internally and with regards to - /// the given pipeline interface. - const VALIDATION = 1; - /// If enabled, `wgpu` will attempt to operate on `Naga`'s internal - /// representation of the shader module for both validation and translation - /// into the backend shader language, on backends where `gfx-hal` supports this. - const EXPERIMENTAL_TRANSLATION = 2; - } -} - /// Dimensions of a particular texture view. #[repr(C)] #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] @@ -1061,6 +1041,16 @@ impl Default for PrimitiveTopology { } } +impl PrimitiveTopology { + /// Returns true for strip topologies. + pub fn is_strip(&self) -> bool { + match *self { + Self::PointList | Self::LineList | Self::TriangleList => false, + Self::LineStrip | Self::TriangleStrip => true, + } + } +} + /// Winding order which classifies the "front" face. #[repr(C)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] @@ -2496,11 +2486,11 @@ impl Extent3d { /// assert_eq!(wgpu::Extent3d { width: 60, height: 60, depth_or_array_layers: 1 }.max_mips(), 6); /// assert_eq!(wgpu::Extent3d { width: 240, height: 1, depth_or_array_layers: 1 }.max_mips(), 8); /// ``` - pub fn max_mips(&self) -> u8 { + pub fn max_mips(&self) -> u32 { let max_dim = self.width.max(self.height.max(self.depth_or_array_layers)); let max_levels = 32 - max_dim.leading_zeros(); - max_levels as u8 + max_levels } } @@ -2583,6 +2573,14 @@ impl TextureDescriptor { }, }) } + + /// Returns the number of array layers. + pub fn array_layer_count(&self) -> u32 { + match self.dimension { + TextureDimension::D1 | TextureDimension::D2 => self.size.depth_or_array_layers, + TextureDimension::D3 => 1, + } + } } /// Kind of data the texture holds.