Grand cleanup and refactor of the descriptors in the API

This commit is contained in:
Dzmitry Malyshau 2020-08-12 14:13:32 -04:00
parent 04f5cfd1c8
commit 9d8dc0b04d
14 changed files with 539 additions and 1267 deletions

View File

@ -12,7 +12,7 @@
use wgc::device::trace;
use std::{borrow::Cow, ffi::CString, fmt::Debug, fs, marker::PhantomData, path::Path, ptr};
use std::{borrow::Cow, fmt::Debug, fs, marker::PhantomData, path::Path};
#[macro_export]
macro_rules! gfx_select {
@ -31,24 +31,6 @@ macro_rules! gfx_select {
};
}
struct Label(Option<CString>);
impl Label {
fn new(text: &str) -> Self {
Self(if text.is_empty() {
None
} else {
Some(CString::new(text).expect("invalid label"))
})
}
fn as_ptr(&self) -> *const std::os::raw::c_char {
match self.0 {
Some(ref c_string) => c_string.as_ptr(),
None => ptr::null(),
}
}
}
#[derive(Debug)]
pub struct IdentityPassThrough<I>(PhantomData<I>);
@ -135,7 +117,7 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
}
}
}
self.command_encoder_finish::<B>(encoder, &wgt::CommandBufferDescriptor { todo: 0 })
self.command_encoder_finish::<B>(encoder, &wgt::CommandBufferDescriptor { label: None })
.unwrap()
}
@ -154,19 +136,15 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
panic!("Unexpected SwapChain action: winit feature is not enabled")
}
A::CreateBuffer(id, desc) => {
let label = Label::new(&desc.label);
self.device_maintain_ids::<B>(device).unwrap();
self.device_create_buffer::<B>(device, &desc.map_label(|_| label.as_ptr()), id)
.unwrap();
self.device_create_buffer::<B>(device, &desc, id).unwrap();
}
A::DestroyBuffer(id) => {
self.buffer_drop::<B>(id, true);
}
A::CreateTexture(id, desc) => {
let label = Label::new(&desc.label);
self.device_maintain_ids::<B>(device).unwrap();
self.device_create_texture::<B>(device, &desc.map_label(|_| label.as_ptr()), id)
.unwrap();
self.device_create_texture::<B>(device, &desc, id).unwrap();
}
A::DestroyTexture(id) => {
self.texture_drop::<B>(id);
@ -176,23 +154,15 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
parent_id,
desc,
} => {
let label = desc.as_ref().map_or(Label(None), |d| Label::new(&d.label));
self.device_maintain_ids::<B>(device).unwrap();
self.texture_create_view::<B>(
parent_id,
desc.map(|d| d.map_label(|_| label.as_ptr())).as_ref(),
id,
)
.unwrap();
self.texture_create_view::<B>(parent_id, &desc, id).unwrap();
}
A::DestroyTextureView(id) => {
self.texture_view_drop::<B>(id).unwrap();
}
A::CreateSampler(id, desc) => {
let label = Label::new(&desc.label);
self.device_maintain_ids::<B>(device).unwrap();
self.device_create_sampler::<B>(device, &desc.map_label(|_| label.as_ptr()), id)
.unwrap();
self.device_create_sampler::<B>(device, &desc, id).unwrap();
}
A::DestroySampler(id) => {
self.sampler_drop::<B>(id);
@ -263,14 +233,11 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
self.render_pipeline_drop::<B>(id);
}
A::CreateRenderBundle { id, desc, base } => {
let label = Label::new(&desc.label.as_ref().unwrap());
let bundle =
wgc::command::RenderBundleEncoder::new(&desc, device, Some(base)).unwrap();
self.render_bundle_encoder_finish::<B>(
bundle,
&wgt::RenderBundleDescriptor {
label: label.as_ptr(),
},
&wgt::RenderBundleDescriptor { label: desc.label },
id,
)
.unwrap();
@ -309,7 +276,7 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
let encoder = self
.device_create_command_encoder::<B>(
device,
&wgt::CommandEncoderDescriptor { label: ptr::null() },
&wgt::CommandEncoderDescriptor { label: None },
comb_manager.alloc(device.backend()),
)
.unwrap();

View File

@ -12,7 +12,7 @@
CreateBuffer(
Id(0, 1, Empty),
(
label: "",
label: Some("dummy"),
size: 16,
usage: (
bits: 41,

View File

@ -7,7 +7,7 @@ use crate::{
id::{BindGroupLayoutId, BufferId, DeviceId, SamplerId, TextureViewId, Valid},
track::{TrackerSet, DUMMY_SELECTOR},
validation::{MissingBufferUsageError, MissingTextureUsageError},
FastHashMap, LifeGuard, MultiRefCount, RefCount, Stored, MAX_BIND_GROUPS,
FastHashMap, Label, LifeGuard, MultiRefCount, RefCount, Stored, MAX_BIND_GROUPS,
};
use arrayvec::ArrayVec;
@ -182,7 +182,7 @@ pub(crate) struct BindingTypeMaxCountValidator {
impl BindingTypeMaxCountValidator {
pub(crate) fn add_binding(&mut self, binding: &wgt::BindGroupLayoutEntry) {
let count = binding.count.unwrap_or(1);
let count = binding.count.map_or(1, |count| count.get());
match binding.ty {
wgt::BindingType::UniformBuffer { dynamic, .. } => {
self.uniform_buffers.add(binding.visibility, count);
@ -261,6 +261,42 @@ impl BindingTypeMaxCountValidator {
}
}
/// Bindable resource and the slot to bind it to.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct BindGroupEntry<'a> {
/// Slot for which binding provides resource. Corresponds to an entry of the same
/// binding index in the [`BindGroupLayoutDescriptor`].
pub binding: u32,
/// Resource to attach to the binding
pub resource: BindingResource<'a>,
}
/// Describes a group of bindings and the resources to be bound.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct BindGroupDescriptor<'a> {
/// Debug label of the bind group. This will show up in graphics debuggers for easy identification.
pub label: Label<'a>,
/// The [`BindGroupLayout`] that corresponds to this bind group.
pub layout: BindGroupLayoutId,
/// The resources to bind to this bind group.
pub entries: Cow<'a, [BindGroupEntry<'a>]>,
}
/// Describes a [`BindGroupLayout`].
#[derive(Clone, Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct BindGroupLayoutDescriptor<'a> {
/// Debug label of the bind group layout. This will show up in graphics debuggers for easy identification.
pub label: Label<'a>,
/// Array of entries in this BindGroupLayout
pub entries: Cow<'a, [wgt::BindGroupLayoutEntry]>,
}
pub(crate) type BindEntryMap = FastHashMap<u32, wgt::BindGroupLayoutEntry>;
#[derive(Debug)]
@ -335,6 +371,26 @@ pub enum PushConstantUploadError {
Unaligned(u32),
}
/// Describes a pipeline layout.
///
/// A `PipelineLayoutDescriptor` can be used to create a pipeline layout.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct PipelineLayoutDescriptor<'a> {
/// Debug label of the pipeine layout. This will show up in graphics debuggers for easy identification.
pub label: Label<'a>,
/// Bind groups that this pipeline uses. The first entry will provide all the bindings for
/// "set = 0", second entry will provide all the bindings for "set = 1" etc.
pub bind_group_layouts: Cow<'a, [BindGroupLayoutId]>,
/// Set of push constant ranges this pipeline uses. Each shader stage that uses push constants
/// must define the range in push constant memory that corresponds to its single `layout(push_constant)`
/// uniform block.
///
/// If this array is non-empty, the [`Features::PUSH_CONSTANTS`] must be enabled.
pub push_constant_ranges: Cow<'a, [wgt::PushConstantRange]>,
}
#[derive(Debug)]
pub struct PipelineLayout<B: hal::Backend> {
pub(crate) raw: B::PipelineLayout,
@ -446,11 +502,6 @@ pub enum BindingResource<'a> {
TextureViewArray(Cow<'a, [TextureViewId]>),
}
pub type BindGroupEntry<'a> = wgt::BindGroupEntry<BindingResource<'a>>;
pub type BindGroupDescriptor<'a> =
wgt::BindGroupDescriptor<'a, BindGroupLayoutId, BindGroupEntry<'a>>;
#[derive(Clone, Debug, Error)]
pub enum BindError {
#[error("number of dynamic offsets ({actual}) doesn't match the number of dynamic bindings in the bind group layout ({expected})")]

View File

@ -41,8 +41,7 @@ use crate::{
command::{BasePass, DrawError, RenderCommand, RenderCommandError},
conv,
device::{
AttachmentData, DeviceError, Label, RenderPassContext, MAX_VERTEX_BUFFERS,
SHADER_STAGE_COUNT,
AttachmentData, DeviceError, RenderPassContext, MAX_VERTEX_BUFFERS, SHADER_STAGE_COUNT,
},
hub::{GfxBackend, Global, GlobalIdentityHandlerFactory, Input, Storage, Token},
id,
@ -50,12 +49,35 @@ use crate::{
span,
track::TrackerSet,
validation::check_buffer_usage,
LifeGuard, RefCount, Stored, MAX_BIND_GROUPS,
Label, LifeGuard, RefCount, Stored, MAX_BIND_GROUPS,
};
use arrayvec::ArrayVec;
use std::{borrow::Borrow, iter, marker::PhantomData, ops::Range};
use std::{
borrow::{Borrow, Cow},
iter,
marker::PhantomData,
ops::Range,
};
use thiserror::Error;
/// Describes a [`RenderBundleEncoder`].
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct RenderBundleEncoderDescriptor<'a> {
/// Debug label of the render bundle encoder. This will show up in graphics debuggers for easy identification.
pub label: Label<'a>,
/// The formats of the color attachments that this render bundle is capable to rendering to. This
/// must match the formats of the color attachments in the renderpass this render bundle is executed in.
pub color_formats: Cow<'a, [wgt::TextureFormat]>,
/// The formats of the depth attachment that this render bundle is capable to rendering to. This
/// must match the formats of the depth attachments in the renderpass this render bundle is executed in.
pub depth_stencil_format: Option<wgt::TextureFormat>,
/// Sample count this render bundle is capable of rendering to. This must match the pipelines and
/// the renderpasses it is used in.
pub sample_count: u32,
}
#[derive(Debug)]
#[cfg_attr(feature = "serial-pass", derive(serde::Deserialize, serde::Serialize))]
pub struct RenderBundleEncoder {
@ -66,7 +88,7 @@ pub struct RenderBundleEncoder {
impl RenderBundleEncoder {
pub fn new(
desc: &wgt::RenderBundleEncoderDescriptor,
desc: &RenderBundleEncoderDescriptor,
parent_id: id::DeviceId,
base: Option<BasePass<RenderCommand>>,
) -> Result<Self, CreateRenderBundleError> {
@ -103,6 +125,8 @@ pub enum CreateRenderBundleError {
InvalidSampleCount(u32),
}
pub type RenderBundleDescriptor<'a> = wgt::RenderBundleDescriptor<Label<'a>>;
//Note: here, `RenderBundle` is just wrapping a raw stream of render commands.
// The plan is to back it by an actual Vulkan secondary buffer, D3D12 Bundle,
// or Metal indirect command buffer.
@ -613,7 +637,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn render_bundle_encoder_finish<B: GfxBackend>(
&self,
bundle_encoder: RenderBundleEncoder,
desc: &wgt::RenderBundleDescriptor<Label>,
desc: &RenderBundleDescriptor,
id_in: Input<G, id::RenderBundleId>,
) -> Result<id::RenderBundleId, RenderBundleError> {
span!(_guard, INFO, "RenderBundleEncoder::finish");
@ -908,9 +932,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
use crate::device::trace;
let (bundle_guard, _) = hub.render_bundles.read(&mut token);
let bundle = &bundle_guard[id];
let label = desc.label.as_ref().map(|l| l.as_ref());
trace.lock().add(trace::Action::CreateRenderBundle {
id: id.0,
desc: trace::new_render_bundle_encoder_descriptor(desc.label, &bundle.context),
desc: trace::new_render_bundle_encoder_descriptor(label, &bundle.context),
base: BasePass::from_ref(bundle.base.as_ref()),
});
}

View File

@ -25,7 +25,7 @@ use crate::{
resource::{Buffer, Texture},
span,
track::TrackerSet,
PrivateFeatures, Stored,
Label, PrivateFeatures, Stored,
};
use hal::command::CommandBuffer as _;
@ -168,7 +168,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn command_encoder_finish<B: GfxBackend>(
&self,
encoder_id: id::CommandEncoderId,
_desc: &wgt::CommandBufferDescriptor,
_desc: &wgt::CommandBufferDescriptor<Label>,
) -> Result<id::CommandBufferId, CommandEncoderError> {
span!(_guard, INFO, "CommandEncoder::finish");

View File

@ -37,7 +37,14 @@ use serde::Deserialize;
#[cfg(any(feature = "serial-pass", feature = "trace"))]
use serde::Serialize;
use std::{borrow::Borrow, collections::hash_map::Entry, fmt, iter, ops::Range, str};
use std::{
borrow::{Borrow, Cow},
collections::hash_map::Entry,
fmt, iter,
num::NonZeroU32,
ops::Range,
str,
};
/// Operation to perform to the output attachment at the start of a renderpass.
#[repr(C)]
@ -65,7 +72,7 @@ pub enum StoreOp {
/// Describes an individual channel within a render pass, such as color, depth, or stencil.
#[repr(C)]
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(any(feature = "serial-pass", feature = "trace"), derive(Serialize))]
#[cfg_attr(any(feature = "serial-pass", feature = "replay"), derive(Deserialize))]
pub struct PassChannel<V> {
@ -83,7 +90,7 @@ pub struct PassChannel<V> {
/// Describes a color attachment to a render pass.
#[repr(C)]
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(any(feature = "serial-pass", feature = "trace"), derive(Serialize))]
#[cfg_attr(any(feature = "serial-pass", feature = "replay"), derive(Deserialize))]
pub struct ColorAttachmentDescriptor {
@ -97,7 +104,7 @@ pub struct ColorAttachmentDescriptor {
/// Describes a depth/stencil attachment to a render pass.
#[repr(C)]
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(any(feature = "serial-pass", feature = "trace"), derive(Serialize))]
#[cfg_attr(any(feature = "serial-pass", feature = "replay"), derive(Deserialize))]
pub struct DepthStencilAttachmentDescriptor {
@ -109,27 +116,32 @@ pub struct DepthStencilAttachmentDescriptor {
pub stencil: PassChannel<u32>,
}
fn is_depth_stencil_read_only(
desc: &DepthStencilAttachmentDescriptor,
aspects: hal::format::Aspects,
) -> Result<bool, RenderPassError> {
if aspects.contains(hal::format::Aspects::DEPTH) && !desc.depth.read_only {
return Ok(false);
impl DepthStencilAttachmentDescriptor {
fn is_read_only(&self, aspects: hal::format::Aspects) -> Result<bool, RenderPassError> {
if aspects.contains(hal::format::Aspects::DEPTH) && !self.depth.read_only {
return Ok(false);
}
if (self.depth.load_op, self.depth.store_op) != (LoadOp::Load, StoreOp::Store) {
return Err(RenderPassError::InvalidDepthOps);
}
if aspects.contains(hal::format::Aspects::STENCIL) && !self.stencil.read_only {
return Ok(false);
}
if (self.stencil.load_op, self.stencil.store_op) != (LoadOp::Load, StoreOp::Store) {
return Err(RenderPassError::InvalidStencilOps);
}
Ok(true)
}
if (desc.depth.load_op, desc.depth.store_op) != (LoadOp::Load, StoreOp::Store) {
return Err(RenderPassError::InvalidDepthOps);
}
if aspects.contains(hal::format::Aspects::STENCIL) && !desc.stencil.read_only {
return Ok(false);
}
if (desc.stencil.load_op, desc.stencil.store_op) != (LoadOp::Load, StoreOp::Store) {
return Err(RenderPassError::InvalidStencilOps);
}
Ok(true)
}
pub type RenderPassDescriptor<'a> =
wgt::RenderPassDescriptor<'a, ColorAttachmentDescriptor, &'a DepthStencilAttachmentDescriptor>;
/// Describes the attachments of a render pass.
#[derive(Clone, Debug, Default, PartialEq)]
pub struct RenderPassDescriptor<'a> {
/// The color attachments of the render pass.
pub color_attachments: Cow<'a, [ColorAttachmentDescriptor]>,
/// The depth and stencil attachment of the render pass, if any.
pub depth_stencil_attachment: Option<&'a DepthStencilAttachmentDescriptor>,
}
#[derive(Clone, Copy, Debug, Default)]
#[cfg_attr(any(feature = "serial-pass", feature = "trace"), derive(Serialize))]
@ -198,7 +210,7 @@ pub enum RenderCommand {
buffer_id: id::BufferId,
offset: BufferAddress,
/// Count of `None` represents a non-multi call.
count: Option<u32>,
count: Option<NonZeroU32>,
indexed: bool,
},
MultiDrawIndirectCount {
@ -425,7 +437,7 @@ pub enum RenderPassError {
#[error("indirect draw with offset {offset}{} uses bytes {begin_offset}..{end_offset} which overruns indirect buffer of size {buffer_size}", count.map_or_else(String::new, |v| format!(" and count {}", v)))]
IndirectBufferOverrun {
offset: u64,
count: Option<u32>,
count: Option<NonZeroU32>,
begin_offset: u64,
end_offset: u64,
buffer_size: u64,
@ -604,7 +616,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let previous_use = base_trackers
.textures
.query(source_id.value, view.range.clone());
let new_use = if is_depth_stencil_read_only(at, view.range.aspects)? {
let new_use = if at.is_read_only(view.range.aspects)? {
is_ds_read_only = true;
TextureUse::ATTACHMENT_READ
} else {
@ -1414,7 +1426,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.unwrap();
check_buffer_usage(buffer.usage, BufferUsage::INDIRECT)?;
let actual_count = count.unwrap_or(1);
let actual_count = count.map_or(1, |c| c.get());
let begin_offset = offset;
let end_offset = offset + stride * actual_count as u64;
@ -1622,7 +1634,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub mod render_ffi {
use super::{super::Rect, RenderCommand, RenderPass};
use crate::{id, span, RawString};
use std::{convert::TryInto, ffi, slice};
use std::{convert::TryInto, ffi, num::NonZeroU32, slice};
use wgt::{BufferAddress, BufferSize, Color, DynamicOffset};
/// # Safety
@ -1840,7 +1852,7 @@ pub mod render_ffi {
pass.base.commands.push(RenderCommand::MultiDrawIndirect {
buffer_id,
offset,
count: Some(count),
count: NonZeroU32::new(count),
indexed: false,
});
}
@ -1856,7 +1868,7 @@ pub mod render_ffi {
pass.base.commands.push(RenderCommand::MultiDrawIndirect {
buffer_id,
offset,
count: Some(count),
count: NonZeroU32::new(count),
indexed: true,
});
}

View File

@ -244,35 +244,26 @@ pub fn map_depth_stencil_state_descriptor(
hal::pso::DepthStencilDesc {
depth: if desc.depth_write_enabled || desc.depth_compare != wgt::CompareFunction::Always {
Some(hal::pso::DepthTest {
fun: map_compare_function(desc.depth_compare)
.expect("DepthStencilStateDescriptor has undefined compare function"),
fun: map_compare_function(desc.depth_compare),
write: desc.depth_write_enabled,
})
} else {
None
},
depth_bounds: false, // TODO
stencil: if desc.stencil_read_mask != !0
|| desc.stencil_write_mask != !0
|| desc.stencil_front != wgt::StencilStateFaceDescriptor::IGNORE
|| desc.stencil_back != wgt::StencilStateFaceDescriptor::IGNORE
{
Some(hal::pso::StencilTest {
faces: hal::pso::Sided {
front: map_stencil_face(&desc.stencil_front),
back: map_stencil_face(&desc.stencil_back),
},
read_masks: hal::pso::State::Static(hal::pso::Sided::new(desc.stencil_read_mask)),
write_masks: hal::pso::State::Static(hal::pso::Sided::new(desc.stencil_write_mask)),
reference_values: if desc.needs_stencil_reference() {
hal::pso::State::Dynamic
} else {
hal::pso::State::Static(hal::pso::Sided::new(0))
},
})
} else {
None
},
stencil: desc.stencil.as_ref().map(|stencil| hal::pso::StencilTest {
faces: hal::pso::Sided {
front: map_stencil_face(&stencil.front),
back: map_stencil_face(&stencil.back),
},
read_masks: hal::pso::State::Static(hal::pso::Sided::new(stencil.read_mask)),
write_masks: hal::pso::State::Static(hal::pso::Sided::new(stencil.write_mask)),
reference_values: if stencil.needs_ref_value() {
hal::pso::State::Dynamic
} else {
hal::pso::State::Static(hal::pso::Sided::new(0))
},
}),
}
}
@ -280,29 +271,25 @@ fn map_stencil_face(
stencil_state_face_desc: &wgt::StencilStateFaceDescriptor,
) -> hal::pso::StencilFace {
hal::pso::StencilFace {
fun: map_compare_function(stencil_state_face_desc.compare)
.expect("StencilStateFaceDescriptor has undefined compare function"),
fun: map_compare_function(stencil_state_face_desc.compare),
op_fail: map_stencil_operation(stencil_state_face_desc.fail_op),
op_depth_fail: map_stencil_operation(stencil_state_face_desc.depth_fail_op),
op_pass: map_stencil_operation(stencil_state_face_desc.pass_op),
}
}
pub fn map_compare_function(
compare_function: wgt::CompareFunction,
) -> Option<hal::pso::Comparison> {
pub fn map_compare_function(compare_function: wgt::CompareFunction) -> hal::pso::Comparison {
use hal::pso::Comparison as H;
use wgt::CompareFunction as Cf;
match compare_function {
Cf::Undefined => None,
Cf::Never => Some(H::Never),
Cf::Less => Some(H::Less),
Cf::Equal => Some(H::Equal),
Cf::LessEqual => Some(H::LessEqual),
Cf::Greater => Some(H::Greater),
Cf::NotEqual => Some(H::NotEqual),
Cf::GreaterEqual => Some(H::GreaterEqual),
Cf::Always => Some(H::Always),
Cf::Never => H::Never,
Cf::Less => H::Less,
Cf::Equal => H::Equal,
Cf::LessEqual => H::LessEqual,
Cf::Greater => H::Greater,
Cf::NotEqual => H::NotEqual,
Cf::GreaterEqual => H::GreaterEqual,
Cf::Always => H::Always,
}
}

View File

@ -12,7 +12,7 @@ use crate::{
id, pipeline, resource, span, swap_chain,
track::{BufferState, TextureState, TrackerSet},
validation::{self, check_buffer_usage, check_texture_usage},
FastHashMap, LifeGuard, MultiRefCount, PrivateFeatures, Stored, SubmissionIndex,
FastHashMap, Label, LifeGuard, MultiRefCount, PrivateFeatures, Stored, SubmissionIndex,
MAX_BIND_GROUPS,
};
@ -30,8 +30,8 @@ use thiserror::Error;
use wgt::{BufferAddress, BufferSize, InputStepMode, TextureDimension, TextureFormat};
use std::{
borrow::Cow, collections::hash_map::Entry, ffi, iter, marker::PhantomData, mem, ops::Range,
ptr, sync::atomic::Ordering,
borrow::Cow, collections::hash_map::Entry, iter, marker::PhantomData, mem, ops::Range, ptr,
sync::atomic::Ordering,
};
mod life;
@ -43,18 +43,6 @@ use smallvec::SmallVec;
#[cfg(feature = "trace")]
use trace::{Action, Trace};
pub type Label = *const std::os::raw::c_char;
#[cfg(feature = "trace")]
fn own_label(label: &Label) -> String {
if label.is_null() {
String::new()
} else {
unsafe { ffi::CStr::from_ptr(*label) }
.to_string_lossy()
.to_string()
}
}
pub const MAX_COLOR_TARGETS: usize = 4;
pub const MAX_MIP_LEVELS: u32 = 16;
pub const MAX_VERTEX_BUFFERS: usize = 16;
@ -394,7 +382,7 @@ impl<B: GfxBackend> Device<B> {
fn create_buffer(
&self,
self_id: id::DeviceId,
desc: &wgt::BufferDescriptor<Label>,
desc: &resource::BufferDescriptor,
memory_kind: gfx_memory::Kind,
) -> Result<resource::Buffer<B>, resource::CreateBufferError> {
debug_assert_eq!(self_id.backend(), B::VARIANT);
@ -428,19 +416,14 @@ impl<B: GfxBackend> Device<B> {
}
};
let mut buffer = unsafe {
self.raw
.create_buffer(desc.size.max(1), usage)
.map_err(|err| match err {
hal::buffer::CreationError::OutOfMemory(_) => DeviceError::OutOfMemory,
_ => panic!("failed to create buffer: {}", err),
})?
};
if !desc.label.is_null() {
unsafe {
let label = ffi::CStr::from_ptr(desc.label).to_string_lossy();
self.raw.set_buffer_name(&mut buffer, &label)
};
let mut buffer = unsafe { self.raw.create_buffer(desc.size.max(1), usage) }.map_err(
|err| match err {
hal::buffer::CreationError::OutOfMemory(_) => DeviceError::OutOfMemory,
_ => panic!("failed to create buffer: {}", err),
},
)?;
if let Some(ref label) = desc.label {
unsafe { self.raw.set_buffer_name(&mut buffer, label) };
}
let requirements = unsafe { self.raw.get_buffer_requirements(&buffer) };
@ -474,7 +457,7 @@ impl<B: GfxBackend> Device<B> {
fn create_texture(
&self,
self_id: id::DeviceId,
desc: &wgt::TextureDescriptor<Label>,
desc: &resource::TextureDescriptor,
) -> Result<resource::Texture<B>, resource::CreateTextureError> {
debug_assert_eq!(self_id.backend(), B::VARIANT);
@ -527,9 +510,8 @@ impl<B: GfxBackend> Device<B> {
hal::image::CreationError::OutOfMemory(_) => DeviceError::OutOfMemory,
_ => panic!("failed to create texture: {}", err),
})?;
if !desc.label.is_null() {
let label = ffi::CStr::from_ptr(desc.label).to_string_lossy();
self.raw.set_image_name(&mut image, &label);
if let Some(ref label) = desc.label {
self.raw.set_image_name(&mut image, label);
}
image
};
@ -638,10 +620,7 @@ impl<B: GfxBackend> Device<B> {
) -> Result<binding_model::BindGroupLayout<B>, binding_model::CreateBindGroupLayoutError> {
// Validate the count parameter
for binding in entry_map.values() {
if let Some(count) = binding.count {
if count == 0 {
return Err(binding_model::CreateBindGroupLayoutError::ZeroCount);
}
if binding.count.is_some() {
match binding.ty {
wgt::BindingType::SampledTexture { .. } => {
if !self
@ -665,7 +644,7 @@ impl<B: GfxBackend> Device<B> {
ty: conv::map_binding_type(entry),
count: entry
.count
.map_or(1, |v| v as hal::pso::DescriptorArrayIndex), //TODO: consolidate
.map_or(1, |v| v.get() as hal::pso::DescriptorArrayIndex), //TODO: consolidate
stage_flags: conv::map_shader_stage_flags(entry.visibility),
immutable_samplers: false, // TODO
})
@ -703,7 +682,7 @@ impl<B: GfxBackend> Device<B> {
desc_counts: raw_bindings.iter().cloned().collect(),
dynamic_count: entry_map
.values()
.filter(|b| b.has_dynamic_offset())
.filter(|b| b.ty.has_dynamic_offset())
.count(),
count_validator,
entries: entry_map,
@ -713,7 +692,7 @@ impl<B: GfxBackend> Device<B> {
fn create_pipeline_layout(
&self,
self_id: id::DeviceId,
desc: &wgt::PipelineLayoutDescriptor<id::BindGroupLayoutId>,
desc: &binding_model::PipelineLayoutDescriptor,
bgl_guard: &Storage<binding_model::BindGroupLayout<B>, id::BindGroupLayoutId>,
) -> Result<binding_model::PipelineLayout<B>, CreatePipelineLayoutError> {
let bind_group_layouts_count = desc.bind_group_layouts.len();
@ -790,12 +769,20 @@ impl<B: GfxBackend> Device<B> {
.iter()
.map(|pc| (conv::map_shader_stage_flags(pc.stages), pc.range.clone()));
let raw = unsafe {
let raw_layout = self
.raw
.create_pipeline_layout(descriptor_set_layouts, push_constants)
.or(Err(DeviceError::OutOfMemory))?;
if let Some(_) = desc.label {
//TODO-0.6: needs gfx changes published
//self.raw.set_pipeline_layout_name(&mut raw_layout, label);
}
raw_layout
};
Ok(binding_model::PipelineLayout {
raw: unsafe {
self.raw
.create_pipeline_layout(descriptor_set_layouts, push_constants)
.or(Err(DeviceError::OutOfMemory))?
},
raw,
device_id: Stored {
value: id::Valid(self_id),
ref_count: self.life_guard.add_ref(),
@ -956,7 +943,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn device_create_buffer<B: GfxBackend>(
&self,
device_id: id::DeviceId,
desc: &wgt::BufferDescriptor<Label>,
desc: &resource::BufferDescriptor,
id_in: Input<G, id::BufferId>,
) -> Result<id::BufferId, resource::CreateBufferError> {
span!(_guard, INFO, "Device::create_buffer");
@ -1000,7 +987,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let mut stage = device.create_buffer(
device_id,
&wgt::BufferDescriptor {
label: b"<init_buffer>\0".as_ptr() as *const _,
label: Some(Cow::Borrowed("<init_buffer>")),
size: desc.size,
usage: wgt::BufferUsage::MAP_WRITE | wgt::BufferUsage::COPY_SRC,
mapped_at_creation: false,
@ -1025,7 +1012,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
#[cfg(feature = "trace")]
match device.trace {
Some(ref trace) => {
let mut desc = desc.map_label(own_label);
let mut desc = desc.clone();
let mapped_at_creation = mem::replace(&mut desc.mapped_at_creation, false);
if mapped_at_creation && !desc.usage.contains(wgt::BufferUsage::MAP_WRITE) {
desc.usage |= wgt::BufferUsage::COPY_DST;
@ -1222,7 +1209,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn device_create_texture<B: GfxBackend>(
&self,
device_id: id::DeviceId,
desc: &wgt::TextureDescriptor<Label>,
desc: &resource::TextureDescriptor,
id_in: Input<G, id::TextureId>,
) -> Result<id::TextureId, resource::CreateTextureError> {
span!(_guard, INFO, "Device::create_texture");
@ -1241,10 +1228,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let id = hub.textures.register_identity(id_in, texture, &mut token);
#[cfg(feature = "trace")]
match device.trace {
Some(ref trace) => trace.lock().add(trace::Action::CreateTexture(
id.0,
desc.map_label(own_label),
)),
Some(ref trace) => trace
.lock()
.add(trace::Action::CreateTexture(id.0, desc.clone())),
None => (),
};
@ -1306,7 +1292,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn texture_create_view<B: GfxBackend>(
&self,
texture_id: id::TextureId,
desc: Option<&wgt::TextureViewDescriptor<Label>>,
desc: &resource::TextureViewDescriptor,
id_in: Input<G, id::TextureViewId>,
) -> Result<id::TextureViewId, resource::CreateTextureViewError> {
span!(_guard, INFO, "Texture::create_view");
@ -1321,62 +1307,57 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.map_err(|_| resource::CreateTextureViewError::InvalidTexture)?;
let device = &device_guard[texture.device_id.value];
let (format, view_kind, range) = match desc {
Some(desc) => {
let kind = conv::map_texture_view_dimension(desc.dimension);
let required_level_count =
desc.base_mip_level + desc.level_count.map_or(1, |count| count.get());
let required_layer_count =
desc.base_array_layer + desc.array_layer_count.map_or(1, |count| count.get());
let level_end = texture.full_range.levels.end;
let layer_end = texture.full_range.layers.end;
if required_level_count > level_end as u32 {
return Err(resource::CreateTextureViewError::InvalidMipLevelCount {
requested: required_level_count,
total: level_end,
});
}
if required_layer_count > layer_end as u32 {
return Err(resource::CreateTextureViewError::InvalidArrayLayerCount {
requested: required_layer_count,
total: layer_end,
});
};
let end_level = desc
.level_count
.map_or(level_end, |_| required_level_count as u8);
let end_layer = desc
.array_layer_count
.map_or(layer_end, |_| required_layer_count as u16);
let aspects = match desc.aspect {
wgt::TextureAspect::All => texture.full_range.aspects,
wgt::TextureAspect::DepthOnly => hal::format::Aspects::DEPTH,
wgt::TextureAspect::StencilOnly => hal::format::Aspects::STENCIL,
};
if !texture.full_range.aspects.contains(aspects) {
return Err(resource::CreateTextureViewError::InvalidAspect {
requested: aspects,
total: texture.full_range.aspects,
});
}
let view_kind = match desc.dimension {
Some(dim) => conv::map_texture_view_dimension(dim),
None => match texture.kind {
hal::image::Kind::D1(_, 1) => hal::image::ViewKind::D1,
hal::image::Kind::D1(..) => hal::image::ViewKind::D1Array,
hal::image::Kind::D2(_, _, 1, _) => hal::image::ViewKind::D2,
hal::image::Kind::D2(..) => hal::image::ViewKind::D2Array,
hal::image::Kind::D3(..) => hal::image::ViewKind::D3,
},
};
let required_level_count =
desc.base_mip_level + desc.level_count.map_or(1, |count| count.get());
let required_layer_count =
desc.base_array_layer + desc.array_layer_count.map_or(1, |count| count.get());
let level_end = texture.full_range.levels.end;
let layer_end = texture.full_range.layers.end;
if required_level_count > level_end as u32 {
return Err(resource::CreateTextureViewError::InvalidMipLevelCount {
requested: required_level_count,
total: level_end,
});
}
if required_layer_count > layer_end as u32 {
return Err(resource::CreateTextureViewError::InvalidArrayLayerCount {
requested: required_layer_count,
total: layer_end,
});
};
let end_level = desc
.level_count
.map_or(level_end, |_| required_level_count as u8);
let end_layer = desc
.array_layer_count
.map_or(layer_end, |_| required_layer_count as u16);
let aspects = match desc.aspect {
wgt::TextureAspect::All => texture.full_range.aspects,
wgt::TextureAspect::DepthOnly => hal::format::Aspects::DEPTH,
wgt::TextureAspect::StencilOnly => hal::format::Aspects::STENCIL,
};
if !texture.full_range.aspects.contains(aspects) {
return Err(resource::CreateTextureViewError::InvalidAspect {
requested: aspects,
total: texture.full_range.aspects,
});
}
let range = hal::image::SubresourceRange {
aspects,
levels: desc.base_mip_level as u8..end_level,
layers: desc.base_array_layer as u16..end_layer,
};
(desc.format, kind, range)
}
None => {
let kind = match texture.kind {
hal::image::Kind::D1(_, 1) => hal::image::ViewKind::D1,
hal::image::Kind::D1(..) => hal::image::ViewKind::D1Array,
hal::image::Kind::D2(_, _, 1, _) => hal::image::ViewKind::D2,
hal::image::Kind::D2(..) => hal::image::ViewKind::D2Array,
hal::image::Kind::D3(..) => hal::image::ViewKind::D3,
};
(texture.format, kind, texture.full_range.clone())
}
let format = desc.format.unwrap_or(texture.format);
let range = hal::image::SubresourceRange {
aspects,
levels: desc.base_mip_level as u8..end_level,
layers: desc.base_array_layer as u16..end_layer,
};
let raw = unsafe {
@ -1414,7 +1395,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
Some(ref trace) => trace.lock().add(trace::Action::CreateTextureView {
id: id.0,
parent_id: texture_id,
desc: desc.map(|d| d.map_label(own_label)),
desc: desc.clone(),
}),
None => (),
};
@ -1482,7 +1463,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn device_create_sampler<B: GfxBackend>(
&self,
device_id: id::DeviceId,
desc: &wgt::SamplerDescriptor<Label>,
desc: &resource::SamplerDescriptor,
id_in: Input<G, id::SamplerId>,
) -> Result<id::SamplerId, resource::CreateSamplerError> {
span!(_guard, INFO, "Device::create_sampler");
@ -1495,6 +1476,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.map_err(|_| DeviceError::Invalid)?;
let actual_clamp = if let Some(clamp) = desc.anisotropy_clamp {
let clamp = clamp.get();
let valid_clamp = clamp <= MAX_ANISOTROPY && conv::is_power_of_two(clamp as u32);
if !valid_clamp {
return Err(resource::CreateSamplerError::InvalidClamp(clamp));
@ -1513,13 +1495,13 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
mag_filter: conv::map_filter(desc.mag_filter),
mip_filter: conv::map_filter(desc.mipmap_filter),
wrap_mode: (
conv::map_wrap(desc.address_mode_u),
conv::map_wrap(desc.address_mode_v),
conv::map_wrap(desc.address_mode_w),
conv::map_wrap(desc.address_modes[0]),
conv::map_wrap(desc.address_modes[1]),
conv::map_wrap(desc.address_modes[2]),
),
lod_bias: hal::image::Lod(0.0),
lod_range: hal::image::Lod(desc.lod_min_clamp)..hal::image::Lod(desc.lod_max_clamp),
comparison: desc.compare.and_then(conv::map_compare_function),
comparison: desc.compare.map(conv::map_compare_function),
border: hal::image::PackedColor(0),
normalized: true,
anisotropy_clamp: actual_clamp,
@ -1549,10 +1531,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let id = hub.samplers.register_identity(id_in, sampler, &mut token);
#[cfg(feature = "trace")]
match device.trace {
Some(ref trace) => trace.lock().add(trace::Action::CreateSampler(
id.0,
desc.map_label(own_label),
)),
Some(ref trace) => trace
.lock()
.add(trace::Action::CreateSampler(id.0, desc.clone())),
None => (),
};
@ -1603,7 +1584,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn device_create_bind_group_layout<B: GfxBackend>(
&self,
device_id: id::DeviceId,
desc: &wgt::BindGroupLayoutDescriptor,
desc: &binding_model::BindGroupLayoutDescriptor,
id_in: Input<G, id::BindGroupLayoutId>,
) -> Result<id::BindGroupLayoutId, binding_model::CreateBindGroupLayoutError> {
span!(_guard, INFO, "Device::create_bind_group_layout");
@ -1695,7 +1676,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn device_create_pipeline_layout<B: GfxBackend>(
&self,
device_id: id::DeviceId,
desc: &wgt::PipelineLayoutDescriptor<id::BindGroupLayoutId>,
desc: &binding_model::PipelineLayoutDescriptor,
id_in: Input<G, id::PipelineLayoutId>,
) -> Result<id::PipelineLayoutId, CreatePipelineLayoutError> {
span!(_guard, INFO, "Device::create_pipeline_layout");
@ -1810,7 +1791,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
Some(dedup_id) => dedup_id,
None => {
#[cfg(feature = "trace")]
let bgl_desc = wgt::BindGroupLayoutDescriptor {
let bgl_desc = binding_model::BindGroupLayoutDescriptor {
label: None,
entries: if device.trace.is_some() {
Cow::Owned(map.values().cloned().collect())
@ -1837,7 +1818,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
derived_group_layout_ids.push(processed_id);
}
let layout_desc = wgt::PipelineLayoutDescriptor {
let layout_desc = binding_model::PipelineLayoutDescriptor {
label: None,
bind_group_layouts: Cow::Borrowed(&derived_group_layout_ids),
push_constant_ranges: Cow::Borrowed(&[]), //TODO?
};
@ -2113,7 +2095,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}
if let Some(count) = decl.count {
let count = count as usize;
let count = count.get() as usize;
let num_bindings = bindings_array.len();
if count != num_bindings {
return Err(CreateBindGroupError::BindingArrayLengthMismatch {
@ -2433,11 +2415,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
unsafe {
let raw_command_buffer = command_buffer.raw.last_mut().unwrap();
if !desc.label.is_null() {
let label = ffi::CStr::from_ptr(desc.label).to_string_lossy();
if let Some(ref label) = desc.label {
device
.raw
.set_command_buffer_name(raw_command_buffer, &label);
.set_command_buffer_name(raw_command_buffer, label);
}
raw_command_buffer.begin_primary(hal::command::CommandBufferFlags::ONE_TIME_SUBMIT);
}
@ -2491,7 +2472,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn device_create_render_bundle_encoder(
&self,
device_id: id::DeviceId,
desc: &wgt::RenderBundleEncoderDescriptor,
desc: &command::RenderBundleEncoderDescriptor,
) -> Result<id::RenderBundleEncoderId, command::CreateRenderBundleError> {
span!(_guard, INFO, "Device::create_render_bundle_encoder");
let encoder = command::RenderBundleEncoder::new(desc, device_id, None);
@ -2933,7 +2914,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}
}
if let Some(ds) = depth_stencil_state.as_ref() {
if ds.needs_stencil_reference() {
if ds.stencil.as_ref().map_or(false, |s| s.needs_ref_value()) {
flags |= pipeline::PipelineFlags::STENCIL_REFERENCE;
}
if !ds.is_read_only() {
@ -2966,7 +2947,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
match device.trace {
Some(ref trace) => trace.lock().add(trace::Action::CreateRenderPipeline(
id.0,
wgt::RenderPipelineDescriptor {
pipeline::RenderPipelineDescriptor {
layout: Some(layout_id),
..desc.clone()
},
@ -3185,7 +3166,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
match device.trace {
Some(ref trace) => trace.lock().add(trace::Action::CreateComputePipeline(
id.0,
wgt::ComputePipelineDescriptor {
pipeline::ComputePipelineDescriptor {
layout: Some(layout_id),
..desc.clone()
},

View File

@ -5,7 +5,7 @@
use crate::id;
#[cfg(feature = "trace")]
use std::io::Write as _;
use std::ops::Range;
use std::{borrow::Cow, ops::Range};
//TODO: consider a readable Id that doesn't include the backend
@ -14,13 +14,13 @@ type FileName = String;
pub const FILE_NAME: &str = "trace.ron";
#[cfg(feature = "trace")]
pub(crate) fn new_render_bundle_encoder_descriptor(
label: super::Label,
context: &super::RenderPassContext,
) -> wgt::RenderBundleEncoderDescriptor {
wgt::RenderBundleEncoderDescriptor {
label: Some(super::own_label(&label).into()),
color_formats: context.attachments.colors.to_vec().into(),
pub(crate) fn new_render_bundle_encoder_descriptor<'a>(
label: Option<&'a str>,
context: &'a super::RenderPassContext,
) -> crate::command::RenderBundleEncoderDescriptor<'a> {
crate::command::RenderBundleEncoderDescriptor {
label: label.map(Cow::Borrowed),
color_formats: Cow::Borrowed(&context.attachments.colors),
depth_stencil_format: context.attachments.depth_stencil,
sample_count: context.sample_count as u32,
}
@ -34,17 +34,17 @@ pub enum Action<'a> {
desc: wgt::DeviceDescriptor,
backend: wgt::Backend,
},
CreateBuffer(id::BufferId, wgt::BufferDescriptor<String>),
CreateBuffer(id::BufferId, crate::resource::BufferDescriptor<'a>),
DestroyBuffer(id::BufferId),
CreateTexture(id::TextureId, wgt::TextureDescriptor<String>),
CreateTexture(id::TextureId, crate::resource::TextureDescriptor<'a>),
DestroyTexture(id::TextureId),
CreateTextureView {
id: id::TextureViewId,
parent_id: id::TextureId,
desc: Option<wgt::TextureViewDescriptor<String>>,
desc: crate::resource::TextureViewDescriptor<'a>,
},
DestroyTextureView(id::TextureViewId),
CreateSampler(id::SamplerId, wgt::SamplerDescriptor<String>),
CreateSampler(id::SamplerId, crate::resource::SamplerDescriptor<'a>),
DestroySampler(id::SamplerId),
CreateSwapChain(id::SwapChainId, wgt::SwapChainDescriptor),
GetSwapChainTexture {
@ -52,20 +52,19 @@ pub enum Action<'a> {
parent_id: id::SwapChainId,
},
PresentSwapChain(id::SwapChainId),
CreateBindGroupLayout(id::BindGroupLayoutId, wgt::BindGroupLayoutDescriptor<'a>),
CreateBindGroupLayout(
id::BindGroupLayoutId,
crate::binding_model::BindGroupLayoutDescriptor<'a>,
),
DestroyBindGroupLayout(id::BindGroupLayoutId),
CreatePipelineLayout(
id::PipelineLayoutId,
wgt::PipelineLayoutDescriptor<'a, id::BindGroupLayoutId>,
crate::binding_model::PipelineLayoutDescriptor<'a>,
),
DestroyPipelineLayout(id::PipelineLayoutId),
CreateBindGroup(
id::BindGroupId,
wgt::BindGroupDescriptor<
'a,
id::BindGroupLayoutId,
wgt::BindGroupEntry<crate::binding_model::BindingResource<'a>>,
>,
crate::binding_model::BindGroupDescriptor<'a>,
),
DestroyBindGroup(id::BindGroupId),
CreateShaderModule {
@ -75,24 +74,17 @@ pub enum Action<'a> {
DestroyShaderModule(id::ShaderModuleId),
CreateComputePipeline(
id::ComputePipelineId,
wgt::ComputePipelineDescriptor<
id::PipelineLayoutId,
wgt::ProgrammableStageDescriptor<'a, id::ShaderModuleId>,
>,
crate::pipeline::ComputePipelineDescriptor<'a>,
),
DestroyComputePipeline(id::ComputePipelineId),
CreateRenderPipeline(
id::RenderPipelineId,
wgt::RenderPipelineDescriptor<
'a,
id::PipelineLayoutId,
wgt::ProgrammableStageDescriptor<'a, id::ShaderModuleId>,
>,
crate::pipeline::RenderPipelineDescriptor<'a>,
),
DestroyRenderPipeline(id::RenderPipelineId),
CreateRenderBundle {
id: id::RenderBundleId,
desc: wgt::RenderBundleEncoderDescriptor<'a>,
desc: crate::command::RenderBundleEncoderDescriptor<'a>,
base: crate::command::BasePass<crate::command::RenderCommand>,
},
DestroyRenderBundle(id::RenderBundleId),

View File

@ -49,7 +49,7 @@ use std::sync::atomic;
use atomic::{AtomicUsize, Ordering};
use std::{os::raw::c_char, ptr};
use std::{borrow::Cow, os::raw::c_char, ptr};
pub const MAX_BIND_GROUPS: usize = 8;
@ -58,6 +58,7 @@ type Index = u32;
type Epoch = u32;
pub type RawString = *const c_char;
pub type Label<'a> = Option<Cow<'a, str>>;
/// Reference count object that is 1:1 with each reference.
#[derive(Debug)]

View File

@ -36,7 +36,17 @@ pub enum CreateShaderModuleError {
Validation(#[from] naga::proc::ValidationError),
}
pub type ProgrammableStageDescriptor<'a> = wgt::ProgrammableStageDescriptor<'a, ShaderModuleId>;
/// Describes a programmable pipeline stage.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct ProgrammableStageDescriptor<'a> {
/// The compiled shader module for this stage.
pub module: ShaderModuleId,
/// The name of the entry point in the compiled shader. There must be a function that returns
/// void with this name in the shader.
pub entry_point: Cow<'a, str>,
}
/// Number of implicit bind groups derived at pipeline creation.
pub type ImplicitBindGroupCount = u8;
@ -53,8 +63,16 @@ pub enum ImplicitLayoutError {
Pipeline(#[from] CreatePipelineLayoutError),
}
pub type ComputePipelineDescriptor<'a> =
wgt::ComputePipelineDescriptor<PipelineLayoutId, ProgrammableStageDescriptor<'a>>;
/// Describes a compute pipeline.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct ComputePipelineDescriptor<'a> {
/// The layout of bind groups for this pipeline.
pub layout: Option<PipelineLayoutId>,
/// The compiled compute stage and its entry point.
pub compute_stage: ProgrammableStageDescriptor<'a>,
}
#[derive(Clone, Debug, Error)]
pub enum CreateComputePipelineError {
@ -82,8 +100,65 @@ impl<B: hal::Backend> Borrow<RefCount> for ComputePipeline<B> {
}
}
pub type RenderPipelineDescriptor<'a> =
wgt::RenderPipelineDescriptor<'a, PipelineLayoutId, ProgrammableStageDescriptor<'a>>;
/// Describes how the vertex buffer is interpreted.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct VertexBufferDescriptor<'a> {
/// The stride, in bytes, between elements of this buffer.
pub stride: BufferAddress,
/// How often this vertex buffer is "stepped" forward.
pub step_mode: InputStepMode,
/// The list of attributes which comprise a single vertex.
pub attributes: Cow<'a, [wgt::VertexAttributeDescriptor]>,
}
/// Describes vertex input state for a render pipeline.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct VertexStateDescriptor<'a> {
/// The format of any index buffers used with this pipeline.
pub index_format: IndexFormat,
/// The format of any vertex buffers used with this pipeline.
pub vertex_buffers: Cow<'a, [VertexBufferDescriptor<'a>]>,
}
/// Describes a render (graphics) pipeline.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct RenderPipelineDescriptor<'a> {
/// The layout of bind groups for this pipeline.
pub layout: Option<PipelineLayoutId>,
/// The compiled vertex stage and its entry point.
pub vertex_stage: ProgrammableStageDescriptor<'a>,
/// The compiled fragment stage and its entry point, if any.
pub fragment_stage: Option<ProgrammableStageDescriptor<'a>>,
/// The rasterization process for this pipeline.
pub rasterization_state: Option<wgt::RasterizationStateDescriptor>,
/// The primitive topology used to interpret vertices.
pub primitive_topology: wgt::PrimitiveTopology,
/// The effect of draw calls on the color aspect of the output target.
pub color_states: Cow<'a, [wgt::ColorStateDescriptor]>,
/// The effect of draw calls on the depth and stencil aspects of the output target, if any.
pub depth_stencil_state: Option<wgt::DepthStencilStateDescriptor>,
/// The vertex input state for this pipeline.
pub vertex_state: VertexStateDescriptor<'a>,
/// The number of samples calculated per pixel (for MSAA). For non-multisampled textures,
/// this should be `1`
pub sample_count: u32,
/// Bitmask that restricts the samples of a pixel modified by this pipeline. All samples
/// can be enabled using the value `!0`
pub sample_mask: u32,
/// When enabled, produces another sample mask per pixel based on the alpha output value, that
/// is ANDed with the sample_mask and the primitive coverage to restrict the set of samples
/// affected by a primitive.
///
/// The implicit mask produced for alpha of zero is guaranteed to be zero, and for alpha of one
/// is guaranteed to be all 1-s.
pub alpha_to_coverage_enabled: bool,
}
#[derive(Clone, Debug, Error)]
pub enum CreateRenderPipelineError {

View File

@ -7,14 +7,17 @@ use crate::{
id::{DeviceId, SwapChainId, TextureId},
track::DUMMY_SELECTOR,
validation::MissingBufferUsageError,
LifeGuard, RefCount, Stored,
Label, LifeGuard, RefCount, Stored,
};
use gfx_memory::MemoryBlock;
use thiserror::Error;
use wgt::{BufferAddress, BufferUsage, TextureFormat, TextureUsage};
use std::{borrow::Borrow, ptr::NonNull};
use std::{
borrow::Borrow,
num::{NonZeroU32, NonZeroU8},
ptr::NonNull,
};
bitflags::bitflags! {
/// The internal enum mirrored from `BufferUsage`. The values don't have to match!
@ -155,13 +158,15 @@ pub(crate) struct BufferPendingMapping {
pub parent_ref_count: RefCount,
}
pub type BufferDescriptor<'a> = wgt::BufferDescriptor<Label<'a>>;
#[derive(Debug)]
pub struct Buffer<B: hal::Backend> {
pub(crate) raw: B::Buffer,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) usage: BufferUsage,
pub(crate) usage: wgt::BufferUsage,
pub(crate) memory: MemoryBlock<B>,
pub(crate) size: BufferAddress,
pub(crate) size: wgt::BufferAddress,
pub(crate) full_range: (),
pub(crate) sync_mapped_writes: Option<hal::memory::Segment>,
pub(crate) life_guard: LifeGuard,
@ -177,7 +182,7 @@ pub enum CreateBufferError {
#[error("buffers that are mapped at creation have to be aligned to `COPY_BUFFER_ALIGNMENT`")]
UnalignedSize,
#[error("`MAP` usage can only be combined with the opposite `COPY`, requested {0:?}")]
UsageMismatch(BufferUsage),
UsageMismatch(wgt::BufferUsage),
}
impl<B: hal::Backend> Borrow<RefCount> for Buffer<B> {
@ -192,14 +197,16 @@ impl<B: hal::Backend> Borrow<()> for Buffer<B> {
}
}
pub type TextureDescriptor<'a> = wgt::TextureDescriptor<Label<'a>>;
#[derive(Debug)]
pub struct Texture<B: hal::Backend> {
pub(crate) raw: B::Image,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) usage: TextureUsage,
pub(crate) usage: wgt::TextureUsage,
pub(crate) dimension: wgt::TextureDimension,
pub(crate) kind: hal::image::Kind,
pub(crate) format: TextureFormat,
pub(crate) format: wgt::TextureFormat,
pub(crate) full_range: hal::image::SubresourceRange,
pub(crate) memory: MemoryBlock<B>,
pub(crate) life_guard: LifeGuard,
@ -226,7 +233,7 @@ pub enum CreateTextureError {
#[error("texture descriptor mip level count ({0}) must be less than `MAX_MIP_LEVELS`")]
InvalidMipLevelCount(u32),
#[error("Feature {0:?} must be enabled to create a texture of type {1:?}")]
MissingFeature(wgt::Features, TextureFormat),
MissingFeature(wgt::Features, wgt::TextureFormat),
}
impl<B: hal::Backend> Borrow<RefCount> for Texture<B> {
@ -241,6 +248,35 @@ impl<B: hal::Backend> Borrow<hal::image::SubresourceRange> for Texture<B> {
}
}
/// Describes a [`TextureView`].
#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct TextureViewDescriptor<'a> {
/// Debug label of the texture view. This will show up in graphics debuggers for easy identification.
pub label: Label<'a>,
/// Format of the texture view, or `None` for the same format as the texture itself.
/// At this time, it must be the same the underlying format of the texture.
pub format: Option<wgt::TextureFormat>,
/// The dimension of the texture view. For 1D textures, this must be `1D`. For 2D textures it must be one of
/// `D2`, `D2Array`, `Cube`, and `CubeArray`. For 3D textures it must be `3D`
pub dimension: Option<wgt::TextureViewDimension>,
/// Aspect of the texture. Color textures must be [`TextureAspect::All`].
pub aspect: wgt::TextureAspect,
/// Base mip level.
pub base_mip_level: u32,
/// Mip level count.
/// If `Some(count)`, `base_mip_level + count` must be less or equal to underlying texture mip count.
/// If `None`, considered to include the rest of the mipmap levels, but at least 1 in total.
pub level_count: Option<NonZeroU32>,
/// Base array layer.
pub base_array_layer: u32,
/// Layer count.
/// If `Some(count)`, `base_array_layer + count` must be less or equal to the underlying array count.
/// If `None`, considered to include the rest of the array layers, but at least 1 in total.
pub array_layer_count: Option<NonZeroU32>,
}
#[derive(Debug)]
pub(crate) enum TextureViewInner<B: hal::Backend> {
Native {
@ -257,7 +293,7 @@ pub(crate) enum TextureViewInner<B: hal::Backend> {
pub struct TextureView<B: hal::Backend> {
pub(crate) inner: TextureViewInner<B>,
//TODO: store device_id for quick access?
pub(crate) format: TextureFormat,
pub(crate) format: wgt::TextureFormat,
pub(crate) extent: hal::image::Extent,
pub(crate) samples: hal::image::NumSamples,
pub(crate) range: hal::image::SubresourceRange,
@ -301,6 +337,47 @@ impl<B: hal::Backend> Borrow<()> for TextureView<B> {
}
}
/// Describes a [`Sampler`]
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct SamplerDescriptor<'a> {
/// Debug label of the sampler. This will show up in graphics debuggers for easy identification.
pub label: Label<'a>,
/// How to deal with out of bounds accesses in the u (i.e. x) direction
pub address_modes: [wgt::AddressMode; 3],
/// How to filter the texture when it needs to be magnified (made larger)
pub mag_filter: wgt::FilterMode,
/// How to filter the texture when it needs to be minified (made smaller)
pub min_filter: wgt::FilterMode,
/// How to filter between mip map levels
pub mipmap_filter: wgt::FilterMode,
/// Minimum level of detail (i.e. mip level) to use
pub lod_min_clamp: f32,
/// Maximum level of detail (i.e. mip level) to use
pub lod_max_clamp: f32,
/// If this is enabled, this is a comparison sampler using the given comparison function.
pub compare: Option<wgt::CompareFunction>,
/// Valid values: 1, 2, 4, 8, and 16.
pub anisotropy_clamp: Option<NonZeroU8>,
}
impl Default for SamplerDescriptor<'_> {
fn default() -> Self {
Self {
label: None,
address_modes: Default::default(),
mag_filter: Default::default(),
min_filter: Default::default(),
mipmap_filter: Default::default(),
lod_min_clamp: 0.0,
lod_max_clamp: std::f32::MAX,
compare: None,
anisotropy_clamp: None,
}
}
}
#[derive(Debug)]
pub struct Sampler<B: hal::Backend> {
pub(crate) raw: B::Sampler,

View File

@ -1,45 +0,0 @@
use std::borrow::Cow;
/// Implements conversion into a cow.
pub trait IntoCow<'c, CowType: ?Sized + ToOwned> {
fn into_cow(self) -> Cow<'c, CowType>;
}
impl<'c, T: Clone> IntoCow<'c, [T]> for &'c [T] {
fn into_cow(self) -> Cow<'c, [T]> {
Cow::Borrowed(self)
}
}
impl<'c> IntoCow<'c, str> for &'c str {
fn into_cow(self) -> Cow<'c, str> {
Cow::Borrowed(self)
}
}
impl<T: Clone> IntoCow<'static, [T]> for Vec<T> {
fn into_cow(self) -> Cow<'static, [T]> {
Cow::Owned(self)
}
}
impl IntoCow<'static, str> for String {
fn into_cow(self) -> Cow<'static, str> {
Cow::Owned(self)
}
}
macro_rules! into_cow_array {
($($number:literal),*) => {$(
impl<'c, T: Clone> IntoCow<'c, [T]> for &'c [T; $number] {
fn into_cow(self) -> Cow<'c, [T]> {
Cow::Borrowed(&self[..])
}
}
)*};
}
into_cow_array!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31, 32
);

File diff suppressed because it is too large Load Diff