Rework shader and pipeline creation

This commit is contained in:
Dzmitry Malyshau 2021-06-05 01:44:21 -04:00
parent 569cd0cdd6
commit 0ea4cac04b
12 changed files with 716 additions and 690 deletions

2
Cargo.lock generated
View File

@ -1890,6 +1890,8 @@ name = "wgpu-hal"
version = "0.1.0"
dependencies = [
"bitflags",
"naga",
"smallvec",
"wgpu-types",
]

View File

@ -7,7 +7,7 @@ members = [
"wgpu-hal",
"wgpu-types",
]
default-members = ["wgpu"]
default-members = ["wgpu", "player"]
[patch."https://github.com/gfx-rs/naga"]
#naga = { path = "../naga" }

View File

@ -3,10 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::{
device::{
descriptor::{DescriptorSet, DescriptorTotalCount},
DeviceError, MissingFeatures, SHADER_STAGE_COUNT,
},
device::{descriptor::DescriptorSet, DeviceError, MissingFeatures, SHADER_STAGE_COUNT},
hub::Resource,
id::{BindGroupLayoutId, BufferId, DeviceId, SamplerId, TextureViewId, Valid},
memory_init_tracker::MemoryInitTrackerAction,
@ -390,11 +387,10 @@ pub(crate) type BindEntryMap = FastHashMap<u32, wgt::BindGroupLayoutEntry>;
#[derive(Debug)]
pub struct BindGroupLayout<A: hal::Api> {
pub(crate) raw: B::DescriptorSetLayout,
pub(crate) raw: A::BindGroupLayout,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) multi_ref_count: MultiRefCount,
pub(crate) entries: BindEntryMap,
pub(crate) desc_count: DescriptorTotalCount,
pub(crate) dynamic_count: usize,
pub(crate) count_validator: BindingTypeMaxCountValidator,
#[cfg(debug_assertions)]
@ -499,7 +495,7 @@ pub struct PipelineLayoutDescriptor<'a> {
#[derive(Debug)]
pub struct PipelineLayout<A: hal::Api> {
pub(crate) raw: B::PipelineLayout,
pub(crate) raw: A::PipelineLayout,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) life_guard: LifeGuard,
pub(crate) bind_group_layout_ids: ArrayVec<[Valid<BindGroupLayoutId>; hal::MAX_BIND_GROUPS]>,

File diff suppressed because it is too large Load Diff

View File

@ -555,7 +555,7 @@ pub struct Hub<A: hal::Api, F: GlobalIdentityHandlerFactory> {
pub samplers: Registry<Sampler<A>, SamplerId, F>,
}
impl<A: HalApi, F: GlobalIdentityHandlerFactory> Hub<B, F> {
impl<A: HalApi, F: GlobalIdentityHandlerFactory> Hub<A, F> {
fn new(factory: &F) -> Self {
Self {
adapters: Registry::new(A::VARIANT, factory),
@ -578,7 +578,7 @@ impl<A: HalApi, F: GlobalIdentityHandlerFactory> Hub<B, F> {
}
}
impl<A: HalApi, F: GlobalIdentityHandlerFactory> Hub<B, F> {
impl<A: HalApi, F: GlobalIdentityHandlerFactory> Hub<A, F> {
//TODO: instead of having a hacky `with_adapters` parameter,
// we should have `clear_device(device_id)` that specifically destroys
// everything related to a logical device.
@ -696,7 +696,7 @@ impl<A: HalApi, F: GlobalIdentityHandlerFactory> Hub<B, F> {
//TODO: hold the surface alive by the swapchain
if surface_guard.contains(suf_id) {
let surface = surface_guard.get_mut(suf_id).unwrap();
let suf = B::get_surface_mut(surface);
let suf = A::get_surface_mut(surface);
unsafe {
suf.unconfigure_swapchain(&device.raw);
}

View File

@ -3,7 +3,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::{
conv,
device::{Device, DeviceDescriptor},
hub::{Global, GlobalIdentityHandlerFactory, HalApi, Input, Token},
id::{AdapterId, DeviceId, SurfaceId, Valid},
@ -85,21 +84,21 @@ impl Instance {
}
}
type GfxSurface<A> = <B as hal::Api>::Surface;
type HalSurface<A> = <A as hal::Api>::Surface;
#[derive(Debug)]
pub struct Surface {
/*
#[cfg(vulkan)]
pub vulkan: Option<GfxSurface<backend::Vulkan>>,
pub vulkan: Option<HalSurface<backend::Vulkan>>,
#[cfg(metal)]
pub metal: Option<GfxSurface<backend::Metal>>,
pub metal: Option<HalSurface<backend::Metal>>,
#[cfg(dx12)]
pub dx12: Option<GfxSurface<backend::Dx12>>,
pub dx12: Option<HalSurface<backend::Dx12>>,
#[cfg(dx11)]
pub dx11: Option<GfxSurface<backend::Dx11>>,
pub dx11: Option<HalSurface<backend::Dx11>>,
#[cfg(gl)]
pub gl: Option<GfxSurface<backend::Gl>>,
pub gl: Option<HalSurface<backend::Gl>>,
*/}
impl crate::hub::Resource for Surface {
@ -142,7 +141,7 @@ impl<A: HalApi> Adapter<A> {
wgt::TextureFormat::Rgba8Unorm,
];
let formats = B::get_surface(surface).supported_formats(&self.raw.adapter);
let formats = A::get_surface(surface).supported_formats(&self.raw.adapter);
preferred_formats
.iter()
.cloned()
@ -487,35 +486,35 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
/*
#[cfg(vulkan)]
let adapters_vk = map((&instance.vulkan, &id_vulkan, {
fn surface_vulkan(surf: &Surface) -> Option<&GfxSurface<backend::Vulkan>> {
fn surface_vulkan(surf: &Surface) -> Option<&HalSurface<backend::Vulkan>> {
surf.vulkan.as_ref()
}
surface_vulkan
}));
#[cfg(metal)]
let adapters_mtl = map((&instance.metal, &id_metal, {
fn surface_metal(surf: &Surface) -> Option<&GfxSurface<backend::Metal>> {
fn surface_metal(surf: &Surface) -> Option<&HalSurface<backend::Metal>> {
surf.metal.as_ref()
}
surface_metal
}));
#[cfg(dx12)]
let adapters_dx12 = map((&instance.dx12, &id_dx12, {
fn surface_dx12(surf: &Surface) -> Option<&GfxSurface<backend::Dx12>> {
fn surface_dx12(surf: &Surface) -> Option<&HalSurface<backend::Dx12>> {
surf.dx12.as_ref()
}
surface_dx12
}));
#[cfg(dx11)]
let adapters_dx11 = map((&instance.dx11, &id_dx11, {
fn surface_dx11(surf: &Surface) -> Option<&GfxSurface<backend::Dx11>> {
fn surface_dx11(surf: &Surface) -> Option<&HalSurface<backend::Dx11>> {
surf.dx11.as_ref()
}
surface_dx11
}));
#[cfg(gl)]
let adapters_gl = map((&instance.gl, &id_gl, {
fn surface_gl(surf: &Surface) -> Option<&GfxSurface<backend::Gl>> {
fn surface_gl(surf: &Surface) -> Option<&HalSurface<backend::Gl>> {
surf.gl.as_ref()
}
surface_gl
@ -604,7 +603,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let (adapter_guard, _) = hub.adapters.read(&mut token);
adapter_guard
.get(adapter_id)
.map(|adapter| conv::map_adapter_info(adapter.raw.info.clone(), adapter_id.backend()))
.map(|adapter| adapter.raw.info.clone())
.map_err(|_| InvalidAdapter)
}

View File

@ -12,11 +12,10 @@ use crate::{
use std::borrow::Cow;
use thiserror::Error;
#[derive(Debug)]
pub enum ShaderModuleSource<'a> {
SpirV(Cow<'a, [u32]>),
Wgsl(Cow<'a, str>),
Naga(naga::Module),
Naga(&'a naga::Module),
}
#[derive(Clone, Debug)]
@ -30,7 +29,7 @@ pub struct ShaderModuleDescriptor<'a> {
#[derive(Debug)]
pub struct ShaderModule<A: hal::Api> {
pub(crate) raw: B::ShaderModule,
pub(crate) raw: A::ShaderModule,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) interface: Option<validation::Interface>,
#[cfg(debug_assertions)]
@ -126,7 +125,7 @@ pub enum CreateComputePipelineError {
#[derive(Debug)]
pub struct ComputePipeline<A: hal::Api> {
pub(crate) raw: B::ComputePipeline,
pub(crate) raw: A::ComputePipeline,
pub(crate) layout_id: Stored<PipelineLayoutId>,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) life_guard: LifeGuard,
@ -290,7 +289,7 @@ bitflags::bitflags! {
#[derive(Debug)]
pub struct RenderPipeline<A: hal::Api> {
pub(crate) raw: B::GraphicsPipeline,
pub(crate) raw: A::RenderPipeline,
pub(crate) layout_id: Stored<PipelineLayoutId>,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) pass_context: RenderPassContext,

View File

@ -16,55 +16,8 @@ use thiserror::Error;
use std::{borrow::Borrow, num::NonZeroU8, ops::Range, ptr::NonNull};
bitflags::bitflags! {
/// The internal enum mirrored from `BufferUsage`. The values don't have to match!
pub struct BufferUse: u32 {
const EMPTY = 0;
const MAP_READ = 1;
const MAP_WRITE = 2;
const COPY_SRC = 4;
const COPY_DST = 8;
const INDEX = 16;
const VERTEX = 32;
const UNIFORM = 64;
const STORAGE_LOAD = 128;
const STORAGE_STORE = 256;
const INDIRECT = 512;
/// The combination of all read-only usages.
const READ_ALL = Self::MAP_READ.bits | Self::COPY_SRC.bits |
Self::INDEX.bits | Self::VERTEX.bits | Self::UNIFORM.bits |
Self::STORAGE_LOAD.bits | Self::INDIRECT.bits;
/// The combination of all write-only and read-write usages.
const WRITE_ALL = Self::MAP_WRITE.bits | Self::COPY_DST.bits | Self::STORAGE_STORE.bits;
/// The combination of all usages that the are guaranteed to be be ordered by the hardware.
/// If a usage is not ordered, then even if it doesn't change between draw calls, there
/// still need to be pipeline barriers inserted for synchronization.
const ORDERED = Self::READ_ALL.bits | Self::MAP_WRITE.bits | Self::COPY_DST.bits;
}
}
bitflags::bitflags! {
/// The internal enum mirrored from `TextureUsage`. The values don't have to match!
pub struct TextureUse: u32 {
const EMPTY = 0;
const COPY_SRC = 1;
const COPY_DST = 2;
const SAMPLED = 4;
const ATTACHMENT_READ = 8;
const ATTACHMENT_WRITE = 16;
const STORAGE_LOAD = 32;
const STORAGE_STORE = 48;
/// The combination of all read-only usages.
const READ_ALL = Self::COPY_SRC.bits | Self::SAMPLED.bits | Self::ATTACHMENT_READ.bits | Self::STORAGE_LOAD.bits;
/// The combination of all write-only and read-write usages.
const WRITE_ALL = Self::COPY_DST.bits | Self::ATTACHMENT_WRITE.bits | Self::STORAGE_STORE.bits;
/// The combination of all usages that the are guaranteed to be be ordered by the hardware.
/// If a usage is not ordered, then even if it doesn't change between draw calls, there
/// still need to be pipeline barriers inserted for synchronization.
const ORDERED = Self::READ_ALL.bits | Self::COPY_DST.bits | Self::ATTACHMENT_WRITE.bits;
const UNINITIALIZED = 0xFFFF;
}
}
//TODO: remove the alias, just use it from `hal`
pub(crate) use hal::{BufferUse, TextureUse};
#[repr(C)]
#[derive(Debug)]

View File

@ -7,7 +7,7 @@ mod range;
mod texture;
use crate::{
conv, hub,
hub,
id::{self, TypedId, Valid},
resource, Epoch, FastHashMap, Index, RefCount,
};
@ -124,24 +124,6 @@ pub(crate) struct PendingTransition<S: ResourceState> {
pub usage: ops::Range<S::Usage>,
}
impl PendingTransition<BufferState> {
/// Produce the gfx-hal barrier corresponding to the transition.
pub fn into_hal<'a, A: hal::Api>(
self,
buf: &'a resource::Buffer<A>,
) -> hal::memory::Barrier<'a, B> {
log::trace!("\tbuffer -> {:?}", self);
let &(ref target, _) = buf.raw.as_ref().expect("Buffer is destroyed");
hal::memory::Barrier::Buffer {
states: conv::map_buffer_state(self.usage.start)
..conv::map_buffer_state(self.usage.end),
target,
range: hal::buffer::SubRange::WHOLE,
families: None,
}
}
}
impl From<PendingTransition<BufferState>> for UsageConflict {
fn from(e: PendingTransition<BufferState>) -> Self {
Self::Buffer {
@ -151,31 +133,6 @@ impl From<PendingTransition<BufferState>> for UsageConflict {
}
}
impl PendingTransition<TextureState> {
/// Produce the gfx-hal barrier corresponding to the transition.
pub fn into_hal<'a, A: hal::Api>(
self,
tex: &'a resource::Texture<A>,
) -> hal::memory::Barrier<'a, B> {
log::trace!("\ttexture -> {:?}", self);
let &(ref target, _) = tex.raw.as_ref().expect("Texture is destroyed");
let aspects = tex.aspects;
hal::memory::Barrier::Image {
states: conv::map_texture_state(self.usage.start, aspects)
..conv::map_texture_state(self.usage.end, aspects),
target,
range: hal::image::SubresourceRange {
aspects,
level_start: self.selector.levels.start,
level_count: Some(self.selector.levels.end - self.selector.levels.start),
layer_start: self.selector.layers.start,
layer_count: Some(self.selector.layers.end - self.selector.layers.start),
},
families: None,
}
}
}
impl From<PendingTransition<TextureState>> for UsageConflict {
fn from(e: PendingTransition<TextureState>) -> Self {
Self::Texture {

View File

@ -15,4 +15,9 @@ license = "MPL-2.0"
[dependencies]
bitflags = "1.0"
smallvec = "1"
wgt = { package = "wgpu-types", path = "../wgpu-types" }
[dependencies.naga]
git = "https://github.com/gfx-rs/naga"
tag = "gfx-25"

View File

@ -1,39 +1,68 @@
#[derive(Clone)]
pub struct Api;
pub struct Surface;
pub struct Adapter;
pub struct Queue;
pub struct Device;
pub struct CommandBuffer;
pub struct RenderPass;
pub struct ComputePass;
pub struct Context;
pub struct Encoder;
#[derive(Debug)]
pub struct Resource;
impl crate::Surface<Api> for Surface {}
impl crate::Api for Api {
type Instance = Context;
type Surface = Context;
type Adapter = Context;
type Queue = Context;
type Device = Context;
impl crate::Adapter<Api> for Adapter {
type CommandBuffer = Encoder;
type RenderPass = Encoder;
type ComputePass = Encoder;
type Buffer = Resource;
type QuerySet = Resource;
type Texture = Resource;
type SwapChainTexture = Resource;
type TextureView = Resource;
type Sampler = Resource;
type BindGroupLayout = Resource;
type BindGroup = Resource;
type PipelineLayout = Resource;
type ShaderModule = Resource;
type RenderPipeline = Resource;
type ComputePipeline = Resource;
}
impl crate::Instance<Api> for Context {
unsafe fn enumerate_adapters(&self) -> Vec<crate::ExposedAdapter<Api>> {
Vec::new()
}
}
impl crate::Surface<Api> for Context {}
impl crate::Adapter<Api> for Context {
unsafe fn open(
&self,
_features: wgt::Features,
) -> Result<crate::OpenDevice<Api>, crate::Error> {
Err(crate::Error::DeviceLost)
}
unsafe fn close(&self, _device: Device) {}
unsafe fn close(&self, _device: Context) {}
unsafe fn texture_format_capabilities(
&self,
_format: wgt::TextureFormat,
) -> crate::TextureFormatCapability {
crate::TextureFormatCapability::empty()
}
unsafe fn surface_formats(&self, _surface: &Surface) -> Vec<wgt::TextureFormat> {
unsafe fn surface_formats(&self, _surface: &Context) -> Vec<wgt::TextureFormat> {
Vec::new()
}
}
impl crate::Queue<Api> for Queue {
unsafe fn submit<I: Iterator<Item = CommandBuffer>>(&mut self, _command_buffers: I) {}
impl crate::Queue<Api> for Context {
unsafe fn submit<I: Iterator<Item = Encoder>>(&mut self, _command_buffers: I) {}
}
impl crate::Device<Api> for Device {
impl crate::Device<Api> for Context {
unsafe fn create_buffer(
&self,
_desc: &wgt::BufferDescriptor<crate::Label>,
@ -79,52 +108,76 @@ impl crate::Device<Api> for Device {
unsafe fn destroy_texture_view(&self, _view: Resource) {}
unsafe fn create_sampler(
&self,
desc: &crate::SamplerDescriptor<crate::Label>,
_desc: &crate::SamplerDescriptor,
) -> Result<Resource, crate::Error> {
Ok(Resource)
}
unsafe fn destroy_sampler(&self, _sampler: Resource) {}
unsafe fn create_command_buffer(&self) -> Result<CommandBuffer, crate::Error> {
Ok(CommandBuffer)
unsafe fn create_command_buffer(&self) -> Result<Encoder, crate::Error> {
Ok(Encoder)
}
unsafe fn destroy_command_buffer(&self, _cmd_buf: Encoder) {}
unsafe fn create_bind_group_layout(
&self,
_desc: &crate::BindGroupLayoutDescriptor,
) -> Result<Resource, crate::Error> {
Ok(Resource)
}
unsafe fn destroy_bind_group_layout(&self, _bg_layout: Resource) {}
unsafe fn create_pipeline_layout(
&self,
_desc: &crate::PipelineLayoutDescriptor<Api>,
) -> Result<Resource, crate::Error> {
Ok(Resource)
}
unsafe fn destroy_pipeline_layout(&self, _pipeline_layout: Resource) {}
unsafe fn create_bind_group(
&self,
_desc: &crate::BindGroupDescriptor<Api>,
) -> Result<Resource, crate::Error> {
Ok(Resource)
}
unsafe fn destroy_bind_group(&self, _group: Resource) {}
unsafe fn create_shader_module(
&self,
_desc: &crate::ShaderModuleDescriptor,
_shader: crate::NagaShader,
) -> Result<Resource, (crate::ShaderError, crate::NagaShader)> {
Ok(Resource)
}
unsafe fn destroy_shader_module(&self, _module: Resource) {}
unsafe fn create_render_pipeline(
&self,
_desc: &crate::RenderPipelineDescriptor<Api>,
) -> Result<Resource, crate::PipelineError> {
Ok(Resource)
}
unsafe fn destroy_render_pipeline(&self, _pipeline: Resource) {}
unsafe fn create_compute_pipeline(
&self,
_desc: &crate::ComputePipelineDescriptor<Api>,
) -> Result<Resource, crate::PipelineError> {
Ok(Resource)
}
unsafe fn destroy_compute_pipeline(&self, _pipeline: Resource) {}
}
impl crate::CommandBuffer<Api> for CommandBuffer {
impl crate::CommandBuffer<Api> for Encoder {
unsafe fn begin(&mut self) {}
unsafe fn end(&mut self) {}
unsafe fn begin_render_pass(&mut self) -> RenderPass {
RenderPass
unsafe fn begin_render_pass(&mut self) -> Encoder {
Encoder
}
unsafe fn end_render_pass(&mut self, _pass: RenderPass) {}
unsafe fn begin_compute_pass(&mut self) -> ComputePass {
ComputePass
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: ComputePass) {}
unsafe fn end_compute_pass(&mut self, _pass: Encoder) {}
}
impl crate::RenderPass<Api> for RenderPass {}
impl crate::ComputePass<Api> for ComputePass {}
impl crate::Api for Api {
type Surface = Surface;
type Adapter = Adapter;
type Queue = Queue;
type Device = Device;
type CommandBuffer = CommandBuffer;
type RenderPass = RenderPass;
type ComputePass = ComputePass;
type Buffer = Resource;
type QuerySet = Resource;
type Texture = Resource;
type SwapChainTexture = Resource;
type TextureView = Resource;
type Sampler = Resource;
unsafe fn enumerate_adapters(&self) -> Vec<crate::ExposedAdapter<Api>> {
Vec::new()
}
}
impl crate::RenderPass<Api> for Encoder {}
impl crate::ComputePass<Api> for Encoder {}

View File

@ -5,11 +5,33 @@
/*! This library describes the internal unsafe graphics abstraction API.
*/
#![allow(
// We use loops for getting early-out of scope without closures.
clippy::never_loop,
// We don't use syntax sugar where it's not necessary.
clippy::match_like_matches_macro,
// Redundant matching is more explicit.
clippy::redundant_pattern_matching,
// Explicit lifetimes are often easier to reason about.
clippy::needless_lifetimes,
// No need for defaults in the internal types.
clippy::new_without_default,
)]
#![warn(
trivial_casts,
trivial_numeric_casts,
unused_extern_crates,
unused_qualifications,
// We don't match on a reference, unless required.
clippy::pattern_type_mismatch,
)]
pub mod empty;
use std::{fmt, num::NonZeroU8, ops::Range, ptr::NonNull};
use std::{borrow::Cow, fmt, num::NonZeroU8, ops::Range, ptr::NonNull};
use bitflags::bitflags;
use smallvec::SmallVec;
pub const MAX_ANISOTROPY: u8 = 16;
pub const MAX_BIND_GROUPS: usize = 8;
@ -35,7 +57,56 @@ impl fmt::Display for Error {
}
impl std::error::Error for Error {}
pub trait Api: Sized {
#[derive(Debug)]
pub enum ShaderError {
Compilation(String),
Device(Error),
}
impl fmt::Display for ShaderError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Self::Compilation(ref message) => write!(f, "compilation failed: {}", message),
Self::Device(_) => Ok(()),
}
}
}
impl std::error::Error for ShaderError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match *self {
Self::Compilation(..) => None,
Self::Device(ref parent) => Some(parent),
}
}
}
#[derive(Debug)]
pub enum PipelineError {
Linkage(wgt::ShaderStage, String),
Device(Error),
}
impl fmt::Display for PipelineError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Self::Linkage(stage, ref message) => {
write!(f, "linkage failed for stage {:?}: {}", stage, message)
}
Self::Device(_) => Ok(()),
}
}
}
impl std::error::Error for PipelineError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match *self {
Self::Linkage(..) => None,
Self::Device(ref parent) => Some(parent),
}
}
}
pub trait Api: Clone + Sized {
type Instance: Instance<Self>;
type Surface: Surface<Self>;
type Adapter: Adapter<Self>;
type Device: Device<Self>;
@ -45,14 +116,23 @@ pub trait Api: Sized {
type RenderPass: RenderPass<Self>;
type ComputePass: ComputePass<Self>;
type Buffer;
type QuerySet;
type Texture;
type SwapChainTexture;
type TextureView;
type Sampler;
type Buffer: fmt::Debug + Send + Sync;
type QuerySet: fmt::Debug + Send + Sync;
type Texture: fmt::Debug + Send + Sync;
type SwapChainTexture: fmt::Debug + Send + Sync;
type TextureView: fmt::Debug + Send + Sync;
type Sampler: fmt::Debug + Send + Sync;
unsafe fn enumerate_adapters(&self) -> Vec<ExposedAdapter<Self>>;
type BindGroupLayout;
type BindGroup: fmt::Debug + Send + Sync;
type PipelineLayout;
type ShaderModule: fmt::Debug + Send + Sync;
type RenderPipeline;
type ComputePipeline;
}
pub trait Instance<A: Api> {
unsafe fn enumerate_adapters(&self) -> Vec<ExposedAdapter<A>>;
}
pub trait Surface<A: Api> {}
@ -102,10 +182,44 @@ pub trait Device<A: Api> {
desc: &TextureViewDescriptor<Label>,
) -> Result<A::TextureView, Error>;
unsafe fn destroy_texture_view(&self, view: A::TextureView);
unsafe fn create_sampler(&self, desc: &SamplerDescriptor<Label>) -> Result<A::Sampler, Error>;
unsafe fn create_sampler(&self, desc: &SamplerDescriptor) -> Result<A::Sampler, Error>;
unsafe fn destroy_sampler(&self, sampler: A::Sampler);
unsafe fn create_command_buffer(&self) -> Result<A::CommandBuffer, Error>;
unsafe fn destroy_command_buffer(&self, cmd_buf: A::CommandBuffer);
unsafe fn create_bind_group_layout(
&self,
desc: &BindGroupLayoutDescriptor,
) -> Result<A::BindGroupLayout, Error>;
unsafe fn destroy_bind_group_layout(&self, bg_layout: A::BindGroupLayout);
unsafe fn create_pipeline_layout(
&self,
desc: &PipelineLayoutDescriptor<A>,
) -> Result<A::PipelineLayout, Error>;
unsafe fn destroy_pipeline_layout(&self, pipeline_layout: A::PipelineLayout);
unsafe fn create_bind_group(
&self,
desc: &BindGroupDescriptor<A>,
) -> Result<A::BindGroup, Error>;
unsafe fn destroy_bind_group(&self, group: A::BindGroup);
unsafe fn create_shader_module(
&self,
desc: &ShaderModuleDescriptor,
shader: NagaShader,
) -> Result<A::ShaderModule, (ShaderError, NagaShader)>;
unsafe fn destroy_shader_module(&self, module: A::ShaderModule);
unsafe fn create_render_pipeline(
&self,
desc: &RenderPipelineDescriptor<A>,
) -> Result<A::RenderPipeline, PipelineError>;
unsafe fn destroy_render_pipeline(&self, pipeline: A::RenderPipeline);
unsafe fn create_compute_pipeline(
&self,
desc: &ComputePipelineDescriptor<A>,
) -> Result<A::ComputePipeline, PipelineError>;
unsafe fn destroy_compute_pipeline(&self, pipeline: A::ComputePipeline);
}
pub trait Queue<A: Api> {
@ -125,38 +239,6 @@ pub trait CommandBuffer<A: Api> {
pub trait RenderPass<A: Api> {}
pub trait ComputePass<A: Api> {}
#[derive(Debug)]
pub struct Alignments {
/// The alignment of the start of the buffer used as a GPU copy source.
pub buffer_copy_offset: wgt::BufferSize,
/// The alignment of the row pitch of the texture data stored in a buffer that is
/// used in a GPU copy operation.
pub buffer_copy_pitch: wgt::BufferSize,
pub storage_buffer_offset: wgt::BufferSize,
pub uniform_buffer_offset: wgt::BufferSize,
}
#[derive(Debug)]
pub struct Capabilities {
pub limits: wgt::Limits,
pub alignments: Alignments,
pub downlevel: wgt::DownlevelCapabilities,
}
#[derive(Debug)]
pub struct ExposedAdapter<A: Api> {
pub adapter: A::Adapter,
pub info: wgt::AdapterInfo,
pub features: wgt::Features,
pub capabilities: Capabilities,
}
#[derive(Debug)]
pub struct OpenDevice<A: Api> {
pub device: A::Device,
pub queue: A::Queue,
}
bitflags!(
/// Texture format capability flags.
pub struct TextureFormatCapability: u32 {
@ -207,6 +289,87 @@ impl From<wgt::TextureFormat> for FormatAspect {
}
}
bitflags::bitflags! {
/// Similar to `wgt::BufferUsage` but for internal use.
pub struct BufferUse: u32 {
const MAP_READ = 1;
const MAP_WRITE = 2;
const COPY_SRC = 4;
const COPY_DST = 8;
const INDEX = 16;
const VERTEX = 32;
const UNIFORM = 64;
const STORAGE_LOAD = 128;
const STORAGE_STORE = 256;
const INDIRECT = 512;
/// The combination of all read-only usages.
const READ_ALL = Self::MAP_READ.bits | Self::COPY_SRC.bits |
Self::INDEX.bits | Self::VERTEX.bits | Self::UNIFORM.bits |
Self::STORAGE_LOAD.bits | Self::INDIRECT.bits;
/// The combination of all write-only and read-write usages.
const WRITE_ALL = Self::MAP_WRITE.bits | Self::COPY_DST.bits | Self::STORAGE_STORE.bits;
/// The combination of all usages that the are guaranteed to be be ordered by the hardware.
/// If a usage is not ordered, then even if it doesn't change between draw calls, there
/// still need to be pipeline barriers inserted for synchronization.
const ORDERED = Self::READ_ALL.bits | Self::MAP_WRITE.bits | Self::COPY_DST.bits;
}
}
bitflags::bitflags! {
/// Similar to `wgt::TextureUsage` but for internal use.
pub struct TextureUse: u32 {
const COPY_SRC = 1;
const COPY_DST = 2;
const SAMPLED = 4;
const COLOR_TARGET = 8;
const DEPTH_STENCIL_READ = 16;
const DEPTH_STENCIL_WRITE = 32;
const STORAGE_LOAD = 64;
const STORAGE_STORE = 128;
/// The combination of all read-only usages.
const READ_ALL = Self::COPY_SRC.bits | Self::SAMPLED.bits | Self::DEPTH_STENCIL_READ.bits | Self::STORAGE_LOAD.bits;
/// The combination of all write-only and read-write usages.
const WRITE_ALL = Self::COPY_DST.bits | Self::COLOR_TARGET.bits | Self::DEPTH_STENCIL_WRITE.bits | Self::STORAGE_STORE.bits;
/// The combination of all usages that the are guaranteed to be be ordered by the hardware.
/// If a usage is not ordered, then even if it doesn't change between draw calls, there
/// still need to be pipeline barriers inserted for synchronization.
const ORDERED = Self::READ_ALL.bits | Self::COPY_DST.bits | Self::COLOR_TARGET.bits | Self::DEPTH_STENCIL_WRITE.bits;
const UNINITIALIZED = 0xFFFF;
}
}
#[derive(Debug)]
pub struct Alignments {
/// The alignment of the start of the buffer used as a GPU copy source.
pub buffer_copy_offset: wgt::BufferSize,
/// The alignment of the row pitch of the texture data stored in a buffer that is
/// used in a GPU copy operation.
pub buffer_copy_pitch: wgt::BufferSize,
pub storage_buffer_offset: wgt::BufferSize,
pub uniform_buffer_offset: wgt::BufferSize,
}
#[derive(Debug)]
pub struct Capabilities {
pub limits: wgt::Limits,
pub alignments: Alignments,
pub downlevel: wgt::DownlevelCapabilities,
}
#[derive(Debug)]
pub struct ExposedAdapter<A: Api> {
pub adapter: A::Adapter,
pub info: wgt::AdapterInfo,
pub features: wgt::Features,
pub capabilities: Capabilities,
}
#[derive(Debug)]
pub struct OpenDevice<A: Api> {
pub device: A::Device,
pub queue: A::Queue,
}
#[derive(Clone, Debug)]
pub struct TextureViewDescriptor<L> {
pub label: L,
@ -227,10 +390,9 @@ impl<L> TextureViewDescriptor<L> {
}
}
/// Describes a [`Sampler`]
#[derive(Clone, Debug)]
pub struct SamplerDescriptor<L> {
pub label: L,
pub struct SamplerDescriptor<'a> {
pub label: Label<'a>,
pub address_modes: [wgt::AddressMode; 3],
pub mag_filter: wgt::FilterMode,
pub min_filter: wgt::FilterMode,
@ -241,6 +403,143 @@ pub struct SamplerDescriptor<L> {
pub border_color: Option<wgt::SamplerBorderColor>,
}
#[derive(Clone, Debug)]
pub struct BindGroupLayoutDescriptor<'a> {
pub label: Label<'a>,
pub entries: Cow<'a, [wgt::BindGroupLayoutEntry]>,
}
#[derive(Clone, Debug)]
pub struct PipelineLayoutDescriptor<'a, A: Api> {
pub label: Label<'a>,
pub bind_group_layouts: Cow<'a, [&'a A::BindGroupLayout]>,
pub push_constant_ranges: Cow<'a, [wgt::PushConstantRange]>,
}
#[derive(Debug)]
pub struct BufferBinding<'a, A: Api> {
pub buffer: &'a A::Buffer,
pub offset: wgt::BufferAddress,
pub size: Option<wgt::BufferSize>,
}
// Rust gets confused about the impl requirements for `A`
impl<A: Api> Clone for BufferBinding<'_, A> {
fn clone(&self) -> Self {
Self {
buffer: self.buffer,
offset: self.offset,
size: self.size,
}
}
}
#[derive(Debug)]
pub enum BindingResource<'a, A: Api> {
Buffers(SmallVec<[BufferBinding<'a, A>; 1]>),
Sampler(&'a A::Sampler),
TextureViews(SmallVec<[&'a A::TextureView; 1]>, TextureUse),
}
// Rust gets confused about the impl requirements for `A`
impl<A: Api> Clone for BindingResource<'_, A> {
fn clone(&self) -> Self {
match *self {
Self::Buffers(ref slice) => Self::Buffers(slice.clone()),
Self::Sampler(sampler) => Self::Sampler(sampler),
Self::TextureViews(ref slice, usage) => Self::TextureViews(slice.clone(), usage),
}
}
}
#[derive(Clone, Debug)]
pub struct BindGroupEntry<'a, A: Api> {
pub binding: u32,
pub resource: BindingResource<'a, A>,
}
#[derive(Clone, Debug)]
pub struct BindGroupDescriptor<'a, A: Api> {
pub label: Label<'a>,
pub layout: &'a A::BindGroupLayout,
pub entries: Cow<'a, [BindGroupEntry<'a, A>]>,
}
/// Naga shader module.
pub struct NagaShader {
/// Shader module IR.
pub module: naga::Module,
/// Analysis information of the module.
pub info: naga::valid::ModuleInfo,
}
pub struct ShaderModuleDescriptor<'a> {
pub label: Label<'a>,
}
/// Describes a programmable pipeline stage.
#[derive(Debug)]
pub struct ProgrammableStage<'a, A: Api> {
/// The compiled shader module for this stage.
pub module: &'a A::ShaderModule,
/// 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>,
}
// Rust gets confused about the impl requirements for `A`
impl<A: Api> Clone for ProgrammableStage<'_, A> {
fn clone(&self) -> Self {
Self {
module: self.module,
entry_point: self.entry_point.clone(),
}
}
}
/// Describes a compute pipeline.
#[derive(Clone, Debug)]
pub struct ComputePipelineDescriptor<'a, A: Api> {
pub label: Label<'a>,
/// The layout of bind groups for this pipeline.
pub layout: &'a A::PipelineLayout,
/// The compiled compute stage and its entry point.
pub stage: ProgrammableStage<'a, A>,
}
/// Describes how the vertex buffer is interpreted.
#[derive(Clone, Debug)]
pub struct VertexBufferLayout<'a> {
/// The stride, in bytes, between elements of this buffer.
pub array_stride: wgt::BufferAddress,
/// How often this vertex buffer is "stepped" forward.
pub step_mode: wgt::InputStepMode,
/// The list of attributes which comprise a single vertex.
pub attributes: Cow<'a, [wgt::VertexAttribute]>,
}
/// Describes a render (graphics) pipeline.
#[derive(Clone, Debug)]
pub struct RenderPipelineDescriptor<'a, A: Api> {
pub label: Label<'a>,
/// The layout of bind groups for this pipeline.
pub layout: &'a A::PipelineLayout,
/// The format of any vertex buffers used with this pipeline.
pub vertex_buffers: Cow<'a, [VertexBufferLayout<'a>]>,
/// The vertex stage for this pipeline.
pub vertex_stage: ProgrammableStage<'a, A>,
/// The properties of the pipeline at the primitive assembly and rasterization level.
pub primitive: wgt::PrimitiveState,
/// The effect of draw calls on the depth and stencil aspects of the output target, if any.
pub depth_stencil: Option<wgt::DepthStencilState>,
/// The multi-sampling properties of the pipeline.
pub multisample: wgt::MultisampleState,
/// The fragment stage for this pipeline.
pub fragment_stage: ProgrammableStage<'a, A>,
/// The effect of draw calls on the color aspect of the output target.
pub color_targets: Cow<'a, [wgt::ColorTargetState]>,
}
#[test]
fn test_default_limits() {
let limits = wgt::Limits::default();