hal:: Fill the command buffer calls

This commit is contained in:
Dzmitry Malyshau 2021-06-06 02:24:59 -04:00
parent 738ae2b227
commit 6d51fab864
15 changed files with 537 additions and 230 deletions

View File

@ -47,10 +47,10 @@ use crate::{
AttachmentData, Device, DeviceError, RenderPassContext, MAX_VERTEX_BUFFERS,
SHADER_STAGE_COUNT,
},
hal::BufferUse,
hub::{GlobalIdentityHandlerFactory, HalApi, Hub, Resource, Storage, Token},
id,
memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction},
resource::BufferUse,
track::{TrackerSet, UsageConflict},
validation::check_buffer_usage,
Label, LabelHelpers, LifeGuard, Stored, MAX_BIND_GROUPS,

View File

@ -18,7 +18,7 @@ use crate::{
Label, DOWNLEVEL_ERROR_WARNING_MESSAGE,
};
use hal::command::CommandBuffer as _;
use hal::CommandBuffer as _;
use thiserror::Error;
use wgt::{BufferAddress, BufferUsage, ShaderStage};
@ -216,7 +216,7 @@ impl State {
fn flush_states<A: HalApi>(
&mut self,
raw_cmd_buf: &mut B::CommandBuffer,
raw_cmd_buf: &mut A::CommandBuffer,
base_trackers: &mut TrackerSet,
bind_group_guard: &Storage<BindGroup<A>, id::BindGroupId>,
buffer_guard: &Storage<Buffer<A>, id::BufferId>,

View File

@ -7,8 +7,8 @@
use crate::{
binding_model::PushConstantUploadError,
hal::BufferUse,
id,
resource::BufferUse,
track::UseExtendError,
validation::{MissingBufferUsageError, MissingTextureUsageError},
};

View File

@ -114,15 +114,13 @@ impl<A: HalApi> CommandBuffer<A> {
}
pub(crate) fn insert_barriers(
raw: &mut B::CommandBuffer,
raw: &mut A::CommandBuffer,
base: &mut TrackerSet,
head_buffers: &ResourceTracker<BufferState>,
head_textures: &ResourceTracker<TextureState>,
buffer_guard: &Storage<Buffer<A>, id::BufferId>,
texture_guard: &Storage<Texture<A>, id::TextureId>,
) {
use hal::command::CommandBuffer as _;
profiling::scope!("insert_barriers");
debug_assert_eq!(A::VARIANT, base.backend());
@ -135,14 +133,9 @@ impl<A: HalApi> CommandBuffer<A> {
pending.into_hal(tex)
});
//TODO: be more deliberate about the stages
let stages = all_buffer_stages() | all_image_stages();
unsafe {
raw.pipeline_barrier(
stages..stages,
hal::memory::Dependencies::empty(),
buffer_barriers.chain(texture_barriers),
);
raw.transition_buffers(buffer_barriers);
raw.transition_textures(texture_barriers);
}
}
}

View File

@ -8,7 +8,6 @@ use hal::command::CommandBuffer as _;
use crate::device::trace::Command as TraceCommand;
use crate::{
command::{CommandBuffer, CommandEncoderError},
device::all_buffer_stages,
hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token},
id::{self, Id, TypedId},
resource::{BufferUse, QuerySet},

View File

@ -24,6 +24,77 @@ pub fn is_valid_copy_dst_texture_format(format: wgt::TextureFormat) -> bool {
}
}
pub fn map_buffer_usage(usage: wgt::BufferUsage) -> hal::BufferUse {
let mut u = hal::BufferUse::empty();
u.set(
hal::BufferUse::MAP_READ,
usage.contains(wgt::BufferUsage::MAP_READ),
);
u.set(
hal::BufferUse::MAP_WRITE,
usage.contains(wgt::BufferUsage::MAP_WRITE),
);
u.set(
hal::BufferUse::COPY_SRC,
usage.contains(wgt::BufferUsage::COPY_SRC),
);
u.set(
hal::BufferUse::COPY_DST,
usage.contains(wgt::BufferUsage::COPY_DST),
);
u.set(
hal::BufferUse::INDEX,
usage.contains(wgt::BufferUsage::INDEX),
);
u.set(
hal::BufferUse::VERTEX,
usage.contains(wgt::BufferUsage::VERTEX),
);
u.set(
hal::BufferUse::UNIFORM,
usage.contains(wgt::BufferUsage::UNIFORM),
);
u.set(
hal::BufferUse::STORAGE,
usage.contains(wgt::BufferUsage::STORAGE),
);
u.set(
hal::BufferUse::INDIRECT,
usage.contains(wgt::BufferUsage::INDIRECT),
);
u
}
pub fn map_texture_usage(usage: wgt::TextureUsage, aspect: hal::FormatAspect) -> hal::TextureUse {
let mut u = hal::TextureUse::empty();
u.set(
hal::TextureUse::COPY_SRC,
usage.contains(wgt::TextureUsage::COPY_SRC),
);
u.set(
hal::TextureUse::COPY_DST,
usage.contains(wgt::TextureUsage::COPY_DST),
);
u.set(
hal::TextureUse::SAMPLED,
usage.contains(wgt::TextureUsage::SAMPLED),
);
u.set(
hal::TextureUse::STORAGE_LOAD | hal::TextureUse::STORAGE_STORE,
usage.contains(wgt::TextureUsage::STORAGE),
);
let is_color = aspect.contains(hal::FormatAspect::COLOR);
u.set(
hal::TextureUse::COLOR_TARGET,
usage.contains(wgt::TextureUsage::RENDER_ATTACHMENT) && is_color,
);
u.set(
hal::TextureUse::DEPTH_STENCIL_READ | hal::TextureUse::DEPTH_STENCIL_WRITE,
usage.contains(wgt::TextureUsage::RENDER_ATTACHMENT) && !is_color,
);
u
}
pub fn check_texture_dimension_size(
dimension: wgt::TextureDimension,
wgt::Extent3d {

View File

@ -448,13 +448,13 @@ impl<A: HalApi> Device<A> {
return Err(resource::CreateBufferError::EmptyUsage);
}
let buffer = unsafe {
self.raw.create_buffer(&resource::BufferDescriptor {
usage,
..desc.clone()
})
}
.map_err(DeviceError::from)?;
let hal_desc = hal::BufferDescriptor {
label: desc.label,
size: desc.size,
usage: conv::map_buffer_usage(usage),
memory_flags: hal::MemoryFlag::empty(),
};
let buffer = unsafe { self.raw.create_buffer(&hal_desc) }.map_err(DeviceError::from)?;
Ok(resource::Buffer {
raw: Some(buffer),
@ -529,10 +529,24 @@ impl<A: HalApi> Device<A> {
return Err(resource::CreateTextureError::InvalidMipLevelCount(mips));
}
let mut image = unsafe { self.raw.create_image(desc).map_err(DeviceError::from)? };
let hal_desc = hal::TextureDescriptor {
label: desc.label,
size: desc.size,
mip_level_count: desc.mip_level_count,
sample_count: desc.sample_count,
dimension: desc.dimension,
format: desc.format,
usage: conv::map_texture_usage(desc.usage, desc.format.into()),
memory_flags: hal::MemoryFlag::empty(),
};
let mut raw = unsafe {
self.raw
.create_texture(&hal_desc)
.map_err(DeviceError::from)?
};
Ok(resource::Texture {
raw: Some(image),
raw: Some(raw),
device_id: Stored {
value: id::Valid(self_id),
ref_count: self.life_guard.add_ref(),
@ -698,9 +712,9 @@ impl<A: HalApi> Device<A> {
samples: texture.kind.num_samples(),
// once a storage - forever a storage
sampled_internal_use: if texture.usage.contains(wgt::TextureUsage::STORAGE) {
resource::TextureUse::SAMPLED | resource::TextureUse::STORAGE_LOAD
hal::TextureUse::SAMPLED | hal::TextureUse::STORAGE_LOAD
} else {
resource::TextureUse::SAMPLED
hal::TextureUse::SAMPLED
},
selector,
life_guard: LifeGuard::new(desc.label.borrow_or_default()),
@ -1083,15 +1097,15 @@ impl<A: HalApi> Device<A> {
let (pub_usage, internal_use, range_limit) = match binding_ty {
wgt::BufferBindingType::Uniform => (
wgt::BufferUsage::UNIFORM,
resource::BufferUse::UNIFORM,
hal::BufferUse::UNIFORM,
limits.max_uniform_buffer_binding_size,
),
wgt::BufferBindingType::Storage { read_only } => (
wgt::BufferUsage::STORAGE,
if read_only {
resource::BufferUse::STORAGE_LOAD
hal::BufferUse::STORAGE_LOAD
} else {
resource::BufferUse::STORAGE_STORE
hal::BufferUse::STORAGE_STORE
},
limits.max_storage_buffer_binding_size,
),
@ -1360,10 +1374,10 @@ impl<A: HalApi> Device<A> {
}
let internal_use = match access {
wgt::StorageTextureAccess::ReadOnly => {
resource::TextureUse::STORAGE_LOAD
hal::TextureUse::STORAGE_LOAD
}
wgt::StorageTextureAccess::WriteOnly => {
resource::TextureUse::STORAGE_STORE
hal::TextureUse::STORAGE_STORE
}
wgt::StorageTextureAccess::ReadWrite => {
if !view.format_features.flags.contains(
@ -1374,8 +1388,7 @@ impl<A: HalApi> Device<A> {
));
}
resource::TextureUse::STORAGE_STORE
| resource::TextureUse::STORAGE_LOAD
hal::TextureUse::STORAGE_STORE | hal::TextureUse::STORAGE_LOAD
}
};
(wgt::TextureUsage::STORAGE, internal_use)
@ -2459,7 +2472,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let ref_count = buffer.life_guard.add_ref();
let buffer_use = if !desc.mapped_at_creation {
resource::BufferUse::EMPTY
hal::BufferUse::EMPTY
} else if desc.usage.contains(wgt::BufferUsage::MAP_WRITE) {
// buffer is mappable, so we are just doing that at start
let map_size = buffer.size;
@ -2480,7 +2493,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
range: 0..map_size,
host: HostMap::Write,
};
resource::BufferUse::MAP_WRITE
hal::BufferUse::MAP_WRITE
} else {
// buffer needs staging area for initialization only
let stage_desc = wgt::BufferDescriptor {
@ -2533,7 +2546,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
stage_buffer,
stage_memory,
};
resource::BufferUse::COPY_DST
hal::BufferUse::COPY_DST
};
let id = fid.assign(buffer, &mut token);
@ -4236,8 +4249,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let mut token = Token::root();
let (device_guard, mut token) = hub.devices.read(&mut token);
let (pub_usage, internal_use) = match op.host {
HostMap::Read => (wgt::BufferUsage::MAP_READ, resource::BufferUse::MAP_READ),
HostMap::Write => (wgt::BufferUsage::MAP_WRITE, resource::BufferUse::MAP_WRITE),
HostMap::Read => (wgt::BufferUsage::MAP_READ, hal::BufferUse::MAP_READ),
HostMap::Write => (wgt::BufferUsage::MAP_WRITE, hal::BufferUse::MAP_WRITE),
};
if range.start % wgt::MAP_ALIGNMENT != 0 || range.end % wgt::COPY_BUFFER_ALIGNMENT != 0 {
@ -4404,32 +4417,26 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.ok_or(resource::BufferAccessError::Destroyed)?;
buffer.life_guard.use_at(device.active_submission_index + 1);
let region = hal::command::BufferCopy {
let region = hal::BufferCopy {
src: 0,
dst: 0,
size: buffer.size,
};
let transition_src = hal::memory::Barrier::Buffer {
states: hal::buffer::Access::HOST_WRITE..hal::buffer::Access::TRANSFER_READ,
target: &stage_buffer,
range: hal::buffer::SubRange::WHOLE,
families: None,
let transition_src = hal::BufferBarrier {
buffer: &stage_buffer,
usage: hal::BufferUse::MAP_WRITE..hal::BufferUse::COPY_SRC,
};
let transition_dst = hal::memory::Barrier::Buffer {
states: hal::buffer::Access::empty()..hal::buffer::Access::TRANSFER_WRITE,
target: buf_raw,
range: hal::buffer::SubRange::WHOLE,
families: None,
let transition_dst = hal::BufferBarrier {
buffer: buf_raw,
usage: hal::BufferUse::empty()..hal::BufferUse::COPY_DST,
};
unsafe {
let cmdbuf = device.borrow_pending_writes();
cmdbuf.pipeline_barrier(
hal::pso::PipelineStage::HOST..hal::pso::PipelineStage::TRANSFER,
hal::memory::Dependencies::empty(),
let cmd_buf = device.borrow_pending_writes();
cmd_buf.transition_buffers(
iter::once(transition_src).chain(iter::once(transition_dst)),
);
if buffer.size > 0 {
cmdbuf.copy_buffer(&stage_buffer, buf_raw, iter::once(region));
cmd_buf.copy_buffer_to_buffer(&stage_buffer, buf_raw, iter::once(region));
}
}
device

View File

@ -7,38 +7,37 @@ use crate::device::trace::Action;
use crate::{
command::{
texture_copy_view_to_hal, validate_linear_texture_data, validate_texture_copy_range,
CommandAllocator, CommandBuffer, CopySide, ImageCopyTexture, TransferError, BITS_PER_BYTE,
CommandBuffer, CopySide, ImageCopyTexture, TransferError, BITS_PER_BYTE,
},
conv,
device::{alloc, DeviceError, WaitIdleError},
device::{DeviceError, WaitIdleError},
hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token},
id,
memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction},
resource::{Buffer, BufferAccessError, BufferMapState, BufferUse, TextureUse},
resource::{Buffer, BufferAccessError, BufferMapState},
FastHashMap, FastHashSet,
};
use hal::{command::CommandBuffer as _, device::Device as _, queue::Queue as _};
use hal::{CommandBuffer as _, Device as _, Queue as _};
use smallvec::SmallVec;
use std::{iter, ops::Range, ptr};
use thiserror::Error;
struct StagingData<A: hal::Api> {
buffer: B::Buffer,
memory: alloc::MemoryBlock<A>,
cmdbuf: B::CommandBuffer,
buffer: A::Buffer,
cmdbuf: A::CommandBuffer,
}
#[derive(Debug)]
pub enum TempResource<A: hal::Api> {
Buffer(B::Buffer),
Image(B::Image),
Buffer(A::Buffer),
Texture(A::Texture),
}
#[derive(Debug)]
pub(crate) struct PendingWrites<A: hal::Api> {
pub command_buffer: Option<B::CommandBuffer>,
pub temp_resources: Vec<(TempResource<A>, alloc::MemoryBlock<A>)>,
pub command_buffer: Option<A::CommandBuffer>,
pub temp_resources: Vec<TempResource<A>>,
pub dst_buffers: FastHashSet<id::BufferId>,
pub dst_textures: FastHashSet<id::TextureId>,
}
@ -53,40 +52,35 @@ impl<A: hal::Api> PendingWrites<A> {
}
}
pub fn dispose(
self,
device: &B::Device,
cmd_allocator: &CommandAllocator<A>,
mem_allocator: &mut alloc::MemoryAllocator<A>,
) {
pub fn dispose(self, device: &A::Device) {
if let Some(raw) = self.command_buffer {
cmd_allocator.discard_internal(raw);
unsafe {
device.destroy_command_buffer(raw);
}
}
for (resource, memory) in self.temp_resources {
mem_allocator.free(device, memory);
for resource in self.temp_resources {
match resource {
TempResource::Buffer(buffer) => unsafe {
device.destroy_buffer(buffer);
},
TempResource::Image(image) => unsafe {
device.destroy_image(image);
TempResource::Texture(texture) => unsafe {
device.destroy_image(texture);
},
}
}
}
pub fn consume_temp(&mut self, resource: TempResource<A>, memory: alloc::MemoryBlock<A>) {
self.temp_resources.push((resource, memory));
pub fn consume_temp(&mut self, resource: TempResource<A>) {
self.temp_resources.push(resource);
}
fn consume(&mut self, stage: StagingData<A>) {
self.temp_resources
.push((TempResource::Buffer(stage.buffer), stage.memory));
self.temp_resources.push(TempResource::Buffer(stage.buffer));
self.command_buffer = Some(stage.cmdbuf);
}
#[must_use]
fn finish(&mut self) -> Option<B::CommandBuffer> {
fn finish(&mut self) -> Option<A::CommandBuffer> {
self.dst_buffers.clear();
self.dst_textures.clear();
self.command_buffer.take().map(|mut cmd_buf| unsafe {
@ -95,13 +89,19 @@ impl<A: hal::Api> PendingWrites<A> {
})
}
fn borrow_cmd_buf(&mut self, cmd_allocator: &CommandAllocator<A>) -> &mut B::CommandBuffer {
fn create_cmd_buf(device: &A::Device) -> A::CommandBuffer {
unsafe {
let mut cmd_buf = device.create_command_buffer(&hal::CommandBufferDescriptor {
label: Some("_PendingWrites"),
});
cmd_buf.begin();
cmd_buf
}
}
fn borrow_cmd_buf(&mut self, device: &A::Device) -> &mut A::CommandBuffer {
if self.command_buffer.is_none() {
let mut cmdbuf = cmd_allocator.allocate_internal();
unsafe {
cmdbuf.begin_primary(hal::command::CommandBufferFlags::ONE_TIME_SUBMIT);
}
self.command_buffer = Some(cmdbuf);
self.command_buffer = Some(Self::create_cmd_buf(device));
}
self.command_buffer.as_mut().unwrap()
}
@ -141,52 +141,25 @@ impl RequiredBufferInits {
}
impl<A: hal::Api> super::Device<A> {
pub fn borrow_pending_writes(&mut self) -> &mut B::CommandBuffer {
self.pending_writes.borrow_cmd_buf(&self.cmd_allocator)
pub fn borrow_pending_writes(&mut self) -> &mut A::CommandBuffer {
self.pending_writes.borrow_cmd_buf(&self.raw)
}
fn prepare_stage(&mut self, size: wgt::BufferAddress) -> Result<StagingData<A>, DeviceError> {
profiling::scope!("prepare_stage");
let mut buffer = unsafe {
self.raw
.create_buffer(
size,
hal::buffer::Usage::TRANSFER_SRC,
hal::memory::SparseFlags::empty(),
)
.map_err(|err| match err {
hal::buffer::CreationError::OutOfMemory(_) => DeviceError::OutOfMemory,
_ => panic!("failed to create staging buffer: {}", err),
})?
let stage_desc = hal::BufferDescriptor {
label: Some("_Staging"),
size,
usage: hal::BufferUse::MAP_WRITE | hal::BufferUse::COPY_SRC,
memory_flags: hal::MemoryFlag::TRANSIENT,
};
//TODO: do we need to transition into HOST_WRITE access first?
let requirements = unsafe {
self.raw.set_buffer_name(&mut buffer, "<write_buffer_temp>");
self.raw.get_buffer_requirements(&buffer)
};
let block = self.mem_allocator.lock().allocate(
&self.raw,
requirements,
gpu_alloc::UsageFlags::UPLOAD | gpu_alloc::UsageFlags::TRANSIENT,
)?;
block.bind_buffer(&self.raw, &mut buffer)?;
let mut buffer = unsafe { self.raw.create_buffer(&stage_desc)? };
let cmdbuf = match self.pending_writes.command_buffer.take() {
Some(cmdbuf) => cmdbuf,
None => {
let mut cmdbuf = self.cmd_allocator.allocate_internal();
unsafe {
cmdbuf.begin_primary(hal::command::CommandBufferFlags::ONE_TIME_SUBMIT);
}
cmdbuf
}
None => PendingWrites::create_cmd_buf(&self.raw),
};
Ok(StagingData {
buffer,
memory: block,
cmdbuf,
})
Ok(StagingData { buffer, cmdbuf })
}
fn initialize_buffer_memory(
@ -217,7 +190,7 @@ impl<A: hal::Api> super::Device<A> {
let transition = trackers.buffers.change_replace_tracked(
id::Valid(buffer_id),
(),
BufferUse::COPY_DST,
hal::BufferUse::COPY_DST,
);
let buffer = buffer_guard.get(buffer_id).unwrap();
let &(ref buffer_raw, _) = buffer
@ -225,27 +198,15 @@ impl<A: hal::Api> super::Device<A> {
.as_ref()
.ok_or(QueueSubmitError::DestroyedBuffer(buffer_id))?;
unsafe {
cmd_buf.pipeline_barrier(
super::all_buffer_stages()..hal::pso::PipelineStage::TRANSFER,
hal::memory::Dependencies::empty(),
transition.map(|pending| pending.into_hal(buffer)),
);
cmd_buf.transition_buffers(transition.map(|pending| pending.into_hal(buffer)));
}
for range in ranges {
let size = range.end - range.start;
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!(size % 4 == 0, "Buffer {:?} has an uninitialized range with a size not aligned to 4 (size was {})", buffer, size);
assert!(range.end % 4 == 0, "Buffer {:?} has an uninitialized range with an end not aligned to 4 (end was {})", buffer, range.end);
unsafe {
cmd_buf.fill_buffer(
buffer_raw,
hal::buffer::SubRange {
offset: range.start,
size: Some(size),
},
0,
);
cmd_buf.fill_buffer(buffer_raw, range, 0);
}
}
}
@ -326,7 +287,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let mut trackers = device.trackers.lock();
let (dst, transition) = trackers
.buffers
.use_replace(&*buffer_guard, buffer_id, (), BufferUse::COPY_DST)
.use_replace(&*buffer_guard, buffer_id, (), hal::BufferUse::COPY_DST)
.map_err(TransferError::InvalidBuffer)?;
let &(ref dst_raw, _) = dst
.raw

View File

@ -16,9 +16,6 @@ use thiserror::Error;
use std::{borrow::Borrow, num::NonZeroU8, ops::Range, ptr::NonNull};
//TODO: remove the alias, just use it from `hal`
pub(crate) use hal::{BufferUse, TextureUse};
#[repr(C)]
#[derive(Debug)]
pub enum BufferMapAsyncStatus {
@ -166,7 +163,7 @@ pub type TextureDescriptor<'a> = wgt::TextureDescriptor<Label<'a>>;
#[derive(Debug)]
pub struct Texture<A: hal::Api> {
pub(crate) raw: Option<A::Image>,
pub(crate) raw: Option<A::Texture>,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) desc: wgt::TextureDescriptor<()>,
pub(crate) format_features: wgt::TextureFormatFeatures,
@ -272,7 +269,7 @@ pub struct TextureView<A: hal::Api> {
pub(crate) extent: wgt::Extent3d,
pub(crate) samples: u32,
/// Internal use of this texture view when used as `BindingType::Texture`.
pub(crate) sampled_internal_use: TextureUse,
pub(crate) sampled_internal_use: hal::TextureUse,
pub(crate) selector: TextureSelector,
pub(crate) life_guard: LifeGuard,
}

View File

@ -210,7 +210,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
},
samples: 1,
framebuffer_attachment: sc.framebuffer_attachment.clone(),
sampled_internal_use: resource::TextureUse::empty(),
sampled_internal_use: hal::TextureUse::empty(),
selector: TextureSelector {
layers: 0..1,
levels: 0..1,

View File

@ -3,12 +3,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use super::{PendingTransition, ResourceState, Unit};
use crate::{
id::{BufferId, Valid},
resource::BufferUse,
};
use crate::id::{BufferId, Valid};
use hal::BufferUse;
//TODO: store `hal::buffer::State` here to avoid extra conversions
pub(crate) type BufferState = Unit<BufferUse>;
impl PendingTransition<BufferState> {

View File

@ -124,6 +124,21 @@ pub(crate) struct PendingTransition<S: ResourceState> {
pub usage: ops::Range<S::Usage>,
}
impl PendingTransition<BufferState> {
/// Produce the hal barrier corresponding to the transition.
pub fn into_hal<'a, A: hal::Api>(
self,
buf: &'a resource::Buffer<A>,
) -> hal::BufferBarrier<'a, A> {
log::trace!("\tbuffer -> {:?}", self);
let &(ref buffer, _) = buf.raw.as_ref().expect("Buffer is destroyed");
hal::BufferBarrier {
buffer,
usage: self.usage,
}
}
}
impl From<PendingTransition<BufferState>> for UsageConflict {
fn from(e: PendingTransition<BufferState>) -> Self {
Self::Buffer {
@ -133,6 +148,22 @@ impl From<PendingTransition<BufferState>> for UsageConflict {
}
}
impl PendingTransition<TextureState> {
/// Produce the hal barrier corresponding to the transition.
pub fn into_hal<'a, A: hal::Api>(
self,
tex: &'a resource::Texture<A>,
) -> hal::TextureBarrier<'a, A> {
log::trace!("\ttexture -> {:?}", self);
let &(ref texture, _) = tex.raw.as_ref().expect("Texture is destroyed");
hal::TextureBarrier {
texture,
subresource: self.selector,
usage: self.usage,
}
}
}
impl From<PendingTransition<TextureState>> for UsageConflict {
fn from(e: PendingTransition<TextureState>) -> Self {
Self::Texture {
@ -514,14 +545,14 @@ pub enum UsageConflict {
)]
Buffer {
id: id::BufferId,
combined_use: resource::BufferUse,
combined_use: hal::BufferUse,
},
#[error("Attempted to use texture {id:?} mips {mip_levels:?} layers {array_layers:?} as a combination of {combined_use:?} within a usage scope.")]
Texture {
id: id::TextureId,
mip_levels: ops::Range<u32>,
array_layers: ops::Range<u32>,
combined_use: resource::TextureUse,
combined_use: hal::TextureUse,
},
}

View File

@ -6,8 +6,8 @@ use super::{range::RangedStates, PendingTransition, ResourceState, Unit};
use crate::{
device::MAX_MIP_LEVELS,
id::{TextureId, Valid},
resource::TextureUse,
};
use hal::TextureUse;
use arrayvec::ArrayVec;

View File

@ -1,3 +1,5 @@
#![allow(unused_variables)]
#[derive(Clone)]
pub struct Api;
pub struct Context;
@ -42,161 +44,241 @@ impl crate::Instance<Api> for Context {
impl crate::Surface<Api> for Context {
unsafe fn configure(
&mut self,
_device: &Context,
_config: &crate::SurfaceConfiguration,
device: &Context,
config: &crate::SurfaceConfiguration,
) -> Result<(), crate::SurfaceError> {
Ok(())
}
unsafe fn unconfigure(&mut self, _device: &Context) {}
unsafe fn unconfigure(&mut self, device: &Context) {}
unsafe fn acquire_texture(
&mut self,
_timeout_ms: u32,
timeout_ms: u32,
) -> Result<(Resource, Option<crate::Suboptimal>), crate::SurfaceError> {
Ok((Resource, None))
}
}
impl crate::Adapter<Api> for Context {
unsafe fn open(&self, _features: wgt::Features) -> DeviceResult<crate::OpenDevice<Api>> {
unsafe fn open(&self, features: wgt::Features) -> DeviceResult<crate::OpenDevice<Api>> {
Err(crate::DeviceError::Lost)
}
unsafe fn close(&self, _device: Context) {}
unsafe fn close(&self, device: Context) {}
unsafe fn texture_format_capabilities(
&self,
_format: wgt::TextureFormat,
format: wgt::TextureFormat,
) -> crate::TextureFormatCapability {
crate::TextureFormatCapability::empty()
}
unsafe fn surface_capabilities(
&self,
_surface: &Context,
) -> Option<crate::SurfaceCapabilities> {
unsafe fn surface_capabilities(&self, surface: &Context) -> Option<crate::SurfaceCapabilities> {
None
}
}
impl crate::Queue<Api> for Context {
unsafe fn submit<I: Iterator<Item = Encoder>>(&mut self, _command_buffers: I) {}
unsafe fn submit<I>(&mut self, command_buffers: I) {}
}
impl crate::Device<Api> for Context {
unsafe fn create_buffer(
&self,
_desc: &wgt::BufferDescriptor<crate::Label>,
) -> DeviceResult<Resource> {
unsafe fn create_buffer(&self, desc: &crate::BufferDescriptor) -> DeviceResult<Resource> {
Ok(Resource)
}
unsafe fn destroy_buffer(&self, _buffer: Resource) {}
unsafe fn destroy_buffer(&self, buffer: Resource) {}
unsafe fn map_buffer(
&self,
_buffer: &Resource,
_range: crate::MemoryRange,
buffer: &Resource,
range: crate::MemoryRange,
) -> DeviceResult<std::ptr::NonNull<u8>> {
Err(crate::DeviceError::Lost)
}
unsafe fn unmap_buffer(&self, _buffer: &Resource) {}
unsafe fn flush_mapped_ranges<I: Iterator<Item = crate::MemoryRange>>(
&self,
_buffer: &Resource,
_ranges: I,
) {
}
unsafe fn invalidate_mapped_ranges<I: Iterator<Item = crate::MemoryRange>>(
&self,
_buffer: &Resource,
_ranges: I,
) {
}
unsafe fn unmap_buffer(&self, buffer: &Resource) {}
unsafe fn flush_mapped_ranges<I>(&self, buffer: &Resource, ranges: I) {}
unsafe fn invalidate_mapped_ranges<I>(&self, buffer: &Resource, ranges: I) {}
unsafe fn create_texture(
&self,
_desc: &wgt::TextureDescriptor<crate::Label>,
) -> DeviceResult<Resource> {
unsafe fn create_texture(&self, desc: &crate::TextureDescriptor) -> DeviceResult<Resource> {
Ok(Resource)
}
unsafe fn destroy_texture(&self, _texture: Resource) {}
unsafe fn destroy_texture(&self, texture: Resource) {}
unsafe fn create_texture_view(
&self,
_texture: &Resource,
_desc: &crate::TextureViewDescriptor,
texture: &Resource,
desc: &crate::TextureViewDescriptor,
) -> DeviceResult<Resource> {
Ok(Resource)
}
unsafe fn destroy_texture_view(&self, _view: Resource) {}
unsafe fn create_sampler(&self, _desc: &crate::SamplerDescriptor) -> DeviceResult<Resource> {
unsafe fn destroy_texture_view(&self, view: Resource) {}
unsafe fn create_sampler(&self, desc: &crate::SamplerDescriptor) -> DeviceResult<Resource> {
Ok(Resource)
}
unsafe fn destroy_sampler(&self, _sampler: Resource) {}
unsafe fn destroy_sampler(&self, sampler: Resource) {}
unsafe fn create_command_buffer(
&self,
_desc: &crate::CommandBufferDescriptor,
desc: &crate::CommandBufferDescriptor,
) -> DeviceResult<Encoder> {
Ok(Encoder)
}
unsafe fn destroy_command_buffer(&self, _cmd_buf: Encoder) {}
unsafe fn destroy_command_buffer(&self, cmd_buf: Encoder) {}
unsafe fn create_bind_group_layout(
&self,
_desc: &crate::BindGroupLayoutDescriptor,
desc: &crate::BindGroupLayoutDescriptor,
) -> DeviceResult<Resource> {
Ok(Resource)
}
unsafe fn destroy_bind_group_layout(&self, _bg_layout: Resource) {}
unsafe fn destroy_bind_group_layout(&self, bg_layout: Resource) {}
unsafe fn create_pipeline_layout(
&self,
_desc: &crate::PipelineLayoutDescriptor<Api>,
desc: &crate::PipelineLayoutDescriptor<Api>,
) -> DeviceResult<Resource> {
Ok(Resource)
}
unsafe fn destroy_pipeline_layout(&self, _pipeline_layout: Resource) {}
unsafe fn destroy_pipeline_layout(&self, pipeline_layout: Resource) {}
unsafe fn create_bind_group(
&self,
_desc: &crate::BindGroupDescriptor<Api>,
desc: &crate::BindGroupDescriptor<Api>,
) -> DeviceResult<Resource> {
Ok(Resource)
}
unsafe fn destroy_bind_group(&self, _group: Resource) {}
unsafe fn destroy_bind_group(&self, group: Resource) {}
unsafe fn create_shader_module(
&self,
_desc: &crate::ShaderModuleDescriptor,
_shader: crate::NagaShader,
desc: &crate::ShaderModuleDescriptor,
shader: crate::NagaShader,
) -> Result<Resource, (crate::ShaderError, crate::NagaShader)> {
Ok(Resource)
}
unsafe fn destroy_shader_module(&self, _module: Resource) {}
unsafe fn destroy_shader_module(&self, module: Resource) {}
unsafe fn create_render_pipeline(
&self,
_desc: &crate::RenderPipelineDescriptor<Api>,
desc: &crate::RenderPipelineDescriptor<Api>,
) -> Result<Resource, crate::PipelineError> {
Ok(Resource)
}
unsafe fn destroy_render_pipeline(&self, _pipeline: Resource) {}
unsafe fn destroy_render_pipeline(&self, pipeline: Resource) {}
unsafe fn create_compute_pipeline(
&self,
_desc: &crate::ComputePipelineDescriptor<Api>,
desc: &crate::ComputePipelineDescriptor<Api>,
) -> Result<Resource, crate::PipelineError> {
Ok(Resource)
}
unsafe fn destroy_compute_pipeline(&self, _pipeline: Resource) {}
unsafe fn destroy_compute_pipeline(&self, pipeline: Resource) {}
}
impl crate::CommandBuffer<Api> for Encoder {
unsafe fn begin(&mut self) {}
unsafe fn end(&mut self) {}
unsafe fn transition_buffers<'a, T>(&mut self, barriers: T)
where
T: Iterator<Item = crate::BufferBarrier<'a, Api>>,
{
}
unsafe fn transition_textures<'a, T>(&mut self, barriers: T)
where
T: Iterator<Item = crate::TextureBarrier<'a, Api>>,
{
}
unsafe fn fill_buffer(&mut self, buffer: &Resource, range: crate::MemoryRange, value: u8) {}
unsafe fn copy_buffer_to_buffer<T>(&mut self, src: &Resource, dst: &Resource, regions: T)
where
T: Iterator<Item = crate::BufferCopy>,
{
}
/// Note: `dst` current usage has to be `TextureUse::COPY_DST`.
unsafe fn copy_texture_to_texture<T>(
&mut self,
src: &Resource,
src_usage: crate::TextureUse,
dst: &Resource,
regions: T,
) {
}
/// Note: `dst` current usage has to be `TextureUse::COPY_DST`.
unsafe fn copy_buffer_to_texture<T>(&mut self, src: &Resource, dst: &Resource, regions: T) {}
unsafe fn copy_texture_to_buffer<T>(
&mut self,
src: &Resource,
src_usage: crate::TextureUse,
dst: &Resource,
regions: T,
) {
}
unsafe fn begin_render_pass(&mut self) -> Encoder {
Encoder
}
unsafe fn end_render_pass(&mut self, _pass: Encoder) {}
unsafe fn end_render_pass(&mut self, pass: Encoder) {}
unsafe fn begin_compute_pass(&mut self) -> Encoder {
Encoder
}
unsafe fn end_compute_pass(&mut self, _pass: Encoder) {}
unsafe fn end_compute_pass(&mut self, pass: Encoder) {}
}
impl crate::RenderPass<Api> for Encoder {}
impl crate::ComputePass<Api> for Encoder {}
impl crate::RenderPass<Api> for Encoder {
unsafe fn set_pipeline(&mut self, pipeline: &Resource) {}
unsafe fn set_bind_group(&mut self, layout: &Resource, index: u32, group: &Resource) {}
unsafe fn set_index_buffer<'a>(
&mut self,
binding: crate::BufferBinding<'a, Api>,
format: wgt::IndexFormat,
) {
}
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_scissor_rect(&mut self, rect: &crate::Rect) {}
unsafe fn set_stencil_reference(&mut self, value: u32) {}
unsafe fn set_blend_constants(&mut self, color: wgt::Color) {}
unsafe fn draw(
&mut self,
start_vertex: u32,
vertex_count: u32,
start_instance: u32,
instance_count: u32,
) {
}
unsafe fn draw_indexed(
&mut self,
start_index: u32,
index_count: u32,
base_vertex: i32,
start_instance: u32,
instance_count: u32,
) {
}
unsafe fn draw_indirect(
&mut self,
buffer: &Resource,
offset: wgt::BufferAddress,
draw_count: u32,
) {
}
unsafe fn draw_indexed_indirect(
&mut self,
buffer: &Resource,
offset: wgt::BufferAddress,
draw_count: u32,
) {
}
}
impl crate::ComputePass<Api> for Encoder {
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_indirect(&mut self, buffer: &Resource, offset: wgt::BufferAddress) {}
}

View File

@ -10,7 +10,7 @@
* - Objects are passed by references and returned by value. No IDs.
* - Mapping is persistent, with explicit synchronization.
* - Resource transitions are explicit.
* - All layouts are explicit.
* - All layouts are explicit. Binding model has compatibility.
*/
#![allow(
@ -107,9 +107,9 @@ pub trait Api: Clone + Sized {
type RenderPass: RenderPass<Self>;
type ComputePass: ComputePass<Self>;
type Buffer: fmt::Debug + Send + Sync;
type Buffer: fmt::Debug + Send + Sync + 'static;
type QuerySet: fmt::Debug + Send + Sync;
type Texture: fmt::Debug + Send + Sync;
type Texture: fmt::Debug + Send + Sync + 'static;
type SurfaceTexture: fmt::Debug + Send + Sync + Borrow<Self::Texture>;
type TextureView: fmt::Debug + Send + Sync;
type Sampler: fmt::Debug + Send + Sync;
@ -158,10 +158,8 @@ pub trait Adapter<A: Api> {
}
pub trait Device<A: Api> {
unsafe fn create_buffer(
&self,
desc: &wgt::BufferDescriptor<Label>,
) -> Result<A::Buffer, DeviceError>;
///Note: `desc.mapped_at_creation` flag is ignored.
unsafe fn create_buffer(&self, desc: &BufferDescriptor) -> Result<A::Buffer, DeviceError>;
unsafe fn destroy_buffer(&self, buffer: A::Buffer);
unsafe fn map_buffer(
&self,
@ -180,10 +178,7 @@ pub trait Device<A: Api> {
ranges: I,
);
unsafe fn create_texture(
&self,
desc: &wgt::TextureDescriptor<Label>,
) -> Result<A::Texture, DeviceError>;
unsafe fn create_texture(&self, desc: &TextureDescriptor) -> Result<A::Texture, DeviceError>;
unsafe fn destroy_texture(&self, texture: A::Texture);
unsafe fn create_texture_view(
&self,
@ -244,14 +239,117 @@ pub trait CommandBuffer<A: Api> {
unsafe fn begin(&mut self);
unsafe fn end(&mut self);
unsafe fn transition_buffers<'a, T>(&mut self, barriers: T)
where
T: Iterator<Item = BufferBarrier<'a, A>>;
unsafe fn transition_textures<'a, T>(&mut self, barriers: T)
where
T: Iterator<Item = TextureBarrier<'a, A>>;
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)
where
T: Iterator<Item = BufferCopy>;
/// Note: `dst` current usage has to be `TextureUse::COPY_DST`.
unsafe fn copy_texture_to_texture<T>(
&mut self,
src: &A::Texture,
src_usage: TextureUse,
dst: &A::Texture,
regions: T,
) where
T: Iterator<Item = TextureCopy>;
/// Note: `dst` current usage has to be `TextureUse::COPY_DST`.
unsafe fn copy_buffer_to_texture<T>(&mut self, src: &A::Buffer, dst: &A::Texture, regions: T)
where
T: Iterator<Item = BufferTextureCopy>;
unsafe fn copy_texture_to_buffer<T>(
&mut self,
src: &A::Texture,
src_usage: TextureUse,
dst: &A::Buffer,
regions: T,
) where
T: Iterator<Item = BufferTextureCopy>;
unsafe fn begin_render_pass(&mut self) -> A::RenderPass;
unsafe fn end_render_pass(&mut self, pass: A::RenderPass);
unsafe fn begin_compute_pass(&mut self) -> A::ComputePass;
unsafe fn end_compute_pass(&mut self, pass: A::ComputePass);
}
pub trait RenderPass<A: Api> {}
pub trait ComputePass<A: Api> {}
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
/// of all the preceeding groups to be taken from `layout`.
unsafe fn set_bind_group(
&mut self,
layout: &A::PipelineLayout,
index: u32,
group: &A::BindGroup,
);
unsafe fn set_index_buffer<'a>(
&mut self,
binding: BufferBinding<'a, A>,
format: wgt::IndexFormat,
);
unsafe fn set_vertex_buffer<'a>(&mut self, index: u32, binding: BufferBinding<'a, A>);
unsafe fn set_viewport(&mut self, rect: &Rect, depth_range: Range<f32>);
unsafe fn set_scissor_rect(&mut self, rect: &Rect);
unsafe fn set_stencil_reference(&mut self, value: u32);
unsafe fn set_blend_constants(&mut self, color: wgt::Color);
unsafe fn draw(
&mut self,
start_vertex: u32,
vertex_count: u32,
start_instance: u32,
instance_count: u32,
);
unsafe fn draw_indexed(
&mut self,
start_index: u32,
index_count: u32,
base_vertex: i32,
start_instance: u32,
instance_count: u32,
);
unsafe fn draw_indirect(
&mut self,
buffer: &A::Buffer,
offset: wgt::BufferAddress,
draw_count: u32,
);
unsafe fn draw_indexed_indirect(
&mut self,
buffer: &A::Buffer,
offset: wgt::BufferAddress,
draw_count: u32,
);
}
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,
layout: &A::PipelineLayout,
index: u32,
group: &A::BindGroup,
);
unsafe fn dispatch(&mut self, count: [u32; 3]);
unsafe fn dispatch_indirect(&mut self, buffer: &A::Buffer, offset: wgt::BufferAddress);
}
bitflags!(
/// Texture format capability flags.
@ -303,6 +401,12 @@ impl From<wgt::TextureFormat> for FormatAspect {
}
}
bitflags!(
pub struct MemoryFlag: u32 {
const TRANSIENT = 1;
}
);
bitflags::bitflags! {
/// Similar to `wgt::BufferUsage` but for internal use.
pub struct BufferUse: u32 {
@ -423,6 +527,26 @@ pub struct OpenDevice<A: Api> {
pub queue: A::Queue,
}
#[derive(Clone, Debug)]
pub struct BufferDescriptor<'a> {
pub label: Label<'a>,
pub size: wgt::BufferAddress,
pub usage: BufferUse,
pub memory_flags: MemoryFlag,
}
#[derive(Clone, Debug)]
pub struct TextureDescriptor<'a> {
pub label: Label<'a>,
pub size: wgt::Extent3d,
pub mip_level_count: u32,
pub sample_count: u32,
pub dimension: wgt::TextureDimension,
pub format: wgt::TextureFormat,
pub usage: TextureUse,
pub memory_flags: MemoryFlag,
}
#[derive(Clone, Debug)]
pub struct TextureViewDescriptor<'a> {
pub label: Label<'a>,
@ -638,6 +762,51 @@ pub struct SurfaceConfiguration {
pub usage: TextureUse,
}
#[derive(Debug, Clone)]
pub struct Rect {
pub x: f32,
pub y: f32,
pub w: f32,
pub h: f32,
}
#[derive(Debug, Clone)]
pub struct BufferBarrier<'a, A: Api> {
pub buffer: &'a A::Buffer,
pub usage: Range<BufferUse>,
}
#[derive(Debug, Clone)]
pub struct TextureBarrier<'a, A: Api> {
pub texture: &'a A::Texture,
pub subresource: wgt::ImageSubresourceRange,
pub usage: Range<TextureUse>,
}
#[derive(Clone, Copy, Debug)]
pub struct BufferCopy {
pub src: wgt::BufferAddress,
pub dst: wgt::BufferAddress,
pub size: wgt::BufferSize,
}
#[derive(Clone, Debug)]
pub struct TextureCopy {
pub src_subresource: wgt::ImageSubresourceRange,
pub src_origin: wgt::Origin3d,
pub dst_subresource: wgt::ImageSubresourceRange,
pub dst_origin: wgt::Origin3d,
pub size: wgt::Extent3d,
}
#[derive(Clone, Debug)]
pub struct BufferTextureCopy {
pub buffer_layout: wgt::ImageDataLayout,
pub texture_mip_level: u32,
pub texture_origin: wgt::Origin3d,
pub size: wgt::Extent3d,
}
#[test]
fn test_default_limits() {
let limits = wgt::Limits::default();