hal: port the rest of wgpu-core

This commit is contained in:
Dzmitry Malyshau 2021-06-08 00:45:41 -04:00
parent c61ee1262b
commit 0a82c232ba
26 changed files with 1599 additions and 1809 deletions

View File

@ -37,7 +37,7 @@ thiserror = "1"
[dependencies.naga] [dependencies.naga]
git = "https://github.com/gfx-rs/naga" git = "https://github.com/gfx-rs/naga"
tag = "gfx-25" tag = "gfx-25"
features = ["spv-in", "spv-out", "wgsl-in"] features = ["spv-in", "wgsl-in"]
[dependencies.wgt] [dependencies.wgt]
path = "../wgpu-types" path = "../wgpu-types"

View File

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::{ use crate::{
device::{descriptor::DescriptorSet, DeviceError, MissingFeatures, SHADER_STAGE_COUNT}, device::{DeviceError, MissingFeatures, SHADER_STAGE_COUNT},
hub::Resource, hub::Resource,
id::{BindGroupLayoutId, BufferId, DeviceId, SamplerId, TextureViewId, Valid}, id::{BindGroupLayoutId, BufferId, DeviceId, SamplerId, TextureViewId, Valid},
memory_init_tracker::MemoryInitTrackerAction, memory_init_tracker::MemoryInitTrackerAction,
@ -633,7 +633,7 @@ pub struct BindGroupDynamicBindingData {
#[derive(Debug)] #[derive(Debug)]
pub struct BindGroup<A: hal::Api> { pub struct BindGroup<A: hal::Api> {
pub(crate) raw: DescriptorSet<A>, pub(crate) raw: A::BindGroup,
pub(crate) device_id: Stored<DeviceId>, pub(crate) device_id: Stored<DeviceId>,
pub(crate) layout_id: Valid<BindGroupLayoutId>, pub(crate) layout_id: Valid<BindGroupLayoutId>,
pub(crate) life_guard: LifeGuard, pub(crate) life_guard: LifeGuard,

View File

@ -7,7 +7,7 @@ use crate::{
device::SHADER_STAGE_COUNT, device::SHADER_STAGE_COUNT,
hub::{HalApi, Storage}, hub::{HalApi, Storage},
id::{BindGroupId, BindGroupLayoutId, PipelineLayoutId, Valid}, id::{BindGroupId, BindGroupLayoutId, PipelineLayoutId, Valid},
Stored, MAX_BIND_GROUPS, Stored,
}; };
use arrayvec::ArrayVec; use arrayvec::ArrayVec;
@ -42,7 +42,7 @@ mod compat {
#[derive(Debug)] #[derive(Debug)]
pub struct Manager<T> { pub struct Manager<T> {
entries: [Entry<T>; crate::MAX_BIND_GROUPS], entries: [Entry<T>; hal::MAX_BIND_GROUPS],
} }
impl<T: Copy + PartialEq> Manager<T> { impl<T: Copy + PartialEq> Manager<T> {
@ -145,7 +145,7 @@ pub(super) struct EntryPayload {
pub(super) struct Binder { pub(super) struct Binder {
pub(super) pipeline_layout_id: Option<Valid<PipelineLayoutId>>, //TODO: strongly `Stored` pub(super) pipeline_layout_id: Option<Valid<PipelineLayoutId>>, //TODO: strongly `Stored`
manager: compat::Manager<Valid<BindGroupLayoutId>>, manager: compat::Manager<Valid<BindGroupLayoutId>>,
payloads: [EntryPayload; MAX_BIND_GROUPS], payloads: [EntryPayload; hal::MAX_BIND_GROUPS],
} }
impl Binder { impl Binder {

View File

@ -43,22 +43,20 @@ use crate::{
StateChange, StateChange,
}, },
conv, conv,
device::{ device::{AttachmentData, Device, DeviceError, RenderPassContext, SHADER_STAGE_COUNT},
AttachmentData, Device, DeviceError, RenderPassContext, MAX_VERTEX_BUFFERS,
SHADER_STAGE_COUNT,
},
hal::BufferUse,
hub::{GlobalIdentityHandlerFactory, HalApi, Hub, Resource, Storage, Token}, hub::{GlobalIdentityHandlerFactory, HalApi, Hub, Resource, Storage, Token},
id, id,
memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction}, memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction},
track::{TrackerSet, UsageConflict}, track::{TrackerSet, UsageConflict},
validation::check_buffer_usage, validation::check_buffer_usage,
Label, LabelHelpers, LifeGuard, Stored, MAX_BIND_GROUPS, Label, LabelHelpers, LifeGuard, Stored,
}; };
use arrayvec::ArrayVec; use arrayvec::ArrayVec;
use std::{borrow::Cow, iter, mem, ops::Range}; use std::{borrow::Cow, mem, ops::Range};
use thiserror::Error; use thiserror::Error;
use hal::CommandBuffer as _;
/// Describes a [`RenderBundleEncoder`]. /// Describes a [`RenderBundleEncoder`].
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))] #[cfg_attr(feature = "trace", derive(serde::Serialize))]
@ -105,7 +103,7 @@ impl RenderBundleEncoder {
if sc == 0 || sc > 32 || !conv::is_power_of_two(sc) { if sc == 0 || sc > 32 || !conv::is_power_of_two(sc) {
return Err(CreateRenderBundleError::InvalidSampleCount(sc)); return Err(CreateRenderBundleError::InvalidSampleCount(sc));
} }
sc as u8 sc
}, },
}, },
}) })
@ -150,10 +148,12 @@ impl RenderBundleEncoder {
let mut state = State { let mut state = State {
trackers: TrackerSet::new(self.parent_id.backend()), trackers: TrackerSet::new(self.parent_id.backend()),
index: IndexState::new(), index: IndexState::new(),
vertex: (0..MAX_VERTEX_BUFFERS) vertex: (0..hal::MAX_VERTEX_BUFFERS)
.map(|_| VertexState::new()) .map(|_| VertexState::new())
.collect(), .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(), push_constant_ranges: PushConstantState::new(),
raw_dynamic_offsets: Vec::new(), raw_dynamic_offsets: Vec::new(),
flat_dynamic_offsets: Vec::new(), flat_dynamic_offsets: Vec::new(),
@ -260,7 +260,7 @@ impl RenderBundleEncoder {
let buffer = state let buffer = state
.trackers .trackers
.buffers .buffers
.use_extend(&*buffer_guard, buffer_id, (), BufferUse::INDEX) .use_extend(&*buffer_guard, buffer_id, (), hal::BufferUse::INDEX)
.unwrap(); .unwrap();
check_buffer_usage(buffer.usage, wgt::BufferUsage::INDEX) check_buffer_usage(buffer.usage, wgt::BufferUsage::INDEX)
.map_pass_err(scope)?; .map_pass_err(scope)?;
@ -287,7 +287,7 @@ impl RenderBundleEncoder {
let buffer = state let buffer = state
.trackers .trackers
.buffers .buffers
.use_extend(&*buffer_guard, buffer_id, (), BufferUse::VERTEX) .use_extend(&*buffer_guard, buffer_id, (), hal::BufferUse::VERTEX)
.unwrap(); .unwrap();
check_buffer_usage(buffer.usage, wgt::BufferUsage::VERTEX) check_buffer_usage(buffer.usage, wgt::BufferUsage::VERTEX)
.map_pass_err(scope)?; .map_pass_err(scope)?;
@ -408,7 +408,7 @@ impl RenderBundleEncoder {
let buffer = state let buffer = state
.trackers .trackers
.buffers .buffers
.use_extend(&*buffer_guard, buffer_id, (), BufferUse::INDIRECT) .use_extend(&*buffer_guard, buffer_id, (), hal::BufferUse::INDIRECT)
.unwrap(); .unwrap();
check_buffer_usage(buffer.usage, wgt::BufferUsage::INDIRECT) check_buffer_usage(buffer.usage, wgt::BufferUsage::INDIRECT)
.map_pass_err(scope)?; .map_pass_err(scope)?;
@ -444,7 +444,7 @@ impl RenderBundleEncoder {
let buffer = state let buffer = state
.trackers .trackers
.buffers .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_err(|err| RenderCommandError::Buffer(buffer_id, err))
.map_pass_err(scope)?; .map_pass_err(scope)?;
check_buffer_usage(buffer.usage, wgt::BufferUsage::INDIRECT) 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. /// The only failure condition is if some of the used buffers are destroyed.
pub(crate) unsafe fn execute<A: HalApi>( pub(crate) unsafe fn execute<A: HalApi>(
&self, &self,
cmd_buf: &mut B::CommandBuffer, cmd_buf: &mut A::CommandBuffer,
pipeline_layout_guard: &Storage< pipeline_layout_guard: &Storage<
crate::binding_model::PipelineLayout<A>, crate::binding_model::PipelineLayout<A>,
id::PipelineLayoutId, id::PipelineLayoutId,
@ -576,12 +576,10 @@ impl RenderBundle {
pipeline_guard: &Storage<crate::pipeline::RenderPipeline<A>, id::RenderPipelineId>, pipeline_guard: &Storage<crate::pipeline::RenderPipeline<A>, id::RenderPipelineId>,
buffer_guard: &Storage<crate::resource::Buffer<A>, id::BufferId>, buffer_guard: &Storage<crate::resource::Buffer<A>, id::BufferId>,
) -> Result<(), ExecutionError> { ) -> Result<(), ExecutionError> {
use hal::command::CommandBuffer as _;
let mut offsets = self.base.dynamic_offsets.as_slice(); let mut offsets = self.base.dynamic_offsets.as_slice();
let mut pipeline_layout_id = None::<id::Valid<id::PipelineLayoutId>>; let mut pipeline_layout_id = None::<id::Valid<id::PipelineLayoutId>>;
if let Some(ref label) = self.base.label { 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() { for command in self.base.commands.iter() {
@ -592,17 +590,17 @@ impl RenderBundle {
bind_group_id, bind_group_id,
} => { } => {
let bind_group = bind_group_guard.get(bind_group_id).unwrap(); 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, &pipeline_layout_guard[pipeline_layout_id.unwrap()].raw,
index as usize, index as u32,
iter::once(bind_group.raw.raw()), &bind_group.raw,
offsets.iter().take(num_dynamic_offsets as usize).cloned(), &offsets[num_dynamic_offsets as usize..],
); );
offsets = &offsets[num_dynamic_offsets as usize..]; offsets = &offsets[num_dynamic_offsets as usize..];
} }
RenderCommand::SetPipeline(pipeline_id) => { RenderCommand::SetPipeline(pipeline_id) => {
let pipeline = pipeline_guard.get(pipeline_id).unwrap(); 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); pipeline_layout_id = Some(pipeline.layout_id.value);
} }
@ -612,19 +610,18 @@ impl RenderBundle {
offset, offset,
size, size,
} => { } => {
let index_type = conv::map_index_format(index_format); let buffer = buffer_guard
let &(ref buffer, _) = buffer_guard
.get(buffer_id) .get(buffer_id)
.unwrap() .unwrap()
.raw .raw
.as_ref() .as_ref()
.ok_or(ExecutionError::DestroyedBuffer(buffer_id))?; .ok_or(ExecutionError::DestroyedBuffer(buffer_id))?;
let range = hal::buffer::SubRange { let bb = hal::BufferBinding {
buffer,
offset, 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 { RenderCommand::SetVertexBuffer {
slot, slot,
@ -632,17 +629,18 @@ impl RenderBundle {
offset, offset,
size, size,
} => { } => {
let &(ref buffer, _) = buffer_guard let buffer = buffer_guard
.get(buffer_id) .get(buffer_id)
.unwrap() .unwrap()
.raw .raw
.as_ref() .as_ref()
.ok_or(ExecutionError::DestroyedBuffer(buffer_id))?; .ok_or(ExecutionError::DestroyedBuffer(buffer_id))?;
let range = hal::buffer::SubRange { let bb = hal::BufferBinding {
buffer,
offset, 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 { RenderCommand::SetPushConstant {
stages, stages,
@ -659,20 +657,15 @@ impl RenderBundle {
let data_slice = &self.base.push_constant_data let data_slice = &self.base.push_constant_data
[(values_offset as usize)..values_end_offset]; [(values_offset as usize)..values_end_offset];
cmd_buf.push_graphics_constants( cmd_buf.set_push_constants(&pipeline_layout.raw, stages, offset, data_slice)
&pipeline_layout.raw,
conv::map_shader_stage_flags(stages),
offset,
&data_slice,
)
} else { } else {
super::push_constant_clear( super::push_constant_clear(
offset, offset,
size_bytes, size_bytes,
|clear_offset, clear_data| { |clear_offset, clear_data| {
cmd_buf.push_graphics_constants( cmd_buf.set_push_constants(
&pipeline_layout.raw, &pipeline_layout.raw,
conv::map_shader_stage_flags(stages), stages,
clear_offset, clear_offset,
clear_data, clear_data,
); );
@ -686,10 +679,7 @@ impl RenderBundle {
first_vertex, first_vertex,
first_instance, first_instance,
} => { } => {
cmd_buf.draw( cmd_buf.draw(first_vertex, vertex_count, first_instance, instance_count);
first_vertex..first_vertex + vertex_count,
first_instance..first_instance + instance_count,
);
} }
RenderCommand::DrawIndexed { RenderCommand::DrawIndexed {
index_count, index_count,
@ -699,9 +689,11 @@ impl RenderBundle {
first_instance, first_instance,
} => { } => {
cmd_buf.draw_indexed( cmd_buf.draw_indexed(
first_index..first_index + index_count, first_index,
index_count,
base_vertex, base_vertex,
first_instance..first_instance + instance_count, first_instance,
instance_count,
); );
} }
RenderCommand::MultiDrawIndirect { RenderCommand::MultiDrawIndirect {
@ -710,13 +702,13 @@ impl RenderBundle {
count: None, count: None,
indexed: false, indexed: false,
} => { } => {
let &(ref buffer, _) = buffer_guard let buffer = buffer_guard
.get(buffer_id) .get(buffer_id)
.unwrap() .unwrap()
.raw .raw
.as_ref() .as_ref()
.ok_or(ExecutionError::DestroyedBuffer(buffer_id))?; .ok_or(ExecutionError::DestroyedBuffer(buffer_id))?;
cmd_buf.draw_indirect(buffer, offset, 1, 0); cmd_buf.draw_indirect(buffer, offset, 1);
} }
RenderCommand::MultiDrawIndirect { RenderCommand::MultiDrawIndirect {
buffer_id, buffer_id,
@ -724,13 +716,13 @@ impl RenderBundle {
count: None, count: None,
indexed: true, indexed: true,
} => { } => {
let &(ref buffer, _) = buffer_guard let buffer = buffer_guard
.get(buffer_id) .get(buffer_id)
.unwrap() .unwrap()
.raw .raw
.as_ref() .as_ref()
.ok_or(ExecutionError::DestroyedBuffer(buffer_id))?; .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::MultiDrawIndirect { .. }
| RenderCommand::MultiDrawIndirectCount { .. } => { | RenderCommand::MultiDrawIndirectCount { .. } => {
@ -943,8 +935,8 @@ struct VertexLimitState {
struct State { struct State {
trackers: TrackerSet, trackers: TrackerSet,
index: IndexState, index: IndexState,
vertex: ArrayVec<[VertexState; MAX_VERTEX_BUFFERS]>, vertex: ArrayVec<[VertexState; hal::MAX_VERTEX_BUFFERS]>,
bind: ArrayVec<[BindState; MAX_BIND_GROUPS]>, bind: ArrayVec<[BindState; hal::MAX_BIND_GROUPS]>,
push_constant_ranges: PushConstantState, push_constant_ranges: PushConstantState,
raw_dynamic_offsets: Vec<wgt::DynamicOffset>, raw_dynamic_offsets: Vec<wgt::DynamicOffset>,
flat_dynamic_offsets: Vec<wgt::DynamicOffset>, flat_dynamic_offsets: Vec<wgt::DynamicOffset>,

View File

@ -8,16 +8,13 @@ use std::{num::NonZeroU32, ops::Range};
use crate::device::trace::Command as TraceCommand; use crate::device::trace::Command as TraceCommand;
use crate::{ use crate::{
command::CommandBuffer, command::CommandBuffer,
conv,
device::all_buffer_stages,
hub::{Global, GlobalIdentityHandlerFactory, HalApi, Token}, hub::{Global, GlobalIdentityHandlerFactory, HalApi, Token},
id::{BufferId, CommandEncoderId, TextureId}, id::{BufferId, CommandEncoderId, TextureId},
memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction}, memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction},
resource::{BufferUse, TextureUse},
track::TextureSelector, track::TextureSelector,
}; };
use hal::command::CommandBuffer as _; use hal::CommandBuffer as _;
use thiserror::Error; use thiserror::Error;
use wgt::{ use wgt::{
BufferAddress, BufferSize, BufferUsage, ImageSubresourceRange, TextureAspect, TextureUsage, BufferAddress, BufferSize, BufferUsage, ImageSubresourceRange, TextureAspect, TextureUsage,
@ -46,22 +43,22 @@ pub enum ClearError {
}, },
#[error("destination buffer/texture is missing the `COPY_DST` usage flag")] #[error("destination buffer/texture is missing the `COPY_DST` usage flag")]
MissingCopyDstUsageFlag(Option<BufferId>, Option<TextureId>), MissingCopyDstUsageFlag(Option<BufferId>, Option<TextureId>),
#[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 { MissingTextureAspect {
texture_aspects: hal::FormatAspect, texture_format: wgt::TextureFormat,
subresource_range_aspects: TextureAspect, subresource_range_aspects: TextureAspect,
}, },
#[error("image subresource level range is outside of the texture's level range. texture range is {texture_level_range:?}, \ #[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:?}")] whereas subesource range specified start {subresource_base_mip_level} and count {subresource_mip_level_count:?}")]
InvalidTextureLevelRange { InvalidTextureLevelRange {
texture_level_range: Range<hal::image::Level>, texture_level_range: Range<u32>,
subresource_base_mip_level: u32, subresource_base_mip_level: u32,
subresource_mip_level_count: Option<NonZeroU32>, subresource_mip_level_count: Option<NonZeroU32>,
}, },
#[error("image subresource layer range is outside of the texture's layer range. texture range is {texture_layer_range:?}, \ #[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:?}")] whereas subesource range specified start {subresource_base_array_layer} and count {subresource_array_layer_count:?}")]
InvalidTextureLayerRange { InvalidTextureLayerRange {
texture_layer_range: Range<hal::image::Layer>, texture_layer_range: Range<u32>,
subresource_base_array_layer: u32, subresource_base_array_layer: u32,
subresource_array_layer_count: Option<NonZeroU32>, subresource_array_layer_count: Option<NonZeroU32>,
}, },
@ -96,9 +93,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let (dst_buffer, dst_pending) = cmd_buf let (dst_buffer, dst_pending) = cmd_buf
.trackers .trackers
.buffers .buffers
.use_replace(&*buffer_guard, dst, (), BufferUse::COPY_DST) .use_replace(&*buffer_guard, dst, (), hal::BufferUse::COPY_DST)
.map_err(ClearError::InvalidBuffer)?; .map_err(ClearError::InvalidBuffer)?;
let &(ref dst_raw, _) = dst_buffer let dst_raw = dst_buffer
.raw .raw
.as_ref() .as_ref()
.ok_or(ClearError::InvalidBuffer(dst))?; .ok_or(ClearError::InvalidBuffer(dst))?;
@ -124,8 +121,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
} }
} }
let num_bytes_filled = size.map_or(dst_buffer.size - offset, |s| s.get()); let end = match size {
if num_bytes_filled == 0 { Some(size) => offset + size.get(),
None => dst_buffer.size,
};
if offset == end {
log::trace!("Ignoring fill_buffer of size 0"); log::trace!("Ignoring fill_buffer of size 0");
return Ok(()); return Ok(());
} }
@ -134,7 +134,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
cmd_buf.buffer_memory_init_actions.extend( cmd_buf.buffer_memory_init_actions.extend(
dst_buffer dst_buffer
.initialization_status .initialization_status
.check(offset..(offset + num_bytes_filled)) .check(offset..end)
.map(|range| MemoryInitTrackerAction { .map(|range| MemoryInitTrackerAction {
id: dst, id: dst,
range, range,
@ -143,24 +143,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
); );
// actual hal barrier & operation // actual hal barrier & operation
let dst_barrier = dst_pending let dst_barrier = dst_pending.map(|pending| pending.into_hal(dst_buffer));
.map(|pending| pending.into_hal(dst_buffer))
.next();
let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap(); let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap();
unsafe { unsafe {
cmd_buf_raw.pipeline_barrier( cmd_buf_raw.transition_buffers(dst_barrier);
all_buffer_stages()..hal::pso::PipelineStage::TRANSFER, cmd_buf_raw.fill_buffer(dst_raw, offset..end, 0);
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,
);
} }
Ok(()) Ok(())
} }
@ -198,24 +185,20 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.map_err(|_| ClearError::InvalidTexture(dst))?; .map_err(|_| ClearError::InvalidTexture(dst))?;
// Check if subresource aspects are valid. // Check if subresource aspects are valid.
let aspects = match subresource_range.aspect { let requested_aspects = hal::FormatAspect::from(subresource_range.aspect);
wgt::TextureAspect::All => dst_texture.aspects, let clear_aspects = hal::FormatAspect::from(dst_texture.desc.format) & requested_aspects;
wgt::TextureAspect::DepthOnly => hal::FormatAspect::DEPTH, if clear_aspects.is_empty() {
wgt::TextureAspect::StencilOnly => hal::FormatAspect::STENCIL,
};
if !dst_texture.aspects.contains(aspects) {
return Err(ClearError::MissingTextureAspect { return Err(ClearError::MissingTextureAspect {
texture_aspects: dst_texture.aspects, texture_format: dst_texture.desc.format,
subresource_range_aspects: subresource_range.aspect, subresource_range_aspects: subresource_range.aspect,
}); });
}; };
// Check if subresource level range is valid // Check if subresource level range is valid
let subresource_level_end = if let Some(count) = subresource_range.mip_level_count { let subresource_level_end = match subresource_range.mip_level_count {
(subresource_range.base_mip_level + count.get()) as u8 Some(count) => subresource_range.base_mip_level + count.get(),
} else { None => dst_texture.full_range.levels.end,
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 || dst_texture.full_range.levels.end < subresource_level_end
{ {
return Err(ClearError::InvalidTextureLevelRange { return Err(ClearError::InvalidTextureLevelRange {
@ -225,12 +208,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}); });
} }
// Check if subresource layer range is valid // Check if subresource layer range is valid
let subresource_layer_end = if let Some(count) = subresource_range.array_layer_count { let subresource_layer_end = match subresource_range.array_layer_count {
(subresource_range.base_array_layer + count.get()) as u16 Some(count) => subresource_range.base_array_layer + count.get(),
} else { None => dst_texture.full_range.layers.end,
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 || dst_texture.full_range.layers.end < subresource_layer_end
{ {
return Err(ClearError::InvalidTextureLayerRange { return Err(ClearError::InvalidTextureLayerRange {
@ -248,31 +230,26 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
&*texture_guard, &*texture_guard,
dst, dst,
TextureSelector { TextureSelector {
levels: subresource_range.base_mip_level as u8..subresource_level_end, levels: subresource_range.base_mip_level..subresource_level_end,
layers: subresource_range.base_array_layer as u16..subresource_layer_end, layers: subresource_range.base_array_layer..subresource_layer_end,
}, },
TextureUse::COPY_DST, hal::TextureUse::COPY_DST,
) )
.map_err(ClearError::InvalidTexture)?; .map_err(ClearError::InvalidTexture)?;
let &(ref dst_raw, _) = dst_texture let dst_raw = dst_texture
.raw .raw
.as_ref() .as_ref()
.ok_or(ClearError::InvalidTexture(dst))?; .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))); return Err(ClearError::MissingCopyDstUsageFlag(None, Some(dst)));
} }
// actual hal barrier & operation // actual hal barrier & operation
let dst_barrier = dst_pending let dst_barrier = dst_pending.map(|pending| pending.into_hal(dst_texture));
.map(|pending| pending.into_hal(dst_texture))
.next();
let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap(); let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap();
unsafe { unsafe {
cmd_buf_raw.pipeline_barrier( cmd_buf_raw.transition_textures(dst_barrier);
all_buffer_stages()..hal::pso::PipelineStage::TRANSFER, /*TODO: image clears
hal::memory::Dependencies::empty(),
dst_barrier.into_iter(),
);
cmd_buf_raw.clear_image( cmd_buf_raw.clear_image(
dst_raw, dst_raw,
hal::image::Layout::TransferDstOptimal, hal::image::Layout::TransferDstOptimal,
@ -288,7 +265,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
layer_start: subresource_range.base_array_layer as u16, layer_start: subresource_range.base_array_layer as u16,
layer_count: subresource_range.array_layer_count.map(|c| c.get() as u16), layer_count: subresource_range.array_layer_count.map(|c| c.get() as u16),
}), }),
); );*/
} }
Ok(()) Ok(())
} }

View File

@ -13,7 +13,7 @@ use crate::{
id, id,
memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction}, memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction},
resource::{Buffer, Texture}, resource::{Buffer, Texture},
track::{StatefulTrackerSubset, TrackerSet, UsageConflict}, track::{StatefulTrackerSubset, TrackerSet, UsageConflict, UseExtendError},
validation::{check_buffer_usage, MissingBufferUsageError}, validation::{check_buffer_usage, MissingBufferUsageError},
Label, DOWNLEVEL_ERROR_WARNING_MESSAGE, Label, DOWNLEVEL_ERROR_WARNING_MESSAGE,
}; };
@ -22,7 +22,6 @@ use hal::CommandBuffer as _;
use thiserror::Error; use thiserror::Error;
use wgt::{BufferAddress, BufferUsage, ShaderStage}; use wgt::{BufferAddress, BufferUsage, ShaderStage};
use crate::track::UseExtendError;
use std::{fmt, mem, str}; use std::{fmt, mem, str};
#[doc(hidden)] #[doc(hidden)]
@ -293,7 +292,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
if let Some(ref label) = base.label { if let Some(ref label) = base.label {
unsafe { unsafe {
raw.begin_debug_marker(label, 0); raw.begin_debug_marker(label);
} }
} }
@ -377,19 +376,16 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
if !entries.is_empty() { if !entries.is_empty() {
let pipeline_layout = let pipeline_layout =
&pipeline_layout_guard[pipeline_layout_id.unwrap()].raw; &pipeline_layout_guard[pipeline_layout_id.unwrap()].raw;
let desc_sets = entries.iter().map(|e| { for (i, e) in entries.iter().enumerate() {
bind_group_guard[e.group_id.as_ref().unwrap().value] let raw_bg = &bind_group_guard[e.group_id.as_ref().unwrap().value].raw;
.raw unsafe {
.raw() raw.set_bind_group(
}); pipeline_layout,
let offsets = entries.iter().flat_map(|e| &e.dynamic_offsets).cloned(); index as u32 + i as u32,
unsafe { raw_bg,
raw.bind_compute_descriptor_sets( &e.dynamic_offsets,
pipeline_layout, );
index as usize, }
desc_sets,
offsets,
);
} }
} }
} }
@ -408,7 +404,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.map_pass_err(scope)?; .map_pass_err(scope)?;
unsafe { unsafe {
raw.bind_compute_pipeline(&pipeline.raw); raw.set_compute_pipeline(&pipeline.raw);
} }
// Rebind resources // Rebind resources
@ -420,19 +416,17 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
pipeline.layout_id.value, pipeline.layout_id.value,
); );
if !entries.is_empty() { if !entries.is_empty() {
let desc_sets = entries.iter().map(|e| { for (i, e) in entries.iter().enumerate() {
bind_group_guard[e.group_id.as_ref().unwrap().value] let raw_bg =
.raw &bind_group_guard[e.group_id.as_ref().unwrap().value].raw;
.raw() unsafe {
}); raw.set_bind_group(
let offsets = entries.iter().flat_map(|e| &e.dynamic_offsets).cloned(); &pipeline_layout.raw,
unsafe { start_index as u32 + i as u32,
raw.bind_compute_descriptor_sets( raw_bg,
&pipeline_layout.raw, &e.dynamic_offsets,
start_index, );
desc_sets, }
offsets,
);
} }
} }
@ -447,8 +441,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
offset, offset,
size_bytes, size_bytes,
|clear_offset, clear_data| unsafe { |clear_offset, clear_data| unsafe {
raw.push_compute_constants( raw.set_push_constants(
&pipeline_layout.raw, &pipeline_layout.raw,
wgt::ShaderStage::COMPUTE,
clear_offset, clear_offset,
clear_data, clear_data,
); );
@ -488,7 +483,14 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
) )
.map_pass_err(scope)?; .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) => { ComputeCommand::Dispatch(groups) => {
let scope = PassErrorScope::Dispatch { let scope = PassErrorScope::Dispatch {
@ -537,7 +539,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.map_pass_err(scope); .map_pass_err(scope);
} }
let &(ref buf_raw, _) = indirect_buffer let buf_raw = indirect_buffer
.raw .raw
.as_ref() .as_ref()
.ok_or(ComputePassErrorInner::InvalidIndirectBuffer(buffer_id)) .ok_or(ComputePassErrorInner::InvalidIndirectBuffer(buffer_id))
@ -569,14 +571,14 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
raw.dispatch_indirect(buf_raw, offset); raw.dispatch_indirect(buf_raw, offset);
} }
} }
ComputeCommand::PushDebugGroup { color, len } => { ComputeCommand::PushDebugGroup { color: _, len } => {
state.debug_scope_depth += 1; state.debug_scope_depth += 1;
let label = let label =
str::from_utf8(&base.string_data[string_offset..string_offset + len]) str::from_utf8(&base.string_data[string_offset..string_offset + len])
.unwrap(); .unwrap();
string_offset += len; string_offset += len;
unsafe { unsafe {
raw.begin_debug_marker(label, color); raw.begin_debug_marker(label);
} }
} }
ComputeCommand::PopDebugGroup => { ComputeCommand::PopDebugGroup => {
@ -591,12 +593,12 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
raw.end_debug_marker(); raw.end_debug_marker();
} }
} }
ComputeCommand::InsertDebugMarker { color, len } => { ComputeCommand::InsertDebugMarker { color: _, len } => {
let label = let label =
str::from_utf8(&base.string_data[string_offset..string_offset + len]) str::from_utf8(&base.string_data[string_offset..string_offset + len])
.unwrap(); .unwrap();
string_offset += len; string_offset += len;
unsafe { raw.insert_debug_marker(label, color) } unsafe { raw.insert_debug_marker(label) }
} }
ComputeCommand::WriteTimestamp { ComputeCommand::WriteTimestamp {
query_set_id, query_set_id,

View File

@ -7,7 +7,6 @@
use crate::{ use crate::{
binding_model::PushConstantUploadError, binding_model::PushConstantUploadError,
hal::BufferUse,
id, id,
track::UseExtendError, track::UseExtendError,
validation::{MissingBufferUsageError, MissingTextureUsageError}, validation::{MissingBufferUsageError, MissingTextureUsageError},
@ -17,7 +16,7 @@ use wgt::{BufferAddress, BufferSize, Color};
use std::num::NonZeroU32; use std::num::NonZeroU32;
use thiserror::Error; use thiserror::Error;
pub type BufferError = UseExtendError<BufferUse>; pub type BufferError = UseExtendError<hal::BufferUse>;
/// Error validating a draw call. /// Error validating a draw call.
#[derive(Clone, Debug, Error, PartialEq)] #[derive(Clone, Debug, Error, PartialEq)]

View File

@ -70,10 +70,11 @@ impl<A: HalApi> CommandBuffer<A> {
#[cfg(feature = "trace")] enable_tracing: bool, #[cfg(feature = "trace")] enable_tracing: bool,
#[cfg(debug_assertions)] label: &Label, #[cfg(debug_assertions)] label: &Label,
) -> Self { ) -> Self {
use crate::LabelHelpers as _;
CommandBuffer { CommandBuffer {
raw: vec![raw], raw: vec![raw],
status: CommandEncoderStatus::Recording, status: CommandEncoderStatus::Recording,
recorded_thread_id: thread::current.id(), recorded_thread_id: thread::current().id(),
device_id, device_id,
trackers: TrackerSet::new(A::VARIANT), trackers: TrackerSet::new(A::VARIANT),
used_swap_chains: Default::default(), used_swap_chains: Default::default(),
@ -88,7 +89,7 @@ impl<A: HalApi> CommandBuffer<A> {
None None
}, },
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
label: label.to_string_or_default(), label: label.borrow_or_default().to_string(),
} }
} }
@ -242,8 +243,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
cmd_buf.status = CommandEncoderStatus::Finished; cmd_buf.status = CommandEncoderStatus::Finished;
// stop tracking the swapchain image, if used // stop tracking the swapchain image, if used
for sc_id in cmd_buf.used_swap_chains.iter() { for sc_id in cmd_buf.used_swap_chains.iter() {
let view_id = swap_chain_guard[sc_id.value] let &(ref view_id, _) = swap_chain_guard[sc_id.value]
.acquired_view_id .acquired_texture
.as_ref() .as_ref()
.expect("Used swap chain frame has already presented"); .expect("Used swap chain frame has already presented");
cmd_buf.trackers.views.remove(view_id.value); cmd_buf.trackers.views.remove(view_id.value);
@ -272,7 +273,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap(); let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap();
unsafe { unsafe {
cmd_buf_raw.begin_debug_marker(label, 0); cmd_buf_raw.begin_debug_marker(label);
} }
Ok(()) Ok(())
} }
@ -292,7 +293,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap(); let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap();
unsafe { unsafe {
cmd_buf_raw.insert_debug_marker(label, 0); cmd_buf_raw.insert_debug_marker(label);
} }
Ok(()) Ok(())
} }

View File

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use hal::command::CommandBuffer as _; use hal::CommandBuffer as _;
#[cfg(feature = "trace")] #[cfg(feature = "trace")]
use crate::device::trace::Command as TraceCommand; use crate::device::trace::Command as TraceCommand;
@ -10,7 +10,7 @@ use crate::{
command::{CommandBuffer, CommandEncoderError}, command::{CommandBuffer, CommandEncoderError},
hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token}, hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token},
id::{self, Id, TypedId}, id::{self, Id, TypedId},
resource::{BufferUse, QuerySet}, resource::QuerySet,
track::UseExtendError, track::UseExtendError,
Epoch, FastHashMap, Index, Epoch, FastHashMap, Index,
}; };
@ -48,7 +48,7 @@ impl<A: hal::Api> QueryResetMap<A> {
pub fn reset_queries( pub fn reset_queries(
self, self,
cmd_buf_raw: &mut B::CommandBuffer, cmd_buf_raw: &mut A::CommandBuffer,
query_set_storage: &Storage<QuerySet<A>, id::QuerySetId>, query_set_storage: &Storage<QuerySet<A>, id::QuerySetId>,
backend: wgt::Backend, backend: wgt::Backend,
) -> Result<(), id::QuerySetId> { ) -> Result<(), id::QuerySetId> {
@ -69,7 +69,7 @@ impl<A: hal::Api> QueryResetMap<A> {
// We've hit the end of a run, dispatch a reset // We've hit the end of a run, dispatch a reset
(Some(start), false) => { (Some(start), false) => {
run_start = None; 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 // We're starting a run
(None, true) => { (None, true) => {
@ -167,7 +167,7 @@ impl<A: HalApi> QuerySet<A> {
query_type: SimplifiedQueryType, query_type: SimplifiedQueryType,
query_index: u32, query_index: u32,
reset_state: Option<&mut QueryResetMap<A>>, reset_state: Option<&mut QueryResetMap<A>>,
) -> Result<hal::query::Query<'_, B>, QueryUseError> { ) -> Result<&A::QuerySet, QueryUseError> {
// We need to defer our resets because we are in a renderpass, add the usage to the reset map. // 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 { if let Some(reset) = reset_state {
let used = reset.use_query_set(query_set_id, self, query_index); let used = reset.use_query_set(query_set_id, self, query_index);
@ -191,23 +191,18 @@ impl<A: HalApi> QuerySet<A> {
}); });
} }
let hal_query = hal::query::Query::<A> { Ok(&self.raw)
pool: &self.raw,
id: query_index,
};
Ok(hal_query)
} }
pub(super) fn validate_and_write_timestamp( pub(super) fn validate_and_write_timestamp(
&self, &self,
cmd_buf_raw: &mut B::CommandBuffer, cmd_buf_raw: &mut A::CommandBuffer,
query_set_id: id::QuerySetId, query_set_id: id::QuerySetId,
query_index: u32, query_index: u32,
reset_state: Option<&mut QueryResetMap<A>>, reset_state: Option<&mut QueryResetMap<A>>,
) -> Result<(), QueryUseError> { ) -> Result<(), QueryUseError> {
let needs_reset = reset_state.is_none(); let needs_reset = reset_state.is_none();
let hal_query = self.validate_query( let query_set = self.validate_query(
query_set_id, query_set_id,
SimplifiedQueryType::Timestamp, SimplifiedQueryType::Timestamp,
query_index, query_index,
@ -217,9 +212,9 @@ impl<A: HalApi> QuerySet<A> {
unsafe { unsafe {
// If we don't have a reset state tracker which can defer resets, we must reset now. // If we don't have a reset state tracker which can defer resets, we must reset now.
if needs_reset { 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(()) Ok(())
@ -227,14 +222,14 @@ impl<A: HalApi> QuerySet<A> {
pub(super) fn validate_and_begin_pipeline_statistics_query( pub(super) fn validate_and_begin_pipeline_statistics_query(
&self, &self,
cmd_buf_raw: &mut B::CommandBuffer, cmd_buf_raw: &mut A::CommandBuffer,
query_set_id: id::QuerySetId, query_set_id: id::QuerySetId,
query_index: u32, query_index: u32,
reset_state: Option<&mut QueryResetMap<A>>, reset_state: Option<&mut QueryResetMap<A>>,
active_query: &mut Option<(id::QuerySetId, u32)>, active_query: &mut Option<(id::QuerySetId, u32)>,
) -> Result<(), QueryUseError> { ) -> Result<(), QueryUseError> {
let needs_reset = reset_state.is_none(); let needs_reset = reset_state.is_none();
let hal_query = self.validate_query( let query_set = self.validate_query(
query_set_id, query_set_id,
SimplifiedQueryType::PipelineStatistics, SimplifiedQueryType::PipelineStatistics,
query_index, query_index,
@ -251,9 +246,9 @@ impl<A: HalApi> QuerySet<A> {
unsafe { unsafe {
// If we don't have a reset state tracker which can defer resets, we must reset now. // If we don't have a reset state tracker which can defer resets, we must reset now.
if needs_reset { 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(()) Ok(())
@ -261,7 +256,7 @@ impl<A: HalApi> QuerySet<A> {
} }
pub(super) fn end_pipeline_statistics_query<A: HalApi>( pub(super) fn end_pipeline_statistics_query<A: HalApi>(
cmd_buf_raw: &mut B::CommandBuffer, cmd_buf_raw: &mut A::CommandBuffer,
storage: &Storage<QuerySet<A>, id::QuerySetId>, storage: &Storage<QuerySet<A>, id::QuerySetId>,
active_query: &mut Option<(id::QuerySetId, u32)>, active_query: &mut Option<(id::QuerySetId, u32)>,
) -> Result<(), QueryUseError> { ) -> Result<(), QueryUseError> {
@ -269,12 +264,7 @@ pub(super) fn end_pipeline_statistics_query<A: HalApi>(
// We can unwrap here as the validity was validated when the active query was set // 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 query_set = storage.get(query_set_id).unwrap();
let hal_query = hal::query::Query::<A> { unsafe { cmd_buf_raw.end_query(&query_set.raw, query_index) };
pool: &query_set.raw,
id: query_index,
};
unsafe { cmd_buf_raw.end_query(hal_query) }
Ok(()) Ok(())
} else { } else {
@ -362,7 +352,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let (dst_buffer, dst_pending) = cmd_buf let (dst_buffer, dst_pending) = cmd_buf
.trackers .trackers
.buffers .buffers
.use_replace(&*buffer_guard, destination, (), BufferUse::COPY_DST) .use_replace(&*buffer_guard, destination, (), hal::BufferUse::COPY_DST)
.map_err(QueryError::InvalidBuffer)?; .map_err(QueryError::InvalidBuffer)?;
let dst_barrier = dst_pending.map(|pending| pending.into_hal(dst_buffer)); let dst_barrier = dst_pending.map(|pending| pending.into_hal(dst_buffer));
@ -380,9 +370,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.into()); .into());
} }
let stride = query_set.elements * wgt::QUERY_SIZE; let bytes_used = (wgt::QUERY_SIZE * query_count) as BufferAddress;
let bytes_used = (stride * query_count) as BufferAddress;
let buffer_start_offset = destination_offset; let buffer_start_offset = destination_offset;
let buffer_end_offset = buffer_start_offset + bytes_used; let buffer_end_offset = buffer_start_offset + bytes_used;
@ -390,7 +378,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
return Err(ResolveError::BufferOverrun { return Err(ResolveError::BufferOverrun {
start_query, start_query,
end_query, end_query,
stride, stride: wgt::QUERY_SIZE,
buffer_size: dst_buffer.size, buffer_size: dst_buffer.size,
buffer_start_offset, buffer_start_offset,
buffer_end_offset, buffer_end_offset,
@ -399,18 +387,12 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
} }
unsafe { unsafe {
cmd_buf_raw.pipeline_barrier( cmd_buf_raw.transition_buffers(dst_barrier);
all_buffer_stages()..hal::pso::PipelineStage::TRANSFER, cmd_buf_raw.copy_query_results(
hal::memory::Dependencies::empty(),
dst_barrier,
);
cmd_buf_raw.copy_query_pool_results(
&query_set.raw, &query_set.raw,
start_query..end_query, start_query..end_query,
&dst_buffer.raw.as_ref().unwrap().0, dst_buffer.raw.as_ref().unwrap(),
destination_offset, destination_offset,
stride,
hal::query::ResultFlags::WAIT | hal::query::ResultFlags::BITS_64,
); );
} }

File diff suppressed because it is too large Load Diff

View File

@ -10,14 +10,15 @@ use crate::{
hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token}, hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token},
id::{BufferId, CommandEncoderId, TextureId}, id::{BufferId, CommandEncoderId, TextureId},
memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction}, memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction},
resource::{Texture, TextureDescriptor, TextureErrorDimension}, resource::{Texture, TextureErrorDimension},
track::TextureSelector,
}; };
use hal::CommandBuffer as _; use hal::CommandBuffer as _;
use thiserror::Error; use thiserror::Error;
use wgt::{BufferAddress, BufferUsage, Extent3d, TextureUsage}; use wgt::{BufferAddress, BufferUsage, Extent3d, TextureUsage};
use std::{iter, num::NonZeroU32}; use std::iter;
pub type ImageCopyBuffer = wgt::ImageCopyBuffer<BufferId>; pub type ImageCopyBuffer = wgt::ImageCopyBuffer<BufferId>;
pub type ImageCopyTexture = wgt::ImageCopyTexture<TextureId>; pub type ImageCopyTexture = wgt::ImageCopyTexture<TextureId>;
@ -106,42 +107,42 @@ pub enum CopyError {
Transfer(#[from] TransferError), Transfer(#[from] TransferError),
} }
pub(crate) fn extract_image_range<A: hal::Api>( pub(crate) fn extract_texture_selector<A: hal::Api>(
copy_texture: &ImageCopyTexture, copy_texture: &ImageCopyTexture,
copy_size: &Extent3d, copy_size: &Extent3d,
texture_guard: &Storage<Texture<A>, TextureId>, texture_guard: &Storage<Texture<A>, TextureId>,
) -> Result<(wgt::ImageSubresourceRange, wgt::TextureFormat), TransferError> { ) -> Result<(TextureSelector, hal::TextureCopyBase, wgt::TextureFormat), TransferError> {
let texture = texture_guard let texture = texture_guard
.get(copy_texture.texture) .get(copy_texture.texture)
.ok_or(TransferError::InvalidTexture(copy_texture.texture))?; .map_err(|_| TransferError::InvalidTexture(copy_texture.texture))?;
let format = texture.desc.format; let format = texture.desc.format;
let copy_aspect = let copy_aspect =
hal::FormatAspect::from(format) & hal::FormatAspect::from(copy_texture.aspect); hal::FormatAspect::from(format) & hal::FormatAspect::from(copy_texture.aspect);
if copy_aspect.is_empty() { if copy_aspect.is_empty() {
return Err(TransferError::MissingTextureAspect { return Err(TransferError::InvalidTextureAspect {
format, format,
aspect: copy_texture.aspect, aspect: copy_texture.aspect,
}); });
} }
let (base_array_layer, array_layer_count) = match texture.desc.dimension {
wgt::TextureDimension::D1 | wgt::TextureDimension::D2 => ( let layers = match texture.desc.dimension {
copy_texture.origin.depth_or_array_layers, wgt::TextureDimension::D1 | wgt::TextureDimension::D2 => {
NonZeroU32::new( copy_texture.origin.z..copy_texture.origin.z + copy_size.depth_or_array_layers
copy_texture.origin.depth_or_array_layers + copy_size.depth_or_array_layers, }
), wgt::TextureDimension::D3 => 0..1,
),
wgt::TextureDimension::D3 => (0, None),
}; };
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, 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 <https://gpuweb.github.io/gpuweb/#copy-between-buffer-texture> /// Function copied with some modifications from webgpu standard <https://gpuweb.github.io/gpuweb/#copy-between-buffer-texture>
@ -242,7 +243,7 @@ pub(crate) fn validate_linear_texture_data(
/// Returns the mip level extent. /// Returns the mip level extent.
pub(crate) fn validate_texture_copy_range( pub(crate) fn validate_texture_copy_range(
texture_copy_view: &ImageCopyTexture, texture_copy_view: &ImageCopyTexture,
desc: &TextureDescriptor, desc: &wgt::TextureDescriptor<()>,
texture_side: CopySide, texture_side: CopySide,
copy_size: &Extent3d, copy_size: &Extent3d,
) -> Result<Extent3d, TransferError> { ) -> Result<Extent3d, TransferError> {
@ -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; 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 { return Err(TransferError::TextureOverrun {
start_offset: texture_copy_view.origin.z, start_offset: texture_copy_view.origin.z,
end_offset: z_copy_max, end_offset: z_copy_max,
texture_size: extent.depth, texture_size: extent.depth_or_array_layers,
dimension: TextureErrorDimension::Z, dimension: TextureErrorDimension::Z,
side: texture_side, side: texture_side,
}); });
@ -342,7 +343,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.buffers .buffers
.use_replace(&*buffer_guard, source, (), hal::BufferUse::COPY_SRC) .use_replace(&*buffer_guard, source, (), hal::BufferUse::COPY_SRC)
.map_err(TransferError::InvalidBuffer)?; .map_err(TransferError::InvalidBuffer)?;
let &(ref src_raw, _) = src_buffer let src_raw = src_buffer
.raw .raw
.as_ref() .as_ref()
.ok_or(TransferError::InvalidBuffer(source))?; .ok_or(TransferError::InvalidBuffer(source))?;
@ -359,7 +360,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.buffers .buffers
.use_replace(&*buffer_guard, destination, (), hal::BufferUse::COPY_DST) .use_replace(&*buffer_guard, destination, (), hal::BufferUse::COPY_DST)
.map_err(TransferError::InvalidBuffer)?; .map_err(TransferError::InvalidBuffer)?;
let &(ref dst_raw, _) = dst_buffer let dst_raw = dst_buffer
.raw .raw
.as_ref() .as_ref()
.ok_or(TransferError::InvalidBuffer(destination))?; .ok_or(TransferError::InvalidBuffer(destination))?;
@ -431,12 +432,12 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let region = hal::BufferCopy { let region = hal::BufferCopy {
src_offset: source_offset, src_offset: source_offset,
dst_offset: destination_offset, dst_offset: destination_offset,
size, size: wgt::BufferSize::new(size).unwrap(),
}; };
let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap(); let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap();
unsafe { unsafe {
cmd_buf_raw.transition_buffers(src_barrier.into_iter().chain(dst_barrier)); 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(()) Ok(())
} }
@ -471,14 +472,15 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
return Ok(()); 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 let (src_buffer, src_pending) = cmd_buf
.trackers .trackers
.buffers .buffers
.use_replace(&*buffer_guard, source.buffer, (), hal::BufferUse::COPY_SRC) .use_replace(&*buffer_guard, source.buffer, (), hal::BufferUse::COPY_SRC)
.map_err(TransferError::InvalidBuffer)?; .map_err(TransferError::InvalidBuffer)?;
let &(ref src_raw, _) = src_buffer let src_raw = src_buffer
.raw .raw
.as_ref() .as_ref()
.ok_or(TransferError::InvalidBuffer(source.buffer))?; .ok_or(TransferError::InvalidBuffer(source.buffer))?;
@ -497,11 +499,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
hal::TextureUse::COPY_DST, hal::TextureUse::COPY_DST,
) )
.unwrap(); .unwrap();
let &(ref dst_raw, _) = dst_texture let dst_raw = dst_texture
.raw .raw
.as_ref() .as_ref()
.ok_or(TransferError::InvalidTexture(destination.texture))?; .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( return Err(
TransferError::MissingCopyDstUsageFlag(None, Some(destination.texture)).into(), TransferError::MissingCopyDstUsageFlag(None, Some(destination.texture)).into(),
); );
@ -511,14 +513,13 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let format_desc = dst_texture.desc.format.describe(); let format_desc = dst_texture.desc.format.describe();
let max_image_extent = validate_texture_copy_range( let max_image_extent = validate_texture_copy_range(
destination, destination,
dst_texture.format, &dst_texture.desc,
dst_texture.kind,
CopySide::Destination, CopySide::Destination,
copy_size, copy_size,
)?; )?;
let required_buffer_bytes_in_copy = validate_linear_texture_data( let required_buffer_bytes_in_copy = validate_linear_texture_data(
&source.layout, &source.layout,
dst_texture.format, dst_texture.desc.format,
src_buffer.size, src_buffer.size,
CopySide::Source, CopySide::Source,
format_desc.block_size as BufferAddress, format_desc.block_size as BufferAddress,
@ -538,8 +539,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
); );
let (block_width, _) = format_desc.block_dimensions; let (block_width, _) = format_desc.block_dimensions;
if !conv::is_valid_copy_dst_texture_format(dst_texture.format) { if !conv::is_valid_copy_dst_texture_format(dst_texture.desc.format) {
return Err(TransferError::CopyToForbiddenTextureFormat(dst_texture.format).into()); return Err(
TransferError::CopyToForbiddenTextureFormat(dst_texture.desc.format).into(),
);
} }
// WebGPU uses the physical size of the texture for copies whereas vulkan uses // WebGPU uses the physical size of the texture for copies whereas vulkan uses
@ -547,9 +550,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
// image extent data directly. We want the provided copy size to be no larger than // image extent data directly. We want the provided copy size to be no larger than
// the virtual size. // the virtual size.
let region = hal::BufferTextureCopy { let region = hal::BufferTextureCopy {
buffer_layout: &source.layout, buffer_layout: source.layout,
texture_mip_level: destination.mip_level, texture_base: dst_base,
texture_origin: destination.origin,
size: Extent3d { size: Extent3d {
width: copy_size.width.min(max_image_extent.width), width: copy_size.width.min(max_image_extent.width),
height: copy_size.height.min(max_image_extent.height), height: copy_size.height.min(max_image_extent.height),
@ -595,7 +597,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
return Ok(()); 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 let (src_texture, src_pending) = cmd_buf
.trackers .trackers
@ -607,16 +610,16 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
hal::TextureUse::COPY_SRC, hal::TextureUse::COPY_SRC,
) )
.unwrap(); .unwrap();
let &(ref src_raw, _) = src_texture let src_raw = src_texture
.raw .raw
.as_ref() .as_ref()
.ok_or(TransferError::InvalidTexture(source.texture))?; .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()); return Err(TransferError::MissingCopySrcUsageFlag.into());
} }
let src_barriers = src_pending.map(|pending| pending.into_hal(src_texture)); 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 .trackers
.buffers .buffers
.use_replace( .use_replace(
@ -626,7 +629,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
hal::BufferUse::COPY_DST, hal::BufferUse::COPY_DST,
) )
.map_err(TransferError::InvalidBuffer)?; .map_err(TransferError::InvalidBuffer)?;
let &(ref dst_raw, _) = dst_buffer let dst_raw = dst_buffer
.raw .raw
.as_ref() .as_ref()
.ok_or(TransferError::InvalidBuffer(destination.buffer))?; .ok_or(TransferError::InvalidBuffer(destination.buffer))?;
@ -635,19 +638,14 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
TransferError::MissingCopyDstUsageFlag(Some(destination.buffer), None).into(), 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 format_desc = src_texture.desc.format.describe();
let max_image_extent = validate_texture_copy_range( let max_image_extent =
source, validate_texture_copy_range(source, &src_texture.desc, CopySide::Source, copy_size)?;
src_texture.format,
src_texture.kind,
CopySide::Source,
copy_size,
)?;
let required_buffer_bytes_in_copy = validate_linear_texture_data( let required_buffer_bytes_in_copy = validate_linear_texture_data(
&destination.layout, &destination.layout,
src_texture.format, src_texture.desc.format,
dst_buffer.size, dst_buffer.size,
CopySide::Destination, CopySide::Destination,
format_desc.block_size as BufferAddress, format_desc.block_size as BufferAddress,
@ -655,9 +653,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
true, true,
)?; )?;
let (block_width, _) = src_texture.format.describe().block_dimensions; let (block_width, _) = format_desc.block_dimensions;
if !conv::is_valid_copy_src_texture_format(src_texture.format) { if !conv::is_valid_copy_src_texture_format(src_texture.desc.format) {
return Err(TransferError::CopyFromForbiddenTextureFormat(src_texture.format).into()); return Err(
TransferError::CopyFromForbiddenTextureFormat(src_texture.desc.format).into(),
);
} }
cmd_buf.buffer_memory_init_actions.extend( cmd_buf.buffer_memory_init_actions.extend(
@ -679,9 +679,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
// image extent data directly. We want the provided copy size to be no larger than // image extent data directly. We want the provided copy size to be no larger than
// the virtual size. // the virtual size.
let region = hal::BufferTextureCopy { let region = hal::BufferTextureCopy {
buffer_layout: &destination.layout, buffer_layout: destination.layout,
texture_mip_level: source.mip_level, texture_base: src_base,
texture_origin: source.origin,
size: Extent3d { size: Extent3d {
width: copy_size.width.min(max_image_extent.width), width: copy_size.width.min(max_image_extent.width),
height: copy_size.height.min(max_image_extent.height), height: copy_size.height.min(max_image_extent.height),
@ -733,9 +732,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
return Ok(()); return Ok(());
} }
let (src_range, _) = extract_image_range(source, copy_size, &*texture_guard)?; let (src_range, src_base, _) =
let (dst_range, _) = extract_image_range(destination, copy_size, &*texture_guard)?; extract_texture_selector(source, copy_size, &*texture_guard)?;
if src_range.aspects != dst_range.aspects { 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()); return Err(TransferError::MismatchedAspects.into());
} }
@ -749,11 +750,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
hal::TextureUse::COPY_SRC, hal::TextureUse::COPY_SRC,
) )
.unwrap(); .unwrap();
let &(ref src_raw, _) = src_texture let src_raw = src_texture
.raw .raw
.as_ref() .as_ref()
.ok_or(TransferError::InvalidTexture(source.texture))?; .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()); return Err(TransferError::MissingCopySrcUsageFlag.into());
} }
//TODO: try to avoid this the collection. It's needed because both //TODO: try to avoid this the collection. It's needed because both
@ -772,11 +773,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
hal::TextureUse::COPY_DST, hal::TextureUse::COPY_DST,
) )
.unwrap(); .unwrap();
let &(ref dst_raw, _) = dst_texture let dst_raw = dst_texture
.raw .raw
.as_ref() .as_ref()
.ok_or(TransferError::InvalidTexture(destination.texture))?; .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( return Err(
TransferError::MissingCopyDstUsageFlag(None, Some(destination.texture)).into(), TransferError::MissingCopyDstUsageFlag(None, Some(destination.texture)).into(),
); );
@ -797,10 +798,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
// image extent data directly. We want the provided copy size to be no larger than // image extent data directly. We want the provided copy size to be no larger than
// the virtual size. // the virtual size.
let region = hal::TextureCopy { let region = hal::TextureCopy {
src_subresource: src_range, src_base,
src_origin: source.origin, dst_base,
dst_subresource: dst_range,
dst_origin: destination.origin,
size: Extent3d { size: Extent3d {
width: copy_size width: copy_size
.width .width

View File

@ -55,7 +55,7 @@ pub fn map_buffer_usage(usage: wgt::BufferUsage) -> hal::BufferUse {
usage.contains(wgt::BufferUsage::UNIFORM), usage.contains(wgt::BufferUsage::UNIFORM),
); );
u.set( u.set(
hal::BufferUse::STORAGE, hal::BufferUse::STORAGE_LOAD | hal::BufferUse::STORAGE_STORE,
usage.contains(wgt::BufferUsage::STORAGE), usage.contains(wgt::BufferUsage::STORAGE),
); );
u.set( u.set(

View File

@ -5,12 +5,7 @@
#[cfg(feature = "trace")] #[cfg(feature = "trace")]
use crate::device::trace; use crate::device::trace;
use crate::{ use crate::{
device::{ device::{queue::TempResource, DeviceError},
alloc,
descriptor::{DescriptorAllocator, DescriptorSet},
queue::TempResource,
DeviceError,
},
hub::{GlobalIdentityHandlerFactory, HalApi, Hub, Token}, hub::{GlobalIdentityHandlerFactory, HalApi, Hub, Token},
id, resource, id, resource,
track::TrackerSet, track::TrackerSet,
@ -18,13 +13,13 @@ use crate::{
}; };
use copyless::VecHelper as _; use copyless::VecHelper as _;
use hal::device::Device as _; use hal::Device as _;
use parking_lot::Mutex; use parking_lot::Mutex;
use thiserror::Error; use thiserror::Error;
use std::sync::atomic::Ordering; 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. /// A struct that keeps lists of resources that are no longer needed by the user.
#[derive(Debug, Default)] #[derive(Debug, Default)]
@ -91,33 +86,31 @@ impl SuspectedResources {
/// A struct that keeps lists of resources that are no longer needed. /// A struct that keeps lists of resources that are no longer needed.
#[derive(Debug)] #[derive(Debug)]
struct NonReferencedResources<A: hal::Api> { struct NonReferencedResources<A: hal::Api> {
buffers: Vec<(B::Buffer, alloc::MemoryBlock<A>)>, buffers: Vec<A::Buffer>,
images: Vec<(B::Image, alloc::MemoryBlock<A>)>, textures: Vec<A::Texture>,
// Note: we keep the associated ID here in order to be able to check // Note: we keep the associated ID here in order to be able to check
// at any point what resources are used in a submission. // at any point what resources are used in a submission.
image_views: Vec<(id::Valid<id::TextureViewId>, B::ImageView)>, texture_views: Vec<(id::Valid<id::TextureViewId>, A::TextureView)>,
samplers: Vec<B::Sampler>, samplers: Vec<A::Sampler>,
framebuffers: Vec<B::Framebuffer>, bind_groups: Vec<A::BindGroup>,
desc_sets: Vec<DescriptorSet<A>>, compute_pipes: Vec<A::ComputePipeline>,
compute_pipes: Vec<B::ComputePipeline>, render_pipes: Vec<A::RenderPipeline>,
graphics_pipes: Vec<B::GraphicsPipeline>, bind_group_layouts: Vec<A::BindGroupLayout>,
descriptor_set_layouts: Vec<B::DescriptorSetLayout>, pipeline_layouts: Vec<A::PipelineLayout>,
pipeline_layouts: Vec<B::PipelineLayout>, query_sets: Vec<A::QuerySet>,
query_sets: Vec<B::QueryPool>,
} }
impl<A: hal::Api> NonReferencedResources<A> { impl<A: hal::Api> NonReferencedResources<A> {
fn new() -> Self { fn new() -> Self {
Self { Self {
buffers: Vec::new(), buffers: Vec::new(),
images: Vec::new(), textures: Vec::new(),
image_views: Vec::new(), texture_views: Vec::new(),
samplers: Vec::new(), samplers: Vec::new(),
framebuffers: Vec::new(), bind_groups: Vec::new(),
desc_sets: Vec::new(),
compute_pipes: Vec::new(), compute_pipes: Vec::new(),
graphics_pipes: Vec::new(), render_pipes: Vec::new(),
descriptor_set_layouts: Vec::new(), bind_group_layouts: Vec::new(),
pipeline_layouts: Vec::new(), pipeline_layouts: Vec::new(),
query_sets: Vec::new(), query_sets: Vec::new(),
} }
@ -125,76 +118,54 @@ impl<A: hal::Api> NonReferencedResources<A> {
fn extend(&mut self, other: Self) { fn extend(&mut self, other: Self) {
self.buffers.extend(other.buffers); self.buffers.extend(other.buffers);
self.images.extend(other.images); self.textures.extend(other.textures);
self.image_views.extend(other.image_views); self.texture_views.extend(other.texture_views);
self.samplers.extend(other.samplers); self.samplers.extend(other.samplers);
self.framebuffers.extend(other.framebuffers); self.bind_groups.extend(other.bind_groups);
self.desc_sets.extend(other.desc_sets);
self.compute_pipes.extend(other.compute_pipes); 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); 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()); assert!(other.pipeline_layouts.is_empty());
} }
unsafe fn clean( unsafe fn clean(&mut self, device: &A::Device) {
&mut self, for raw in self.buffers.drain(..) {
device: &B::Device, device.destroy_buffer(raw);
memory_allocator_mutex: &Mutex<alloc::MemoryAllocator<A>>,
descriptor_allocator_mutex: &Mutex<DescriptorAllocator<A>>,
) {
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);
}
} }
for raw in self.textures.drain(..) {
for (_, raw) in self.image_views.drain(..) { device.destroy_texture(raw);
device.destroy_image_view(raw); }
for (_, raw) in self.texture_views.drain(..) {
device.destroy_texture_view(raw);
} }
for raw in self.samplers.drain(..) { for raw in self.samplers.drain(..) {
device.destroy_sampler(raw); device.destroy_sampler(raw);
} }
for raw in self.framebuffers.drain(..) { for raw in self.bind_groups.drain(..) {
device.destroy_framebuffer(raw); device.destroy_bind_group(raw);
} }
if !self.desc_sets.is_empty() {
descriptor_allocator_mutex
.lock()
.free(device, self.desc_sets.drain(..));
}
for raw in self.compute_pipes.drain(..) { for raw in self.compute_pipes.drain(..) {
device.destroy_compute_pipeline(raw); device.destroy_compute_pipeline(raw);
} }
for raw in self.graphics_pipes.drain(..) { for raw in self.render_pipes.drain(..) {
device.destroy_graphics_pipeline(raw); device.destroy_render_pipeline(raw);
} }
for raw in self.descriptor_set_layouts.drain(..) { for raw in self.bind_group_layouts.drain(..) {
device.destroy_descriptor_set_layout(raw); device.destroy_bind_group_layout(raw);
} }
for raw in self.pipeline_layouts.drain(..) { for raw in self.pipeline_layouts.drain(..) {
device.destroy_pipeline_layout(raw); device.destroy_pipeline_layout(raw);
} }
for raw in self.query_sets.drain(..) { for raw in self.query_sets.drain(..) {
device.destroy_query_pool(raw); device.destroy_query_set(raw);
} }
} }
} }
#[derive(Debug)]
struct ActiveSubmission<A: hal::Api> { struct ActiveSubmission<A: hal::Api> {
index: SubmissionIndex, index: SubmissionIndex,
fence: B::Fence, fence: A::Fence,
last_resources: NonReferencedResources<A>, last_resources: NonReferencedResources<A>,
mapped: Vec<id::Valid<id::BufferId>>, mapped: Vec<id::Valid<id::BufferId>>,
} }
@ -215,7 +186,6 @@ pub enum WaitIdleError {
/// and register the buffer with either a submission in flight, or straight into `ready_to_map` vector. /// 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. /// 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. /// 4. Finally, `handle_mapping` issues all the callbacks.
#[derive(Debug)]
pub(super) struct LifetimeTracker<A: hal::Api> { pub(super) struct LifetimeTracker<A: hal::Api> {
/// Resources that the user has requested be mapped, but are still in use. /// Resources that the user has requested be mapped, but are still in use.
mapped: Vec<Stored<id::BufferId>>, mapped: Vec<Stored<id::BufferId>>,
@ -252,15 +222,15 @@ impl<A: hal::Api> LifetimeTracker<A> {
pub fn track_submission( pub fn track_submission(
&mut self, &mut self,
index: SubmissionIndex, index: SubmissionIndex,
fence: B::Fence, fence: A::Fence,
new_suspects: &SuspectedResources, new_suspects: &SuspectedResources,
temp_resources: impl Iterator<Item = (TempResource<A>, alloc::MemoryBlock<A>)>, temp_resources: impl Iterator<Item = TempResource<A>>,
) { ) {
let mut last_resources = NonReferencedResources::new(); let mut last_resources = NonReferencedResources::new();
for (res, memory) in temp_resources { for res in temp_resources {
match res { match res {
TempResource::Buffer(raw) => last_resources.buffers.push((raw, memory)), TempResource::Buffer(raw) => last_resources.buffers.push(raw),
TempResource::Image(raw) => last_resources.images.push((raw, memory)), TempResource::Texture(raw) => last_resources.textures.push(raw),
} }
} }
@ -288,20 +258,23 @@ impl<A: hal::Api> LifetimeTracker<A> {
self.mapped.push(Stored { value, ref_count }); 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() { if !self.active.is_empty() {
log::debug!("Waiting for IDLE..."); log::debug!("Waiting for IDLE...");
let status = unsafe { let mut status = true;
device //TODO: change this to wait for the last fence value only
.wait_for_fences( for a in self.active.iter() {
self.active.iter().map(|a| &a.fence), status &= unsafe {
hal::device::WaitFor::All, device
CLEANUP_WAIT_MS * 1_000_000, .wait(
) &a.fence,
.map_err(DeviceError::from)? a.index as u64, //TODO: check this
}; CLEANUP_WAIT_MS,
)
.map_err(DeviceError::from)?
};
}
log::debug!("...Done"); log::debug!("...Done");
if !status { if !status {
// We timed out while waiting for the fences // We timed out while waiting for the fences
return Err(WaitIdleError::StuckGpu); return Err(WaitIdleError::StuckGpu);
@ -313,10 +286,11 @@ impl<A: hal::Api> LifetimeTracker<A> {
/// Returns the last submission index that is done. /// Returns the last submission index that is done.
pub fn triage_submissions( pub fn triage_submissions(
&mut self, &mut self,
device: &B::Device, device: &A::Device,
force_wait: bool, force_wait: bool,
) -> Result<SubmissionIndex, WaitIdleError> { ) -> Result<SubmissionIndex, WaitIdleError> {
profiling::scope!("triage_submissions"); profiling::scope!("triage_submissions");
/* TODO: better sync
if force_wait { if force_wait {
self.wait_idle(device)?; self.wait_idle(device)?;
} }
@ -325,7 +299,7 @@ impl<A: hal::Api> LifetimeTracker<A> {
let done_count = self let done_count = self
.active .active
.iter() .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()); .unwrap_or_else(|| self.active.len());
let last_done = match done_count.checked_sub(1) { let last_done = match done_count.checked_sub(1) {
Some(i) => self.active[i].index, Some(i) => self.active[i].index,
@ -339,29 +313,22 @@ impl<A: hal::Api> LifetimeTracker<A> {
unsafe { unsafe {
device.destroy_fence(a.fence); device.destroy_fence(a.fence);
} }
} }*/
let last_done = 0;
Ok(last_done) Ok(last_done)
} }
pub fn cleanup( pub fn cleanup(&mut self, device: &A::Device) {
&mut self,
device: &B::Device,
memory_allocator_mutex: &Mutex<alloc::MemoryAllocator<A>>,
descriptor_allocator_mutex: &Mutex<DescriptorAllocator<A>>,
) {
profiling::scope!("cleanup"); profiling::scope!("cleanup");
unsafe { unsafe {
self.free_resources self.free_resources.clean(device);
.clean(device, memory_allocator_mutex, descriptor_allocator_mutex);
descriptor_allocator_mutex.lock().cleanup(device);
} }
} }
pub fn schedule_resource_destruction( pub fn schedule_resource_destruction(
&mut self, &mut self,
temp_resource: TempResource<A>, temp_resource: TempResource<A>,
memory: alloc::MemoryBlock<A>,
last_submit_index: SubmissionIndex, last_submit_index: SubmissionIndex,
) { ) {
let resources = self let resources = self
@ -370,8 +337,8 @@ impl<A: hal::Api> LifetimeTracker<A> {
.find(|a| a.index == last_submit_index) .find(|a| a.index == last_submit_index)
.map_or(&mut self.free_resources, |a| &mut a.last_resources); .map_or(&mut self.free_resources, |a| &mut a.last_resources);
match temp_resource { match temp_resource {
TempResource::Buffer(raw) => resources.buffers.push((raw, memory)), TempResource::Buffer(raw) => resources.buffers.push(raw),
TempResource::Image(raw) => resources.images.push((raw, memory)), TempResource::Texture(raw) => resources.textures.push(raw),
} }
} }
} }
@ -423,7 +390,7 @@ impl<A: HalApi> LifetimeTracker<A> {
.iter_mut() .iter_mut()
.find(|a| a.index == submit_index) .find(|a| a.index == submit_index)
.map_or(&mut self.free_resources, |a| &mut a.last_resources) .map_or(&mut self.free_resources, |a| &mut a.last_resources)
.desc_sets .bind_groups
.push(res.raw); .push(res.raw);
} }
} }
@ -442,12 +409,11 @@ impl<A: HalApi> LifetimeTracker<A> {
} }
if let Some(res) = hub.texture_views.unregister_locked(id.0, &mut *guard) { if let Some(res) = hub.texture_views.unregister_locked(id.0, &mut *guard) {
let raw = match res.inner { match res.source {
resource::TextureViewInner::Native { raw, source_id } => { resource::TextureViewSource::Native(source_id) => {
self.suspected_resources.textures.push(source_id.value); 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); let submit_index = res.life_guard.submission_index.load(Ordering::Acquire);
@ -455,8 +421,8 @@ impl<A: HalApi> LifetimeTracker<A> {
.iter_mut() .iter_mut()
.find(|a| a.index == submit_index) .find(|a| a.index == submit_index)
.map_or(&mut self.free_resources, |a| &mut a.last_resources) .map_or(&mut self.free_resources, |a| &mut a.last_resources)
.image_views .texture_views
.push((id, raw)); .push((id, res.raw));
} }
} }
} }
@ -479,7 +445,7 @@ impl<A: HalApi> LifetimeTracker<A> {
.iter_mut() .iter_mut()
.find(|a| a.index == submit_index) .find(|a| a.index == submit_index)
.map_or(&mut self.free_resources, |a| &mut a.last_resources) .map_or(&mut self.free_resources, |a| &mut a.last_resources)
.images .textures
.extend(res.raw); .extend(res.raw);
} }
} }
@ -524,15 +490,8 @@ impl<A: HalApi> LifetimeTracker<A> {
if let Some(res) = hub.buffers.unregister_locked(id.0, &mut *guard) { if let Some(res) = hub.buffers.unregister_locked(id.0, &mut *guard) {
let submit_index = res.life_guard.submission_index.load(Ordering::Acquire); let submit_index = res.life_guard.submission_index.load(Ordering::Acquire);
if let resource::BufferMapState::Init { if let resource::BufferMapState::Init { stage_buffer, .. } = res.map_state {
stage_buffer, self.free_resources.buffers.push(stage_buffer);
stage_memory,
..
} = res.map_state
{
self.free_resources
.buffers
.push((stage_buffer, stage_memory));
} }
self.active self.active
.iter_mut() .iter_mut()
@ -586,7 +545,7 @@ impl<A: HalApi> LifetimeTracker<A> {
.iter_mut() .iter_mut()
.find(|a| a.index == submit_index) .find(|a| a.index == submit_index)
.map_or(&mut self.free_resources, |a| &mut a.last_resources) .map_or(&mut self.free_resources, |a| &mut a.last_resources)
.graphics_pipes .render_pipes
.push(res.raw); .push(res.raw);
} }
} }
@ -632,7 +591,7 @@ impl<A: HalApi> LifetimeTracker<A> {
t.lock().add(trace::Action::DestroyBindGroupLayout(id.0)); t.lock().add(trace::Action::DestroyBindGroupLayout(id.0));
} }
if let Some(lay) = hub.bind_group_layouts.unregister_locked(id.0, &mut *guard) { 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<A: HalApi> LifetimeTracker<A> {
pub(super) fn handle_mapping<G: GlobalIdentityHandlerFactory>( pub(super) fn handle_mapping<G: GlobalIdentityHandlerFactory>(
&mut self, &mut self,
hub: &Hub<A, G>, hub: &Hub<A, G>,
raw: &B::Device, raw: &A::Device,
trackers: &Mutex<TrackerSet>, trackers: &Mutex<TrackerSet>,
token: &mut Token<super::Device<A>>, token: &mut Token<super::Device<A>>,
) -> Vec<super::BufferMapPendingCallback> { ) -> Vec<super::BufferMapPendingCallback> {
@ -740,10 +699,7 @@ impl<A: HalApi> LifetimeTracker<A> {
Ok(ptr) => { Ok(ptr) => {
buffer.map_state = resource::BufferMapState::Active { buffer.map_state = resource::BufferMapState::Active {
ptr, ptr,
sub_range: hal::buffer::SubRange { range: mapping.range.start..mapping.range.start + size,
offset: mapping.range.start,
size: Some(size),
},
host, host,
}; };
resource::BufferMapAsyncStatus::Success resource::BufferMapAsyncStatus::Success

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@
use crate::device::trace::Action; use crate::device::trace::Action;
use crate::{ use crate::{
command::{ 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, CommandBuffer, CopySide, ImageCopyTexture, TransferError,
}, },
conv, conv,
@ -26,6 +26,21 @@ use thiserror::Error;
struct StagingData<A: hal::Api> { struct StagingData<A: hal::Api> {
buffer: A::Buffer, buffer: A::Buffer,
cmdbuf: A::CommandBuffer, cmdbuf: A::CommandBuffer,
is_coherent: bool,
}
impl<A: hal::Api> StagingData<A> {
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)] #[derive(Debug)]
@ -64,7 +79,7 @@ impl<A: hal::Api> PendingWrites<A> {
device.destroy_buffer(buffer); device.destroy_buffer(buffer);
}, },
TempResource::Texture(texture) => unsafe { TempResource::Texture(texture) => unsafe {
device.destroy_image(texture); device.destroy_texture(texture);
}, },
} }
} }
@ -91,11 +106,11 @@ impl<A: hal::Api> PendingWrites<A> {
fn create_cmd_buf(device: &A::Device) -> A::CommandBuffer { fn create_cmd_buf(device: &A::Device) -> A::CommandBuffer {
unsafe { unsafe {
let mut cmd_buf = device.create_command_buffer(&hal::CommandBufferDescriptor { device
label: Some("_PendingWrites"), .create_command_buffer(&hal::CommandBufferDescriptor {
}); label: Some("_PendingWrites"),
cmd_buf.begin(); })
cmd_buf .unwrap()
} }
} }
@ -157,9 +172,13 @@ impl<A: hal::Api> super::Device<A> {
let cmdbuf = match self.pending_writes.command_buffer.take() { let cmdbuf = match self.pending_writes.command_buffer.take() {
Some(cmdbuf) => cmdbuf, Some(cmdbuf) => cmdbuf,
None => PendingWrites::create_cmd_buf(&self.raw), None => PendingWrites::<A>::create_cmd_buf(&self.raw),
}; };
Ok(StagingData { buffer, cmdbuf }) Ok(StagingData {
buffer,
cmdbuf,
is_coherent: true, //TODO
})
} }
fn initialize_buffer_memory( fn initialize_buffer_memory(
@ -171,7 +190,7 @@ impl<A: hal::Api> super::Device<A> {
.dst_buffers .dst_buffers
.extend(required_buffer_inits.map.keys()); .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(); let mut trackers = self.trackers.lock();
for (buffer_id, mut ranges) in required_buffer_inits.map.drain() { for (buffer_id, mut ranges) in required_buffer_inits.map.drain() {
@ -193,7 +212,7 @@ impl<A: hal::Api> super::Device<A> {
hal::BufferUse::COPY_DST, hal::BufferUse::COPY_DST,
); );
let buffer = buffer_guard.get(buffer_id).unwrap(); let buffer = buffer_guard.get(buffer_id).unwrap();
let &(ref buffer_raw, _) = buffer let raw_buf = buffer
.raw .raw
.as_ref() .as_ref()
.ok_or(QueueSubmitError::DestroyedBuffer(buffer_id))?; .ok_or(QueueSubmitError::DestroyedBuffer(buffer_id))?;
@ -202,11 +221,11 @@ impl<A: hal::Api> super::Device<A> {
} }
for range in ranges { 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.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 {})", buffer, range.end); assert!(range.end % 4 == 0, "Buffer {:?} has an uninitialized range with an end not aligned to 4 (end was {})", raw_buf, range.end);
unsafe { unsafe {
cmd_buf.fill_buffer(buffer_raw, range, 0); cmd_buf.fill_buffer(raw_buf, range, 0);
} }
} }
} }
@ -282,14 +301,14 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
} }
let mut stage = device.prepare_stage(data_size)?; 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 mut trackers = device.trackers.lock();
let (dst, transition) = trackers let (dst, transition) = trackers
.buffers .buffers
.use_replace(&*buffer_guard, buffer_id, (), hal::BufferUse::COPY_DST) .use_replace(&*buffer_guard, buffer_id, (), hal::BufferUse::COPY_DST)
.map_err(TransferError::InvalidBuffer)?; .map_err(TransferError::InvalidBuffer)?;
let &(ref dst_raw, _) = dst let dst_raw = dst
.raw .raw
.as_ref() .as_ref()
.ok_or(TransferError::InvalidBuffer(buffer_id))?; .ok_or(TransferError::InvalidBuffer(buffer_id))?;
@ -314,11 +333,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.into()); .into());
} }
let region = hal::BufferCopy { let region = wgt::BufferSize::new(data.len() as u64).map(|size| hal::BufferCopy {
src_offset: 0, src_offset: 0,
dst_offset: buffer_offset, dst_offset: buffer_offset,
size: data.len() as _, size,
}; });
let barriers = iter::once(hal::BufferBarrier { let barriers = iter::once(hal::BufferBarrier {
buffer: &stage.buffer, buffer: &stage.buffer,
usage: hal::BufferUse::MAP_WRITE..hal::BufferUse::COPY_SRC, usage: hal::BufferUse::MAP_WRITE..hal::BufferUse::COPY_SRC,
@ -328,7 +347,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
stage.cmdbuf.transition_buffers(barriers); stage.cmdbuf.transition_buffers(barriers);
stage stage
.cmdbuf .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); device.pending_writes.consume(stage);
@ -382,8 +401,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
} }
let (texture_guard, _) = hub.textures.read(&mut token); let (texture_guard, _) = hub.textures.read(&mut token);
let (image_range, texture_format) = let (selector, texture_base, texture_format) =
extract_image_range(destination, size, &*texture_guard)?; extract_texture_selector(destination, size, &*texture_guard)?;
let format_desc = texture_format.describe(); let format_desc = texture_format.describe();
validate_linear_texture_data( validate_linear_texture_data(
data_layout, data_layout,
@ -414,11 +433,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let block_rows_per_image = texel_rows_per_image / block_height; let block_rows_per_image = texel_rows_per_image / block_height;
let bytes_per_row_alignment = get_lowest_common_denom( let bytes_per_row_alignment = get_lowest_common_denom(
device.hal_limits.optimal_buffer_copy_pitch_alignment as u32, device.alignments.buffer_copy_pitch.get() as u32,
format_desc.block_size, format_desc.block_size as u32,
); );
let stage_bytes_per_row = align_to( 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, bytes_per_row_alignment,
); );
@ -433,39 +452,34 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.use_replace( .use_replace(
&*texture_guard, &*texture_guard,
destination.texture, destination.texture,
image_range, selector,
hal::TextureUse::COPY_DST, hal::TextureUse::COPY_DST,
) )
.unwrap(); .unwrap();
let &(ref dst_raw, _) = dst let dst_raw = dst
.raw .raw
.as_ref() .as_ref()
.ok_or(TransferError::InvalidTexture(destination.texture))?; .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( return Err(
TransferError::MissingCopyDstUsageFlag(None, Some(destination.texture)).into(), TransferError::MissingCopyDstUsageFlag(None, Some(destination.texture)).into(),
); );
} }
let max_image_extent = validate_texture_copy_range( let max_image_extent =
destination, validate_texture_copy_range(destination, &dst.desc, CopySide::Destination, size)?;
dst.format,
dst.kind,
CopySide::Destination,
size,
)?;
dst.life_guard.use_at(device.active_submission_index + 1); 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 { let bytes_per_row = if let Some(bytes_per_row) = data_layout.bytes_per_row {
bytes_per_row.get() bytes_per_row.get()
} else { } 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 { unsafe {
profiling::scope!("copy"); profiling::scope!("copy");
//TODO: https://github.com/zakarumych/gpu-alloc/issues/13
if stage_bytes_per_row == bytes_per_row { if stage_bytes_per_row == bytes_per_row {
// Fast path if the data isalready being aligned optimally. // Fast path if the data isalready being aligned optimally.
ptr::copy_nonoverlapping(data.as_ptr(), ptr.as_ptr(), stage_size as usize); ptr::copy_nonoverlapping(data.as_ptr(), ptr.as_ptr(), stage_size as usize);
@ -487,9 +501,14 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
} }
} }
} }
stage.memory.unmap(&device.raw); device
if !stage.memory.is_coherent() { .raw
stage.memory.flush_range(&device.raw, 0, None)?; .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 // WebGPU uses the physical size of the texture for copies whereas vulkan uses
@ -499,11 +518,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let region = hal::BufferTextureCopy { let region = hal::BufferTextureCopy {
buffer_layout: wgt::ImageDataLayout { buffer_layout: wgt::ImageDataLayout {
offset: 0, offset: 0,
bytes_per_row: stage_bytes_per_row, bytes_per_row: NonZeroU32::new(stage_bytes_per_row),
rows_per_image: texel_rows_per_image, rows_per_image: NonZeroU32::new(texel_rows_per_image),
}, },
texture_mip_level: destination.mip_level, texture_base,
texture_origin: destination.origin,
size: wgt::Extent3d { size: wgt::Extent3d {
width: size.width.min(max_image_extent.width), width: size.width.min(max_image_extent.width),
height: size.height.min(max_image_extent.height), height: size.height.min(max_image_extent.height),
@ -520,12 +538,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
stage stage
.cmdbuf .cmdbuf
.transition_textures(transition.map(|pending| pending.into_hal(dst))); .transition_textures(transition.map(|pending| pending.into_hal(dst)));
stage.cmdbuf.copy_buffer_to_image( stage
&stage.buffer, .cmdbuf
dst_raw, .copy_buffer_to_texture(&stage.buffer, dst_raw, iter::once(region));
hal::TextureUse::COPY_DST,
iter::once(region),
);
} }
device.pending_writes.consume(stage); device.pending_writes.consume(stage);
@ -607,7 +622,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
for sc_id in cmdbuf.used_swap_chains.drain(..) { for sc_id in cmdbuf.used_swap_chains.drain(..) {
let sc = &mut swap_chain_guard[sc_id.value]; 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); return Err(QueueSubmitError::SwapChainOutputDropped);
} }
if sc.active_submission_index != submit_index { if sc.active_submission_index != submit_index {
@ -621,13 +636,17 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
// update submission IDs // update submission IDs
for id in cmdbuf.trackers.buffers.used() { for id in cmdbuf.trackers.buffers.used() {
let buffer = &mut buffer_guard[id]; let buffer = &mut buffer_guard[id];
if buffer.raw.is_none() { let raw_buf = match buffer.raw {
return Err(QueueSubmitError::DestroyedBuffer(id.0)); Some(ref raw) => raw,
} None => {
return Err(QueueSubmitError::DestroyedBuffer(id.0));
}
};
if !buffer.life_guard.use_at(submit_index) { if !buffer.life_guard.use_at(submit_index) {
if let BufferMapState::Active { .. } = buffer.map_state { if let BufferMapState::Active { .. } = buffer.map_state {
log::warn!("Dropped buffer has a pending mapping."); 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); device.temp_suspected.buffers.push(id);
} else { } else {
@ -677,18 +696,17 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
} }
} }
// execute resource transitions
let mut transit =
device
.raw
.create_command_buffer(&hal::CommandBufferDescriptor {
label: Some("_Transit"),
});
unsafe { unsafe {
// the last buffer was open, closing now // the last buffer was open, closing now
cmdbuf.raw.last_mut().unwrap().end(); cmdbuf.raw.last_mut().unwrap().finish();
transit.begin();
} }
// 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); log::trace!("Stitching command buffer {:?} before submission", cmb_id);
trackers.merge_extend_stateless(&cmdbuf.trackers); trackers.merge_extend_stateless(&cmdbuf.trackers);
CommandBuffer::insert_barriers( CommandBuffer::insert_barriers(
@ -700,7 +718,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
&*texture_guard, &*texture_guard,
); );
unsafe { unsafe {
transit.end(); transit.finish();
} }
cmdbuf.raw.insert(0, transit); cmdbuf.raw.insert(0, transit);
} }
@ -714,42 +732,28 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
} }
// now prepare the GPU submission // now prepare the GPU submission
let mut fence = device let mut fence = device.raw.create_fence().map_err(DeviceError::from)?;
.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);
//Note: we could technically avoid the heap Vec here //Note: we could technically avoid the heap Vec here
let mut command_buffers = Vec::new(); 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() { for &cmd_buf_id in command_buffer_ids.iter() {
match command_buffer_guard.get(cmd_buf_id) { match command_buffer_guard.get(cmd_buf_id) {
Ok(cmd_buf) if cmd_buf.is_finished() => { 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 { unsafe {
device.queue_group.queues[0].submit( device
command_buffers.into_iter(), .queue
iter::empty(), .submit(command_buffers.into_iter(), Some((&mut fence, fence_value)));
signal_semaphores,
Some(&mut fence),
);
} }
fence 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) { let callbacks = match device.maintain(&hub, false, &mut token) {
Ok(callbacks) => callbacks, Ok(callbacks) => callbacks,
Err(WaitIdleError::Device(err)) => return Err(QueueSubmitError::Queue(err)), Err(WaitIdleError::Device(err)) => return Err(QueueSubmitError::Queue(err)),
@ -764,15 +768,6 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
device.pending_writes.temp_resources.drain(..), 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 callbacks
}; };
@ -791,7 +786,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let mut token = Token::root(); let mut token = Token::root();
let (device_guard, _) = hub.devices.read(&mut token); let (device_guard, _) = hub.devices.read(&mut token);
match device_guard.get(queue_id) { 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), Err(_) => Err(InvalidQueue),
} }
} }

View File

@ -6,14 +6,10 @@ use crate::{
binding_model::{BindGroup, BindGroupLayout, PipelineLayout}, binding_model::{BindGroup, BindGroupLayout, PipelineLayout},
command::{CommandBuffer, RenderBundle}, command::{CommandBuffer, RenderBundle},
device::Device, device::Device,
id::{ id,
AdapterId, BindGroupId, BindGroupLayoutId, BufferId, CommandBufferId, ComputePipelineId,
DeviceId, PipelineLayoutId, RenderBundleId, RenderPipelineId, SamplerId, ShaderModuleId,
SurfaceId, SwapChainId, TextureId, TextureViewId, TypedId, Valid,
},
instance::{Adapter, Instance, Surface}, instance::{Adapter, Instance, Surface},
pipeline::{ComputePipeline, RenderPipeline, ShaderModule}, pipeline::{ComputePipeline, RenderPipeline, ShaderModule},
resource::{Buffer, Sampler, Texture, TextureView}, resource::{Buffer, QuerySet, Sampler, Texture, TextureView},
swap_chain::SwapChain, swap_chain::SwapChain,
Epoch, Index, Epoch, Index,
}; };
@ -21,8 +17,6 @@ use crate::{
use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard}; use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};
use wgt::Backend; use wgt::Backend;
use crate::id::QuerySetId;
use crate::resource::QuerySet;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
use std::cell::Cell; use std::cell::Cell;
use std::{fmt::Debug, marker::PhantomData, ops}; use std::{fmt::Debug, marker::PhantomData, ops};
@ -51,7 +45,7 @@ impl IdentityManager {
} }
} }
pub fn alloc<I: TypedId>(&mut self, backend: Backend) -> I { pub fn alloc<I: id::TypedId>(&mut self, backend: Backend) -> I {
match self.free.pop() { match self.free.pop() {
Some(index) => I::zip(index, self.epochs[index as usize], backend), Some(index) => I::zip(index, self.epochs[index as usize], backend),
None => { None => {
@ -63,7 +57,7 @@ impl IdentityManager {
} }
} }
pub fn free<I: TypedId + Debug>(&mut self, id: I) { pub fn free<I: id::TypedId + Debug>(&mut self, id: I) {
let (index, epoch, _backend) = id.unzip(); let (index, epoch, _backend) = id.unzip();
// avoid doing this check in release // avoid doing this check in release
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
@ -87,26 +81,26 @@ enum Element<T> {
pub(crate) struct InvalidId; pub(crate) struct InvalidId;
#[derive(Debug)] #[derive(Debug)]
pub struct Storage<T, I: TypedId> { pub struct Storage<T, I: id::TypedId> {
map: Vec<Element<T>>, map: Vec<Element<T>>,
kind: &'static str, kind: &'static str,
_phantom: PhantomData<I>, _phantom: PhantomData<I>,
} }
impl<T, I: TypedId> ops::Index<Valid<I>> for Storage<T, I> { impl<T, I: id::TypedId> ops::Index<id::Valid<I>> for Storage<T, I> {
type Output = T; type Output = T;
fn index(&self, id: Valid<I>) -> &T { fn index(&self, id: id::Valid<I>) -> &T {
self.get(id.0).unwrap() self.get(id.0).unwrap()
} }
} }
impl<T, I: TypedId> ops::IndexMut<Valid<I>> for Storage<T, I> { impl<T, I: id::TypedId> ops::IndexMut<id::Valid<I>> for Storage<T, I> {
fn index_mut(&mut self, id: Valid<I>) -> &mut T { fn index_mut(&mut self, id: id::Valid<I>) -> &mut T {
self.get_mut(id.0).unwrap() self.get_mut(id.0).unwrap()
} }
} }
impl<T, I: TypedId> Storage<T, I> { impl<T, I: id::TypedId> Storage<T, I> {
pub(crate) fn contains(&self, id: I) -> bool { pub(crate) fn contains(&self, id: I) -> bool {
let (index, epoch, _) = id.unzip(); let (index, epoch, _) = id.unzip();
match self.map[index as usize] { match self.map[index as usize] {
@ -347,7 +341,7 @@ pub trait IdentityHandler<I>: Debug {
fn free(&self, id: I); fn free(&self, id: I);
} }
impl<I: TypedId + Debug> IdentityHandler<I> for Mutex<IdentityManager> { impl<I: id::TypedId + Debug> IdentityHandler<I> for Mutex<IdentityManager> {
type Input = PhantomData<I>; type Input = PhantomData<I>;
fn process(&self, _id: Self::Input, backend: Backend) -> I { fn process(&self, _id: Self::Input, backend: Backend) -> I {
self.lock().alloc(backend) self.lock().alloc(backend)
@ -365,7 +359,7 @@ pub trait IdentityHandlerFactory<I> {
#[derive(Debug)] #[derive(Debug)]
pub struct IdentityManagerFactory; pub struct IdentityManagerFactory;
impl<I: TypedId + Debug> IdentityHandlerFactory<I> for IdentityManagerFactory { impl<I: id::TypedId + Debug> IdentityHandlerFactory<I> for IdentityManagerFactory {
type Filter = Mutex<IdentityManager>; type Filter = Mutex<IdentityManager>;
fn spawn(&self, min_index: Index) -> Self::Filter { fn spawn(&self, min_index: Index) -> Self::Filter {
Mutex::new(IdentityManager::from_index(min_index)) Mutex::new(IdentityManager::from_index(min_index))
@ -373,23 +367,23 @@ impl<I: TypedId + Debug> IdentityHandlerFactory<I> for IdentityManagerFactory {
} }
pub trait GlobalIdentityHandlerFactory: pub trait GlobalIdentityHandlerFactory:
IdentityHandlerFactory<AdapterId> IdentityHandlerFactory<id::AdapterId>
+ IdentityHandlerFactory<DeviceId> + IdentityHandlerFactory<id::DeviceId>
+ IdentityHandlerFactory<SwapChainId> + IdentityHandlerFactory<id::SwapChainId>
+ IdentityHandlerFactory<PipelineLayoutId> + IdentityHandlerFactory<id::PipelineLayoutId>
+ IdentityHandlerFactory<ShaderModuleId> + IdentityHandlerFactory<id::ShaderModuleId>
+ IdentityHandlerFactory<BindGroupLayoutId> + IdentityHandlerFactory<id::BindGroupLayoutId>
+ IdentityHandlerFactory<BindGroupId> + IdentityHandlerFactory<id::BindGroupId>
+ IdentityHandlerFactory<CommandBufferId> + IdentityHandlerFactory<id::CommandBufferId>
+ IdentityHandlerFactory<RenderBundleId> + IdentityHandlerFactory<id::RenderBundleId>
+ IdentityHandlerFactory<RenderPipelineId> + IdentityHandlerFactory<id::RenderPipelineId>
+ IdentityHandlerFactory<ComputePipelineId> + IdentityHandlerFactory<id::ComputePipelineId>
+ IdentityHandlerFactory<QuerySetId> + IdentityHandlerFactory<id::QuerySetId>
+ IdentityHandlerFactory<BufferId> + IdentityHandlerFactory<id::BufferId>
+ IdentityHandlerFactory<TextureId> + IdentityHandlerFactory<id::TextureId>
+ IdentityHandlerFactory<TextureViewId> + IdentityHandlerFactory<id::TextureViewId>
+ IdentityHandlerFactory<SamplerId> + IdentityHandlerFactory<id::SamplerId>
+ IdentityHandlerFactory<SurfaceId> + IdentityHandlerFactory<id::SurfaceId>
{ {
} }
@ -409,13 +403,13 @@ pub trait Resource {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Registry<T: Resource, I: TypedId, F: IdentityHandlerFactory<I>> { pub struct Registry<T: Resource, I: id::TypedId, F: IdentityHandlerFactory<I>> {
identity: F::Filter, identity: F::Filter,
data: RwLock<Storage<T, I>>, data: RwLock<Storage<T, I>>,
backend: Backend, backend: Backend,
} }
impl<T: Resource, I: TypedId, F: IdentityHandlerFactory<I>> Registry<T, I, F> { impl<T: Resource, I: id::TypedId, F: IdentityHandlerFactory<I>> Registry<T, I, F> {
fn new(backend: Backend, factory: &F) -> Self { fn new(backend: Backend, factory: &F) -> Self {
Self { Self {
identity: factory.spawn(0), identity: factory.spawn(0),
@ -442,12 +436,12 @@ impl<T: Resource, I: TypedId, F: IdentityHandlerFactory<I>> Registry<T, I, F> {
} }
#[must_use] #[must_use]
pub(crate) struct FutureId<'a, I: TypedId, T> { pub(crate) struct FutureId<'a, I: id::TypedId, T> {
id: I, id: I,
data: &'a RwLock<Storage<T, I>>, data: &'a RwLock<Storage<T, I>>,
} }
impl<I: TypedId + Copy, T> FutureId<'_, I, T> { impl<I: id::TypedId + Copy, T> FutureId<'_, I, T> {
#[cfg(feature = "trace")] #[cfg(feature = "trace")]
pub fn id(&self) -> I { pub fn id(&self) -> I {
self.id self.id
@ -457,9 +451,9 @@ impl<I: TypedId + Copy, T> FutureId<'_, I, T> {
self.id self.id
} }
pub fn assign<'a, A: Access<T>>(self, value: T, _: &'a mut Token<A>) -> Valid<I> { pub fn assign<'a, A: Access<T>>(self, value: T, _: &'a mut Token<A>) -> id::Valid<I> {
self.data.write().insert(self.id, value); self.data.write().insert(self.id, value);
Valid(self.id) id::Valid(self.id)
} }
pub fn assign_error<'a, A: Access<T>>(self, label: &str, _: &'a mut Token<A>) -> I { pub fn assign_error<'a, A: Access<T>>(self, label: &str, _: &'a mut Token<A>) -> I {
@ -468,7 +462,7 @@ impl<I: TypedId + Copy, T> FutureId<'_, I, T> {
} }
} }
impl<T: Resource, I: TypedId + Copy, F: IdentityHandlerFactory<I>> Registry<T, I, F> { impl<T: Resource, I: id::TypedId + Copy, F: IdentityHandlerFactory<I>> Registry<T, I, F> {
pub(crate) fn prepare( pub(crate) fn prepare(
&self, &self,
id_in: <F::Filter as IdentityHandler<I>>::Input, id_in: <F::Filter as IdentityHandler<I>>::Input,
@ -535,24 +529,23 @@ impl<T: Resource, I: TypedId + Copy, F: IdentityHandlerFactory<I>> Registry<T, I
} }
} }
#[derive(Debug)]
pub struct Hub<A: hal::Api, F: GlobalIdentityHandlerFactory> { pub struct Hub<A: hal::Api, F: GlobalIdentityHandlerFactory> {
pub adapters: Registry<Adapter<A>, AdapterId, F>, pub adapters: Registry<Adapter<A>, id::AdapterId, F>,
pub devices: Registry<Device<A>, DeviceId, F>, pub devices: Registry<Device<A>, id::DeviceId, F>,
pub swap_chains: Registry<SwapChain<A>, SwapChainId, F>, pub swap_chains: Registry<SwapChain<A>, id::SwapChainId, F>,
pub pipeline_layouts: Registry<PipelineLayout<A>, PipelineLayoutId, F>, pub pipeline_layouts: Registry<PipelineLayout<A>, id::PipelineLayoutId, F>,
pub shader_modules: Registry<ShaderModule<A>, ShaderModuleId, F>, pub shader_modules: Registry<ShaderModule<A>, id::ShaderModuleId, F>,
pub bind_group_layouts: Registry<BindGroupLayout<A>, BindGroupLayoutId, F>, pub bind_group_layouts: Registry<BindGroupLayout<A>, id::BindGroupLayoutId, F>,
pub bind_groups: Registry<BindGroup<A>, BindGroupId, F>, pub bind_groups: Registry<BindGroup<A>, id::BindGroupId, F>,
pub command_buffers: Registry<CommandBuffer<A>, CommandBufferId, F>, pub command_buffers: Registry<CommandBuffer<A>, id::CommandBufferId, F>,
pub render_bundles: Registry<RenderBundle, RenderBundleId, F>, pub render_bundles: Registry<RenderBundle, id::RenderBundleId, F>,
pub render_pipelines: Registry<RenderPipeline<A>, RenderPipelineId, F>, pub render_pipelines: Registry<RenderPipeline<A>, id::RenderPipelineId, F>,
pub compute_pipelines: Registry<ComputePipeline<A>, ComputePipelineId, F>, pub compute_pipelines: Registry<ComputePipeline<A>, id::ComputePipelineId, F>,
pub query_sets: Registry<QuerySet<A>, QuerySetId, F>, pub query_sets: Registry<QuerySet<A>, id::QuerySetId, F>,
pub buffers: Registry<Buffer<A>, BufferId, F>, pub buffers: Registry<Buffer<A>, id::BufferId, F>,
pub textures: Registry<Texture<A>, TextureId, F>, pub textures: Registry<Texture<A>, id::TextureId, F>,
pub texture_views: Registry<TextureView<A>, TextureViewId, F>, pub texture_views: Registry<TextureView<A>, id::TextureViewId, F>,
pub samplers: Registry<Sampler<A>, SamplerId, F>, pub samplers: Registry<Sampler<A>, id::SamplerId, F>,
} }
impl<A: HalApi, F: GlobalIdentityHandlerFactory> Hub<A, F> { impl<A: HalApi, F: GlobalIdentityHandlerFactory> Hub<A, F> {
@ -582,9 +575,9 @@ impl<A: HalApi, F: GlobalIdentityHandlerFactory> Hub<A, F> {
//TODO: instead of having a hacky `with_adapters` parameter, //TODO: instead of having a hacky `with_adapters` parameter,
// we should have `clear_device(device_id)` that specifically destroys // we should have `clear_device(device_id)` that specifically destroys
// everything related to a logical device. // everything related to a logical device.
fn clear(&self, surface_guard: &mut Storage<Surface, SurfaceId>, with_adapters: bool) { fn clear(&self, surface_guard: &mut Storage<Surface, id::SurfaceId>, with_adapters: bool) {
use crate::resource::TextureViewInner; use crate::resource::TextureViewSource;
use hal::Device as _; use hal::{Device as _, Surface as _};
let mut devices = self.devices.data.write(); let mut devices = self.devices.data.write();
for element in devices.map.iter_mut() { for element in devices.map.iter_mut() {
@ -606,14 +599,14 @@ impl<A: HalApi, F: GlobalIdentityHandlerFactory> Hub<A, F> {
let textures = self.textures.data.read(); let textures = self.textures.data.read();
for element in self.texture_views.data.write().map.drain(..) { for element in self.texture_views.data.write().map.drain(..) {
if let Element::Occupied(texture_view, _) = element { if let Element::Occupied(texture_view, _) = element {
match texture_view.inner { match texture_view.source {
TextureViewInner::Native { raw, source_id } => { TextureViewSource::Native(source_id) => {
let device = &devices[textures[source_id.value].device_id.value]; let device = &devices[textures[source_id.value].device_id.value];
unsafe { 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<A: HalApi, F: GlobalIdentityHandlerFactory> Hub<A, F> {
for element in self.command_buffers.data.write().map.drain(..) { for element in self.command_buffers.data.write().map.drain(..) {
if let Element::Occupied(command_buffer, _) = element { if let Element::Occupied(command_buffer, _) = element {
let device = &devices[command_buffer.device_id.value]; let device = &devices[command_buffer.device_id.value];
device for raw in command_buffer.raw {
.cmd_allocator device.raw.destroy_command_buffer(raw);
.after_submit(command_buffer, &device.raw, 0); }
} }
} }
for element in self.bind_groups.data.write().map.drain(..) { for element in self.bind_groups.data.write().map.drain(..) {
if let Element::Occupied(bind_group, _) = element { if let Element::Occupied(bind_group, _) = element {
let device = &devices[bind_group.device_id.value]; 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<A: HalApi, F: GlobalIdentityHandlerFactory> Hub<A, F> {
if let Element::Occupied(bgl, _) = element { if let Element::Occupied(bgl, _) = element {
let device = &devices[bgl.device_id.value]; let device = &devices[bgl.device_id.value];
unsafe { unsafe {
device.raw.destroy_descriptor_set_layout(bgl.raw); device.raw.destroy_bind_group_layout(bgl.raw);
} }
} }
} }
@ -681,7 +674,7 @@ impl<A: HalApi, F: GlobalIdentityHandlerFactory> Hub<A, F> {
if let Element::Occupied(pipeline, _) = element { if let Element::Occupied(pipeline, _) = element {
let device = &devices[pipeline.device_id.value]; let device = &devices[pipeline.device_id.value];
unsafe { unsafe {
device.raw.destroy_graphics_pipeline(pipeline.raw); device.raw.destroy_render_pipeline(pipeline.raw);
} }
} }
} }
@ -689,16 +682,13 @@ impl<A: HalApi, F: GlobalIdentityHandlerFactory> Hub<A, F> {
for (index, element) in self.swap_chains.data.write().map.drain(..).enumerate() { for (index, element) in self.swap_chains.data.write().map.drain(..).enumerate() {
if let Element::Occupied(swap_chain, epoch) = element { if let Element::Occupied(swap_chain, epoch) = element {
let device = &devices[swap_chain.device_id.value]; let device = &devices[swap_chain.device_id.value];
unsafe { let suf_id = id::TypedId::zip(index as Index, epoch, A::VARIANT);
device.raw.destroy_semaphore(swap_chain.semaphore);
}
let suf_id = TypedId::zip(index as Index, epoch, A::VARIANT);
//TODO: hold the surface alive by the swapchain //TODO: hold the surface alive by the swapchain
if surface_guard.contains(suf_id) { if surface_guard.contains(suf_id) {
let surface = surface_guard.get_mut(suf_id).unwrap(); let surface = surface_guard.get_mut(suf_id).unwrap();
let suf = A::get_surface_mut(surface); let suf = A::get_surface_mut(surface);
unsafe { unsafe {
suf.unconfigure_swapchain(&device.raw); suf.unconfigure(&device.raw);
} }
} }
} }
@ -708,7 +698,7 @@ impl<A: HalApi, F: GlobalIdentityHandlerFactory> Hub<A, F> {
if let Element::Occupied(query_set, _) = element { if let Element::Occupied(query_set, _) = element {
let device = &devices[query_set.device_id.value]; let device = &devices[query_set.device_id.value];
unsafe { unsafe {
device.raw.destroy_query_pool(query_set.raw); device.raw.destroy_query_set(query_set.raw);
} }
} }
} }
@ -727,16 +717,18 @@ impl<A: HalApi, F: GlobalIdentityHandlerFactory> Hub<A, F> {
#[derive(Debug)] #[derive(Debug)]
pub struct Hubs<F: GlobalIdentityHandlerFactory> { pub struct Hubs<F: GlobalIdentityHandlerFactory> {
/* /*
#[cfg(vulkan)] #[cfg(vulkan)]
vulkan: Hub<backend::Vulkan, F>, vulkan: Hub<backend::Vulkan, F>,
#[cfg(metal)] #[cfg(metal)]
metal: Hub<backend::Metal, F>, metal: Hub<backend::Metal, F>,
#[cfg(dx12)] #[cfg(dx12)]
dx12: Hub<backend::Dx12, F>, dx12: Hub<backend::Dx12, F>,
#[cfg(dx11)] #[cfg(dx11)]
dx11: Hub<backend::Dx11, F>, dx11: Hub<backend::Dx11, F>,
#[cfg(gl)] #[cfg(gl)]
gl: Hub<backend::Gl, F>,*/} gl: Hub<backend::Gl, F>,*/
marker: PhantomData<F>,
}
impl<F: GlobalIdentityHandlerFactory> Hubs<F> { impl<F: GlobalIdentityHandlerFactory> Hubs<F> {
fn new(factory: &F) -> Self { fn new(factory: &F) -> Self {
@ -753,6 +745,7 @@ impl<F: GlobalIdentityHandlerFactory> Hubs<F> {
#[cfg(gl)] #[cfg(gl)]
gl: Hub::new(factory), gl: Hub::new(factory),
*/ */
marker: PhantomData,
} }
} }
} }
@ -760,7 +753,7 @@ impl<F: GlobalIdentityHandlerFactory> Hubs<F> {
#[derive(Debug)] #[derive(Debug)]
pub struct Global<G: GlobalIdentityHandlerFactory> { pub struct Global<G: GlobalIdentityHandlerFactory> {
pub instance: Instance, pub instance: Instance,
pub surfaces: Registry<Surface, SurfaceId, G>, pub surfaces: Registry<Surface, id::SurfaceId, G>,
hubs: Hubs<G>, hubs: Hubs<G>,
} }

View File

@ -113,7 +113,6 @@ impl crate::hub::Resource for Surface {
} }
} }
#[derive(Debug)]
pub struct Adapter<A: hal::Api> { pub struct Adapter<A: hal::Api> {
pub(crate) raw: hal::ExposedAdapter<A>, pub(crate) raw: hal::ExposedAdapter<A>,
life_guard: LifeGuard, life_guard: LifeGuard,
@ -141,11 +140,16 @@ impl<A: HalApi> Adapter<A> {
wgt::TextureFormat::Rgba8Unorm, 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 preferred_formats
.iter() .iter()
.cloned() .cloned()
.find(|preferred| formats.contains(preferred)) .find(|preferred| caps.formats.contains(preferred))
.ok_or(GetSwapChainPreferredFormatError::NotFound) .ok_or(GetSwapChainPreferredFormatError::NotFound)
} }
@ -204,7 +208,8 @@ impl<A: HalApi> Adapter<A> {
)); ));
} }
if !self.downlevel.is_webgpu_compliant() { let caps = &self.raw.capabilities;
if !caps.downlevel.is_webgpu_compliant() {
log::warn!("{}", DOWNLEVEL_WARNING_MESSAGE); log::warn!("{}", DOWNLEVEL_WARNING_MESSAGE);
} }
@ -218,15 +223,14 @@ impl<A: HalApi> Adapter<A> {
} }
let gpu = unsafe { self.raw.adapter.open(desc.features) }.map_err(|err| match err { let gpu = unsafe { self.raw.adapter.open(desc.features) }.map_err(|err| match err {
hal::Error::DeviceLost => RequestDeviceError::DeviceLost, hal::DeviceError::Lost => RequestDeviceError::DeviceLost,
hal::Error::OutOfMemory => RequestDeviceError::OutOfMemory, hal::DeviceError::OutOfMemory => RequestDeviceError::OutOfMemory,
})?; })?;
if let Some(_) = desc.label { if let Some(_) = desc.label {
//TODO //TODO
} }
let caps = &self.raw.capabilities;
assert_eq!( assert_eq!(
0, 0,
BIND_BUFFER_ALIGNMENT % caps.alignments.storage_buffer_offset, BIND_BUFFER_ALIGNMENT % caps.alignments.storage_buffer_offset,
@ -237,7 +241,7 @@ impl<A: HalApi> Adapter<A> {
BIND_BUFFER_ALIGNMENT % caps.alignments.uniform_buffer_offset, BIND_BUFFER_ALIGNMENT % caps.alignments.uniform_buffer_offset,
"Adapter uniform buffer offset alignment not compatible with WGPU" "Adapter uniform buffer offset alignment not compatible with WGPU"
); );
if self.raw.limits < desc.limits { if caps.limits < desc.limits {
return Err(RequestDeviceError::LimitsExceeded); return Err(RequestDeviceError::LimitsExceeded);
} }
@ -375,11 +379,12 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
profiling::scope!("create_surface_metal", "Instance"); profiling::scope!("create_surface_metal", "Instance");
let surface = Surface { let surface = Surface {
/*
metal: self.instance.metal.as_ref().map(|inst| { metal: self.instance.metal.as_ref().map(|inst| {
// we don't want to link to metal-rs for this // we don't want to link to metal-rs for this
#[allow(clippy::transmute_ptr_to_ref)] #[allow(clippy::transmute_ptr_to_ref)]
inst.create_surface_from_layer(unsafe { std::mem::transmute(layer) }) inst.create_surface_from_layer(unsafe { std::mem::transmute(layer) })
}), }),*/
}; };
let mut token = Token::root(); let mut token = Token::root();
@ -630,7 +635,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let (adapter_guard, _) = hub.adapters.read(&mut token); let (adapter_guard, _) = hub.adapters.read(&mut token);
adapter_guard adapter_guard
.get(adapter_id) .get(adapter_id)
.map(|adapter| adapter.features) .map(|adapter| adapter.raw.features)
.map_err(|_| InvalidAdapter) .map_err(|_| InvalidAdapter)
} }
@ -643,7 +648,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let (adapter_guard, _) = hub.adapters.read(&mut token); let (adapter_guard, _) = hub.adapters.read(&mut token);
adapter_guard adapter_guard
.get(adapter_id) .get(adapter_id)
.map(|adapter| adapter.limits.clone()) .map(|adapter| adapter.raw.capabilities.limits.clone())
.map_err(|_| InvalidAdapter) .map_err(|_| InvalidAdapter)
} }
@ -656,7 +661,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let (adapter_guard, _) = hub.adapters.read(&mut token); let (adapter_guard, _) = hub.adapters.read(&mut token);
adapter_guard adapter_guard
.get(adapter_id) .get(adapter_id)
.map(|adapter| adapter.raw.downlevel) .map(|adapter| adapter.raw.capabilities.downlevel)
.map_err(|_| InvalidAdapter) .map_err(|_| InvalidAdapter)
} }

View File

@ -78,18 +78,15 @@ pub type RawString = *const c_char;
pub type Label<'a> = Option<Cow<'a, str>>; pub type Label<'a> = Option<Cow<'a, str>>;
trait LabelHelpers<'a> { 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; fn borrow_or_default(&'a self) -> &'a str;
} }
impl<'a> LabelHelpers<'a> for Label<'a> { impl<'a> LabelHelpers<'a> for Label<'a> {
fn borrow_or_default(&'a self) -> &'a str { fn borrow_option(&'a self) -> Option<&'a str> {
self.as_ref().map(|cow| cow.as_ref()).unwrap_or("") self.as_ref().map(|cow| cow.as_ref())
} }
fn to_string_or_default(&'a self) -> String { fn borrow_or_default(&'a self) -> &'a str {
self.as_ref() self.borrow_option().unwrap_or_default()
.map(|cow| cow.as_ref())
.unwrap_or("")
.to_string()
} }
} }

View File

@ -15,7 +15,7 @@ use thiserror::Error;
pub enum ShaderModuleSource<'a> { pub enum ShaderModuleSource<'a> {
SpirV(Cow<'a, [u32]>), SpirV(Cow<'a, [u32]>),
Wgsl(Cow<'a, str>), Wgsl(Cow<'a, str>),
Naga(&'a naga::Module), Naga(naga::Module),
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -23,15 +23,13 @@ pub enum ShaderModuleSource<'a> {
#[cfg_attr(feature = "replay", derive(serde::Deserialize))] #[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct ShaderModuleDescriptor<'a> { pub struct ShaderModuleDescriptor<'a> {
pub label: Label<'a>, pub label: Label<'a>,
#[cfg_attr(any(feature = "replay", feature = "trace"), serde(default))]
pub flags: wgt::ShaderFlags,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct ShaderModule<A: hal::Api> { pub struct ShaderModule<A: hal::Api> {
pub(crate) raw: A::ShaderModule, pub(crate) raw: A::ShaderModule,
pub(crate) device_id: Stored<DeviceId>, pub(crate) device_id: Stored<DeviceId>,
pub(crate) interface: Option<validation::Interface>, pub(crate) interface: validation::Interface,
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
pub(crate) label: String, pub(crate) label: String,
} }
@ -53,7 +51,7 @@ impl<A: hal::Api> Resource for ShaderModule<A> {
#[derive(Clone, Debug, Error)] #[derive(Clone, Debug, Error)]
pub enum CreateShaderModuleError { pub enum CreateShaderModuleError {
#[error("Failed to parse WGSL")] #[error("Failed to parse a shader")]
Parsing, Parsing,
#[error("Failed to generate the backend-specific code")] #[error("Failed to generate the backend-specific code")]
Generation, Generation,

View File

@ -242,15 +242,9 @@ pub struct TextureViewDescriptor<'a> {
} }
#[derive(Debug)] #[derive(Debug)]
pub(crate) enum TextureViewInner<A: hal::Api> { pub(crate) enum TextureViewSource {
Native { Native(Stored<TextureId>),
raw: A::TextureView, SwapChain(Stored<SwapChainId>),
source_id: Stored<TextureId>,
},
SwapChain {
raw: A::SurfaceTexture,
source_id: Stored<SwapChainId>,
},
} }
#[derive(Debug)] #[derive(Debug)]
@ -260,9 +254,16 @@ pub(crate) struct HalTextureViewDescriptor {
pub range: wgt::ImageSubresourceRange, 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)] #[derive(Debug)]
pub struct TextureView<A: hal::Api> { pub struct TextureView<A: hal::Api> {
pub(crate) inner: TextureViewInner<A>, pub(crate) raw: A::TextureView,
pub(crate) source: TextureViewSource,
//TODO: store device_id for quick access? //TODO: store device_id for quick access?
pub(crate) desc: HalTextureViewDescriptor, pub(crate) desc: HalTextureViewDescriptor,
pub(crate) format_features: wgt::TextureFormatFeatures, pub(crate) format_features: wgt::TextureFormatFeatures,
@ -280,30 +281,35 @@ pub enum CreateTextureViewError {
InvalidTexture, InvalidTexture,
#[error("not enough memory left")] #[error("not enough memory left")]
OutOfMemory, OutOfMemory,
#[error("Invalid texture view dimension `{view:?}` with texture of dimension `{image:?}`")] #[error("Invalid texture view dimension `{view:?}` with texture of dimension `{texture:?}`")]
InvalidTextureViewDimension { InvalidTextureViewDimension {
view: wgt::TextureViewDimension, 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.")] #[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.")] #[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( #[error(
"TextureView mip level count + base mip level {requested} must be <= Texture mip level count {total}" "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}")] #[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:?}")] #[error("Requested array layer count {requested} is not valid for the target view dimension {dim:?}")]
InvalidArrayLayerCount { InvalidArrayLayerCount {
requested: u32, requested: u32,
dim: wgt::TextureViewDimension, 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 { InvalidAspect {
requested: hal::FormatAspect, texture_format: wgt::TextureFormat,
total: hal::FormatAspect, 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<A: hal::Api> {
pub(crate) raw: A::QuerySet, pub(crate) raw: A::QuerySet,
pub(crate) device_id: Stored<DeviceId>, pub(crate) device_id: Stored<DeviceId>,
pub(crate) life_guard: LifeGuard, pub(crate) life_guard: LifeGuard,
/// Amount of queries in the query set.
pub(crate) desc: wgt::QuerySetDescriptor, 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<A: hal::Api> Resource for QuerySet<A> { impl<A: hal::Api> Resource for QuerySet<A> {

View File

@ -35,7 +35,6 @@
#[cfg(feature = "trace")] #[cfg(feature = "trace")]
use crate::device::trace::Action; use crate::device::trace::Action;
use crate::{ use crate::{
conv,
device::DeviceError, device::DeviceError,
hub::{Global, GlobalIdentityHandlerFactory, HalApi, Input, Token}, hub::{Global, GlobalIdentityHandlerFactory, HalApi, Input, Token},
id::{DeviceId, SwapChainId, TextureViewId, Valid}, id::{DeviceId, SwapChainId, TextureViewId, Valid},
@ -44,23 +43,23 @@ use crate::{
LifeGuard, Stored, SubmissionIndex, 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 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; pub const DESIRED_NUM_FRAMES: u32 = 3;
#[derive(Debug)] #[derive(Debug)]
pub struct SwapChain<A: hal::Api> { pub struct SwapChain<A: hal::Api> {
pub(crate) life_guard: LifeGuard, pub(crate) life_guard: LifeGuard,
pub(crate) device_id: Stored<DeviceId>, pub(crate) device_id: Stored<DeviceId>,
pub(crate) desc: SwapChainDescriptor, pub(crate) desc: wgt::SwapChainDescriptor,
pub(crate) num_frames: hal::window::SwapImageIndex, pub(crate) num_frames: u32,
pub(crate) semaphore: B::Semaphore, pub(crate) acquired_texture: Option<(Stored<TextureViewId>, A::SurfaceTexture)>,
pub(crate) acquired_view_id: Option<Stored<TextureViewId>>,
pub(crate) active_submission_index: SubmissionIndex, pub(crate) active_submission_index: SubmissionIndex,
pub(crate) framebuffer_attachment: hal::image::FramebufferAttachment, pub(crate) marker: PhantomData<A>,
} }
impl<A: hal::Api> crate::hub::Resource for SwapChain<A> { impl<A: hal::Api> crate::hub::Resource for SwapChain<A> {
@ -99,37 +98,17 @@ pub enum CreateSwapChainError {
UnsupportedQueueFamily, UnsupportedQueueFamily,
#[error("requested format {requested:?} is not in list of supported formats: {available:?}")] #[error("requested format {requested:?} is not in list of supported formats: {available:?}")]
UnsupportedFormat { UnsupportedFormat {
requested: hal::format::Format, requested: wgt::TextureFormat,
available: Vec<hal::format::Format>, available: Vec<wgt::TextureFormat>,
}, },
} #[error("requested usage is not supported")]
UnsupportedUsage,
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
} }
#[repr(C)] #[repr(C)]
#[derive(Debug)] #[derive(Debug)]
pub struct SwapChainOutput { pub struct SwapChainOutput {
pub status: SwapChainStatus, pub status: Status,
pub view_id: Option<TextureViewId>, pub view_id: Option<TextureViewId>,
} }
@ -155,7 +134,6 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.get_mut(swap_chain_id) .get_mut(swap_chain_id)
.map_err(|_| SwapChainError::Invalid)?; .map_err(|_| SwapChainError::Invalid)?;
#[allow(unused_variables)]
let device = &device_guard[sc.device_id.value]; let device = &device_guard[sc.device_id.value];
#[cfg(feature = "trace")] #[cfg(feature = "trace")]
if let Some(ref trace) = device.trace { if let Some(ref trace) = device.trace {
@ -165,51 +143,64 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}); });
} }
let suf = B::get_surface_mut(surface); let suf = A::get_surface_mut(surface);
let (image, status) = match unsafe { suf.acquire_image(FRAME_TIMEOUT_MS * 1_000_000) } { let (texture, status) = match unsafe { suf.acquire_texture(FRAME_TIMEOUT_MS) } {
Ok((surface_image, None)) => (Some(surface_image), SwapChainStatus::Good), Ok(Some(ast)) => {
Ok((surface_image, Some(_))) => (Some(surface_image), SwapChainStatus::Suboptimal), let status = if ast.suboptimal {
Status::Suboptimal
} else {
Status::Good
};
(Some(ast.texture), status)
}
Ok(None) => (None, Status::Timeout),
Err(err) => ( Err(err) => (
None, None,
match err { match err {
hal::window::AcquireError::OutOfMemory(_) => { hal::SurfaceError::Lost => Status::Lost,
return Err(DeviceError::OutOfMemory.into()) hal::SurfaceError::Device(err) => {
} return Err(DeviceError::from(err).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::Outdated => Status::Outdated,
}, },
), ),
}; };
let view_id = match image { let hal_desc = hal::TextureViewDescriptor {
Some(image) => { 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 { let view = resource::TextureView {
inner: resource::TextureViewInner::SwapChain { raw,
image, source: resource::TextureViewSource::SwapChain(Stored {
source_id: Stored { value: Valid(swap_chain_id),
value: Valid(swap_chain_id), ref_count: sc.life_guard.add_ref(),
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 { format_features: wgt::TextureFormatFeatures {
allowed_usages: wgt::TextureUsage::RENDER_ATTACHMENT, allowed_usages: wgt::TextureUsage::RENDER_ATTACHMENT,
flags: wgt::TextureFormatFeatureFlags::empty(), flags: wgt::TextureFormatFeatureFlags::empty(),
filterable: false, filterable: false,
}, },
dimension: wgt::TextureViewDimension::D2,
extent: wgt::Extent3d { extent: wgt::Extent3d {
width: sc.desc.width, width: sc.desc.width,
height: sc.desc.height, height: sc.desc.height,
depth_or_array_layers: 1, depth_or_array_layers: 1,
}, },
samples: 1, samples: 1,
framebuffer_attachment: sc.framebuffer_attachment.clone(),
sampled_internal_use: hal::TextureUse::empty(), sampled_internal_use: hal::TextureUse::empty(),
selector: TextureSelector { selector: TextureSelector {
layers: 0..1, layers: 0..1,
@ -221,14 +212,17 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let ref_count = view.life_guard.add_ref(); let ref_count = view.life_guard.add_ref();
let id = fid.assign(view, &mut token); let id = fid.assign(view, &mut token);
if sc.acquired_view_id.is_some() { if sc.acquired_texture.is_some() {
return Err(SwapChainError::AlreadyAcquired); return Err(SwapChainError::AlreadyAcquired);
} }
sc.acquired_view_id = Some(Stored { sc.acquired_texture = Some((
value: id, Stored {
ref_count, value: id,
}); ref_count,
},
suf_texture,
));
Some(id.0) Some(id.0)
} }
@ -241,7 +235,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn swap_chain_present<A: HalApi>( pub fn swap_chain_present<A: HalApi>(
&self, &self,
swap_chain_id: SwapChainId, swap_chain_id: SwapChainId,
) -> Result<SwapChainStatus, SwapChainError> { ) -> Result<Status, SwapChainError> {
profiling::scope!("present", "SwapChain"); profiling::scope!("present", "SwapChain");
let hub = A::hub(self); let hub = A::hub(self);
@ -263,44 +257,33 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
trace.lock().add(Action::PresentSwapChain(swap_chain_id)); trace.lock().add(Action::PresentSwapChain(swap_chain_id));
} }
let view = { let suf_texture = {
let view_id = sc let (view_id, suf_texture) = sc
.acquired_view_id .acquired_texture
.take() .take()
.ok_or(SwapChainError::AlreadyAcquired)?; .ok_or(SwapChainError::AlreadyAcquired)?;
let (view_maybe, _) = hub.texture_views.unregister(view_id.value.0, &mut token); let (view_maybe, _) = hub.texture_views.unregister(view_id.value.0, &mut token);
view_maybe.ok_or(SwapChainError::Invalid)? let view = view_maybe.ok_or(SwapChainError::Invalid)?;
}; if view.life_guard.ref_count.unwrap().load() != 1 {
if view.life_guard.ref_count.unwrap().load() != 1 { return Err(SwapChainError::StillReferenced);
return Err(SwapChainError::StillReferenced); }
} suf_texture
let image = match view.inner {
resource::TextureViewInner::Native { .. } => unreachable!(),
resource::TextureViewInner::SwapChain { image, .. } => image,
}; };
let sem = if sc.active_submission_index > device.last_completed_submission_index() { let result = unsafe {
Some(&mut sc.semaphore) device
} else { .queue
None .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"); log::debug!("Presented. End of Frame");
match result { match result {
Ok(None) => Ok(SwapChainStatus::Good), Ok(()) => Ok(Status::Good),
Ok(Some(_)) => Ok(SwapChainStatus::Suboptimal),
Err(err) => match err { Err(err) => match err {
hal::window::PresentError::OutOfMemory(_) => { hal::SurfaceError::Lost => Ok(Status::Lost),
Err(SwapChainError::Device(DeviceError::OutOfMemory)) hal::SurfaceError::Device(err) => Err(SwapChainError::from(DeviceError::from(err))),
} hal::SurfaceError::Outdated => Ok(Status::Outdated),
hal::window::PresentError::OutOfDate(_) => Ok(SwapChainStatus::Outdated),
hal::window::PresentError::SurfaceLost(_) => Ok(SwapChainStatus::Lost),
hal::window::PresentError::DeviceLost(_) => {
Err(SwapChainError::Device(DeviceError::Lost))
}
}, },
} }
} }

View File

@ -12,7 +12,9 @@ use crate::{
resource, Epoch, FastHashMap, Index, RefCount, 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; use thiserror::Error;
pub(crate) use buffer::BufferState; pub(crate) use buffer::BufferState;
@ -131,7 +133,7 @@ impl PendingTransition<BufferState> {
buf: &'a resource::Buffer<A>, buf: &'a resource::Buffer<A>,
) -> hal::BufferBarrier<'a, A> { ) -> hal::BufferBarrier<'a, A> {
log::trace!("\tbuffer -> {:?}", self); 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 { hal::BufferBarrier {
buffer, buffer,
usage: self.usage, usage: self.usage,
@ -155,10 +157,20 @@ impl PendingTransition<TextureState> {
tex: &'a resource::Texture<A>, tex: &'a resource::Texture<A>,
) -> hal::TextureBarrier<'a, A> { ) -> hal::TextureBarrier<'a, A> {
log::trace!("\ttexture -> {:?}", self); 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 { hal::TextureBarrier {
texture, 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, usage: self.usage,
} }
} }
@ -168,8 +180,8 @@ impl From<PendingTransition<TextureState>> for UsageConflict {
fn from(e: PendingTransition<TextureState>) -> Self { fn from(e: PendingTransition<TextureState>) -> Self {
Self::Texture { Self::Texture {
id: e.id.0, id: e.id.0,
mip_levels: e.selector.levels.start as u32..e.selector.levels.end as u32, mip_levels: e.selector.levels.start..e.selector.levels.end,
array_layers: e.selector.layers.start as u32..e.selector.layers.end as u32, array_layers: e.selector.layers.start..e.selector.layers.end,
combined_use: e.usage.end, combined_use: e.usage.end,
} }
} }

View File

@ -3,28 +3,26 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use super::{range::RangedStates, PendingTransition, ResourceState, Unit}; use super::{range::RangedStates, PendingTransition, ResourceState, Unit};
use crate::{ use crate::id::{TextureId, Valid};
device::MAX_MIP_LEVELS,
id::{TextureId, Valid},
};
use hal::TextureUse; use hal::TextureUse;
use arrayvec::ArrayVec; use arrayvec::ArrayVec;
use std::{iter, ops::Range}; use std::{iter, ops::Range};
type PlaneStates = RangedStates<hal::ArrayLayer, Unit<TextureUse>>; type PlaneStates = RangedStates<u32, Unit<TextureUse>>;
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct TextureSelector { pub struct TextureSelector {
//TODO: rename to `mip_levels` and `array_layers` for consistency
//pub aspects: hal::FormatAspect, //pub aspects: hal::FormatAspect,
pub levels: Range<hal::MipLevel>, pub levels: Range<u32>,
pub layers: Range<hal::ArrayLayer>, pub layers: Range<u32>,
} }
#[derive(Clone, Debug, Default, PartialEq)] #[derive(Clone, Debug, Default, PartialEq)]
pub(crate) struct TextureState { 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 /// True if we have the information about all the subresources here
full: bool, full: bool,
} }
@ -43,7 +41,7 @@ impl PendingTransition<TextureState> {
} }
impl TextureState { 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 { Self {
mips: iter::repeat_with(|| { mips: iter::repeat_with(|| {
PlaneStates::from_range(0..array_layer_count, Unit::new(TextureUse::UNINITIALIZED)) PlaneStates::from_range(0..array_layer_count, Unit::new(TextureUse::UNINITIALIZED))
@ -103,7 +101,7 @@ impl ResourceState for TextureState {
.iter_mut() .iter_mut()
.enumerate() .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)); let layers = mip.isolate(&selector.layers, Unit::new(usage));
for &mut (ref range, ref mut unit) in layers { for &mut (ref range, ref mut unit) in layers {
if unit.last == usage && TextureUse::ORDERED.contains(usage) { if unit.last == usage && TextureUse::ORDERED.contains(usage) {
@ -153,7 +151,7 @@ impl ResourceState for TextureState {
.iter_mut() .iter_mut()
.enumerate() .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)); let layers = mip.isolate(&selector.layers, Unit::new(usage));
for &mut (ref range, ref mut unit) in layers { for &mut (ref range, ref mut unit) in layers {
match unit.first { 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() { 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)); temp.extend(mip_self.merge(mip_other, 0));
mip_self.clear(); mip_self.clear();
@ -374,7 +372,7 @@ mod test {
2..3, 2..3,
Unit { Unit {
first: Some(TextureUse::COPY_SRC), 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), ts1.mips[0].query(&(2..3), |&v| v),
Some(Ok(Unit { Some(Ok(Unit {
first: Some(TextureUse::SAMPLED), first: Some(TextureUse::SAMPLED),
last: TextureUse::ATTACHMENT_WRITE, last: TextureUse::COLOR_TARGET,
})), })),
"wrong final layer 2 state" "wrong final layer 2 state"
); );
@ -424,7 +422,7 @@ mod test {
ts2.mips[0] = PlaneStates::from_slice(&[( ts2.mips[0] = PlaneStates::from_slice(&[(
2..3, 2..3,
Unit { Unit {
first: Some(TextureUse::ATTACHMENT_WRITE), first: Some(TextureUse::COLOR_TARGET),
last: TextureUse::COPY_SRC, last: TextureUse::COPY_SRC,
}, },
)]); )]);

View File

@ -1,5 +1,7 @@
#![allow(unused_variables)] #![allow(unused_variables)]
use std::ops::Range;
#[derive(Clone)] #[derive(Clone)]
pub struct Api; pub struct Api;
pub struct Context; pub struct Context;
@ -17,15 +19,14 @@ impl crate::Api for Api {
type Device = Context; type Device = Context;
type CommandBuffer = Encoder; type CommandBuffer = Encoder;
type RenderPass = Encoder;
type ComputePass = Encoder;
type Buffer = Resource; type Buffer = Resource;
type QuerySet = Resource;
type Texture = Resource; type Texture = Resource;
type SurfaceTexture = Resource; type SurfaceTexture = Resource;
type TextureView = Resource; type TextureView = Resource;
type Sampler = Resource; type Sampler = Resource;
type QuerySet = Resource;
type Fence = Resource;
type BindGroupLayout = Resource; type BindGroupLayout = Resource;
type BindGroup = Resource; type BindGroup = Resource;
@ -55,9 +56,10 @@ impl crate::Surface<Api> for Context {
unsafe fn acquire_texture( unsafe fn acquire_texture(
&mut self, &mut self,
timeout_ms: u32, timeout_ms: u32,
) -> Result<(Resource, Option<crate::Suboptimal>), crate::SurfaceError> { ) -> Result<Option<crate::AcquiredSurfaceTexture<Api>>, crate::SurfaceError> {
Ok((Resource, None)) Ok(None)
} }
unsafe fn discard_texture(&mut self, texture: Resource) {}
} }
impl crate::Adapter<Api> for Context { impl crate::Adapter<Api> for Context {
@ -77,7 +79,19 @@ impl crate::Adapter<Api> for Context {
} }
impl crate::Queue<Api> for Context { impl crate::Queue<Api> for Context {
unsafe fn submit<I>(&mut self, command_buffers: I) {} unsafe fn submit<I>(
&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<Api> for Context { impl crate::Device<Api> for Context {
@ -92,7 +106,9 @@ impl crate::Device<Api> for Context {
) -> DeviceResult<std::ptr::NonNull<u8>> { ) -> DeviceResult<std::ptr::NonNull<u8>> {
Err(crate::DeviceError::Lost) 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<I>(&self, buffer: &Resource, ranges: I) {} unsafe fn flush_mapped_ranges<I>(&self, buffer: &Resource, ranges: I) {}
unsafe fn invalidate_mapped_ranges<I>(&self, buffer: &Resource, ranges: I) {} unsafe fn invalidate_mapped_ranges<I>(&self, buffer: &Resource, ranges: I) {}
@ -165,11 +181,35 @@ impl crate::Device<Api> for Context {
Ok(Resource) Ok(Resource)
} }
unsafe fn destroy_compute_pipeline(&self, pipeline: Resource) {} unsafe fn destroy_compute_pipeline(&self, pipeline: Resource) {}
unsafe fn create_query_set(&self, desc: &wgt::QuerySetDescriptor) -> DeviceResult<Resource> {
Ok(Resource)
}
unsafe fn destroy_query_set(&self, set: Resource) {}
unsafe fn create_fence(&self) -> DeviceResult<Resource> {
Ok(Resource)
}
unsafe fn destroy_fence(&self, fence: Resource) {}
unsafe fn get_fence_value(&self, fence: &Resource) -> DeviceResult<crate::FenceValue> {
Ok(0)
}
unsafe fn wait(
&self,
fence: &Resource,
value: crate::FenceValue,
timeout_ms: u32,
) -> DeviceResult<bool> {
Ok(true)
}
unsafe fn start_capture(&self) -> bool {
false
}
unsafe fn stop_capture(&self) {}
} }
impl crate::CommandBuffer<Api> for Encoder { impl crate::CommandBuffer<Api> for Encoder {
unsafe fn begin(&mut self) {} unsafe fn finish(&mut self) {}
unsafe fn end(&mut self) {}
unsafe fn transition_buffers<'a, T>(&mut self, barriers: T) unsafe fn transition_buffers<'a, T>(&mut self, barriers: T)
where where
@ -213,20 +253,46 @@ impl crate::CommandBuffer<Api> for Encoder {
) { ) {
} }
unsafe fn begin_render_pass(&mut self) -> Encoder { unsafe fn begin_query(&mut self, set: &Resource, index: u32) {}
Encoder 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<u32>) {}
unsafe fn copy_query_results(
&mut self,
set: &Resource,
range: Range<u32>,
buffer: &Resource,
offset: wgt::BufferAddress,
) {
} }
unsafe fn end_render_pass(&mut self, pass: Encoder) {}
unsafe fn begin_compute_pass(&mut self) -> Encoder { unsafe fn begin_render_pass(&mut self, desc: &crate::RenderPassDescriptor<Api>) {}
Encoder 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 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<Api> for Encoder { unsafe fn insert_debug_marker(&mut self, label: &str) {}
unsafe fn set_pipeline(&mut self, pipeline: &Resource) {} 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>( unsafe fn set_index_buffer<'a>(
&mut self, &mut self,
@ -236,10 +302,10 @@ impl crate::RenderPass<Api> for Encoder {
} }
unsafe fn set_vertex_buffer<'a>(&mut self, index: u32, binding: crate::BufferBinding<'a, Api>) { 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<f32>) {} unsafe fn set_viewport(&mut self, rect: &crate::Rect<f32>, depth_range: Range<f32>) {}
unsafe fn set_scissor_rect(&mut self, rect: &crate::Rect) {} unsafe fn set_scissor_rect(&mut self, rect: &crate::Rect<u32>) {}
unsafe fn set_stencil_reference(&mut self, value: u32) {} 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( unsafe fn draw(
&mut self, &mut self,
@ -272,12 +338,26 @@ impl crate::RenderPass<Api> for Encoder {
draw_count: u32, draw_count: u32,
) { ) {
} }
} 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,
) {
}
impl crate::ComputePass<Api> for Encoder { unsafe fn set_compute_pipeline(&mut self, pipeline: &Resource) {}
unsafe fn set_pipeline(&mut self, pipeline: &Resource) {}
unsafe fn set_bind_group(&mut self, layout: &Resource, index: u32, group: &Resource) {}
unsafe fn dispatch(&mut self, count: [u32; 3]) {} unsafe fn dispatch(&mut self, count: [u32; 3]) {}
unsafe fn dispatch_indirect(&mut self, buffer: &Resource, offset: wgt::BufferAddress) {} unsafe fn dispatch_indirect(&mut self, buffer: &Resource, offset: wgt::BufferAddress) {}

View File

@ -11,6 +11,8 @@
* - Mapping is persistent, with explicit synchronization. * - Mapping is persistent, with explicit synchronization.
* - Resource transitions are explicit. * - Resource transitions are explicit.
* - All layouts are explicit. Binding model has compatibility. * - All layouts are explicit. Binding model has compatibility.
*
* General design direction: follow 2/3 major target APIs.
*/ */
#![allow( #![allow(
@ -50,11 +52,13 @@ use thiserror::Error;
pub const MAX_ANISOTROPY: u8 = 16; pub const MAX_ANISOTROPY: u8 = 16;
pub const MAX_BIND_GROUPS: usize = 8; 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 Label<'a> = Option<&'a str>;
pub type MemoryRange = Range<wgt::BufferAddress>; pub type MemoryRange = Range<wgt::BufferAddress>;
pub type MipLevel = u8; pub type FenceValue = u64;
pub type ArrayLayer = u16;
#[derive(Clone, Debug, PartialEq, Error)] #[derive(Clone, Debug, PartialEq, Error)]
pub enum DeviceError { pub enum DeviceError {
@ -84,35 +88,29 @@ pub enum PipelineError {
pub enum SurfaceError { pub enum SurfaceError {
#[error("surface is lost")] #[error("surface is lost")]
Lost, Lost,
#[error("surface is outdated, needs to be re-created")]
Outdated,
#[error(transparent)] #[error(transparent)]
Device(#[from] DeviceError), Device(#[from] DeviceError),
#[error("other reason: {0}")] #[error("other reason: {0}")]
Other(&'static str), 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 { pub trait Api: Clone + Sized {
type Instance: Instance<Self>; type Instance: Instance<Self>;
type Surface: Surface<Self>; type Surface: Surface<Self>;
type Adapter: Adapter<Self>; type Adapter: Adapter<Self>;
type Device: Device<Self>; type Device: Device<Self>;
type Queue: Queue<Self>; type Queue: Queue<Self>;
type CommandBuffer: CommandBuffer<Self>; type CommandBuffer: CommandBuffer<Self>;
type RenderPass: RenderPass<Self>;
type ComputePass: ComputePass<Self>;
type Buffer: fmt::Debug + Send + Sync + 'static; type Buffer: fmt::Debug + Send + Sync + 'static;
type QuerySet: fmt::Debug + Send + Sync;
type Texture: fmt::Debug + Send + Sync + 'static; type Texture: fmt::Debug + Send + Sync + 'static;
type SurfaceTexture: fmt::Debug + Send + Sync + Borrow<Self::Texture>; type SurfaceTexture: fmt::Debug + Send + Sync + Borrow<Self::Texture>;
type TextureView: fmt::Debug + Send + Sync; type TextureView: fmt::Debug + Send + Sync;
type Sampler: 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 BindGroupLayout;
type BindGroup: fmt::Debug + Send + Sync; type BindGroup: fmt::Debug + Send + Sync;
@ -135,10 +133,12 @@ pub trait Surface<A: Api> {
unsafe fn unconfigure(&mut self, device: &A::Device); unsafe fn unconfigure(&mut self, device: &A::Device);
/// Returns `None` on timing out.
unsafe fn acquire_texture( unsafe fn acquire_texture(
&mut self, &mut self,
timeout_ms: u32, timeout_ms: u32,
) -> Result<(A::SurfaceTexture, Option<Suboptimal>), SurfaceError>; ) -> Result<Option<AcquiredSurfaceTexture<A>>, SurfaceError>;
unsafe fn discard_texture(&mut self, texture: A::SurfaceTexture);
} }
pub trait Adapter<A: Api> { pub trait Adapter<A: Api> {
@ -168,7 +168,7 @@ pub trait Device<A: Api> {
buffer: &A::Buffer, buffer: &A::Buffer,
range: MemoryRange, range: MemoryRange,
) -> Result<NonNull<u8>, DeviceError>; ) -> Result<NonNull<u8>, DeviceError>;
unsafe fn unmap_buffer(&self, buffer: &A::Buffer); unsafe fn unmap_buffer(&self, buffer: &A::Buffer) -> Result<(), DeviceError>;
unsafe fn flush_mapped_ranges<I: Iterator<Item = MemoryRange>>( unsafe fn flush_mapped_ranges<I: Iterator<Item = MemoryRange>>(
&self, &self,
buffer: &A::Buffer, buffer: &A::Buffer,
@ -233,17 +233,43 @@ pub trait Device<A: Api> {
desc: &ComputePipelineDescriptor<A>, desc: &ComputePipelineDescriptor<A>,
) -> Result<A::ComputePipeline, PipelineError>; ) -> Result<A::ComputePipeline, PipelineError>;
unsafe fn destroy_compute_pipeline(&self, pipeline: A::ComputePipeline); unsafe fn destroy_compute_pipeline(&self, pipeline: A::ComputePipeline);
unsafe fn create_query_set(
&self,
desc: &wgt::QuerySetDescriptor,
) -> Result<A::QuerySet, DeviceError>;
unsafe fn destroy_query_set(&self, set: A::QuerySet);
unsafe fn create_fence(&self) -> Result<A::Fence, DeviceError>;
unsafe fn destroy_fence(&self, fence: A::Fence);
unsafe fn get_fence_value(&self, fence: &A::Fence) -> Result<FenceValue, DeviceError>;
unsafe fn wait(
&self,
fence: &A::Fence,
value: FenceValue,
timeout_ms: u32,
) -> Result<bool, DeviceError>;
unsafe fn start_capture(&self) -> bool;
unsafe fn stop_capture(&self);
} }
pub trait Queue<A: Api> { pub trait Queue<A: Api> {
unsafe fn submit<I: Iterator<Item = A::CommandBuffer>>(&mut self, command_buffers: I); unsafe fn submit<I: Iterator<Item = A::CommandBuffer>>(
&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<A: Api> {} pub trait SwapChain<A: Api> {}
pub trait CommandBuffer<A: Api> { pub trait CommandBuffer<A: Api> {
unsafe fn begin(&mut self); unsafe fn finish(&mut self);
unsafe fn end(&mut self);
unsafe fn transition_buffers<'a, T>(&mut self, barriers: T) unsafe fn transition_buffers<'a, T>(&mut self, barriers: T)
where where
@ -253,6 +279,8 @@ pub trait CommandBuffer<A: Api> {
where where
T: Iterator<Item = TextureBarrier<'a, A>>; T: Iterator<Item = TextureBarrier<'a, A>>;
// copy operations
unsafe fn fill_buffer(&mut self, buffer: &A::Buffer, range: MemoryRange, value: u8); unsafe fn fill_buffer(&mut self, buffer: &A::Buffer, range: MemoryRange, value: u8);
unsafe fn copy_buffer_to_buffer<T>(&mut self, src: &A::Buffer, dst: &A::Buffer, regions: T) unsafe fn copy_buffer_to_buffer<T>(&mut self, src: &A::Buffer, dst: &A::Buffer, regions: T)
@ -283,14 +311,7 @@ pub trait CommandBuffer<A: Api> {
) where ) where
T: Iterator<Item = BufferTextureCopy>; T: Iterator<Item = BufferTextureCopy>;
unsafe fn begin_render_pass(&mut self) -> A::RenderPass; // pass common
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<A: Api> {
unsafe fn set_pipeline(&mut self, pipeline: &A::RenderPipeline);
/// Sets the bind group at `index` to `group`, assuming the layout /// Sets the bind group at `index` to `group`, assuming the layout
/// of all the preceeding groups to be taken from `layout`. /// of all the preceeding groups to be taken from `layout`.
@ -299,18 +320,53 @@ pub trait RenderPass<A: Api> {
layout: &A::PipelineLayout, layout: &A::PipelineLayout,
index: u32, index: u32,
group: &A::BindGroup, 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<u32>);
unsafe fn copy_query_results(
&mut self,
set: &A::QuerySet,
range: Range<u32>,
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<A>);
unsafe fn end_render_pass(&mut self);
unsafe fn set_render_pipeline(&mut self, pipeline: &A::RenderPipeline);
unsafe fn set_index_buffer<'a>( unsafe fn set_index_buffer<'a>(
&mut self, &mut self,
binding: BufferBinding<'a, A>, binding: BufferBinding<'a, A>,
format: wgt::IndexFormat, format: wgt::IndexFormat,
); );
unsafe fn set_vertex_buffer<'a>(&mut self, index: u32, binding: BufferBinding<'a, A>); 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<f32>); unsafe fn set_viewport(&mut self, rect: &Rect<f32>, depth_range: Range<f32>);
unsafe fn set_scissor_rect(&mut self, rect: &Rect); unsafe fn set_scissor_rect(&mut self, rect: &Rect<u32>);
unsafe fn set_stencil_reference(&mut self, value: u32); 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( unsafe fn draw(
&mut self, &mut self,
@ -339,19 +395,30 @@ pub trait RenderPass<A: Api> {
offset: wgt::BufferAddress, offset: wgt::BufferAddress,
draw_count: u32, draw_count: u32,
); );
} unsafe fn draw_indirect_count(
pub trait ComputePass<A: Api> {
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(
&mut self, &mut self,
layout: &A::PipelineLayout, buffer: &A::Buffer,
index: u32, offset: wgt::BufferAddress,
group: &A::BindGroup, 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(&mut self, count: [u32; 3]);
unsafe fn dispatch_indirect(&mut self, buffer: &A::Buffer, offset: wgt::BufferAddress); 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! { bitflags::bitflags! {
/// Similar to `wgt::BufferUsage` but for internal use. /// Similar to `wgt::BufferUsage` but for internal use.
pub struct BufferUse: u32 { pub struct BufferUse: u32 {
@ -472,7 +546,7 @@ bitflags::bitflags! {
} }
} }
#[derive(Debug)] #[derive(Clone, Debug)]
pub struct Alignments { pub struct Alignments {
/// The alignment of the start of the buffer used as a GPU copy source. /// The alignment of the start of the buffer used as a GPU copy source.
pub buffer_copy_offset: wgt::BufferSize, pub buffer_copy_offset: wgt::BufferSize,
@ -483,7 +557,7 @@ pub struct Alignments {
pub uniform_buffer_offset: wgt::BufferSize, pub uniform_buffer_offset: wgt::BufferSize,
} }
#[derive(Debug)] #[derive(Clone, Debug)]
pub struct Capabilities { pub struct Capabilities {
pub limits: wgt::Limits, pub limits: wgt::Limits,
pub alignments: Alignments, pub alignments: Alignments,
@ -505,7 +579,7 @@ pub struct SurfaceCapabilities {
/// List of supported texture formats. /// List of supported texture formats.
/// ///
/// Must be at least one. /// Must be at least one.
pub texture_formats: Vec<wgt::TextureFormat>, pub formats: Vec<wgt::TextureFormat>,
/// Range for the swap chain sizes. /// Range for the swap chain sizes.
/// ///
@ -524,12 +598,12 @@ pub struct SurfaceCapabilities {
/// Supported texture usage flags. /// Supported texture usage flags.
/// ///
/// Must have at least `TextureUse::COLOR_TARGET` /// Must have at least `TextureUse::COLOR_TARGET`
pub texture_uses: TextureUse, pub usage: TextureUse,
/// List of supported V-sync modes. /// List of supported V-sync modes.
/// ///
/// Must be at least one. /// Must be at least one.
pub vsync_modes: Vec<VsyncMode>, pub present_modes: Vec<wgt::PresentMode>,
/// List of supported alpha composition modes. /// List of supported alpha composition modes.
/// ///
@ -537,6 +611,15 @@ pub struct SurfaceCapabilities {
pub composite_alpha_modes: Vec<CompositeAlphaMode>, pub composite_alpha_modes: Vec<CompositeAlphaMode>,
} }
#[derive(Debug)]
pub struct AcquiredSurfaceTexture<A: Api> {
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)] #[derive(Debug)]
pub struct OpenDevice<A: Api> { pub struct OpenDevice<A: Api> {
pub device: A::Device, pub device: A::Device,
@ -721,24 +804,11 @@ pub struct RenderPipelineDescriptor<'a, A: Api> {
/// The multi-sampling properties of the pipeline. /// The multi-sampling properties of the pipeline.
pub multisample: wgt::MultisampleState, pub multisample: wgt::MultisampleState,
/// The fragment stage for this pipeline. /// The fragment stage for this pipeline.
pub fragment_stage: ProgrammableStage<'a, A>, pub fragment_stage: Option<ProgrammableStage<'a, A>>,
/// The effect of draw calls on the color aspect of the output target. /// The effect of draw calls on the color aspect of the output target.
pub color_targets: Cow<'a, [wgt::ColorTargetState]>, 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) /// Specifies how the alpha channel of the textures should be handled during (martin mouv i step)
/// compositing. /// compositing.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -766,7 +836,7 @@ pub struct SurfaceConfiguration {
/// `SurfaceCapabilities::swap_chain_size` range. /// `SurfaceCapabilities::swap_chain_size` range.
pub swap_chain_size: u32, pub swap_chain_size: u32,
/// Vertical synchronization mode. /// Vertical synchronization mode.
pub vsync_mode: VsyncMode, pub present_mode: wgt::PresentMode,
/// Alpha composition mode. /// Alpha composition mode.
pub composite_alpha_mode: CompositeAlphaMode, pub composite_alpha_mode: CompositeAlphaMode,
/// Format of the surface textures. /// Format of the surface textures.
@ -779,11 +849,11 @@ pub struct SurfaceConfiguration {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Rect { pub struct Rect<T> {
pub x: f32, pub x: T,
pub y: f32, pub y: T,
pub w: f32, pub w: T,
pub h: f32, pub h: T,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -795,7 +865,7 @@ pub struct BufferBarrier<'a, A: Api> {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct TextureBarrier<'a, A: Api> { pub struct TextureBarrier<'a, A: Api> {
pub texture: &'a A::Texture, pub texture: &'a A::Texture,
pub subresource: wgt::ImageSubresourceRange, pub range: wgt::ImageSubresourceRange,
pub usage: Range<TextureUse>, pub usage: Range<TextureUse>,
} }
@ -806,23 +876,85 @@ pub struct BufferCopy {
pub size: wgt::BufferSize, pub size: wgt::BufferSize,
} }
#[derive(Clone, Debug)]
pub struct TextureCopyBase {
pub origin: wgt::Origin3d,
pub mip_level: u32,
pub aspect: FormatAspect,
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct TextureCopy { pub struct TextureCopy {
pub src_subresource: wgt::ImageSubresourceRange, pub src_base: TextureCopyBase,
pub src_origin: wgt::Origin3d, pub dst_base: TextureCopyBase,
pub dst_subresource: wgt::ImageSubresourceRange,
pub dst_origin: wgt::Origin3d,
pub size: wgt::Extent3d, pub size: wgt::Extent3d,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct BufferTextureCopy { pub struct BufferTextureCopy {
pub buffer_layout: wgt::ImageDataLayout, pub buffer_layout: wgt::ImageDataLayout,
pub texture_mip_level: u32, pub texture_base: TextureCopyBase,
pub texture_origin: wgt::Origin3d,
pub size: wgt::Extent3d, 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<TextureUse>,
}
// Rust gets confused about the impl requirements for `A`
impl<A: Api> 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<Attachment<'a, A>>,
pub ops: AttachmentOp,
pub clear_value: wgt::Color,
}
// Rust gets confused about the impl requirements for `A`
impl<A: Api> 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<DepthStencilAttachment<'a, A>>,
}
#[test] #[test]
fn test_default_limits() { fn test_default_limits() {
let limits = wgt::Limits::default(); let limits = wgt::Limits::default();

View File

@ -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. /// Dimensions of a particular texture view.
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] #[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. /// Winding order which classifies the "front" face.
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[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: 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); /// 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_dim = self.width.max(self.height.max(self.depth_or_array_layers));
let max_levels = 32 - max_dim.leading_zeros(); let max_levels = 32 - max_dim.leading_zeros();
max_levels as u8 max_levels
} }
} }
@ -2583,6 +2573,14 @@ impl<L> TextureDescriptor<L> {
}, },
}) })
} }
/// 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. /// Kind of data the texture holds.