summaryrefslogtreecommitdiffstats
path: root/third_party/rust/gfx-hal
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/gfx-hal
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/gfx-hal')
-rw-r--r--third_party/rust/gfx-hal/.cargo-checksum.json1
-rw-r--r--third_party/rust/gfx-hal/Cargo.toml28
-rw-r--r--third_party/rust/gfx-hal/src/adapter.rs179
-rw-r--r--third_party/rust/gfx-hal/src/buffer.rs192
-rw-r--r--third_party/rust/gfx-hal/src/command/clear.rs73
-rw-r--r--third_party/rust/gfx-hal/src/command/mod.rs645
-rw-r--r--third_party/rust/gfx-hal/src/command/structs.rs86
-rw-r--r--third_party/rust/gfx-hal/src/device.rs997
-rw-r--r--third_party/rust/gfx-hal/src/format.rs625
-rw-r--r--third_party/rust/gfx-hal/src/image.rs753
-rw-r--r--third_party/rust/gfx-hal/src/lib.rs643
-rw-r--r--third_party/rust/gfx-hal/src/memory.rs130
-rw-r--r--third_party/rust/gfx-hal/src/pass.rs197
-rw-r--r--third_party/rust/gfx-hal/src/pool.rs65
-rw-r--r--third_party/rust/gfx-hal/src/pso/compute.rs31
-rw-r--r--third_party/rust/gfx-hal/src/pso/descriptor.rs316
-rw-r--r--third_party/rust/gfx-hal/src/pso/graphics.rs298
-rw-r--r--third_party/rust/gfx-hal/src/pso/input_assembler.rs145
-rw-r--r--third_party/rust/gfx-hal/src/pso/mod.rs220
-rw-r--r--third_party/rust/gfx-hal/src/pso/output_merger.rs359
-rw-r--r--third_party/rust/gfx-hal/src/pso/specialization.rs134
-rw-r--r--third_party/rust/gfx-hal/src/query.rs119
-rw-r--r--third_party/rust/gfx-hal/src/queue/family.rs55
-rw-r--r--third_party/rust/gfx-hal/src/queue/mod.rs139
-rw-r--r--third_party/rust/gfx-hal/src/window.rs563
25 files changed, 6993 insertions, 0 deletions
diff --git a/third_party/rust/gfx-hal/.cargo-checksum.json b/third_party/rust/gfx-hal/.cargo-checksum.json
new file mode 100644
index 0000000000..b1f24c056b
--- /dev/null
+++ b/third_party/rust/gfx-hal/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"7e23678de266bc2fbbd13526cc72b2798889a9f947f6341a3361f64ed1ac3444","src/adapter.rs":"cb59da51cba0d8c4fe9921d9343426361b2360373b0a67a00f8fc66291a28650","src/buffer.rs":"483730967af6860e1f0704ab95e83306d19a6bb3684a2b08c6bde86bb3c77ee9","src/command/clear.rs":"c1105fc5fa3ffdf2a77226e8451a7237b6c7583e5e83120f99692a304a355a3d","src/command/mod.rs":"61aa276c165c0b4273bcb47569e6e228e077455016101247a25fa751ac8f8a60","src/command/structs.rs":"00b5850540ae21227c6578866e86cc741d074601239f8b1bbd0342a5e5f74623","src/device.rs":"66a5d7ef2953b8c72d31cc3c29852f395780693de94897835e41313dcd3c6187","src/format.rs":"43411bb348d24847a51c4f404110865eee9d9d68c9bc9c61bab6c6b0f92e5bee","src/image.rs":"c3a8be75ef64874860d8c8924b2f35c4abd3b51035459daab13ece375ad27a8d","src/lib.rs":"40b8b104fc796fffb1e5ed115825b58666c5d2a17e69b9e97e20687b9faaea35","src/memory.rs":"cb6af7749c0a9d9b33c77dcefe9bb424281112145cc302decec7ded729c5adb4","src/pass.rs":"10e60b840ceca18d1a37003653d14e47c1d9e31948dab554f933c1778e46639f","src/pool.rs":"59357105050616b833d2dd23e31e67b2f89da52c593a833be20e820cfecfbcce","src/pso/compute.rs":"fb9a5748c3b9174924db13c1c59388bcd75279ff6d40d1a068fb52e70e5ccb94","src/pso/descriptor.rs":"0c780f1a42ba85624e0cd09fcbd1d4ca9962e3df7dde822bd412c4778706199f","src/pso/graphics.rs":"989c02c95181d704c092dcfc9135c9fcc2ab7592d186f928c65116168fd487d4","src/pso/input_assembler.rs":"0f75dcbc26e253a3ad531089b969e25b9cc86ec9c938f056a62e82ad36383ccb","src/pso/mod.rs":"35573da503ba7168c98ded648209bd1f707338f48a0f2fbb194739b832fa6c8f","src/pso/output_merger.rs":"cfd3b9ba8b8ba85c497e8bdb9f594a1bd83b1c12b99f40c833e1be4ceadace80","src/pso/specialization.rs":"c6335efebcd358250c54c3698e86b2897bcc04e9e1318708b80330f09a0b8521","src/query.rs":"6df341eb2a887c32f9f2b767718550404e684f12b3f8adb64f635999bff1b2e9","src/queue/family.rs":"a769ed5ba31a1cb41c962d17786d00c41cb3e84c4d17e29732416786259c95a9","src/queue/mod.rs":"9cbd2076812339f2111305d93e4d4cdfffa7906ec5c9d2af24c72a0452bd10e7","src/window.rs":"0921a59aeef918e04f12ca07e7660d81b0c21407aaa3e986f3a0a197ac01bf72"},"package":null} \ No newline at end of file
diff --git a/third_party/rust/gfx-hal/Cargo.toml b/third_party/rust/gfx-hal/Cargo.toml
new file mode 100644
index 0000000000..bce6f9760b
--- /dev/null
+++ b/third_party/rust/gfx-hal/Cargo.toml
@@ -0,0 +1,28 @@
+[package]
+name = "gfx-hal"
+version = "0.6.0"
+description = "gfx-rs hardware abstraction layer"
+homepage = "https://github.com/gfx-rs/gfx"
+repository = "https://github.com/gfx-rs/gfx"
+keywords = ["graphics"]
+license = "MIT OR Apache-2.0"
+authors = ["The Gfx-rs Developers"]
+documentation = "https://docs.rs/gfx-hal"
+workspace = "../.."
+edition = "2018"
+
+[features]
+unstable = []
+
+[lib]
+name = "gfx_hal"
+path = "src/lib.rs"
+
+[dependencies]
+bitflags = "1.0"
+mint = { version = "0.5", optional = true }
+raw-window-handle = "0.3"
+serde = { version = "1", features = ["serde_derive"], optional = true }
+
+[dev-dependencies]
+gfx-backend-empty = { path = "../backend/empty", version = "0.6" }
diff --git a/third_party/rust/gfx-hal/src/adapter.rs b/third_party/rust/gfx-hal/src/adapter.rs
new file mode 100644
index 0000000000..3674a058dc
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/adapter.rs
@@ -0,0 +1,179 @@
+//! Physical graphics devices.
+//!
+//! The [`PhysicalDevice`][PhysicalDevice] trait specifies the API a backend
+//! must provide for dealing with and querying a physical device, such as
+//! a particular GPU.
+//!
+//! An [adapter][Adapter] is a struct containing a physical device and metadata
+//! for a particular GPU, generally created from an [instance][crate::Instance]
+//! of that [backend][crate::Backend].
+
+use std::{any::Any, fmt};
+
+use crate::{
+ device, format, image, memory,
+ queue::{QueueGroup, QueuePriority},
+ Backend, Features, Hints, Limits,
+};
+
+/// A description for a single type of memory in a heap.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct MemoryType {
+ /// Properties of the associated memory, such as synchronization
+ /// properties or whether it's on the CPU or GPU.
+ pub properties: memory::Properties,
+ /// Index to the underlying memory heap in `Gpu::memory_heaps`
+ pub heap_index: usize,
+}
+
+/// A description for a memory heap.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct MemoryHeap {
+ /// Total size of the heap.
+ pub size: u64,
+ /// Heap flags.
+ pub flags: memory::HeapFlags,
+}
+
+/// Types of memory supported by this adapter and available memory.
+#[derive(Clone, Debug, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct MemoryProperties {
+ /// Each memory type is associated with one heap of `memory_heaps`.
+ /// Multiple types can point to the same heap.
+ pub memory_types: Vec<MemoryType>,
+ /// Memory heaps with their size in bytes.
+ pub memory_heaps: Vec<MemoryHeap>,
+}
+
+/// Represents a combination of a [logical device][crate::device::Device] and the
+/// [hardware queues][QueueGroup] it provides.
+///
+/// This structure is typically created from an [adapter][crate::adapter::Adapter].
+#[derive(Debug)]
+pub struct Gpu<B: Backend> {
+ /// [Logical device][crate::device::Device] for a given backend.
+ pub device: B::Device,
+ /// The [command queues][crate::queue::CommandQueue] that the device provides.
+ pub queue_groups: Vec<QueueGroup<B>>,
+}
+
+/// Represents a physical device (such as a GPU) capable of supporting the given backend.
+pub trait PhysicalDevice<B: Backend>: fmt::Debug + Any + Send + Sync {
+ /// Create a new [logical device][crate::device::Device] with the requested features.
+ /// If `requested_features` is [empty][crate::Features::empty], then only
+ /// the core features are supported.
+ ///
+ /// # Arguments
+ ///
+ /// * `families` - which [queue families][crate::queue::family::QueueFamily]
+ /// to create queues from. The implementation may allocate more processing time to
+ /// the queues with higher [priority][QueuePriority].
+ /// * `requested_features` - device features to enable. Must be a subset of
+ /// the [features][PhysicalDevice::features] supported by this device.
+ ///
+ /// # Errors
+ ///
+ /// - Returns `TooManyObjects` if the implementation can't create a new logical device.
+ /// - Returns `MissingFeature` if the implementation does not support a requested feature.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # extern crate gfx_backend_empty as empty;
+ /// # extern crate gfx_hal;
+ /// # fn main() {
+ /// use gfx_hal::{adapter::PhysicalDevice, Features};
+ ///
+ /// # let physical_device: empty::PhysicalDevice = return;
+ /// # let family: empty::QueueFamily = return;
+ /// # unsafe {
+ /// let gpu = physical_device.open(&[(&family, &[1.0; 1])], Features::empty());
+ /// # }}
+ /// ```
+ unsafe fn open(
+ &self,
+ families: &[(&B::QueueFamily, &[QueuePriority])],
+ requested_features: Features,
+ ) -> Result<Gpu<B>, device::CreationError>;
+
+ /// Fetch details for a particular format.
+ fn format_properties(&self, format: Option<format::Format>) -> format::Properties;
+
+ /// Fetch details for a particular image format.
+ fn image_format_properties(
+ &self,
+ format: format::Format,
+ dimensions: u8,
+ tiling: image::Tiling,
+ usage: image::Usage,
+ view_caps: image::ViewCapabilities,
+ ) -> Option<image::FormatProperties>;
+
+ /// Fetch details for the memory regions provided by the device.
+ fn memory_properties(&self) -> MemoryProperties;
+
+ /// Returns the features of this `PhysicalDevice`. This usually depends on the graphics API being
+ /// used.
+ fn features(&self) -> Features;
+
+ /// Returns the performance hints of this `PhysicalDevice`.
+ fn hints(&self) -> Hints;
+
+ /// Returns the resource limits of this `PhysicalDevice`.
+ fn limits(&self) -> Limits;
+
+ /// Check cache compatibility with the `PhysicalDevice`.
+ fn is_valid_cache(&self, _cache: &[u8]) -> bool {
+ false
+ }
+}
+
+/// The type of a physical graphics device
+#[derive(Clone, PartialEq, Eq, Debug)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum DeviceType {
+ /// Other
+ Other = 0,
+ /// Integrated
+ IntegratedGpu = 1,
+ /// Discrete
+ DiscreteGpu = 2,
+ /// Virtual / Hosted
+ VirtualGpu = 3,
+ /// CPU / Software Rendering
+ Cpu = 4,
+}
+
+/// Metadata about a backend [adapter][Adapter].
+#[derive(Clone, Debug, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct AdapterInfo {
+ /// Adapter name
+ pub name: String,
+ /// PCI ID of the device vendor
+ pub vendor: usize,
+ /// PCI ID of the device
+ pub device: usize,
+ /// Type of device
+ pub device_type: DeviceType,
+}
+
+/// Information about a graphics device, supported by the backend.
+///
+/// The list of available adapters is obtained by calling
+/// [`Instance::enumerate_adapters`][crate::Instance::enumerate_adapters].
+///
+/// To create a [`Gpu`][Gpu] from this type you can use the [`open`](PhysicalDevice::open)
+/// method on its [`physical_device`][Adapter::physical_device] field.
+#[derive(Debug)]
+pub struct Adapter<B: Backend> {
+ /// General information about this adapter.
+ pub info: AdapterInfo,
+ /// Actual [physical device][PhysicalDevice].
+ pub physical_device: B::PhysicalDevice,
+ /// [Queue families][crate::queue::family::QueueFamily] supported by this adapter.
+ pub queue_families: Vec<B::QueueFamily>,
+}
diff --git a/third_party/rust/gfx-hal/src/buffer.rs b/third_party/rust/gfx-hal/src/buffer.rs
new file mode 100644
index 0000000000..a772ae2a9d
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/buffer.rs
@@ -0,0 +1,192 @@
+//! Memory buffers.
+//!
+//! Buffers interpret memory slices as linear contiguous data array.
+//!
+//! They can be used as shader resources, vertex buffers, index buffers or for
+//! specifying the action commands for indirect execution.
+
+use crate::{device::OutOfMemory, format::Format};
+
+/// An offset inside a buffer, in bytes.
+pub type Offset = u64;
+
+/// A subrange of the buffer.
+#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct SubRange {
+ /// Offset to the subrange.
+ pub offset: Offset,
+ /// Size of the subrange, or None for the remaining size of the buffer.
+ pub size: Option<Offset>,
+}
+
+impl SubRange {
+ /// Whole buffer subrange.
+ pub const WHOLE: Self = SubRange {
+ offset: 0,
+ size: None,
+ };
+
+ /// Return the stored size, if present, or computed size based on the limit.
+ pub fn size_to(&self, limit: Offset) -> Offset {
+ self.size.unwrap_or(limit - self.offset)
+ }
+}
+
+/// Buffer state.
+pub type State = Access;
+
+/// Error creating a buffer.
+#[derive(Clone, Debug, PartialEq)]
+pub enum CreationError {
+ /// Out of either host or device memory.
+ OutOfMemory(OutOfMemory),
+
+ /// Requested buffer usage is not supported.
+ ///
+ /// Older GL version don't support constant buffers or multiple usage flags.
+ UnsupportedUsage {
+ /// Unsupported usage passed on buffer creation.
+ usage: Usage,
+ },
+}
+
+impl From<OutOfMemory> for CreationError {
+ fn from(error: OutOfMemory) -> Self {
+ CreationError::OutOfMemory(error)
+ }
+}
+
+impl std::fmt::Display for CreationError {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ CreationError::OutOfMemory(err) => write!(fmt, "Failed to create buffer: {}", err),
+ CreationError::UnsupportedUsage { usage } => write!(
+ fmt,
+ "Failed to create buffer: Unsupported usage: {:?}",
+ usage
+ ),
+ }
+ }
+}
+
+impl std::error::Error for CreationError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self {
+ CreationError::OutOfMemory(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+/// Error creating a buffer view.
+#[derive(Clone, Debug, PartialEq)]
+pub enum ViewCreationError {
+ /// Out of either host or device memory.
+ OutOfMemory(OutOfMemory),
+
+ /// Buffer view format is not supported.
+ UnsupportedFormat(Option<Format>),
+}
+
+impl From<OutOfMemory> for ViewCreationError {
+ fn from(error: OutOfMemory) -> Self {
+ ViewCreationError::OutOfMemory(error)
+ }
+}
+
+impl std::fmt::Display for ViewCreationError {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ ViewCreationError::OutOfMemory(err) => {
+ write!(fmt, "Failed to create buffer view: {}", err)
+ }
+ ViewCreationError::UnsupportedFormat(Some(format)) => write!(
+ fmt,
+ "Failed to create buffer view: Unsupported format {:?}",
+ format
+ ),
+ ViewCreationError::UnsupportedFormat(None) => {
+ write!(fmt, "Failed to create buffer view: Unspecified format")
+ }
+ }
+ }
+}
+
+impl std::error::Error for ViewCreationError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self {
+ ViewCreationError::OutOfMemory(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+bitflags!(
+ /// Buffer usage flags.
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct Usage: u32 {
+ ///
+ const TRANSFER_SRC = 0x1;
+ ///
+ const TRANSFER_DST = 0x2;
+ ///
+ const UNIFORM_TEXEL = 0x4;
+ ///
+ const STORAGE_TEXEL = 0x8;
+ ///
+ const UNIFORM = 0x10;
+ ///
+ const STORAGE = 0x20;
+ ///
+ const INDEX = 0x40;
+ ///
+ const VERTEX = 0x80;
+ ///
+ const INDIRECT = 0x100;
+ }
+);
+
+impl Usage {
+ /// Returns if the buffer can be used in transfer operations.
+ pub fn can_transfer(&self) -> bool {
+ self.intersects(Usage::TRANSFER_SRC | Usage::TRANSFER_DST)
+ }
+}
+
+bitflags!(
+ /// Buffer access flags.
+ ///
+ /// Access of buffers by the pipeline or shaders.
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct Access: u32 {
+ /// Read commands instruction for indirect execution.
+ const INDIRECT_COMMAND_READ = 0x1;
+ /// Read index values for indexed draw commands.
+ ///
+ /// See [`draw_indexed`](../command/trait.RawCommandBuffer.html#tymethod.draw_indexed)
+ /// and [`draw_indexed_indirect`](../command/trait.RawCommandBuffer.html#tymethod.draw_indexed_indirect).
+ const INDEX_BUFFER_READ = 0x2;
+ /// Read vertices from vertex buffer for draw commands in the [`VERTEX_INPUT`](
+ /// ../pso/struct.PipelineStage.html#associatedconstant.VERTEX_INPUT) stage.
+ const VERTEX_BUFFER_READ = 0x4;
+ ///
+ const UNIFORM_READ = 0x8;
+ ///
+ const SHADER_READ = 0x20;
+ ///
+ const SHADER_WRITE = 0x40;
+ ///
+ const TRANSFER_READ = 0x800;
+ ///
+ const TRANSFER_WRITE = 0x1000;
+ ///
+ const HOST_READ = 0x2000;
+ ///
+ const HOST_WRITE = 0x4000;
+ ///
+ const MEMORY_READ = 0x8000;
+ ///
+ const MEMORY_WRITE = 0x10000;
+ }
+);
diff --git a/third_party/rust/gfx-hal/src/command/clear.rs b/third_party/rust/gfx-hal/src/command/clear.rs
new file mode 100644
index 0000000000..b620e472de
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/command/clear.rs
@@ -0,0 +1,73 @@
+use crate::pso;
+use std::fmt;
+
+/// A clear color union, which can be either `f32`, `i32`, or `u32`.
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub union ClearColor {
+ /// `f32` variant
+ pub float32: [f32; 4],
+ /// `i32` variant
+ pub sint32: [i32; 4],
+ /// `u32` variant
+ pub uint32: [u32; 4],
+}
+
+impl fmt::Debug for ClearColor {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ writeln![f, "ClearColor"]
+ }
+}
+
+/// A combination of depth and stencil clear values.
+#[repr(C)]
+#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct ClearDepthStencil {
+ /// Depth value
+ pub depth: f32,
+ /// Stencil value
+ pub stencil: u32,
+}
+
+/// A set of clear values for a single attachment.
+///
+/// These are passed to a command buffer by
+/// [beginning a render pass][crate::command::CommandBuffer::begin_render_pass].
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub union ClearValue {
+ /// Clear color
+ pub color: ClearColor,
+ /// Clear depth and stencil
+ pub depth_stencil: ClearDepthStencil,
+ _align: [u32; 4],
+}
+
+impl fmt::Debug for ClearValue {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("ClearValue")
+ .field("color", unsafe { &self.color.uint32 })
+ .field("depth_stencil", unsafe { &self.depth_stencil })
+ .finish()
+ }
+}
+
+/// Attachment clear description for the current subpass.
+#[derive(Clone, Copy, Debug)]
+pub enum AttachmentClear {
+ /// Clear color attachment.
+ Color {
+ /// Index inside the `SubpassDesc::colors` array.
+ index: usize,
+ /// Value to clear with.
+ value: ClearColor,
+ },
+ /// Clear depth-stencil attachment.
+ DepthStencil {
+ /// Depth value to clear with.
+ depth: Option<pso::DepthValue>,
+ /// Stencil value to clear with.
+ stencil: Option<pso::StencilValue>,
+ },
+}
diff --git a/third_party/rust/gfx-hal/src/command/mod.rs b/third_party/rust/gfx-hal/src/command/mod.rs
new file mode 100644
index 0000000000..6c90f97e74
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/command/mod.rs
@@ -0,0 +1,645 @@
+//! Command buffers.
+//!
+//! A command buffer collects a list of commands to be submitted to the device.
+//!
+//! Each command buffer has specific capabilities for graphics, compute or transfer operations,
+//! and can be either a *primary* command buffer or a *secondary* command buffer.
+//!
+//! Operations are always initiated by a primary command buffer,
+//! but a primary command buffer can contain calls to secondary command buffers
+//! that contain snippets of commands that do specific things, similar to function calls.
+//!
+//! All the possible commands are exposed by the [`CommandBuffer`][CommandBuffer] trait.
+
+// TODO: Document pipelines and subpasses better.
+
+mod clear;
+mod structs;
+
+use std::{any::Any, borrow::Borrow, fmt, ops::Range};
+
+use crate::{
+ buffer,
+ image::{Filter, Layout, SubresourceRange},
+ memory::{Barrier, Dependencies},
+ pass, pso, query, Backend, DrawCount, IndexCount, IndexType, InstanceCount, TaskCount,
+ VertexCount, VertexOffset, WorkGroupCount,
+};
+
+pub use self::clear::*;
+pub use self::structs::*;
+
+/// Offset for dynamic descriptors.
+pub type DescriptorSetOffset = u32;
+
+bitflags! {
+ /// Option flags for various command buffer settings.
+ #[derive(Default)]
+ pub struct CommandBufferFlags: u32 {
+ /// Says that the command buffer will be recorded, submitted only once, and then reset and re-filled
+ /// for another submission.
+ const ONE_TIME_SUBMIT = 0x1;
+
+ /// If set on a secondary command buffer, it says the command buffer takes place entirely inside
+ /// a render pass. Ignored on primary command buffer.
+ const RENDER_PASS_CONTINUE = 0x2;
+
+ /// Says that a command buffer can be recorded into multiple primary command buffers,
+ /// and submitted to a queue while it is still pending.
+ const SIMULTANEOUS_USE = 0x4;
+ }
+}
+
+/// An enum that indicates whether a command buffer is primary or secondary.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum Level {
+ /// Can be submitted to a queue for execution, but cannot be called from other
+ /// command buffers.
+ Primary,
+ /// Cannot be submitted directly, but can be called from primary command buffers.
+ Secondary,
+}
+
+/// Specifies how commands for the following renderpasses will be recorded.
+#[derive(Debug)]
+pub enum SubpassContents {
+ /// Contents of the subpass will be inline in the command buffer,
+ /// NOT in secondary command buffers.
+ Inline,
+ /// Contents of the subpass will be in secondary command buffers, and
+ /// the primary command buffer will only contain `execute_command()` calls
+ /// until the subpass or render pass is complete.
+ SecondaryBuffers,
+}
+
+#[allow(missing_docs)]
+#[derive(Debug)]
+pub struct CommandBufferInheritanceInfo<'a, B: Backend> {
+ pub subpass: Option<pass::Subpass<'a, B>>,
+ pub framebuffer: Option<&'a B::Framebuffer>,
+ pub occlusion_query_enable: bool,
+ pub occlusion_query_flags: query::ControlFlags,
+ pub pipeline_statistics: query::PipelineStatistic,
+}
+
+impl<'a, B: Backend> Default for CommandBufferInheritanceInfo<'a, B> {
+ fn default() -> Self {
+ CommandBufferInheritanceInfo {
+ subpass: None,
+ framebuffer: None,
+ occlusion_query_enable: false,
+ occlusion_query_flags: query::ControlFlags::empty(),
+ pipeline_statistics: query::PipelineStatistic::empty(),
+ }
+ }
+}
+
+/// A trait that describes all the operations that must be
+/// provided by a `Backend`'s command buffer.
+pub trait CommandBuffer<B: Backend>: fmt::Debug + Any + Send + Sync {
+ /// Begins recording commands to a command buffer.
+ unsafe fn begin(
+ &mut self,
+ flags: CommandBufferFlags,
+ inheritance_info: CommandBufferInheritanceInfo<B>,
+ );
+
+ /// Begins recording a primary command buffer
+ /// (that has no inheritance information).
+ unsafe fn begin_primary(&mut self, flags: CommandBufferFlags) {
+ self.begin(flags, CommandBufferInheritanceInfo::default());
+ }
+
+ /// Finish recording commands to a command buffer.
+ unsafe fn finish(&mut self);
+
+ /// Empties the command buffer, optionally releasing all
+ /// resources from the commands that have been submitted.
+ unsafe fn reset(&mut self, release_resources: bool);
+
+ // TODO: This REALLY needs to be deeper, but it's complicated.
+ // Should probably be a whole book chapter on synchronization and stuff really.
+ /// Inserts a synchronization dependency between pipeline stages
+ /// in the command buffer.
+ unsafe fn pipeline_barrier<'a, T>(
+ &mut self,
+ stages: Range<pso::PipelineStage>,
+ dependencies: Dependencies,
+ barriers: T,
+ ) where
+ T: IntoIterator,
+ T::Item: Borrow<Barrier<'a, B>>;
+
+ /// Fill a buffer with the given `u32` value.
+ unsafe fn fill_buffer(&mut self, buffer: &B::Buffer, range: buffer::SubRange, data: u32);
+
+ /// Copy data from the given slice into a buffer.
+ unsafe fn update_buffer(&mut self, buffer: &B::Buffer, offset: buffer::Offset, data: &[u8]);
+
+ /// Clears an image to the given color/depth/stencil.
+ unsafe fn clear_image<T>(
+ &mut self,
+ image: &B::Image,
+ layout: Layout,
+ value: ClearValue,
+ subresource_ranges: T,
+ ) where
+ T: IntoIterator,
+ T::Item: Borrow<SubresourceRange>;
+
+ /// Takes an iterator of attachments and an iterator of rect's,
+ /// and clears the given rect's for *each* attachment.
+ unsafe fn clear_attachments<T, U>(&mut self, clears: T, rects: U)
+ where
+ T: IntoIterator,
+ T::Item: Borrow<AttachmentClear>,
+ T::IntoIter: ExactSizeIterator,
+ U: IntoIterator,
+ U::Item: Borrow<pso::ClearRect>,
+ U::IntoIter: ExactSizeIterator;
+
+ /// "Resolves" a multisampled image, converting it into a non-multisampled
+ /// image. Takes an iterator of regions to apply the resolution to.
+ unsafe fn resolve_image<T>(
+ &mut self,
+ src: &B::Image,
+ src_layout: Layout,
+ dst: &B::Image,
+ dst_layout: Layout,
+ regions: T,
+ ) where
+ T: IntoIterator,
+ T::Item: Borrow<ImageResolve>,
+ T::IntoIter: ExactSizeIterator;
+
+ /// Copies regions from the source to destination image,
+ /// applying scaling, filtering and potentially format conversion.
+ unsafe fn blit_image<T>(
+ &mut self,
+ src: &B::Image,
+ src_layout: Layout,
+ dst: &B::Image,
+ dst_layout: Layout,
+ filter: Filter,
+ regions: T,
+ ) where
+ T: IntoIterator,
+ T::Item: Borrow<ImageBlit>,
+ T::IntoIter: ExactSizeIterator;
+
+ /// Bind the index buffer view, making it the "current" one that draw commands
+ /// will operate on.
+ unsafe fn bind_index_buffer(
+ &mut self,
+ buffer: &B::Buffer,
+ sub: buffer::SubRange,
+ ty: IndexType,
+ );
+
+ /// Bind the vertex buffer set, making it the "current" one that draw commands
+ /// will operate on.
+ ///
+ /// Each buffer passed corresponds to the vertex input binding with the same index,
+ /// starting from an offset index `first_binding`. For example an iterator with
+ /// two items and `first_binding` of 1 would fill vertex buffer binding numbers
+ /// 1 and 2.
+ ///
+ /// This binding number refers only to binding points for vertex buffers and is
+ /// completely separate from the binding numbers of `Descriptor`s in `DescriptorSet`s.
+ /// It needs to match with the `VertexBufferDesc` and `AttributeDesc`s to which the
+ /// data from each bound vertex buffer should flow.
+ ///
+ /// The `buffers` iterator should yield the `Buffer` to bind, as well as a subrange,
+ /// in bytes, into that buffer where the vertex data that should be bound.
+ unsafe fn bind_vertex_buffers<I, T>(&mut self, first_binding: pso::BufferIndex, buffers: I)
+ where
+ I: IntoIterator<Item = (T, buffer::SubRange)>,
+ T: Borrow<B::Buffer>,
+ I::IntoIter: ExactSizeIterator;
+
+ /// Set the [viewport][crate::pso::Viewport] parameters for the rasterizer.
+ ///
+ /// Each viewport passed corresponds to the viewport with the same index,
+ /// starting from an offset index `first_viewport`.
+ ///
+ /// # Errors
+ ///
+ /// This function does not return an error. Invalid usage of this function
+ /// will result in undefined behavior.
+ ///
+ /// - Command buffer must be in recording state.
+ /// - Number of viewports must be between 1 and `max_viewports - first_viewport`.
+ /// - The first viewport must be less than `max_viewports`.
+ /// - Only queues with graphics capability support this function.
+ /// - The bound pipeline must not have baked viewport state.
+ /// - All viewports used by the pipeline must be specified before the first
+ /// draw call.
+ unsafe fn set_viewports<T>(&mut self, first_viewport: u32, viewports: T)
+ where
+ T: IntoIterator,
+ T::Item: Borrow<pso::Viewport>,
+ T::IntoIter: ExactSizeIterator;
+
+ /// Set the scissor rectangles for the rasterizer.
+ ///
+ /// Each scissor corresponds to the viewport with the same index, starting
+ /// from an offset index `first_scissor`.
+ ///
+ /// # Errors
+ ///
+ /// This function does not return an error. Invalid usage of this function
+ /// will result in undefined behavior.
+ ///
+ /// - Command buffer must be in recording state.
+ /// - Number of scissors must be between 1 and `max_viewports - first_scissor`.
+ /// - The first scissor must be less than `max_viewports`.
+ /// - Only queues with graphics capability support this function.
+ /// - The bound pipeline must not have baked scissor state.
+ /// - All scissors used by the pipeline must be specified before the first draw
+ /// call.
+ unsafe fn set_scissors<T>(&mut self, first_scissor: u32, rects: T)
+ where
+ T: IntoIterator,
+ T::Item: Borrow<pso::Rect>,
+ T::IntoIter: ExactSizeIterator;
+
+ /// Sets the stencil reference value for comparison operations and store operations.
+ /// Will be used on the LHS of stencil compare ops and as store value when the
+ /// store op is Reference.
+ unsafe fn set_stencil_reference(&mut self, faces: pso::Face, value: pso::StencilValue);
+
+ /// Sets the stencil read mask.
+ unsafe fn set_stencil_read_mask(&mut self, faces: pso::Face, value: pso::StencilValue);
+
+ /// Sets the stencil write mask.
+ unsafe fn set_stencil_write_mask(&mut self, faces: pso::Face, value: pso::StencilValue);
+
+ /// Set the blend constant values dynamically.
+ unsafe fn set_blend_constants(&mut self, color: pso::ColorValue);
+
+ /// Set the depth bounds test values dynamically.
+ unsafe fn set_depth_bounds(&mut self, bounds: Range<f32>);
+
+ /// Set the line width dynamically.
+ ///
+ /// Only valid to call if `Features::LINE_WIDTH` is enabled.
+ unsafe fn set_line_width(&mut self, width: f32);
+
+ /// Set the depth bias dynamically.
+ unsafe fn set_depth_bias(&mut self, depth_bias: pso::DepthBias);
+
+ /// Begins recording commands for a render pass on the given framebuffer.
+ ///
+ /// # Arguments
+ ///
+ /// * `render_area` - section of the framebuffer to render.
+ /// * `clear_values` - iterator of [clear values][crate::command::ClearValue]
+ /// to use to use for `clear_*` commands, one for each attachment of the render pass
+ /// that has a clear operation.
+ /// * `first_subpass` - specifies, for the first subpass, whether the
+ /// rendering commands are provided inline or whether the render
+ /// pass is composed of subpasses.
+ unsafe fn begin_render_pass<T>(
+ &mut self,
+ render_pass: &B::RenderPass,
+ framebuffer: &B::Framebuffer,
+ render_area: pso::Rect,
+ clear_values: T,
+ first_subpass: SubpassContents,
+ ) where
+ T: IntoIterator,
+ T::Item: Borrow<ClearValue>,
+ T::IntoIter: ExactSizeIterator;
+
+ /// Steps to the next subpass in the current render pass.
+ unsafe fn next_subpass(&mut self, contents: SubpassContents);
+
+ /// Finishes recording commands for the current a render pass.
+ unsafe fn end_render_pass(&mut self);
+
+ /// Bind a graphics pipeline.
+ ///
+ /// # Errors
+ ///
+ /// This function does not return an error. Invalid usage of this function
+ /// will result in an error on `finish`.
+ ///
+ /// - Command buffer must be in recording state.
+ /// - Only queues with graphics capability support this function.
+ unsafe fn bind_graphics_pipeline(&mut self, pipeline: &B::GraphicsPipeline);
+
+ /// Takes an iterator of graphics `DescriptorSet`'s, and binds them to the command buffer.
+ /// `first_set` is the index that the first descriptor is mapped to in the command buffer.
+ unsafe fn bind_graphics_descriptor_sets<I, J>(
+ &mut self,
+ layout: &B::PipelineLayout,
+ first_set: usize,
+ sets: I,
+ offsets: J,
+ ) where
+ I: IntoIterator,
+ I::Item: Borrow<B::DescriptorSet>,
+ I::IntoIter: ExactSizeIterator,
+ J: IntoIterator,
+ J::Item: Borrow<DescriptorSetOffset>,
+ J::IntoIter: ExactSizeIterator;
+
+ /// Bind a compute pipeline.
+ ///
+ /// # Errors
+ ///
+ /// This function does not return an error. Invalid usage of this function
+ /// will result in an error on `finish`.
+ ///
+ /// - Command buffer must be in recording state.
+ /// - Only queues with compute capability support this function.
+ unsafe fn bind_compute_pipeline(&mut self, pipeline: &B::ComputePipeline);
+
+ /// Takes an iterator of compute `DescriptorSet`'s, and binds them to the command buffer,
+ /// `first_set` is the index that the first descriptor is mapped to in the command buffer.
+ unsafe fn bind_compute_descriptor_sets<I, J>(
+ &mut self,
+ layout: &B::PipelineLayout,
+ first_set: usize,
+ sets: I,
+ offsets: J,
+ ) where
+ I: IntoIterator,
+ I::Item: Borrow<B::DescriptorSet>,
+ I::IntoIter: ExactSizeIterator,
+ J: IntoIterator,
+ J::Item: Borrow<DescriptorSetOffset>,
+ J::IntoIter: ExactSizeIterator;
+
+ /// Execute a workgroup in the compute pipeline. `x`, `y` and `z` are the
+ /// number of local workgroups to dispatch along each "axis"; a total of `x`*`y`*`z`
+ /// local workgroups will be created.
+ ///
+ /// # Errors
+ ///
+ /// This function does not return an error. Invalid usage of this function
+ /// will result in an error on `finish`.
+ ///
+ /// - Command buffer must be in recording state.
+ /// - A compute pipeline must be bound using `bind_compute_pipeline`.
+ /// - Only queues with compute capability support this function.
+ /// - This function must be called outside of a render pass.
+ /// - `count` must be less than or equal to `Limits::max_compute_work_group_count`
+ ///
+ /// TODO:
+ unsafe fn dispatch(&mut self, count: WorkGroupCount);
+
+ /// Works similarly to `dispatch()` but reads parameters from the given
+ /// buffer during execution.
+ unsafe fn dispatch_indirect(&mut self, buffer: &B::Buffer, offset: buffer::Offset);
+
+ /// Adds a command to copy regions from the source to destination buffer.
+ unsafe fn copy_buffer<T>(&mut self, src: &B::Buffer, dst: &B::Buffer, regions: T)
+ where
+ T: IntoIterator,
+ T::Item: Borrow<BufferCopy>,
+ T::IntoIter: ExactSizeIterator;
+
+ /// Copies regions from the source to the destination images, which
+ /// have the given layouts. No format conversion is done; the source and destination
+ /// `Layout`'s **must** have the same sized image formats (such as `Rgba8Unorm` and
+ /// `R32`, both of which are 32 bits).
+ unsafe fn copy_image<T>(
+ &mut self,
+ src: &B::Image,
+ src_layout: Layout,
+ dst: &B::Image,
+ dst_layout: Layout,
+ regions: T,
+ ) where
+ T: IntoIterator,
+ T::Item: Borrow<ImageCopy>,
+ T::IntoIter: ExactSizeIterator;
+
+ /// Copies regions from the source buffer to the destination image.
+ unsafe fn copy_buffer_to_image<T>(
+ &mut self,
+ src: &B::Buffer,
+ dst: &B::Image,
+ dst_layout: Layout,
+ regions: T,
+ ) where
+ T: IntoIterator,
+ T::Item: Borrow<BufferImageCopy>,
+ T::IntoIter: ExactSizeIterator;
+
+ /// Copies regions from the source image to the destination buffer.
+ unsafe fn copy_image_to_buffer<T>(
+ &mut self,
+ src: &B::Image,
+ src_layout: Layout,
+ dst: &B::Buffer,
+ regions: T,
+ ) where
+ T: IntoIterator,
+ T::Item: Borrow<BufferImageCopy>,
+ T::IntoIter: ExactSizeIterator;
+
+ // TODO: This explanation needs improvement.
+ /// Performs a non-indexed drawing operation, fetching vertex attributes
+ /// from the currently bound vertex buffers. It performs instanced
+ /// drawing, drawing `instances.len()`
+ /// times with an `instanceIndex` starting with the start of the range.
+ unsafe fn draw(&mut self, vertices: Range<VertexCount>, instances: Range<InstanceCount>);
+
+ /// Performs indexed drawing, drawing the range of indices
+ /// given by the current index buffer and any bound vertex buffers.
+ /// `base_vertex` specifies the vertex offset corresponding to index 0.
+ /// That is, the offset into the vertex buffer is `(current_index + base_vertex)`
+ ///
+ /// It also performs instanced drawing, identical to `draw()`.
+ unsafe fn draw_indexed(
+ &mut self,
+ indices: Range<IndexCount>,
+ base_vertex: VertexOffset,
+ instances: Range<InstanceCount>,
+ );
+
+ /// Functions identically to `draw()`, except the parameters are read
+ /// from the given buffer, starting at `offset` and increasing `stride`
+ /// bytes with each successive draw. Performs `draw_count` draws total.
+ /// `draw_count` may be zero.
+ ///
+ /// Each draw command in the buffer is a series of 4 `u32` values specifying,
+ /// in order, the number of vertices to draw, the number of instances to draw,
+ /// the index of the first vertex to draw, and the instance ID of the first
+ /// instance to draw.
+ unsafe fn draw_indirect(
+ &mut self,
+ buffer: &B::Buffer,
+ offset: buffer::Offset,
+ draw_count: DrawCount,
+ stride: u32,
+ );
+
+ /// Like `draw_indirect()`, this does indexed drawing a la `draw_indexed()` but
+ /// reads the draw parameters out of the given buffer.
+ ///
+ /// Each draw command in the buffer is a series of 5 values specifying,
+ /// in order, the number of indices, the number of instances, the first index,
+ /// the vertex offset, and the first instance. All are `u32`'s except
+ /// the vertex offset, which is an `i32`.
+ unsafe fn draw_indexed_indirect(
+ &mut self,
+ buffer: &B::Buffer,
+ offset: buffer::Offset,
+ draw_count: DrawCount,
+ stride: u32,
+ );
+
+ /// Functions identically to `draw_indirect()`, except the amount of draw
+ /// calls are specified by the u32 in `count_buffer` at `count_buffer_offset`.
+ /// There is a limit of `max_draw_count` invocations.
+ ///
+ /// Each draw command in the buffer is a series of 4 `u32` values specifying,
+ /// in order, the number of vertices to draw, the number of instances to draw,
+ /// the index of the first vertex to draw, and the instance ID of the first
+ /// instance to draw.
+ unsafe fn draw_indirect_count(
+ &mut self,
+ _buffer: &B::Buffer,
+ _offset: buffer::Offset,
+ _count_buffer: &B::Buffer,
+ _count_buffer_offset: buffer::Offset,
+ _max_draw_count: u32,
+ _stride: u32,
+ );
+
+ /// Functions identically to `draw_indexed_indirect()`, except the amount of draw
+ /// calls are specified by the u32 in `count_buffer` at `count_buffer_offset`.
+ /// There is a limit of `max_draw_count` invocations.
+ ///
+ /// Each draw command in the buffer is a series of 5 values specifying,
+ /// in order, the number of indices, the number of instances, the first index,
+ /// the vertex offset, and the first instance. All are `u32`'s except
+ /// the vertex offset, which is an `i32`.
+ unsafe fn draw_indexed_indirect_count(
+ &mut self,
+ _buffer: &B::Buffer,
+ _offset: buffer::Offset,
+ _count_buffer: &B::Buffer,
+ _count_buffer_offset: buffer::Offset,
+ _max_draw_count: u32,
+ _stride: u32,
+ );
+
+ /// Dispatches `task_count` of threads. Similar to compute dispatch.
+ unsafe fn draw_mesh_tasks(&mut self, task_count: TaskCount, first_task: TaskCount);
+
+ /// Indirect version of `draw_mesh_tasks`. Analogous to `draw_indirect`, but for mesh shaders.
+ unsafe fn draw_mesh_tasks_indirect(
+ &mut self,
+ buffer: &B::Buffer,
+ offset: buffer::Offset,
+ draw_count: DrawCount,
+ stride: u32,
+ );
+
+ /// Like `draw_mesh_tasks_indirect` except that the draw count is read by
+ /// the device from a buffer during execution. The command will read an
+ /// unsigned 32-bit integer from `count_buffer` located at `count_buffer_offset`
+ /// and use this as the draw count.
+ unsafe fn draw_mesh_tasks_indirect_count(
+ &mut self,
+ buffer: &B::Buffer,
+ offset: buffer::Offset,
+ count_buffer: &B::Buffer,
+ count_buffer_offset: buffer::Offset,
+ max_draw_count: DrawCount,
+ stride: u32,
+ );
+
+ /// Signals an event once all specified stages of the shader pipeline have completed.
+ unsafe fn set_event(&mut self, event: &B::Event, stages: pso::PipelineStage);
+
+ /// Resets an event once all specified stages of the shader pipeline have completed.
+ unsafe fn reset_event(&mut self, event: &B::Event, stages: pso::PipelineStage);
+
+ /// Waits at some shader stage(s) until all events have been signalled.
+ ///
+ /// - `src_stages` specifies the shader pipeline stages in which the events were signalled.
+ /// - `dst_stages` specifies the shader pipeline stages at which execution should wait.
+ /// - `barriers` specifies a series of memory barriers to be executed before pipeline execution
+ /// resumes.
+ unsafe fn wait_events<'a, I, J>(
+ &mut self,
+ events: I,
+ stages: Range<pso::PipelineStage>,
+ barriers: J,
+ ) where
+ I: IntoIterator,
+ I::Item: Borrow<B::Event>,
+ I::IntoIter: ExactSizeIterator,
+ J: IntoIterator,
+ J::Item: Borrow<Barrier<'a, B>>,
+ J::IntoIter: ExactSizeIterator;
+
+ /// Begins a query operation. Queries count operations or record timestamps
+ /// resulting from commands that occur between the beginning and end of the query,
+ /// and save the results to the query pool.
+ unsafe fn begin_query(&mut self, query: query::Query<B>, flags: query::ControlFlags);
+
+ /// End a query.
+ unsafe fn end_query(&mut self, query: query::Query<B>);
+
+ /// Reset/clear the values in the given range of the query pool.
+ unsafe fn reset_query_pool(&mut self, pool: &B::QueryPool, queries: Range<query::Id>);
+
+ /// Copy query results into a buffer.
+ unsafe fn copy_query_pool_results(
+ &mut self,
+ pool: &B::QueryPool,
+ queries: Range<query::Id>,
+ buffer: &B::Buffer,
+ offset: buffer::Offset,
+ stride: buffer::Offset,
+ flags: query::ResultFlags,
+ );
+
+ /// Requests a timestamp to be written.
+ unsafe fn write_timestamp(&mut self, stage: pso::PipelineStage, query: query::Query<B>);
+
+ /// Modify constant data in a graphics pipeline. Push constants are intended to modify data in a
+ /// pipeline more quickly than a updating the values inside a descriptor set.
+ ///
+ /// Push constants must be aligned to 4 bytes, and to guarantee alignment, this function takes a
+ /// `&[u32]` instead of a `&[u8]`. Note that the offset is still specified in units of bytes.
+ unsafe fn push_graphics_constants(
+ &mut self,
+ layout: &B::PipelineLayout,
+ stages: pso::ShaderStageFlags,
+ offset: u32,
+ constants: &[u32],
+ );
+
+ /// Modify constant data in a compute pipeline. Push constants are intended to modify data in a
+ /// pipeline more quickly than a updating the values inside a descriptor set.
+ ///
+ /// Push constants must be aligned to 4 bytes, and to guarantee alignment, this function takes a
+ /// `&[u32]` instead of a `&[u8]`. Note that the offset is still specified in units of bytes.
+ unsafe fn push_compute_constants(
+ &mut self,
+ layout: &B::PipelineLayout,
+ offset: u32,
+ constants: &[u32],
+ );
+
+ /// Execute the given secondary command buffers.
+ unsafe fn execute_commands<'a, T, I>(&mut self, cmd_buffers: I)
+ where
+ T: 'a + Borrow<B::CommandBuffer>,
+ I: IntoIterator<Item = &'a T>,
+ I::IntoIter: ExactSizeIterator;
+
+ /// Debug mark the current spot in the command buffer.
+ unsafe fn insert_debug_marker(&mut self, name: &str, color: u32);
+ /// Start a debug marker at the current place in the command buffer.
+ unsafe fn begin_debug_marker(&mut self, name: &str, color: u32);
+ /// End the last started debug marker scope.
+ unsafe fn end_debug_marker(&mut self);
+}
diff --git a/third_party/rust/gfx-hal/src/command/structs.rs b/third_party/rust/gfx-hal/src/command/structs.rs
new file mode 100644
index 0000000000..d3c412f8c4
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/command/structs.rs
@@ -0,0 +1,86 @@
+use crate::{buffer, image};
+
+use std::ops::Range;
+
+/// Specifies a source region and a destination
+/// region in a buffer for copying. All values
+/// are in units of bytes.
+#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct BufferCopy {
+ /// Buffer region source offset.
+ pub src: buffer::Offset,
+ /// Buffer region destination offset.
+ pub dst: buffer::Offset,
+ /// Region size.
+ pub size: buffer::Offset,
+}
+
+/// Bundles together all the parameters needed to copy data from one `Image`
+/// to another.
+#[derive(Clone, Debug)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct ImageCopy {
+ /// The image subresource to copy from.
+ pub src_subresource: image::SubresourceLayers,
+ /// The source offset.
+ pub src_offset: image::Offset,
+ /// The image subresource to copy to.
+ pub dst_subresource: image::SubresourceLayers,
+ /// The destination offset.
+ pub dst_offset: image::Offset,
+ /// The extent of the region to copy.
+ pub extent: image::Extent,
+}
+
+/// Bundles together all the parameters needed to copy a buffer
+/// to an image or vice-versa.
+#[derive(Clone, Debug)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct BufferImageCopy {
+ /// Buffer offset in bytes.
+ pub buffer_offset: buffer::Offset,
+ /// Width of a buffer 'row' in texels.
+ pub buffer_width: u32,
+ /// Height of a buffer 'image slice' in texels.
+ pub buffer_height: u32,
+ /// The image subresource.
+ pub image_layers: image::SubresourceLayers,
+ /// The offset of the portion of the image to copy.
+ pub image_offset: image::Offset,
+ /// Size of the portion of the image to copy.
+ pub image_extent: image::Extent,
+}
+
+/// Parameters for an image resolve operation,
+/// where a multi-sampled image is copied into a single-sampled
+/// image.
+#[derive(Clone, Debug)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct ImageResolve {
+ /// Source image and layers.
+ pub src_subresource: image::SubresourceLayers,
+ /// Source image offset.
+ pub src_offset: image::Offset,
+ /// Destination image and layers.
+ pub dst_subresource: image::SubresourceLayers,
+ /// Destination image offset.
+ pub dst_offset: image::Offset,
+ /// Image extent.
+ pub extent: image::Extent,
+}
+
+/// Parameters for an image blit operation, where a portion of one image
+/// is copied into another, possibly with scaling and filtering.
+#[derive(Clone, Debug)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct ImageBlit {
+ /// Source image and layers.
+ pub src_subresource: image::SubresourceLayers,
+ /// Source image bounds.
+ pub src_bounds: Range<image::Offset>,
+ /// Destination image and layers.
+ pub dst_subresource: image::SubresourceLayers,
+ /// Destination image bounds.
+ pub dst_bounds: Range<image::Offset>,
+}
diff --git a/third_party/rust/gfx-hal/src/device.rs b/third_party/rust/gfx-hal/src/device.rs
new file mode 100644
index 0000000000..e8aa1ec5ae
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/device.rs
@@ -0,0 +1,997 @@
+//! Logical graphics device.
+//!
+//! # Device
+//!
+//! This module exposes the [`Device`][Device] trait, which provides methods for creating
+//! and managing graphics resources such as buffers, images and memory.
+//!
+//! The `Adapter` and `Device` types are very similar to the Vulkan concept of
+//! "physical devices" vs. "logical devices"; an `Adapter` is single GPU
+//! (or CPU) that implements a backend, a `Device` is a
+//! handle to that physical device that has the requested capabilities
+//! and is used to actually do things.
+
+use std::any::Any;
+use std::borrow::Borrow;
+use std::ops::Range;
+use std::{fmt, iter};
+
+use crate::{
+ buffer, format, image,
+ memory::{Requirements, Segment},
+ pass,
+ pool::CommandPoolCreateFlags,
+ pso,
+ pso::DescriptorPoolCreateFlags,
+ query,
+ queue::QueueFamilyId,
+ Backend, MemoryTypeId,
+};
+
+/// Error occurred caused device to be lost.
+#[derive(Clone, Debug, PartialEq)]
+pub struct DeviceLost;
+
+impl std::fmt::Display for DeviceLost {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ fmt.write_str("Device lost")
+ }
+}
+
+impl std::error::Error for DeviceLost {}
+
+/// Error occurred caused surface to be lost.
+#[derive(Clone, Debug, PartialEq)]
+pub struct SurfaceLost;
+
+impl std::fmt::Display for SurfaceLost {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ fmt.write_str("Surface lost")
+ }
+}
+
+impl std::error::Error for SurfaceLost {}
+
+/// Native window is already in use by graphics API.
+#[derive(Clone, Debug, PartialEq)]
+pub struct WindowInUse;
+
+impl std::fmt::Display for WindowInUse {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ fmt.write_str("Window is in use")
+ }
+}
+
+impl std::error::Error for WindowInUse {}
+
+/// Error allocating memory.
+#[derive(Clone, Debug, PartialEq)]
+pub enum OutOfMemory {
+ /// Host memory exhausted.
+ Host,
+ /// Device memory exhausted.
+ Device,
+}
+
+impl std::fmt::Display for OutOfMemory {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ OutOfMemory::Host => write!(fmt, "Out of host memory"),
+ OutOfMemory::Device => write!(fmt, "Out of device memory"),
+ }
+ }
+}
+
+impl std::error::Error for OutOfMemory {}
+
+/// Error occurred caused device to be lost
+/// or out of memory error.
+#[derive(Clone, Debug, PartialEq)]
+pub enum OomOrDeviceLost {
+ /// Out of either host or device memory.
+ OutOfMemory(OutOfMemory),
+ /// Device is lost
+ DeviceLost(DeviceLost),
+}
+
+impl From<OutOfMemory> for OomOrDeviceLost {
+ fn from(error: OutOfMemory) -> Self {
+ OomOrDeviceLost::OutOfMemory(error)
+ }
+}
+
+impl From<DeviceLost> for OomOrDeviceLost {
+ fn from(error: DeviceLost) -> Self {
+ OomOrDeviceLost::DeviceLost(error)
+ }
+}
+
+impl std::fmt::Display for OomOrDeviceLost {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ OomOrDeviceLost::DeviceLost(err) => write!(fmt, "Failed querying device: {}", err),
+ OomOrDeviceLost::OutOfMemory(err) => write!(fmt, "Failed querying device: {}", err),
+ }
+ }
+}
+
+impl std::error::Error for OomOrDeviceLost {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self {
+ OomOrDeviceLost::DeviceLost(err) => Some(err),
+ OomOrDeviceLost::OutOfMemory(err) => Some(err),
+ }
+ }
+}
+
+/// Possible cause of allocation failure.
+#[derive(Clone, Debug, PartialEq)]
+pub enum AllocationError {
+ /// Out of either host or device memory.
+ OutOfMemory(OutOfMemory),
+
+ /// Cannot create any more objects.
+ TooManyObjects,
+}
+
+impl From<OutOfMemory> for AllocationError {
+ fn from(error: OutOfMemory) -> Self {
+ AllocationError::OutOfMemory(error)
+ }
+}
+
+impl std::fmt::Display for AllocationError {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ AllocationError::OutOfMemory(err) => write!(fmt, "Failed to allocate object: {}", err),
+ AllocationError::TooManyObjects => {
+ write!(fmt, "Failed to allocate object: Too many objects")
+ }
+ }
+ }
+}
+
+impl std::error::Error for AllocationError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self {
+ AllocationError::OutOfMemory(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+/// Device creation errors during `open`.
+#[derive(Clone, Debug, PartialEq)]
+pub enum CreationError {
+ /// Out of either host or device memory.
+ OutOfMemory(OutOfMemory),
+ /// Device initialization failed due to implementation specific errors.
+ InitializationFailed,
+ /// At least one of the user requested extensions if not supported by the
+ /// physical device.
+ MissingExtension,
+ /// At least one of the user requested features if not supported by the
+ /// physical device.
+ ///
+ /// Use [`features`](trait.PhysicalDevice.html#tymethod.features)
+ /// for checking the supported features.
+ MissingFeature,
+ /// Too many logical devices have been created from this physical device.
+ ///
+ /// The implementation may only support one logical device for each physical
+ /// device or lacks resources to allocate a new device.
+ TooManyObjects,
+ /// The logical or physical device are lost during the device creation
+ /// process.
+ ///
+ /// This may be caused by hardware failure, physical device removal,
+ /// power outage, etc.
+ DeviceLost,
+}
+
+impl std::fmt::Display for CreationError {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ CreationError::OutOfMemory(err) => write!(fmt, "Failed to create device: {}", err),
+ CreationError::InitializationFailed => write!(
+ fmt,
+ "Failed to create device: Implementation specific error occurred"
+ ),
+ CreationError::MissingExtension => write!(
+ fmt,
+ "Failed to create device: Requested extension is missing"
+ ),
+ CreationError::MissingFeature => {
+ write!(fmt, "Failed to create device: Requested feature is missing")
+ }
+ CreationError::TooManyObjects => {
+ write!(fmt, "Failed to create device: Too many objects")
+ }
+ CreationError::DeviceLost => write!(
+ fmt,
+ "Failed to create device: Logical or Physical device was lost during creation"
+ ),
+ }
+ }
+}
+
+impl std::error::Error for CreationError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self {
+ CreationError::OutOfMemory(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+/// Error accessing a mapping.
+#[derive(Clone, Debug, PartialEq)]
+pub enum MapError {
+ /// Out of either host or device memory.
+ OutOfMemory(OutOfMemory),
+ /// The requested mapping range is outside of the resource.
+ OutOfBounds,
+ /// Failed to allocate an appropriately sized contiguous virtual address range
+ MappingFailed,
+ /// Memory is not CPU visible
+ Access,
+}
+
+impl From<OutOfMemory> for MapError {
+ fn from(error: OutOfMemory) -> Self {
+ MapError::OutOfMemory(error)
+ }
+}
+
+impl std::fmt::Display for MapError {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ MapError::OutOfMemory(err) => write!(fmt, "Failed to map memory: {}", err),
+ MapError::OutOfBounds => write!(fmt, "Failed to map memory: Requested range is outside the resource"),
+ MapError::MappingFailed => write!(
+ fmt,
+ "Failed to map memory: Unable to allocate an appropriately sized contiguous virtual address range"
+ ),
+ MapError::Access => write!(fmt, "Failed to map memory: Memory is not CPU visible"),
+ }
+ }
+}
+
+impl std::error::Error for MapError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self {
+ MapError::OutOfMemory(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+/// Error binding a resource to memory allocation.
+#[derive(Clone, Debug, PartialEq)]
+pub enum BindError {
+ /// Out of either host or device memory.
+ OutOfMemory(OutOfMemory),
+ /// Requested binding to memory that doesn't support the required operations.
+ WrongMemory,
+ /// Requested binding to an invalid memory.
+ OutOfBounds,
+}
+
+impl From<OutOfMemory> for BindError {
+ fn from(error: OutOfMemory) -> Self {
+ BindError::OutOfMemory(error)
+ }
+}
+
+impl std::fmt::Display for BindError {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ BindError::OutOfMemory(err) => {
+ write!(fmt, "Failed to bind object to memory range: {}", err)
+ }
+ BindError::OutOfBounds => write!(
+ fmt,
+ "Failed to bind object to memory range: Requested range is outside the resource"
+ ),
+ BindError::WrongMemory => {
+ write!(fmt, "Failed to bind object to memory range: Wrong memory")
+ }
+ }
+ }
+}
+
+impl std::error::Error for BindError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self {
+ BindError::OutOfMemory(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+/// Specifies the waiting targets.
+#[derive(Clone, Debug, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum WaitFor {
+ /// Wait for any target.
+ Any,
+ /// Wait for all targets at once.
+ All,
+}
+
+/// An error from creating a shader module.
+#[derive(Clone, Debug, PartialEq)]
+pub enum ShaderError {
+ /// The shader failed to compile.
+ CompilationFailed(String),
+ /// The shader is missing an entry point.
+ MissingEntryPoint(String),
+ /// The shader has a mismatch of interface (e.g missing push constants).
+ InterfaceMismatch(String),
+ /// The shader stage is not supported.
+ UnsupportedStage(pso::ShaderStageFlags),
+ /// Out of either host or device memory.
+ OutOfMemory(OutOfMemory),
+}
+
+impl From<OutOfMemory> for ShaderError {
+ fn from(error: OutOfMemory) -> Self {
+ ShaderError::OutOfMemory(error)
+ }
+}
+
+impl std::fmt::Display for ShaderError {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ ShaderError::OutOfMemory(err) => write!(fmt, "Shader error: {}", err),
+ ShaderError::CompilationFailed(string) => {
+ write!(fmt, "Shader error: Compilation failed: {}", string)
+ }
+ ShaderError::MissingEntryPoint(string) => {
+ write!(fmt, "Shader error: Missing entry point: {}", string)
+ }
+ ShaderError::InterfaceMismatch(string) => {
+ write!(fmt, "Shader error: Interface mismatch: {}", string)
+ }
+ ShaderError::UnsupportedStage(stage) => {
+ write!(fmt, "Shader error: Unsupported stage: {:?}", stage)
+ }
+ }
+ }
+}
+
+impl std::error::Error for ShaderError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self {
+ ShaderError::OutOfMemory(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+/// Logical device handle, responsible for creating and managing resources
+/// for the physical device it was created from.
+///
+/// ## Resource Construction and Handling
+///
+/// This device structure can then be used to create and manage different resources,
+/// like [buffers][Device::create_buffer], [shader modules][Device::create_shader_module]
+/// and [images][Device::create_image]. See the individual methods for more information.
+///
+/// ## Mutability
+///
+/// All the methods get `&self`. Any internal mutability of the `Device` is hidden from the user.
+///
+/// ## Synchronization
+///
+/// `Device` should be usable concurrently from multiple threads. The `Send` and `Sync` bounds
+/// are not enforced at the HAL level due to OpenGL constraint (to be revised). Users can still
+/// benefit from the backends that support synchronization of the `Device`.
+///
+pub trait Device<B: Backend>: fmt::Debug + Any + Send + Sync {
+ /// Allocates a memory segment of a specified type.
+ ///
+ /// There is only a limited amount of allocations allowed depending on the implementation!
+ ///
+ /// # Arguments
+ ///
+ /// * `memory_type` - Index of the memory type in the memory properties of the associated physical device.
+ /// * `size` - Size of the allocation.
+ unsafe fn allocate_memory(
+ &self,
+ memory_type: MemoryTypeId,
+ size: u64,
+ ) -> Result<B::Memory, AllocationError>;
+
+ /// Free device memory
+ unsafe fn free_memory(&self, memory: B::Memory);
+
+ /// Create a new [command pool][crate::pool::CommandPool] for a given queue family.
+ ///
+ /// *Note*: the family has to be associated with one of [the queue groups
+ /// of this device][crate::adapter::Gpu::queue_groups].
+ unsafe fn create_command_pool(
+ &self,
+ family: QueueFamilyId,
+ create_flags: CommandPoolCreateFlags,
+ ) -> Result<B::CommandPool, OutOfMemory>;
+
+ /// Destroy a command pool.
+ unsafe fn destroy_command_pool(&self, pool: B::CommandPool);
+
+ /// Create a [render pass][crate::pass] with the given attachments and subpasses.
+ ///
+ /// The use of a render pass in a command buffer is a *render pass* instance.
+ ///
+ /// # Arguments
+ ///
+ /// * `attachments` - [image attachments][crate::pass::Attachment] to be used in
+ /// this render pass. Usually you need at least one attachment, to be used as output.
+ /// * `subpasses` - [subpasses][crate::pass::SubpassDesc] to use.
+ /// You need to use at least one subpass.
+ /// * `dependencies` - [dependencies between subpasses][crate::pass::SubpassDependency].
+ /// Can be empty.
+ unsafe fn create_render_pass<'a, IA, IS, ID>(
+ &self,
+ attachments: IA,
+ subpasses: IS,
+ dependencies: ID,
+ ) -> Result<B::RenderPass, OutOfMemory>
+ where
+ IA: IntoIterator,
+ IA::Item: Borrow<pass::Attachment>,
+ IA::IntoIter: ExactSizeIterator,
+ IS: IntoIterator,
+ IS::Item: Borrow<pass::SubpassDesc<'a>>,
+ IS::IntoIter: ExactSizeIterator,
+ ID: IntoIterator,
+ ID::Item: Borrow<pass::SubpassDependency>,
+ ID::IntoIter: ExactSizeIterator;
+
+ /// Destroys a *render pass* created by this device.
+ unsafe fn destroy_render_pass(&self, rp: B::RenderPass);
+
+ /// Create a new pipeline layout object.
+ ///
+ /// # Arguments
+ ///
+ /// * `set_layouts` - Descriptor set layouts
+ /// * `push_constants` - Ranges of push constants. A shader stage may only contain one push
+ /// constant block. The range is defined in units of bytes.
+ ///
+ /// # PipelineLayout
+ ///
+ /// Access to descriptor sets from a pipeline is accomplished through a *pipeline layout*.
+ /// Zero or more descriptor set layouts and zero or more push constant ranges are combined to
+ /// form a pipeline layout object which describes the complete set of resources that **can** be
+ /// accessed by a pipeline. The pipeline layout represents a sequence of descriptor sets with
+ /// each having a specific layout. This sequence of layouts is used to determine the interface
+ /// between shader stages and shader resources. Each pipeline is created using a pipeline layout.
+ unsafe fn create_pipeline_layout<IS, IR>(
+ &self,
+ set_layouts: IS,
+ push_constant: IR,
+ ) -> Result<B::PipelineLayout, OutOfMemory>
+ where
+ IS: IntoIterator,
+ IS::Item: Borrow<B::DescriptorSetLayout>,
+ IS::IntoIter: ExactSizeIterator,
+ IR: IntoIterator,
+ IR::Item: Borrow<(pso::ShaderStageFlags, Range<u32>)>,
+ IR::IntoIter: ExactSizeIterator;
+
+ /// Destroy a pipeline layout object
+ unsafe fn destroy_pipeline_layout(&self, layout: B::PipelineLayout);
+
+ /// Create a pipeline cache object.
+ unsafe fn create_pipeline_cache(
+ &self,
+ data: Option<&[u8]>,
+ ) -> Result<B::PipelineCache, OutOfMemory>;
+
+ /// Retrieve data from pipeline cache object.
+ unsafe fn get_pipeline_cache_data(
+ &self,
+ cache: &B::PipelineCache,
+ ) -> Result<Vec<u8>, OutOfMemory>;
+
+ /// Merge a number of source pipeline caches into the target one.
+ unsafe fn merge_pipeline_caches<I>(
+ &self,
+ target: &B::PipelineCache,
+ sources: I,
+ ) -> Result<(), OutOfMemory>
+ where
+ I: IntoIterator,
+ I::Item: Borrow<B::PipelineCache>,
+ I::IntoIter: ExactSizeIterator;
+
+ /// Destroy a pipeline cache object.
+ unsafe fn destroy_pipeline_cache(&self, cache: B::PipelineCache);
+
+ /// Create a graphics pipeline.
+ ///
+ /// # Arguments
+ ///
+ /// * `desc` - the [description][crate::pso::GraphicsPipelineDesc] of
+ /// the graphics pipeline to create.
+ /// * `cache` - the pipeline cache,
+ /// [obtained from this device][Device::create_pipeline_cache],
+ /// used for faster PSO creation.
+ unsafe fn create_graphics_pipeline<'a>(
+ &self,
+ desc: &pso::GraphicsPipelineDesc<'a, B>,
+ cache: Option<&B::PipelineCache>,
+ ) -> Result<B::GraphicsPipeline, pso::CreationError>;
+
+ /// Create multiple graphics pipelines.
+ unsafe fn create_graphics_pipelines<'a, I>(
+ &self,
+ descs: I,
+ cache: Option<&B::PipelineCache>,
+ ) -> Vec<Result<B::GraphicsPipeline, pso::CreationError>>
+ where
+ I: IntoIterator,
+ I::Item: Borrow<pso::GraphicsPipelineDesc<'a, B>>,
+ {
+ descs
+ .into_iter()
+ .map(|desc| self.create_graphics_pipeline(desc.borrow(), cache))
+ .collect()
+ }
+
+ /// Destroy a graphics pipeline.
+ ///
+ /// The graphics pipeline shouldn't be destroyed before any submitted command buffer,
+ /// which references the graphics pipeline, has finished execution.
+ unsafe fn destroy_graphics_pipeline(&self, pipeline: B::GraphicsPipeline);
+
+ /// Create a compute pipeline.
+ unsafe fn create_compute_pipeline<'a>(
+ &self,
+ desc: &pso::ComputePipelineDesc<'a, B>,
+ cache: Option<&B::PipelineCache>,
+ ) -> Result<B::ComputePipeline, pso::CreationError>;
+
+ /// Create compute pipelines.
+ unsafe fn create_compute_pipelines<'a, I>(
+ &self,
+ descs: I,
+ cache: Option<&B::PipelineCache>,
+ ) -> Vec<Result<B::ComputePipeline, pso::CreationError>>
+ where
+ I: IntoIterator,
+ I::Item: Borrow<pso::ComputePipelineDesc<'a, B>>,
+ {
+ descs
+ .into_iter()
+ .map(|desc| self.create_compute_pipeline(desc.borrow(), cache))
+ .collect()
+ }
+
+ /// Destroy a compute pipeline.
+ ///
+ /// The compute pipeline shouldn't be destroyed before any submitted command buffer,
+ /// which references the compute pipeline, has finished execution.
+ unsafe fn destroy_compute_pipeline(&self, pipeline: B::ComputePipeline);
+
+ /// Create a new framebuffer object.
+ ///
+ /// # Safety
+ /// - `extent.width`, `extent.height` and `extent.depth` **must** be greater than `0`.
+ unsafe fn create_framebuffer<I>(
+ &self,
+ pass: &B::RenderPass,
+ attachments: I,
+ extent: image::Extent,
+ ) -> Result<B::Framebuffer, OutOfMemory>
+ where
+ I: IntoIterator,
+ I::Item: Borrow<B::ImageView>;
+
+ /// Destroy a framebuffer.
+ ///
+ /// The framebuffer shouldn't be destroy before any submitted command buffer,
+ /// which references the framebuffer, has finished execution.
+ unsafe fn destroy_framebuffer(&self, buf: B::Framebuffer);
+
+ /// Create a new shader module object from the SPIR-V binary data.
+ ///
+ /// Once a shader module has been created, any [entry points][crate::pso::EntryPoint]
+ /// it contains can be used in pipeline shader stages of
+ /// [compute pipelines][crate::pso::ComputePipelineDesc] and
+ /// [graphics pipelines][crate::pso::GraphicsPipelineDesc].
+ unsafe fn create_shader_module(
+ &self,
+ spirv_data: &[u32],
+ ) -> Result<B::ShaderModule, ShaderError>;
+
+ /// Destroy a shader module module
+ ///
+ /// A shader module can be destroyed while pipelines created using its shaders are still in use.
+ unsafe fn destroy_shader_module(&self, shader: B::ShaderModule);
+
+ /// Create a new buffer (unbound).
+ ///
+ /// The created buffer won't have associated memory until `bind_buffer_memory` is called.
+ unsafe fn create_buffer(
+ &self,
+ size: u64,
+ usage: buffer::Usage,
+ ) -> Result<B::Buffer, buffer::CreationError>;
+
+ /// Get memory requirements for the buffer
+ unsafe fn get_buffer_requirements(&self, buf: &B::Buffer) -> Requirements;
+
+ /// Bind memory to a buffer.
+ ///
+ /// Be sure to check that there is enough memory available for the buffer.
+ /// Use `get_buffer_requirements` to acquire the memory requirements.
+ unsafe fn bind_buffer_memory(
+ &self,
+ memory: &B::Memory,
+ offset: u64,
+ buf: &mut B::Buffer,
+ ) -> Result<(), BindError>;
+
+ /// Destroy a buffer.
+ ///
+ /// The buffer shouldn't be destroyed before any submitted command buffer,
+ /// which references the images, has finished execution.
+ unsafe fn destroy_buffer(&self, buffer: B::Buffer);
+
+ /// Create a new buffer view object
+ unsafe fn create_buffer_view(
+ &self,
+ buf: &B::Buffer,
+ fmt: Option<format::Format>,
+ range: buffer::SubRange,
+ ) -> Result<B::BufferView, buffer::ViewCreationError>;
+
+ /// Destroy a buffer view object
+ unsafe fn destroy_buffer_view(&self, view: B::BufferView);
+
+ /// Create a new image object
+ unsafe fn create_image(
+ &self,
+ kind: image::Kind,
+ mip_levels: image::Level,
+ format: format::Format,
+ tiling: image::Tiling,
+ usage: image::Usage,
+ view_caps: image::ViewCapabilities,
+ ) -> Result<B::Image, image::CreationError>;
+
+ /// Get memory requirements for the Image
+ unsafe fn get_image_requirements(&self, image: &B::Image) -> Requirements;
+
+ ///
+ unsafe fn get_image_subresource_footprint(
+ &self,
+ image: &B::Image,
+ subresource: image::Subresource,
+ ) -> image::SubresourceFootprint;
+
+ /// Bind device memory to an image object
+ unsafe fn bind_image_memory(
+ &self,
+ memory: &B::Memory,
+ offset: u64,
+ image: &mut B::Image,
+ ) -> Result<(), BindError>;
+
+ /// Destroy an image.
+ ///
+ /// The image shouldn't be destroyed before any submitted command buffer,
+ /// which references the images, has finished execution.
+ unsafe fn destroy_image(&self, image: B::Image);
+
+ /// Create an image view from an existing image
+ unsafe fn create_image_view(
+ &self,
+ image: &B::Image,
+ view_kind: image::ViewKind,
+ format: format::Format,
+ swizzle: format::Swizzle,
+ range: image::SubresourceRange,
+ ) -> Result<B::ImageView, image::ViewCreationError>;
+
+ /// Destroy an image view object
+ unsafe fn destroy_image_view(&self, view: B::ImageView);
+
+ /// Create a new sampler object
+ unsafe fn create_sampler(
+ &self,
+ desc: &image::SamplerDesc,
+ ) -> Result<B::Sampler, AllocationError>;
+
+ /// Destroy a sampler object
+ unsafe fn destroy_sampler(&self, sampler: B::Sampler);
+
+ /// Create a descriptor pool.
+ ///
+ /// Descriptor pools allow allocation of descriptor sets.
+ /// The pool can't be modified directly, only through updating descriptor sets.
+ unsafe fn create_descriptor_pool<I>(
+ &self,
+ max_sets: usize,
+ descriptor_ranges: I,
+ flags: DescriptorPoolCreateFlags,
+ ) -> Result<B::DescriptorPool, OutOfMemory>
+ where
+ I: IntoIterator,
+ I::Item: Borrow<pso::DescriptorRangeDesc>,
+ I::IntoIter: ExactSizeIterator;
+
+ /// Destroy a descriptor pool object
+ ///
+ /// When a pool is destroyed, all descriptor sets allocated from the pool are implicitly freed
+ /// and become invalid. Descriptor sets allocated from a given pool do not need to be freed
+ /// before destroying that descriptor pool.
+ unsafe fn destroy_descriptor_pool(&self, pool: B::DescriptorPool);
+
+ /// Create a descriptor set layout.
+ ///
+ /// A descriptor set layout object is defined by an array of zero or more descriptor bindings.
+ /// Each individual descriptor binding is specified by a descriptor type, a count (array size)
+ /// of the number of descriptors in the binding, a set of shader stages that **can** access the
+ /// binding, and (if using immutable samplers) an array of sampler descriptors.
+ unsafe fn create_descriptor_set_layout<I, J>(
+ &self,
+ bindings: I,
+ immutable_samplers: J,
+ ) -> Result<B::DescriptorSetLayout, OutOfMemory>
+ where
+ I: IntoIterator,
+ I::Item: Borrow<pso::DescriptorSetLayoutBinding>,
+ J: IntoIterator,
+ J::Item: Borrow<B::Sampler>,
+ J::IntoIter: ExactSizeIterator;
+
+ /// Destroy a descriptor set layout object
+ unsafe fn destroy_descriptor_set_layout(&self, layout: B::DescriptorSetLayout);
+
+ /// Specifying the parameters of a descriptor set write operation
+ unsafe fn write_descriptor_sets<'a, I, J>(&self, write_iter: I)
+ where
+ I: IntoIterator<Item = pso::DescriptorSetWrite<'a, B, J>>,
+ J: IntoIterator,
+ J::Item: Borrow<pso::Descriptor<'a, B>>;
+
+ /// Structure specifying a copy descriptor set operation
+ unsafe fn copy_descriptor_sets<'a, I>(&self, copy_iter: I)
+ where
+ I: IntoIterator,
+ I::Item: Borrow<pso::DescriptorSetCopy<'a, B>>,
+ I::IntoIter: ExactSizeIterator;
+
+ /// Map a memory object into application address space
+ ///
+ /// Call `map_memory()` to retrieve a host virtual address pointer to a region of a mappable memory object
+ unsafe fn map_memory(&self, memory: &B::Memory, segment: Segment) -> Result<*mut u8, MapError>;
+
+ /// Flush mapped memory ranges
+ unsafe fn flush_mapped_memory_ranges<'a, I>(&self, ranges: I) -> Result<(), OutOfMemory>
+ where
+ I: IntoIterator,
+ I::Item: Borrow<(&'a B::Memory, Segment)>;
+
+ /// Invalidate ranges of non-coherent memory from the host caches
+ unsafe fn invalidate_mapped_memory_ranges<'a, I>(&self, ranges: I) -> Result<(), OutOfMemory>
+ where
+ I: IntoIterator,
+ I::Item: Borrow<(&'a B::Memory, Segment)>;
+
+ /// Unmap a memory object once host access to it is no longer needed by the application
+ unsafe fn unmap_memory(&self, memory: &B::Memory);
+
+ /// Create a new semaphore object.
+ fn create_semaphore(&self) -> Result<B::Semaphore, OutOfMemory>;
+
+ /// Destroy a semaphore object.
+ unsafe fn destroy_semaphore(&self, semaphore: B::Semaphore);
+
+ /// Create a new fence object.
+ ///
+ /// Fences are a synchronization primitive that **can** be used to insert a dependency from
+ /// a queue to the host.
+ /// Fences have two states - signaled and unsignaled.
+ ///
+ /// A fence **can** be signaled as part of the execution of a
+ /// [queue submission][crate::queue::CommandQueue::submit] command.
+ ///
+ /// Fences **can** be unsignaled on the host with
+ /// [`reset_fences`][Device::reset_fences].
+ ///
+ /// Fences **can** be waited on by the host with the
+ /// [`wait_for_fences`][Device::wait_for_fences] command.
+ ///
+ /// A fence's current state **can** be queried with
+ /// [`get_fence_status`][Device::get_fence_status].
+ ///
+ /// # Arguments
+ ///
+ /// * `signaled` - the fence will be in its signaled state.
+ fn create_fence(&self, signaled: bool) -> Result<B::Fence, OutOfMemory>;
+
+ /// Resets a given fence to its original, unsignaled state.
+ unsafe fn reset_fence(&self, fence: &B::Fence) -> Result<(), OutOfMemory> {
+ self.reset_fences(iter::once(fence))
+ }
+
+ /// Resets multiple fences to their original states.
+ unsafe fn reset_fences<I>(&self, fences: I) -> Result<(), OutOfMemory>
+ where
+ I: IntoIterator,
+ I::Item: Borrow<B::Fence>,
+ I::IntoIter: ExactSizeIterator,
+ {
+ for fence in fences {
+ self.reset_fence(fence.borrow())?;
+ }
+ Ok(())
+ }
+
+ /// Blocks until the given fence is signaled.
+ /// Returns true if the fence was signaled before the timeout.
+ unsafe fn wait_for_fence(
+ &self,
+ fence: &B::Fence,
+ timeout_ns: u64,
+ ) -> Result<bool, OomOrDeviceLost> {
+ self.wait_for_fences(iter::once(fence), WaitFor::All, timeout_ns)
+ }
+
+ /// Blocks until all or one of the given fences are signaled.
+ /// Returns true if fences were signaled before the timeout.
+ unsafe fn wait_for_fences<I>(
+ &self,
+ fences: I,
+ wait: WaitFor,
+ timeout_ns: u64,
+ ) -> Result<bool, OomOrDeviceLost>
+ where
+ I: IntoIterator,
+ I::Item: Borrow<B::Fence>,
+ I::IntoIter: ExactSizeIterator,
+ {
+ use std::{thread, time};
+ fn to_ns(duration: time::Duration) -> u64 {
+ duration.as_secs() * 1_000_000_000 + duration.subsec_nanos() as u64
+ }
+
+ let start = time::Instant::now();
+ match wait {
+ WaitFor::All => {
+ for fence in fences {
+ if !self.wait_for_fence(fence.borrow(), 0)? {
+ let elapsed_ns = to_ns(start.elapsed());
+ if elapsed_ns > timeout_ns {
+ return Ok(false);
+ }
+ if !self.wait_for_fence(fence.borrow(), timeout_ns - elapsed_ns)? {
+ return Ok(false);
+ }
+ }
+ }
+ Ok(true)
+ }
+ WaitFor::Any => {
+ let fences: Vec<_> = fences.into_iter().collect();
+ loop {
+ for fence in &fences {
+ if self.wait_for_fence(fence.borrow(), 0)? {
+ return Ok(true);
+ }
+ }
+ if to_ns(start.elapsed()) >= timeout_ns {
+ return Ok(false);
+ }
+ thread::sleep(time::Duration::from_millis(1));
+ }
+ }
+ }
+ }
+
+ /// true for signaled, false for not ready
+ unsafe fn get_fence_status(&self, fence: &B::Fence) -> Result<bool, DeviceLost>;
+
+ /// Destroy a fence object
+ unsafe fn destroy_fence(&self, fence: B::Fence);
+
+ /// Create an event object.
+ fn create_event(&self) -> Result<B::Event, OutOfMemory>;
+
+ /// Destroy an event object.
+ unsafe fn destroy_event(&self, event: B::Event);
+
+ /// Query the status of an event.
+ ///
+ /// Returns `true` if the event is set, or `false` if it is reset.
+ unsafe fn get_event_status(&self, event: &B::Event) -> Result<bool, OomOrDeviceLost>;
+
+ /// Sets an event.
+ unsafe fn set_event(&self, event: &B::Event) -> Result<(), OutOfMemory>;
+
+ /// Resets an event.
+ unsafe fn reset_event(&self, event: &B::Event) -> Result<(), OutOfMemory>;
+
+ /// Create a new query pool object
+ ///
+ /// Queries are managed using query pool objects. Each query pool is a collection of a specific
+ /// number of queries of a particular type.
+ unsafe fn create_query_pool(
+ &self,
+ ty: query::Type,
+ count: query::Id,
+ ) -> Result<B::QueryPool, query::CreationError>;
+
+ /// Destroy a query pool object
+ unsafe fn destroy_query_pool(&self, pool: B::QueryPool);
+
+ /// Get query pool results into the specified CPU memory.
+ /// Returns `Ok(false)` if the results are not ready yet and neither of `WAIT` or `PARTIAL` flags are set.
+ unsafe fn get_query_pool_results(
+ &self,
+ pool: &B::QueryPool,
+ queries: Range<query::Id>,
+ data: &mut [u8],
+ stride: buffer::Offset,
+ flags: query::ResultFlags,
+ ) -> Result<bool, OomOrDeviceLost>;
+
+ /// Wait for all queues associated with this device to idle.
+ ///
+ /// Host access to all queues needs to be **externally** sycnhronized!
+ fn wait_idle(&self) -> Result<(), OutOfMemory>;
+
+ /// Associate a name with an image, for easier debugging in external tools or with validation
+ /// layers that can print a friendly name when referring to objects in error messages
+ unsafe fn set_image_name(&self, image: &mut B::Image, name: &str);
+ /// Associate a name with a buffer, for easier debugging in external tools or with validation
+ /// layers that can print a friendly name when referring to objects in error messages
+ unsafe fn set_buffer_name(&self, buffer: &mut B::Buffer, name: &str);
+ /// Associate a name with a command buffer, for easier debugging in external tools or with
+ /// validation layers that can print a friendly name when referring to objects in error messages
+ unsafe fn set_command_buffer_name(&self, command_buffer: &mut B::CommandBuffer, name: &str);
+ /// Associate a name with a semaphore, for easier debugging in external tools or with validation
+ /// layers that can print a friendly name when referring to objects in error messages
+ unsafe fn set_semaphore_name(&self, semaphore: &mut B::Semaphore, name: &str);
+ /// Associate a name with a fence, for easier debugging in external tools or with validation
+ /// layers that can print a friendly name when referring to objects in error messages
+ unsafe fn set_fence_name(&self, fence: &mut B::Fence, name: &str);
+ /// Associate a name with a framebuffer, for easier debugging in external tools or with
+ /// validation layers that can print a friendly name when referring to objects in error messages
+ unsafe fn set_framebuffer_name(&self, framebuffer: &mut B::Framebuffer, name: &str);
+ /// Associate a name with a render pass, for easier debugging in external tools or with
+ /// validation layers that can print a friendly name when referring to objects in error messages
+ unsafe fn set_render_pass_name(&self, render_pass: &mut B::RenderPass, name: &str);
+ /// Associate a name with a descriptor set, for easier debugging in external tools or with
+ /// validation layers that can print a friendly name when referring to objects in error messages
+ unsafe fn set_descriptor_set_name(&self, descriptor_set: &mut B::DescriptorSet, name: &str);
+ /// Associate a name with a descriptor set layout, for easier debugging in external tools or
+ /// with validation layers that can print a friendly name when referring to objects in error
+ /// messages
+ unsafe fn set_descriptor_set_layout_name(
+ &self,
+ descriptor_set_layout: &mut B::DescriptorSetLayout,
+ name: &str,
+ );
+ /// Associate a name with a pipeline layout, for easier debugging in external tools or with
+ /// validation layers that can print a friendly name when referring to objects in error messages
+ unsafe fn set_pipeline_layout_name(&self, pipeline_layout: &mut B::PipelineLayout, name: &str);
+ /// Associate a name with a compute pipeline, for easier debugging in external tools or with
+ /// validation layers that can print a friendly name when referring to objects in error messages
+ unsafe fn set_compute_pipeline_name(
+ &self,
+ compute_pipeline: &mut B::ComputePipeline,
+ name: &str,
+ );
+ /// Associate a name with a graphics pipeline, for easier debugging in external tools or with
+ /// validation layers that can print a friendly name when referring to objects in error messages
+ unsafe fn set_graphics_pipeline_name(
+ &self,
+ graphics_pipeline: &mut B::GraphicsPipeline,
+ name: &str,
+ );
+}
diff --git a/third_party/rust/gfx-hal/src/format.rs b/third_party/rust/gfx-hal/src/format.rs
new file mode 100644
index 0000000000..2415b57cf2
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/format.rs
@@ -0,0 +1,625 @@
+//! Universal format specification.
+//! Applicable to textures, views, and vertex buffers.
+//!
+//! For a more detailed description of all the specific format specifiers,
+//! please see [the official Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.0/man/html/VkFormat.html)
+//!
+//! `gfx-rs` splits a `Format` into two sub-components, a `SurfaceType` and
+//! a `ChannelType`. The `SurfaceType` specifies how the large the channels are,
+//! for instance `R32_G32_B32_A32`. The `ChannelType` specifies how the
+//! components are interpreted, for instance `Sfloat` or `Sint`.
+
+bitflags!(
+ /// Bitflags which describe what properties of an image
+ /// a format specifies or does not specify. For example,
+ /// the `Rgba8Unorm` format only specifies a `COLOR` aspect,
+ /// while `D32SfloatS8Uint` specifies both a depth and stencil
+ /// aspect but no color.
+ #[derive(Default)]
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct Aspects: u8 {
+ /// Color aspect.
+ const COLOR = 0x1;
+ /// Depth aspect.
+ const DEPTH = 0x2;
+ /// Stencil aspect.
+ const STENCIL = 0x4;
+ }
+);
+
+/// Description of a format.
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct FormatDesc {
+ /// Total number of bits.
+ ///
+ /// * Depth/Stencil formats are opaque formats, where the total number of bits is unknown.
+ /// A dummy value is used for these formats instead (sum of depth and stencil bits).
+ /// For copy operations, the number of bits of the corresponding aspect should be used.
+ /// * The total number can be larger than the sum of individual format bits
+ /// (`color`, `alpha`, `depth` and `stencil`) for packed formats.
+ /// * For compressed formats, this denotes the number of bits per block.
+ pub bits: u16,
+ /// Dimensions (width, height) of the texel blocks.
+ pub dim: (u8, u8),
+ /// The format representation depends on the endianness of the platform.
+ ///
+ /// * On little-endian systems, the actual oreder of components is reverse of what
+ /// a surface type specifies.
+ pub packed: bool,
+ /// Format aspects
+ pub aspects: Aspects,
+}
+
+impl FormatDesc {
+ /// Check if the format is compressed.
+ pub fn is_compressed(&self) -> bool {
+ self.dim != (1, 1)
+ }
+}
+
+/// Description of the bits distribution of a format.
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct FormatBits {
+ /// Number of color bits (summed for R/G/B).
+ ///
+ /// For compressed formats, this value is 0.
+ pub color: u8,
+ /// Number of alpha bits.
+ ///
+ /// For compressed formats, this value is 0.
+ pub alpha: u8,
+ /// Number of depth bits
+ pub depth: u8,
+ /// Number of stencil bits
+ pub stencil: u8,
+}
+
+/// Format bits configuration with no bits assigned.
+pub const BITS_ZERO: FormatBits = FormatBits {
+ color: 0,
+ alpha: 0,
+ depth: 0,
+ stencil: 0,
+};
+
+/// Source channel in a swizzle configuration. Some may redirect onto
+/// different physical channels, some may be hardcoded to 0 or 1.
+#[repr(u8)]
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum Component {
+ //TODO: add `Identity = 0`?
+ /// Hardcoded zero
+ Zero = 1,
+ /// Hardcoded one
+ One = 2,
+ /// Red channel
+ R = 3,
+ /// Green channel
+ G = 4,
+ /// Blue channel
+ B = 5,
+ /// Alpha channel.
+ A = 6,
+}
+
+/// Channel swizzle configuration for the resource views.
+/// This specifies a "swizzle" operation which remaps the various
+/// channels of a format into a different order. For example,
+/// `Swizzle(Component::B, Component::G, Component::R, Component::A)`
+/// will swap `RGBA` formats into `BGRA` formats and back.
+///
+/// Note: It's not currently mirrored at compile-time,
+/// thus providing less safety and convenience.
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct Swizzle(pub Component, pub Component, pub Component, pub Component);
+
+impl Swizzle {
+ /// A trivially non-swizzling configuration; performs no changes.
+ pub const NO: Swizzle = Swizzle(Component::R, Component::G, Component::B, Component::A);
+}
+
+impl Default for Swizzle {
+ fn default() -> Self {
+ Self::NO
+ }
+}
+
+/// Format properties of the physical device.
+#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct Properties {
+ /// A bitmask of the features supported when an image with linear tiling is requested.
+ /// Linear tiling has a known layout in-memory so data can be copied to and from host
+ /// memory.
+ pub linear_tiling: ImageFeature,
+ /// A bitmask of the features supported when an image with optimal tiling is requested.
+ /// Optimal tiling is arranged however the GPU wants; its exact layout is undefined.
+ pub optimal_tiling: ImageFeature,
+ /// The features supported by buffers.
+ pub buffer_features: BufferFeature,
+}
+
+bitflags!(
+ /// Image feature flags.
+ #[derive(Default)]
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct ImageFeature: u32 {
+ /// Image view can be sampled.
+ const SAMPLED = 0x1;
+ /// Image view can be used as storage image.
+ const STORAGE = 0x2;
+ /// Image view can be used as storage image (with atomics).
+ const STORAGE_ATOMIC = 0x4;
+ /// Image view can be used as color and input attachment.
+ const COLOR_ATTACHMENT = 0x80;
+ /// Image view can be used as color (with blending) and input attachment.
+ const COLOR_ATTACHMENT_BLEND = 0x100;
+ /// Image view can be used as depth-stencil and input attachment.
+ const DEPTH_STENCIL_ATTACHMENT = 0x200;
+ /// Image can be used as source for blit commands.
+ const BLIT_SRC = 0x400;
+ /// Image can be used as destination for blit commands.
+ const BLIT_DST = 0x800;
+ /// Image can be sampled with a (mipmap) linear sampler or as blit source
+ /// with linear sampling.
+ /// Requires `SAMPLED` or `BLIT_SRC` flag.
+ const SAMPLED_LINEAR = 0x1000;
+ }
+);
+
+bitflags!(
+ /// Buffer feature flags.
+ #[derive(Default)]
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct BufferFeature: u32 {
+ /// Buffer view can be used as uniform texel buffer.
+ const UNIFORM_TEXEL = 0x8;
+ /// Buffer view can be used as storage texel buffer.
+ const STORAGE_TEXEL = 0x10;
+ /// Buffer view can be used as storage texel buffer (with atomics).
+ const STORAGE_TEXEL_ATOMIC = 0x20;
+ /// Image view can be used as vertex buffer.
+ const VERTEX = 0x40;
+ }
+);
+
+/// Type of a surface channel. This is how we interpret the
+/// storage allocated with `SurfaceType`.
+#[repr(u8)]
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum ChannelType {
+ /// Unsigned normalized.
+ Unorm,
+ /// Signed normalized.
+ Snorm,
+ /// Unsigned integer.
+ Uint,
+ /// Signed integer.
+ Sint,
+ /// Unsigned floating-point.
+ Ufloat,
+ /// Signed floating-point.
+ Sfloat,
+ /// Unsigned scaled integer.
+ Uscaled,
+ /// Signed scaled integer.
+ Sscaled,
+ /// Unsigned normalized, SRGB non-linear encoded.
+ Srgb,
+}
+
+macro_rules! surface_types {
+ { $($name:ident { $total:expr, $($aspect:ident)|*, $dim:expr $( ,$component:ident : $bits:expr )*} ,)* } => {
+ /// Type of the allocated texture surface. It is supposed to only
+ /// carry information about the number of bits per each channel.
+ /// The actual types are up to the views to decide and interpret.
+ /// The actual components are up to the swizzle to define.
+ #[repr(u8)]
+ #[allow(missing_docs, non_camel_case_types)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub enum SurfaceType {
+ $( $name, )*
+ }
+
+ impl SurfaceType {
+ /// Return the bits for this format.
+ pub fn describe_bits(&self) -> FormatBits {
+ match *self {
+ $( SurfaceType::$name => FormatBits {
+ $( $component: $bits, )*
+ .. BITS_ZERO
+ }, )*
+ }
+ }
+
+ /// Return the format descriptor.
+ pub fn desc(&self) -> FormatDesc {
+ match *self {
+ $( SurfaceType::$name => FormatDesc {
+ bits: $total.min(!$total),
+ dim: $dim,
+ packed: $total > 0x1000,
+ aspects: $(Aspects::$aspect)|*,
+ }, )*
+ }
+ }
+ }
+ }
+}
+
+// ident { num_bits, aspects, dim, (color, alpha, ..) }
+// if the number of bits is given with exclamation (e.g. `!16`), the format is considered packed
+surface_types! {
+ R4_G4 { !8, COLOR, (1, 1), color: 8 },
+ R4_G4_B4_A4 { !16, COLOR, (1, 1), color: 12, alpha: 4 },
+ B4_G4_R4_A4 { !16, COLOR, (1, 1), color: 12, alpha: 4 },
+ R5_G6_B5 { !16, COLOR, (1, 1), color: 16 },
+ B5_G6_R5 { !16, COLOR, (1, 1), color: 16 },
+ R5_G5_B5_A1 { !16, COLOR, (1, 1), color: 15, alpha: 1 },
+ B5_G5_R5_A1 { !16, COLOR, (1, 1), color: 15, alpha: 1 },
+ A1_R5_G5_B5 { !16, COLOR, (1, 1), color: 15, alpha: 1 },
+ R8 { 8, COLOR, (1, 1), color: 8 },
+ R8_G8 { 16, COLOR, (1, 1), color: 16 },
+ R8_G8_B8 { 24, COLOR, (1, 1), color: 24 },
+ B8_G8_R8 { 24, COLOR, (1, 1), color: 24 },
+ R8_G8_B8_A8 { 32, COLOR, (1, 1), color: 24, alpha: 8 },
+ B8_G8_R8_A8 { 32, COLOR, (1, 1), color: 24, alpha: 8 },
+ A8_B8_G8_R8 { !32, COLOR, (1, 1), color: 24, alpha: 8 },
+ A2_R10_G10_B10 { !32, COLOR, (1, 1), color: 30, alpha: 2 },
+ A2_B10_G10_R10 { !32, COLOR, (1, 1), color: 30, alpha: 2 },
+ R16 { 16, COLOR, (1, 1), color: 16 },
+ R16_G16 { 32, COLOR, (1, 1), color: 32 },
+ R16_G16_B16 { 48, COLOR, (1, 1), color: 48 },
+ R16_G16_B16_A16 { 64, COLOR, (1, 1), color: 48, alpha: 16 },
+ R32 { 32, COLOR, (1, 1), color: 32 },
+ R32_G32 { 64, COLOR, (1, 1), color: 64 },
+ R32_G32_B32 { 96, COLOR, (1, 1), color: 96 },
+ R32_G32_B32_A32 { 128, COLOR, (1, 1), color: 96, alpha: 32 },
+ R64 { 64, COLOR, (1, 1), color: 64 },
+ R64_G64 { 128, COLOR, (1, 1), color: 128 },
+ R64_G64_B64 { 192, COLOR, (1, 1), color: 192 },
+ R64_G64_B64_A64 { 256, COLOR, (1, 1), color: 192, alpha: 64 },
+ B10_G11_R11 { !32, COLOR, (1, 1), color: 32 },
+ E5_B9_G9_R9 { !32, COLOR, (1, 1), color: 27 },
+ D16 { 16, DEPTH, (1, 1), depth: 16 },
+ X8D24 { !32, DEPTH, (1, 1), depth: 24 },
+ D32 { 32, DEPTH, (1, 1), depth: 32 },
+ S8 { 8, STENCIL, (1, 1), stencil: 8 },
+ D16_S8 { 24, DEPTH | STENCIL, (1, 1), depth: 16, stencil: 8 },
+ D24_S8 { 32, DEPTH | STENCIL, (1, 1), depth: 24, stencil: 8 },
+ D32_S8 { 40, DEPTH | STENCIL, (1, 1), depth: 32, stencil: 8 },
+ BC1_RGB { 64, COLOR, (4, 4) },
+ BC1_RGBA { 64, COLOR, (4, 4) },
+ BC2 { 128, COLOR, (4, 4) },
+ BC3 { 128, COLOR, (4, 4) },
+ BC4 { 64, COLOR, (4, 4) },
+ BC5 { 128, COLOR, (4, 4) },
+ BC6 { 128, COLOR, (4, 4) },
+ BC7 { 128, COLOR, (4, 4) },
+ ETC2_R8_G8_B8 { 64, COLOR, (4, 4) },
+ ETC2_R8_G8_B8_A1 { 64, COLOR, (4, 4) },
+ ETC2_R8_G8_B8_A8 { 128, COLOR, (4, 4) },
+ EAC_R11 { 64, COLOR, (4, 4) },
+ EAC_R11_G11 { 128, COLOR, (4, 4) },
+ ASTC_4x4 { 128, COLOR, (4, 4) },
+ ASTC_5x4 { 128, COLOR, (5, 4) },
+ ASTC_5x5 { 128, COLOR, (5, 5) },
+ ASTC_6x5 { 128, COLOR, (6, 5) },
+ ASTC_6x6 { 128, COLOR, (6, 6) },
+ ASTC_8x5 { 128, COLOR, (8, 5) },
+ ASTC_8x6 { 128, COLOR, (8, 6) },
+ ASTC_8x8 { 128, COLOR, (8, 8) },
+ ASTC_10x5 { 128, COLOR, (10, 5) },
+ ASTC_10x6 { 128, COLOR, (10, 6) },
+ ASTC_10x8 { 128, COLOR, (10, 8) },
+ ASTC_10x10 { 128, COLOR, (10, 10) },
+ ASTC_12x10 { 128, COLOR, (12, 10) },
+ ASTC_12x12 { 128, COLOR, (12, 12) },
+}
+
+/// Generic run-time base format.
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct BaseFormat(pub SurfaceType, pub ChannelType);
+
+/// Conversion trait into `Format`;
+pub trait AsFormat {
+ /// Associated format.
+ const SELF: Format;
+}
+
+macro_rules! formats {
+ {
+ $name:ident = ($surface:ident, $channel:ident),
+ $($name_tail:ident = ($surface_tail:ident, $channel_tail:ident),)*
+ } => {
+ /// A format descriptor that describes the channels present in a
+ /// texture or view, how they are laid out, what size they are,
+ /// and how the elements of the channels are interpreted (integer,
+ /// float, etc.)
+ #[allow(missing_docs)]
+ #[repr(u32)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub enum Format {
+ $name = 1,
+ $( $name_tail, )*
+
+ // This serves as safety net for conversion from Vulkan -> HAL,
+ // in case Vulkan adds new formats:
+ // 1. We can check if a format is out of range
+ // 2. We 'ensure' that backend implementations do non-exhaustive matching
+ #[doc(hidden)]
+ __NumFormats,
+ }
+
+ /// Number of formats.
+ pub const NUM_FORMATS: usize = Format::__NumFormats as _;
+
+ /// Conversion table from `Format` to `BaseFormat`, excluding `Undefined`.
+ pub const BASE_FORMATS: [BaseFormat; NUM_FORMATS-1] = [
+ BaseFormat(SurfaceType::$surface, ChannelType::$channel),
+ $(BaseFormat(SurfaceType::$surface_tail, ChannelType::$channel_tail), )*
+ ];
+
+ /// A struct equivalent to the matching `Format` enum member, which allows
+ /// an API to be strongly typed on particular formats.
+ #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct $name;
+
+ impl AsFormat for $name {
+ const SELF: Format = Format::$name;
+ }
+
+ $(
+ /// A struct equivalent to the matching `Format` enum member, which allows
+ /// an API to be strongly typed on particular formats.
+ #[allow(missing_docs)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct $name_tail;
+
+ impl AsFormat for $name_tail {
+ const SELF: Format = Format::$name_tail;
+ }
+
+ )*
+ }
+}
+
+// Format order has to match the order exposed by the Vulkan API.
+formats! {
+ Rg4Unorm = (R4_G4, Unorm),
+ Rgba4Unorm = (R4_G4_B4_A4, Unorm),
+ Bgra4Unorm = (B4_G4_R4_A4, Unorm),
+ R5g6b5Unorm = (R5_G6_B5, Unorm),
+ B5g6r5Unorm = (B5_G6_R5, Unorm),
+ R5g5b5a1Unorm = (R5_G5_B5_A1, Unorm),
+ B5g5r5a1Unorm = (B5_G5_R5_A1, Unorm),
+ A1r5g5b5Unorm = (A1_R5_G5_B5, Unorm),
+ R8Unorm = (R8, Unorm),
+ R8Snorm = (R8, Snorm),
+ R8Uscaled = (R8, Uscaled),
+ R8Sscaled = (R8, Sscaled),
+ R8Uint = (R8, Uint),
+ R8Sint = (R8, Sint),
+ R8Srgb = (R8, Srgb),
+ Rg8Unorm = (R8_G8, Unorm),
+ Rg8Snorm = (R8_G8, Snorm),
+ Rg8Uscaled = (R8_G8, Uscaled),
+ Rg8Sscaled = (R8_G8, Sscaled),
+ Rg8Uint = (R8_G8, Uint),
+ Rg8Sint = (R8_G8, Sint),
+ Rg8Srgb = (R8_G8, Srgb),
+ Rgb8Unorm = (R8_G8_B8, Unorm),
+ Rgb8Snorm = (R8_G8_B8, Snorm),
+ Rgb8Uscaled = (R8_G8_B8, Uscaled),
+ Rgb8Sscaled = (R8_G8_B8, Sscaled),
+ Rgb8Uint = (R8_G8_B8, Uint),
+ Rgb8Sint = (R8_G8_B8, Sint),
+ Rgb8Srgb = (R8_G8_B8, Srgb),
+ Bgr8Unorm = (B8_G8_R8, Unorm),
+ Bgr8Snorm = (B8_G8_R8, Snorm),
+ Bgr8Uscaled = (B8_G8_R8, Uscaled),
+ Bgr8Sscaled = (B8_G8_R8, Sscaled),
+ Bgr8Uint = (B8_G8_R8, Uint),
+ Bgr8Sint = (B8_G8_R8, Sint),
+ Bgr8Srgb = (B8_G8_R8, Srgb),
+ Rgba8Unorm = (R8_G8_B8_A8, Unorm),
+ Rgba8Snorm = (R8_G8_B8_A8, Snorm),
+ Rgba8Uscaled = (R8_G8_B8_A8, Uscaled),
+ Rgba8Sscaled = (R8_G8_B8_A8, Sscaled),
+ Rgba8Uint = (R8_G8_B8_A8, Uint),
+ Rgba8Sint = (R8_G8_B8_A8, Sint),
+ Rgba8Srgb = (R8_G8_B8_A8, Srgb),
+ Bgra8Unorm = (B8_G8_R8_A8, Unorm),
+ Bgra8Snorm = (B8_G8_R8_A8, Snorm),
+ Bgra8Uscaled = (B8_G8_R8_A8, Uscaled),
+ Bgra8Sscaled = (B8_G8_R8_A8, Sscaled),
+ Bgra8Uint = (B8_G8_R8_A8, Uint),
+ Bgra8Sint = (B8_G8_R8_A8, Sint),
+ Bgra8Srgb = (B8_G8_R8_A8, Srgb),
+ Abgr8Unorm = (A8_B8_G8_R8, Unorm),
+ Abgr8Snorm = (A8_B8_G8_R8, Snorm),
+ Abgr8Uscaled = (A8_B8_G8_R8, Uscaled),
+ Abgr8Sscaled = (A8_B8_G8_R8, Sscaled),
+ Abgr8Uint = (A8_B8_G8_R8, Uint),
+ Abgr8Sint = (A8_B8_G8_R8, Sint),
+ Abgr8Srgb = (A8_B8_G8_R8, Srgb),
+ A2r10g10b10Unorm = (A2_R10_G10_B10, Unorm),
+ A2r10g10b10Snorm = (A2_R10_G10_B10, Snorm),
+ A2r10g10b10Uscaled = (A2_R10_G10_B10, Uscaled),
+ A2r10g10b10Sscaled = (A2_R10_G10_B10, Sscaled),
+ A2r10g10b10Uint = (A2_R10_G10_B10, Uint),
+ A2r10g10b10Sint = (A2_R10_G10_B10, Sint),
+ A2b10g10r10Unorm = (A2_B10_G10_R10, Unorm),
+ A2b10g10r10Snorm = (A2_B10_G10_R10, Snorm),
+ A2b10g10r10Uscaled = (A2_B10_G10_R10, Uscaled),
+ A2b10g10r10Sscaled = (A2_B10_G10_R10, Sscaled),
+ A2b10g10r10Uint = (A2_B10_G10_R10, Uint),
+ A2b10g10r10Sint = (A2_B10_G10_R10, Sint),
+ R16Unorm = (R16, Unorm),
+ R16Snorm = (R16, Snorm),
+ R16Uscaled = (R16, Uscaled),
+ R16Sscaled = (R16, Sscaled),
+ R16Uint = (R16, Uint),
+ R16Sint = (R16, Sint),
+ R16Sfloat = (R16, Sfloat),
+ Rg16Unorm = (R16_G16, Unorm),
+ Rg16Snorm = (R16_G16, Snorm),
+ Rg16Uscaled = (R16_G16, Uscaled),
+ Rg16Sscaled = (R16_G16, Sscaled),
+ Rg16Uint = (R16_G16, Uint),
+ Rg16Sint = (R16_G16, Sint),
+ Rg16Sfloat = (R16_G16, Sfloat),
+ Rgb16Unorm = (R16_G16_B16, Unorm),
+ Rgb16Snorm = (R16_G16_B16, Snorm),
+ Rgb16Uscaled = (R16_G16_B16, Uscaled),
+ Rgb16Sscaled = (R16_G16_B16, Sscaled),
+ Rgb16Uint = (R16_G16_B16, Uint),
+ Rgb16Sint = (R16_G16_B16, Sint),
+ Rgb16Sfloat = (R16_G16_B16, Sfloat),
+ Rgba16Unorm = (R16_G16_B16_A16, Unorm),
+ Rgba16Snorm = (R16_G16_B16_A16, Snorm),
+ Rgba16Uscaled = (R16_G16_B16_A16, Uscaled),
+ Rgba16Sscaled = (R16_G16_B16_A16, Sscaled),
+ Rgba16Uint = (R16_G16_B16_A16, Uint),
+ Rgba16Sint = (R16_G16_B16_A16, Sint),
+ Rgba16Sfloat = (R16_G16_B16_A16, Sfloat),
+ R32Uint = (R32, Uint),
+ R32Sint = (R32, Sint),
+ R32Sfloat = (R32, Sfloat),
+ Rg32Uint = (R32_G32, Uint),
+ Rg32Sint = (R32_G32, Sint),
+ Rg32Sfloat = (R32_G32, Sfloat),
+ Rgb32Uint = (R32_G32_B32, Uint),
+ Rgb32Sint = (R32_G32_B32, Sint),
+ Rgb32Sfloat = (R32_G32_B32, Sfloat),
+ Rgba32Uint = (R32_G32_B32_A32, Uint),
+ Rgba32Sint = (R32_G32_B32_A32, Sint),
+ Rgba32Sfloat = (R32_G32_B32_A32, Sfloat),
+ R64Uint = (R64, Uint),
+ R64Sint = (R64, Sint),
+ R64Sfloat = (R64, Sfloat),
+ Rg64Uint = (R64_G64, Uint),
+ Rg64Sint = (R64_G64, Sint),
+ Rg64Sfloat = (R64_G64, Sfloat),
+ Rgb64Uint = (R64_G64_B64, Uint),
+ Rgb64Sint = (R64_G64_B64, Sint),
+ Rgb64Sfloat = (R64_G64_B64, Sfloat),
+ Rgba64Uint = (R64_G64_B64_A64, Uint),
+ Rgba64Sint = (R64_G64_B64_A64, Sint),
+ Rgba64Sfloat = (R64_G64_B64_A64, Sfloat),
+ B10g11r11Ufloat = (B10_G11_R11, Ufloat),
+ E5b9g9r9Ufloat = (E5_B9_G9_R9, Ufloat),
+ D16Unorm = (D16, Unorm),
+ X8D24Unorm = (X8D24, Unorm),
+ D32Sfloat = (D32, Sfloat),
+ S8Uint = (S8, Uint),
+ D16UnormS8Uint = (D16_S8, Unorm),
+ D24UnormS8Uint = (D24_S8, Unorm),
+ D32SfloatS8Uint = (D32_S8, Sfloat),
+ Bc1RgbUnorm = (BC1_RGB, Unorm),
+ Bc1RgbSrgb = (BC1_RGB, Srgb),
+ Bc1RgbaUnorm = (BC1_RGBA, Unorm),
+ Bc1RgbaSrgb = (BC1_RGBA, Srgb),
+ Bc2Unorm = (BC2, Unorm),
+ Bc2Srgb = (BC2, Srgb),
+ Bc3Unorm = (BC3, Unorm),
+ Bc3Srgb = (BC3, Srgb),
+ Bc4Unorm = (BC4, Unorm),
+ Bc4Snorm = (BC4, Snorm),
+ Bc5Unorm = (BC5, Unorm),
+ Bc5Snorm = (BC5, Snorm),
+ Bc6hUfloat = (BC6, Ufloat),
+ Bc6hSfloat = (BC6, Sfloat),
+ Bc7Unorm = (BC7, Unorm),
+ Bc7Srgb = (BC7, Srgb),
+ Etc2R8g8b8Unorm = (ETC2_R8_G8_B8, Unorm),
+ Etc2R8g8b8Srgb = (ETC2_R8_G8_B8, Srgb),
+ Etc2R8g8b8a1Unorm = (ETC2_R8_G8_B8_A1, Unorm),
+ Etc2R8g8b8a1Srgb = (ETC2_R8_G8_B8_A1, Srgb),
+ Etc2R8g8b8a8Unorm = (ETC2_R8_G8_B8_A8, Unorm),
+ Etc2R8g8b8a8Srgb = (ETC2_R8_G8_B8_A8, Srgb),
+ EacR11Unorm = (EAC_R11, Unorm),
+ EacR11Snorm = (EAC_R11, Snorm),
+ EacR11g11Unorm = (EAC_R11_G11, Unorm),
+ EacR11g11Snorm = (EAC_R11_G11, Snorm),
+ Astc4x4Unorm = (ASTC_4x4, Unorm),
+ Astc4x4Srgb = (ASTC_4x4, Srgb),
+ Astc5x4Unorm = (ASTC_5x4, Unorm),
+ Astc5x4Srgb = (ASTC_5x4, Srgb),
+ Astc5x5Unorm = (ASTC_5x5, Unorm),
+ Astc5x5Srgb = (ASTC_5x5, Srgb),
+ Astc6x5Unorm = (ASTC_6x5, Unorm),
+ Astc6x5Srgb = (ASTC_6x5, Srgb),
+ Astc6x6Unorm = (ASTC_6x6, Unorm),
+ Astc6x6Srgb = (ASTC_6x6, Srgb),
+ Astc8x5Unorm = (ASTC_8x5, Unorm),
+ Astc8x5Srgb = (ASTC_8x5, Srgb),
+ Astc8x6Unorm = (ASTC_8x6, Unorm),
+ Astc8x6Srgb = (ASTC_8x6, Srgb),
+ Astc8x8Unorm = (ASTC_8x8, Unorm),
+ Astc8x8Srgb = (ASTC_8x8, Srgb),
+ Astc10x5Unorm = (ASTC_10x5, Unorm),
+ Astc10x5Srgb = (ASTC_10x5, Srgb),
+ Astc10x6Unorm = (ASTC_10x6, Unorm),
+ Astc10x6Srgb = (ASTC_10x6, Srgb),
+ Astc10x8Unorm = (ASTC_10x8, Unorm),
+ Astc10x8Srgb = (ASTC_10x8, Srgb),
+ Astc10x10Unorm = (ASTC_10x10, Unorm),
+ Astc10x10Srgb = (ASTC_10x10, Srgb),
+ Astc12x10Unorm = (ASTC_12x10, Unorm),
+ Astc12x10Srgb = (ASTC_12x10, Srgb),
+ Astc12x12Unorm = (ASTC_12x12, Unorm),
+ Astc12x12Srgb = (ASTC_12x12, Srgb),
+}
+
+impl Format {
+ /// Get base format.
+ ///
+ /// Returns `None` if format is `Undefined`.
+ pub fn base_format(self) -> BaseFormat {
+ assert!(self as usize != 0 && NUM_FORMATS > self as usize);
+ BASE_FORMATS[self as usize - 1]
+ }
+
+ /// A shortcut to obtain surface format description.
+ pub fn surface_desc(&self) -> FormatDesc {
+ self.base_format().0.desc()
+ }
+
+ /// Returns if the format has a color aspect.
+ pub fn is_color(self) -> bool {
+ self.surface_desc().aspects.contains(Aspects::COLOR)
+ }
+
+ /// Returns if the format has a depth aspect.
+ pub fn is_depth(self) -> bool {
+ self.surface_desc().aspects.contains(Aspects::DEPTH)
+ }
+
+ /// Returns if the format has a stencil aspect.
+ pub fn is_stencil(self) -> bool {
+ self.surface_desc().aspects.contains(Aspects::STENCIL)
+ }
+}
+
+// Common vertex attribute formats
+impl AsFormat for f32 {
+ const SELF: Format = Format::R32Sfloat;
+}
+impl AsFormat for [f32; 2] {
+ const SELF: Format = Format::Rg32Sfloat;
+}
+impl AsFormat for [f32; 3] {
+ const SELF: Format = Format::Rgb32Sfloat;
+}
+impl AsFormat for [f32; 4] {
+ const SELF: Format = Format::Rgba32Sfloat;
+}
diff --git a/third_party/rust/gfx-hal/src/image.rs b/third_party/rust/gfx-hal/src/image.rs
new file mode 100644
index 0000000000..16a3f90d7e
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/image.rs
@@ -0,0 +1,753 @@
+//! Image related structures.
+//!
+//! An image is a block of GPU memory representing a grid of texels.
+
+use crate::{
+ buffer::Offset as RawOffset,
+ device, format,
+ pso::{Comparison, Rect},
+};
+use std::{f32, hash, ops::Range};
+
+/// Dimension size.
+pub type Size = u32;
+/// Number of MSAA samples.
+pub type NumSamples = u8;
+/// Image layer.
+pub type Layer = u16;
+/// Image mipmap level.
+pub type Level = u8;
+/// Maximum accessible mipmap level of an image.
+pub const MAX_LEVEL: Level = 15;
+/// A texel coordinate in an image.
+pub type TexelCoordinate = i32;
+
+/// Describes the size of an image, which may be up to three dimensional.
+#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct Extent {
+ /// Image width
+ pub width: Size,
+ /// Image height
+ pub height: Size,
+ /// Image depth.
+ pub depth: Size,
+}
+
+impl Extent {
+ /// Return true if one of the dimensions is zero.
+ pub fn is_empty(&self) -> bool {
+ self.width == 0 || self.height == 0 || self.depth == 0
+ }
+ /// Get the extent at a particular mipmap level.
+ pub fn at_level(&self, level: Level) -> Self {
+ Extent {
+ width: 1.max(self.width >> level),
+ height: 1.max(self.height >> level),
+ depth: 1.max(self.depth >> level),
+ }
+ }
+ /// Get a rectangle for the full area of extent.
+ pub fn rect(&self) -> Rect {
+ Rect {
+ x: 0,
+ y: 0,
+ w: self.width as i16,
+ h: self.height as i16,
+ }
+ }
+}
+
+/// An offset into an `Image` used for image-to-image
+/// copy operations. All offsets are in texels, and
+/// specifying offsets other than 0 for dimensions
+/// that do not exist is undefined behavior -- for
+/// example, specifying a `z` offset of `1` in a
+/// two-dimensional image.
+#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct Offset {
+ /// X offset.
+ pub x: TexelCoordinate,
+ /// Y offset.
+ pub y: TexelCoordinate,
+ /// Z offset.
+ pub z: TexelCoordinate,
+}
+
+impl Offset {
+ /// Zero offset shortcut.
+ pub const ZERO: Self = Offset { x: 0, y: 0, z: 0 };
+
+ /// Convert the offset into 2-sided bounds given the extent.
+ pub fn into_bounds(self, extent: &Extent) -> Range<Offset> {
+ let end = Offset {
+ x: self.x + extent.width as i32,
+ y: self.y + extent.height as i32,
+ z: self.z + extent.depth as i32,
+ };
+ self..end
+ }
+}
+
+/// Image tiling modes.
+#[repr(u32)]
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum Tiling {
+ /// Optimal tiling for GPU memory access. Implementation-dependent.
+ Optimal = 0,
+ /// Optimal for CPU read/write. Texels are laid out in row-major order,
+ /// possibly with some padding on each row.
+ Linear = 1,
+}
+
+/// Pure image object creation error.
+#[derive(Clone, Debug, PartialEq)]
+pub enum CreationError {
+ /// Out of either host or device memory.
+ OutOfMemory(device::OutOfMemory),
+ /// The format is not supported by the device.
+ Format(format::Format),
+ /// The kind doesn't support a particular operation.
+ Kind,
+ /// Failed to map a given multisampled kind to the device.
+ Samples(NumSamples),
+ /// Unsupported size in one of the dimensions.
+ Size(Size),
+ /// The given data has a different size than the target image slice.
+ Data(usize),
+ /// The mentioned usage mode is not supported
+ Usage(Usage),
+}
+
+impl From<device::OutOfMemory> for CreationError {
+ fn from(error: device::OutOfMemory) -> Self {
+ CreationError::OutOfMemory(error)
+ }
+}
+
+impl std::fmt::Display for CreationError {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ CreationError::OutOfMemory(err) => write!(fmt, "Failed to create image: {}", err),
+ CreationError::Format(format) => write!(fmt, "Failed to create image: Unsupported format: {:?}", format),
+ CreationError::Kind => write!(fmt, "Failed to create image: Specified kind doesn't support particular operation"), // Room for improvement.
+ CreationError::Samples(samples) => write!(fmt, "Failed to create image: Specified format doesn't support specified sampling {}", samples),
+ CreationError::Size(size) => write!(fmt, "Failed to create image: Unsupported size in one of the dimensions {}", size),
+ CreationError::Data(data) => write!(fmt, "Failed to create image: The given data has a different size {{{}}} than the target image slice", data), // Actually nothing emits this.
+ CreationError::Usage(usage) => write!(fmt, "Failed to create image: Unsupported usage: {:?}", usage),
+ }
+ }
+}
+
+impl std::error::Error for CreationError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self {
+ CreationError::OutOfMemory(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+/// Error creating an `ImageView`.
+#[derive(Clone, Debug, PartialEq)]
+pub enum ViewCreationError {
+ /// The required usage flag is not present in the image.
+ Usage(Usage),
+ /// Selected mip level doesn't exist.
+ Level(Level),
+ /// Selected array layer doesn't exist.
+ Layer(LayerError),
+ /// An incompatible format was requested for the view.
+ BadFormat(format::Format),
+ /// An incompatible view kind was requested for the view.
+ BadKind(ViewKind),
+ /// Out of either Host or Device memory
+ OutOfMemory(device::OutOfMemory),
+ /// The backend refused for some reason.
+ Unsupported,
+}
+
+impl From<device::OutOfMemory> for ViewCreationError {
+ fn from(error: device::OutOfMemory) -> Self {
+ ViewCreationError::OutOfMemory(error)
+ }
+}
+
+impl std::fmt::Display for ViewCreationError {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ ViewCreationError::Usage(usage) => write!(fmt, "Failed to create image view: Specified usage flags are not present in the image {:?}", usage),
+ ViewCreationError::Level(level) => write!(fmt, "Failed to create image view: Selected level doesn't exist in the image {}", level),
+ ViewCreationError::Layer(err) => write!(fmt, "Failed to create image view: {}", err),
+ ViewCreationError::BadFormat(format) => write!(fmt, "Failed to create image view: Incompatible format {:?}", format),
+ ViewCreationError::BadKind(kind) => write!(fmt, "Failed to create image view: Incompatible kind {:?}", kind),
+ ViewCreationError::OutOfMemory(err) => write!(fmt, "Failed to create image view: {}", err),
+ ViewCreationError::Unsupported => write!(fmt, "Failed to create image view: Implementation specific error occurred"),
+ }
+ }
+}
+
+impl std::error::Error for ViewCreationError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self {
+ ViewCreationError::OutOfMemory(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+/// An error associated with selected image layer.
+#[derive(Clone, Debug, PartialEq)]
+pub enum LayerError {
+ /// The source image kind doesn't support array slices.
+ NotExpected(Kind),
+ /// Selected layers are outside of the provided range.
+ OutOfBounds,
+}
+
+impl std::fmt::Display for LayerError {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ LayerError::NotExpected(kind) => {
+ write!(fmt, "Kind {{{:?}}} does not support arrays", kind)
+ }
+ LayerError::OutOfBounds => write!(fmt, "Out of bounds layers"),
+ }
+ }
+}
+
+/// How to [filter](https://en.wikipedia.org/wiki/Texture_filtering) the
+/// image when sampling. They correspond to increasing levels of quality,
+/// but also cost.
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum Filter {
+ /// Selects a single texel from the current mip level and uses its value.
+ ///
+ /// Mip filtering selects the filtered value from one level.
+ Nearest,
+ /// Selects multiple texels and calculates the value via multivariate interpolation.
+ /// * 1D: Linear interpolation
+ /// * 2D/Cube: Bilinear interpolation
+ /// * 3D: Trilinear interpolation
+ Linear,
+}
+
+/// The face of a cube image to do an operation on.
+#[allow(missing_docs)]
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[repr(u8)]
+pub enum CubeFace {
+ PosX,
+ NegX,
+ PosY,
+ NegY,
+ PosZ,
+ NegZ,
+}
+
+/// A constant array of cube faces in the order they map to the hardware.
+pub const CUBE_FACES: [CubeFace; 6] = [
+ CubeFace::PosX,
+ CubeFace::NegX,
+ CubeFace::PosY,
+ CubeFace::NegY,
+ CubeFace::PosZ,
+ CubeFace::NegZ,
+];
+
+/// Specifies the dimensionality of an image to be allocated,
+/// along with the number of mipmap layers and MSAA samples
+/// if applicable.
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum Kind {
+ /// A single one-dimensional row of texels.
+ D1(Size, Layer),
+ /// Two-dimensional image.
+ D2(Size, Size, Layer, NumSamples),
+ /// Volumetric image.
+ D3(Size, Size, Size),
+}
+
+impl Kind {
+ /// Get the image extent.
+ pub fn extent(&self) -> Extent {
+ match *self {
+ Kind::D1(width, _) => Extent {
+ width,
+ height: 1,
+ depth: 1,
+ },
+ Kind::D2(width, height, _, _) => Extent {
+ width,
+ height,
+ depth: 1,
+ },
+ Kind::D3(width, height, depth) => Extent {
+ width,
+ height,
+ depth,
+ },
+ }
+ }
+
+ /// Get the extent of a particular mipmap level.
+ pub fn level_extent(&self, level: Level) -> Extent {
+ use std::cmp::{max, min};
+ // must be at least 1
+ let map = |val| max(min(val, 1), val >> min(level, MAX_LEVEL));
+ match *self {
+ Kind::D1(w, _) => Extent {
+ width: map(w),
+ height: 1,
+ depth: 1,
+ },
+ Kind::D2(w, h, _, _) => Extent {
+ width: map(w),
+ height: map(h),
+ depth: 1,
+ },
+ Kind::D3(w, h, d) => Extent {
+ width: map(w),
+ height: map(h),
+ depth: map(d),
+ },
+ }
+ }
+
+ /// Count the number of mipmap levels.
+ pub fn compute_num_levels(&self) -> Level {
+ use std::cmp::max;
+ match *self {
+ Kind::D2(_, _, _, s) if s > 1 => {
+ // anti-aliased images can't have mipmaps
+ 1
+ }
+ _ => {
+ let extent = self.extent();
+ let dominant = max(max(extent.width, extent.height), extent.depth);
+ (1..).find(|level| dominant >> level == 0).unwrap()
+ }
+ }
+ }
+
+ /// Return the number of layers in an array type.
+ ///
+ /// Each cube face counts as separate layer.
+ pub fn num_layers(&self) -> Layer {
+ match *self {
+ Kind::D1(_, a) | Kind::D2(_, _, a, _) => a,
+ Kind::D3(..) => 1,
+ }
+ }
+
+ /// Return the number of MSAA samples for the kind.
+ pub fn num_samples(&self) -> NumSamples {
+ match *self {
+ Kind::D1(..) => 1,
+ Kind::D2(_, _, _, s) => s,
+ Kind::D3(..) => 1,
+ }
+ }
+}
+
+/// Specifies the kind/dimensionality of an image view.
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum ViewKind {
+ /// A single one-dimensional row of texels.
+ D1,
+ /// An array of rows of texels. Equivalent to `D2` except that texels
+ /// in different rows are not sampled, so filtering will be constrained
+ /// to a single row of texels at a time.
+ D1Array,
+ /// A traditional 2D image, with rows arranged contiguously.
+ D2,
+ /// An array of 2D images. Equivalent to `D3` except that texels in
+ /// a different depth level are not sampled.
+ D2Array,
+ /// A volume image, with each 2D layer arranged contiguously.
+ D3,
+ /// A set of 6 2D images, one for each face of a cube.
+ Cube,
+ /// An array of Cube images.
+ CubeArray,
+}
+
+bitflags!(
+ /// Capabilities to create views into an image.
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct ViewCapabilities: u32 {
+ /// Support creation of views with different formats.
+ const MUTABLE_FORMAT = 0x0000_0008;
+ /// Support creation of `Cube` and `CubeArray` kinds of views.
+ const KIND_CUBE = 0x0000_0010;
+ /// Support creation of `D2Array` kind of view.
+ const KIND_2D_ARRAY = 0x0000_0020;
+ }
+);
+
+bitflags!(
+ /// TODO: Find out if TRANSIENT_ATTACHMENT + INPUT_ATTACHMENT
+ /// are applicable on backends other than Vulkan. --AP
+ /// Image usage flags
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct Usage: u32 {
+ /// The image is used as a transfer source.
+ const TRANSFER_SRC = 0x1;
+ /// The image is used as a transfer destination.
+ const TRANSFER_DST = 0x2;
+ /// The image is a [sampled image](https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#descriptorsets-sampledimage)
+ const SAMPLED = 0x4;
+ /// The image is a [storage image](https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#descriptorsets-storageimage)
+ const STORAGE = 0x8;
+ /// The image is used as a color attachment -- that is, color input to a rendering pass.
+ const COLOR_ATTACHMENT = 0x10;
+ /// The image is used as a depth attachment.
+ const DEPTH_STENCIL_ATTACHMENT = 0x20;
+ ///
+ const TRANSIENT_ATTACHMENT = 0x40;
+ ///
+ const INPUT_ATTACHMENT = 0x80;
+
+ }
+);
+
+impl Usage {
+ /// Returns true if this image can be used in transfer operations.
+ pub fn can_transfer(&self) -> bool {
+ self.intersects(Usage::TRANSFER_SRC | Usage::TRANSFER_DST)
+ }
+
+ /// Returns true if this image can be used as a target.
+ pub fn can_target(&self) -> bool {
+ self.intersects(Usage::COLOR_ATTACHMENT | Usage::DEPTH_STENCIL_ATTACHMENT)
+ }
+}
+
+/// Specifies how image coordinates outside the range `[0, 1]` are handled.
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum WrapMode {
+ /// Tile the image, that is, sample the coordinate modulo `1.0`, so
+ /// addressing the image beyond an edge will "wrap" back from the
+ /// other edge.
+ Tile,
+ /// Mirror the image. Like tile, but uses abs(coord) before the modulo.
+ Mirror,
+ /// Clamp the image to the value at `0.0` or `1.0` respectively.
+ Clamp,
+ /// Use border color.
+ Border,
+ /// Mirror once and clamp to edge otherwise.
+ ///
+ /// Only valid if `Features::SAMPLER_MIRROR_CLAMP_EDGE` is enabled.
+ MirrorClamp,
+}
+
+/// A wrapper for the LOD level of an image. Needed so that we can
+/// implement Eq and Hash for it.
+#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct Lod(pub f32);
+
+impl Lod {
+ /// Possible LOD range.
+ pub const RANGE: Range<Self> = Lod(f32::MIN)..Lod(f32::MAX);
+}
+
+impl Eq for Lod {}
+impl hash::Hash for Lod {
+ fn hash<H: hash::Hasher>(&self, state: &mut H) {
+ self.0.to_bits().hash(state)
+ }
+}
+
+/// A wrapper for an RGBA color with 8 bits per texel, encoded as a u32.
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct PackedColor(pub u32);
+
+impl From<[f32; 4]> for PackedColor {
+ fn from(c: [f32; 4]) -> PackedColor {
+ PackedColor(
+ c.iter()
+ .rev()
+ .fold(0, |u, &c| (u << 8) + (c * 255.0) as u32),
+ )
+ }
+}
+
+impl Into<[f32; 4]> for PackedColor {
+ fn into(self) -> [f32; 4] {
+ let mut out = [0.0; 4];
+ for (i, channel) in out.iter_mut().enumerate() {
+ let byte = (self.0 >> (i << 3)) & 0xFF;
+ *channel = byte as f32 / 255.0;
+ }
+ out
+ }
+}
+
+/// The border color for `WrapMode::Border` wrap mode.
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum BorderColor {
+ ///
+ TransparentBlack,
+ ///
+ OpaqueBlack,
+ ///
+ OpaqueWhite,
+}
+
+impl Into<[f32; 4]> for BorderColor {
+ fn into(self) -> [f32; 4] {
+ match self {
+ BorderColor::TransparentBlack => [0.0, 0.0, 0.0, 0.0],
+ BorderColor::OpaqueBlack => [0.0, 0.0, 0.0, 1.0],
+ BorderColor::OpaqueWhite => [1.0, 1.0, 1.0, 1.0],
+ }
+ }
+}
+
+/// Specifies how to sample from an image. These are all the parameters
+/// available that alter how the GPU goes from a coordinate in an image
+/// to producing an actual value from the texture, including filtering/
+/// scaling, wrap mode, etc.
+// TODO: document the details of sampling.
+#[derive(Clone, Debug, Eq, Hash, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct SamplerDesc {
+ /// Minification filter method to use.
+ pub min_filter: Filter,
+ /// Magnification filter method to use.
+ pub mag_filter: Filter,
+ /// Mip filter method to use.
+ pub mip_filter: Filter,
+ /// Wrapping mode for each of the U, V, and W axis (S, T, and R in OpenGL
+ /// speak).
+ pub wrap_mode: (WrapMode, WrapMode, WrapMode),
+ /// This bias is added to every computed mipmap level (N + lod_bias). For
+ /// example, if it would select mipmap level 2 and lod_bias is 1, it will
+ /// use mipmap level 3.
+ pub lod_bias: Lod,
+ /// This range is used to clamp LOD level used for sampling.
+ pub lod_range: Range<Lod>,
+ /// Comparison mode, used primary for a shadow map.
+ pub comparison: Option<Comparison>,
+ /// Border color is used when one of the wrap modes is set to border.
+ pub border: BorderColor,
+ /// Specifies whether the texture coordinates are normalized.
+ pub normalized: bool,
+ /// Anisotropic filtering.
+ ///
+ /// Can be `Some(_)` only if `Features::SAMPLER_ANISOTROPY` is enabled.
+ pub anisotropy_clamp: Option<u8>,
+}
+
+impl SamplerDesc {
+ /// Create a new sampler description with a given filter method for all filtering operations
+ /// and a wrapping mode, using no LOD modifications.
+ pub fn new(filter: Filter, wrap: WrapMode) -> Self {
+ SamplerDesc {
+ min_filter: filter,
+ mag_filter: filter,
+ mip_filter: filter,
+ wrap_mode: (wrap, wrap, wrap),
+ lod_bias: Lod(0.0),
+ lod_range: Lod::RANGE.clone(),
+ comparison: None,
+ border: BorderColor::TransparentBlack,
+ normalized: true,
+ anisotropy_clamp: None,
+ }
+ }
+}
+
+/// Specifies options for how memory for an image is arranged.
+/// These are hints to the GPU driver and may or may not have actual
+/// performance effects, but describe constraints on how the data
+/// may be used that a program *must* obey. They do not specify
+/// how channel values or such are laid out in memory; the actual
+/// image data is considered opaque.
+///
+/// Details may be found in [the Vulkan spec](https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#resources-image-layouts)
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum Layout {
+ /// General purpose, no restrictions on usage.
+ General,
+ /// Must only be used as a color attachment in a framebuffer.
+ ColorAttachmentOptimal,
+ /// Must only be used as a depth attachment in a framebuffer.
+ DepthStencilAttachmentOptimal,
+ /// Must only be used as a depth attachment in a framebuffer,
+ /// or as a read-only depth or stencil buffer in a shader.
+ DepthStencilReadOnlyOptimal,
+ /// Must only be used as a read-only image in a shader.
+ ShaderReadOnlyOptimal,
+ /// Must only be used as the source for a transfer command.
+ TransferSrcOptimal,
+ /// Must only be used as the destination for a transfer command.
+ TransferDstOptimal,
+ /// No layout, does not support device access. Only valid as a
+ /// source layout when transforming data to a specific destination
+ /// layout or initializing data. Does NOT guarentee that the contents
+ /// of the source buffer are preserved.
+ Undefined,
+ /// Like `Undefined`, but does guarentee that the contents of the source
+ /// buffer are preserved.
+ Preinitialized,
+ /// The layout that an image must be in to be presented to the display.
+ Present,
+}
+
+impl Default for Layout {
+ fn default() -> Self {
+ Self::General
+ }
+}
+
+bitflags!(
+ /// Bitflags to describe how memory in an image or buffer can be accessed.
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct Access: u32 {
+ /// Read access to an input attachment from within a fragment shader.
+ const INPUT_ATTACHMENT_READ = 0x10;
+ /// Read-only state for SRV access, or combine with `SHADER_WRITE` to have r/w access to UAV.
+ const SHADER_READ = 0x20;
+ /// Writeable state for UAV access.
+ /// Combine with `SHADER_READ` to have r/w access to UAV.
+ const SHADER_WRITE = 0x40;
+ /// Read state but can only be combined with `COLOR_ATTACHMENT_WRITE`.
+ const COLOR_ATTACHMENT_READ = 0x80;
+ /// Write-only state but can be combined with `COLOR_ATTACHMENT_READ`.
+ const COLOR_ATTACHMENT_WRITE = 0x100;
+ /// Read access to a depth/stencil attachment in a depth or stencil operation.
+ const DEPTH_STENCIL_ATTACHMENT_READ = 0x200;
+ /// Write access to a depth/stencil attachment in a depth or stencil operation.
+ const DEPTH_STENCIL_ATTACHMENT_WRITE = 0x400;
+ /// Read access to the buffer in a copy operation.
+ const TRANSFER_READ = 0x800;
+ /// Write access to the buffer in a copy operation.
+ const TRANSFER_WRITE = 0x1000;
+ /// Read access for raw memory to be accessed by the host system (ie, CPU).
+ const HOST_READ = 0x2000;
+ /// Write access for raw memory to be accessed by the host system.
+ const HOST_WRITE = 0x4000;
+ /// Read access for memory to be accessed by a non-specific entity. This may
+ /// be the host system, or it may be something undefined or specified by an
+ /// extension.
+ const MEMORY_READ = 0x8000;
+ /// Write access for memory to be accessed by a non-specific entity.
+ const MEMORY_WRITE = 0x10000;
+ }
+);
+
+/// Image state, combining access methods and the image's layout.
+pub type State = (Access, Layout);
+
+/// Selector of a concrete subresource in an image.
+#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct Subresource {
+ /// Included aspects: color/depth/stencil
+ pub aspects: format::Aspects,
+ /// Selected mipmap level
+ pub level: Level,
+ /// Selected array level
+ pub layer: Layer,
+}
+
+/// A subset of resource layers contained within an image's level.
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct SubresourceLayers {
+ /// Included aspects: color/depth/stencil
+ pub aspects: format::Aspects,
+ /// Selected mipmap level
+ pub level: Level,
+ /// Included array levels
+ pub layers: Range<Layer>,
+}
+
+/// A subset of resources contained within an image.
+#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct SubresourceRange {
+ /// Included aspects: color/depth/stencil
+ pub aspects: format::Aspects,
+ /// First mipmap level in this subresource
+ pub level_start: Level,
+ /// Number of sequential levels in this subresource.
+ ///
+ /// A value of `None` indicates the subresource contains
+ /// all of the remaining levels.
+ pub level_count: Option<Level>,
+ /// First layer in this subresource
+ pub layer_start: Layer,
+ /// Number of sequential layers in this subresource.
+ ///
+ /// A value of `None` indicates the subresource contains
+ /// all of the remaining layers.
+ pub layer_count: Option<Layer>,
+}
+
+impl From<SubresourceLayers> for SubresourceRange {
+ fn from(sub: SubresourceLayers) -> Self {
+ SubresourceRange {
+ aspects: sub.aspects,
+ level_start: sub.level,
+ level_count: Some(1),
+ layer_start: sub.layers.start,
+ layer_count: Some(sub.layers.end - sub.layers.start),
+ }
+ }
+}
+
+impl SubresourceRange {
+ /// Resolve the concrete level count based on the total number of layers in an image.
+ pub fn resolve_level_count(&self, total: Level) -> Level {
+ self.level_count.unwrap_or(total - self.level_start)
+ }
+
+ /// Resolve the concrete layer count based on the total number of layer in an image.
+ pub fn resolve_layer_count(&self, total: Layer) -> Layer {
+ self.layer_count.unwrap_or(total - self.layer_start)
+ }
+}
+
+/// Image format properties.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct FormatProperties {
+ /// Maximum extent.
+ pub max_extent: Extent,
+ /// Max number of mipmap levels.
+ pub max_levels: Level,
+ /// Max number of array layers.
+ pub max_layers: Layer,
+ /// Bit mask of supported sample counts.
+ pub sample_count_mask: NumSamples,
+ /// Maximum size of the resource in bytes.
+ pub max_resource_size: usize,
+}
+
+/// Footprint of a subresource in memory.
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct SubresourceFootprint {
+ /// Byte slice occupied by the subresource.
+ pub slice: Range<RawOffset>,
+ /// Byte distance between rows.
+ pub row_pitch: RawOffset,
+ /// Byte distance between array layers.
+ pub array_pitch: RawOffset,
+ /// Byte distance between depth slices.
+ pub depth_pitch: RawOffset,
+}
diff --git a/third_party/rust/gfx-hal/src/lib.rs b/third_party/rust/gfx-hal/src/lib.rs
new file mode 100644
index 0000000000..eb5948c054
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/lib.rs
@@ -0,0 +1,643 @@
+#![warn(
+ trivial_casts,
+ trivial_numeric_casts,
+ unused_extern_crates,
+ unused_import_braces,
+ unused_qualifications
+)]
+#![deny(
+ broken_intra_doc_links,
+ missing_debug_implementations,
+ missing_docs,
+ unused
+)]
+
+//! Low-level graphics abstraction for Rust. Mostly operates on data, not types.
+//! Designed for use by libraries and higher-level abstractions only.
+//!
+//! This crate provides a [hardware abstraction layer][hal] for [graphics adapters][gpus],
+//! for both compute and graphics operations. The API design is heavily inspired by
+//! the [Vulkan API](https://www.khronos.org/vulkan/), and borrows some of the terminology.
+//!
+//! [hal]: https://en.wikipedia.org/wiki/Hardware_abstraction
+//! [gpus]: https://en.wikipedia.org/wiki/Video_card
+//!
+//! # Usage
+//!
+//! Most of the functionality is implemented in separate crates, one for each backend.
+//! This crate only exposes a few generic traits and structures. You can import
+//! all the necessary traits through the [`prelude`][prelude] module.
+//!
+//! The first step to using `gfx-hal` is to initialize one of the available
+//! [backends][Backend], by creating an [`Instance`][Instance]. Then proceed by
+//! [enumerating][Instance::enumerate_adapters] the available
+//! [graphics adapters][adapter::Adapter] and querying their available
+//! [features][Features] and [queues][queue::family::QueueFamily].
+//!
+//! You can use the [`open`][adapter::PhysicalDevice::open] method on a
+//! [`PhysicalDevice`][adapter::PhysicalDevice] to get a [logical device
+//! handle][device::Device], from which you can manage all the other device-specific
+//! resources.
+
+#[macro_use]
+extern crate bitflags;
+
+#[cfg(feature = "serde")]
+#[macro_use]
+extern crate serde;
+
+use std::any::Any;
+use std::fmt;
+use std::hash::Hash;
+
+pub mod adapter;
+pub mod buffer;
+pub mod command;
+pub mod device;
+pub mod format;
+pub mod image;
+pub mod memory;
+pub mod pass;
+pub mod pool;
+pub mod pso;
+pub mod query;
+pub mod queue;
+pub mod window;
+
+/// Prelude module re-exports all the traits necessary to use `gfx-hal`.
+pub mod prelude {
+ pub use crate::{
+ adapter::PhysicalDevice,
+ command::CommandBuffer,
+ device::Device,
+ pool::CommandPool,
+ pso::DescriptorPool,
+ queue::{CommandQueue, QueueFamily},
+ window::{PresentationSurface, Surface},
+ Instance,
+ };
+}
+
+/// Draw vertex count.
+pub type VertexCount = u32;
+/// Draw vertex base offset.
+pub type VertexOffset = i32;
+/// Draw number of indices.
+pub type IndexCount = u32;
+/// Draw number of instances.
+pub type InstanceCount = u32;
+/// Indirect draw calls count.
+pub type DrawCount = u32;
+/// Number of work groups.
+pub type WorkGroupCount = [u32; 3];
+/// Number of tasks.
+pub type TaskCount = u32;
+
+bitflags! {
+ //TODO: add a feature for non-normalized samplers
+ //TODO: add a feature for mutable comparison samplers
+ /// Features that the device supports.
+ ///
+ /// These only include features of the core interface and not API extensions.
+ ///
+ /// Can be obtained from a [physical device][adapter::PhysicalDevice] by calling
+ /// [`features`][adapter::PhysicalDevice::features].
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct Features: u128 {
+ /// Bit mask of Vulkan Core/Extension features.
+ const CORE_MASK = 0xFFFF_FFFF_FFFF_FFFF;
+ /// Bit mask of Vulkan Portability features.
+ const PORTABILITY_MASK = 0x0000_FFFF_0000_0000_0000_0000;
+ /// Bit mask for extra WebGPU features.
+ const WEBGPU_MASK = 0xFFFF_0000_0000_0000_0000_0000;
+ /// Bit mask for all extensions.
+ const EXTENSIONS_MASK = 0xFFFF_FFFF_0000_0000_0000_0000_0000_0000;
+
+ /// Support for robust buffer access.
+ /// Buffer access by SPIR-V shaders is checked against the buffer/image boundaries.
+ const ROBUST_BUFFER_ACCESS = 0x0000_0000_0000_0001;
+ /// Support the full 32-bit range of indexed for draw calls.
+ /// If not supported, the maximum index value is determined by `Limits::max_draw_index_value`.
+ const FULL_DRAW_INDEX_U32 = 0x0000_0000_0000_0002;
+ /// Support cube array image views.
+ const IMAGE_CUBE_ARRAY = 0x0000_0000_0000_0004;
+ /// Support different color blending settings per attachments on graphics pipeline creation.
+ const INDEPENDENT_BLENDING = 0x0000_0000_0000_0008;
+ /// Support geometry shader.
+ const GEOMETRY_SHADER = 0x0000_0000_0000_0010;
+ /// Support tessellation shaders.
+ const TESSELLATION_SHADER = 0x0000_0000_0000_0020;
+ /// Support per-sample shading and multisample interpolation.
+ const SAMPLE_RATE_SHADING = 0x0000_0000_0000_0040;
+ /// Support dual source blending.
+ const DUAL_SRC_BLENDING = 0x0000_0000_0000_0080;
+ /// Support logic operations.
+ const LOGIC_OP = 0x0000_0000_0000_0100;
+ /// Support multiple draws per indirect call.
+ const MULTI_DRAW_INDIRECT = 0x0000_0000_0000_0200;
+ /// Support indirect drawing with first instance value.
+ /// If not supported the first instance value **must** be 0.
+ const DRAW_INDIRECT_FIRST_INSTANCE = 0x0000_0000_0000_0400;
+ /// Support depth clamping.
+ const DEPTH_CLAMP = 0x0000_0000_0000_0800;
+ /// Support depth bias clamping.
+ const DEPTH_BIAS_CLAMP = 0x0000_0000_0000_1000;
+ /// Support non-fill polygon modes.
+ const NON_FILL_POLYGON_MODE = 0x0000_0000_0000_2000;
+ /// Support depth bounds test.
+ const DEPTH_BOUNDS = 0x0000_0000_0000_4000;
+ /// Support lines with width other than 1.0.
+ const LINE_WIDTH = 0x0000_0000_0000_8000;
+ /// Support points with size greater than 1.0.
+ const POINT_SIZE = 0x0000_0000_0001_0000;
+ /// Support replacing alpha values with 1.0.
+ const ALPHA_TO_ONE = 0x0000_0000_0002_0000;
+ /// Support multiple viewports and scissors.
+ const MULTI_VIEWPORTS = 0x0000_0000_0004_0000;
+ /// Support anisotropic filtering.
+ const SAMPLER_ANISOTROPY = 0x0000_0000_0008_0000;
+ /// Support ETC2 texture compression formats.
+ const FORMAT_ETC2 = 0x0000_0000_0010_0000;
+ /// Support ASTC (LDR) texture compression formats.
+ const FORMAT_ASTC_LDR = 0x0000_0000_0020_0000;
+ /// Support BC texture compression formats.
+ const FORMAT_BC = 0x0000_0000_0040_0000;
+ /// Support precise occlusion queries, returning the actual number of samples.
+ /// If not supported, queries return a non-zero value when at least **one** sample passes.
+ const PRECISE_OCCLUSION_QUERY = 0x0000_0000_0080_0000;
+ /// Support query of pipeline statistics.
+ const PIPELINE_STATISTICS_QUERY = 0x0000_0000_0100_0000;
+ /// Support unordered access stores and atomic ops in the vertex, geometry
+ /// and tessellation shader stage.
+ /// If not supported, the shader resources **must** be annotated as read-only.
+ const VERTEX_STORES_AND_ATOMICS = 0x0000_0000_0200_0000;
+ /// Support unordered access stores and atomic ops in the fragment shader stage
+ /// If not supported, the shader resources **must** be annotated as read-only.
+ const FRAGMENT_STORES_AND_ATOMICS = 0x0000_0000_0400_0000;
+ ///
+ const SHADER_TESSELLATION_AND_GEOMETRY_POINT_SIZE = 0x0000_0000_0800_0000;
+ ///
+ const SHADER_IMAGE_GATHER_EXTENDED = 0x0000_0000_1000_0000;
+ ///
+ const SHADER_STORAGE_IMAGE_EXTENDED_FORMATS = 0x0000_0000_2000_0000;
+ ///
+ const SHADER_STORAGE_IMAGE_MULTISAMPLE = 0x0000_0000_4000_0000;
+ ///
+ const SHADER_STORAGE_IMAGE_READ_WITHOUT_FORMAT = 0x0000_0000_8000_0000;
+ ///
+ const SHADER_STORAGE_IMAGE_WRITE_WITHOUT_FORMAT = 0x0000_0001_0000_0000;
+ ///
+ const SHADER_UNIFORM_BUFFER_ARRAY_DYNAMIC_INDEXING = 0x0000_0002_0000_0000;
+ ///
+ const SHADER_SAMPLED_IMAGE_ARRAY_DYNAMIC_INDEXING = 0x0000_0004_0000_0000;
+ ///
+ const SHADER_STORAGE_BUFFER_ARRAY_DYNAMIC_INDEXING = 0x0000_0008_0000_0000;
+ ///
+ const SHADER_STORAGE_IMAGE_ARRAY_DYNAMIC_INDEXING = 0x0000_0010_0000_0000;
+ ///
+ const SHADER_CLIP_DISTANCE = 0x0000_0020_0000_0000;
+ ///
+ const SHADER_CULL_DISTANCE = 0x0000_0040_0000_0000;
+ ///
+ const SHADER_FLOAT64 = 0x0000_0080_0000_0000;
+ ///
+ const SHADER_INT64 = 0x0000_0100_0000_0000;
+ ///
+ const SHADER_INT16 = 0x0000_0200_0000_0000;
+ ///
+ const SHADER_RESOURCE_RESIDENCY = 0x0000_0400_0000_0000;
+ ///
+ const SHADER_RESOURCE_MIN_LOD = 0x0000_0800_0000_0000;
+ ///
+ const SPARSE_BINDING = 0x0000_1000_0000_0000;
+ ///
+ const SPARSE_RESIDENCY_BUFFER = 0x0000_2000_0000_0000;
+ ///
+ const SPARSE_RESIDENCY_IMAGE_2D = 0x0000_4000_0000_0000;
+ ///
+ const SPARSE_RESIDENCY_IMAGE_3D = 0x0000_8000_0000_0000;
+ ///
+ const SPARSE_RESIDENCY_2_SAMPLES = 0x0001_0000_0000_0000;
+ ///
+ const SPARSE_RESIDENCY_4_SAMPLES = 0x0002_0000_0000_0000;
+ ///
+ const SPARSE_RESIDENCY_8_SAMPLES = 0x0004_0000_0000_0000;
+ ///
+ const SPARSE_RESIDENCY_16_SAMPLES = 0x0008_0000_0000_0000;
+ ///
+ const SPARSE_RESIDENCY_ALIASED = 0x0010_0000_0000_0000;
+ ///
+ const VARIABLE_MULTISAMPLE_RATE = 0x0020_0000_0000_0000;
+ ///
+ const INHERITED_QUERIES = 0x0040_0000_0000_0000;
+ /// Support for arrays of texture descriptors
+ const TEXTURE_DESCRIPTOR_ARRAY = 0x0080_0000_0000_0000;
+ /// Support for
+ const SAMPLER_MIRROR_CLAMP_EDGE = 0x0100_0000_0000_0000;
+ /// Allow indexing sampled texture descriptor arrays with dynamically non-uniform data
+ const SAMPLED_TEXTURE_DESCRIPTOR_INDEXING = 0x0200_0000_0000_0000;
+ /// Allow indexing storage texture descriptor arrays with dynamically non-uniform data
+ const STORAGE_TEXTURE_DESCRIPTOR_INDEXING = 0x0400_0000_0000_0000;
+ /// Allow descriptor arrays to be unsized in shaders
+ const UNSIZED_DESCRIPTOR_ARRAY = 0x0800_0000_0000_0000;
+ /// Enable draw_indirect_count and draw_indexed_indirect_count
+ const DRAW_INDIRECT_COUNT = 0x1000_0000_0000_0000;
+
+ /// Support triangle fan primitive topology.
+ const TRIANGLE_FAN = 0x0001 << 64;
+ /// Support separate stencil reference values for front and back sides.
+ const SEPARATE_STENCIL_REF_VALUES = 0x0002 << 64;
+ /// Support manually specified vertex attribute rates (divisors).
+ const INSTANCE_RATE = 0x0004 << 64;
+ /// Support non-zero mipmap bias on samplers.
+ const SAMPLER_MIP_LOD_BIAS = 0x0008 << 64;
+ /// Support sampler wrap mode that clamps to border.
+ const SAMPLER_BORDER_COLOR = 0x0010 << 64;
+ /// Can create comparison samplers in regular descriptor sets.
+ const MUTABLE_COMPARISON_SAMPLER = 0x0020 << 64;
+
+ /// Make the NDC coordinate system pointing Y up, to match D3D and Metal.
+ const NDC_Y_UP = 0x0001 << 80;
+
+ /// Supports task shader stage.
+ const TASK_SHADER = 0x0001 << 96;
+ /// Supports mesh shader stage.
+ const MESH_SHADER = 0x0002 << 96;
+ }
+}
+
+bitflags! {
+ /// Features that the device supports natively, but is able to emulate.
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct Hints: u32 {
+ /// Support indexed, instanced drawing with base vertex and instance.
+ const BASE_VERTEX_INSTANCE_DRAWING = 0x0001;
+ }
+}
+
+/// Resource limits of a particular graphics device.
+#[derive(Clone, Copy, Debug, Default, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct Limits {
+ /// Maximum supported image 1D size.
+ pub max_image_1d_size: image::Size,
+ /// Maximum supported image 2D size.
+ pub max_image_2d_size: image::Size,
+ /// Maximum supported image 3D size.
+ pub max_image_3d_size: image::Size,
+ /// Maximum supported image cube size.
+ pub max_image_cube_size: image::Size,
+ /// Maximum supporter image array size.
+ pub max_image_array_layers: image::Layer,
+ /// Maximum number of elements for the BufferView to see.
+ pub max_texel_elements: usize,
+ ///
+ pub max_uniform_buffer_range: buffer::Offset,
+ ///
+ pub max_storage_buffer_range: buffer::Offset,
+ ///
+ pub max_push_constants_size: usize,
+ ///
+ pub max_memory_allocation_count: usize,
+ ///
+ pub max_sampler_allocation_count: usize,
+ ///
+ pub max_bound_descriptor_sets: pso::DescriptorSetIndex,
+ ///
+ pub max_framebuffer_layers: usize,
+ ///
+ pub max_per_stage_descriptor_samplers: usize,
+ ///
+ pub max_per_stage_descriptor_uniform_buffers: usize,
+ ///
+ pub max_per_stage_descriptor_storage_buffers: usize,
+ ///
+ pub max_per_stage_descriptor_sampled_images: usize,
+ ///
+ pub max_per_stage_descriptor_storage_images: usize,
+ ///
+ pub max_per_stage_descriptor_input_attachments: usize,
+ ///
+ pub max_per_stage_resources: usize,
+
+ ///
+ pub max_descriptor_set_samplers: usize,
+ ///
+ pub max_descriptor_set_uniform_buffers: usize,
+ ///
+ pub max_descriptor_set_uniform_buffers_dynamic: usize,
+ ///
+ pub max_descriptor_set_storage_buffers: usize,
+ ///
+ pub max_descriptor_set_storage_buffers_dynamic: usize,
+ ///
+ pub max_descriptor_set_sampled_images: usize,
+ ///
+ pub max_descriptor_set_storage_images: usize,
+ ///
+ pub max_descriptor_set_input_attachments: usize,
+
+ /// Maximum number of vertex input attributes that can be specified for a graphics pipeline.
+ pub max_vertex_input_attributes: usize,
+ /// Maximum number of vertex buffers that can be specified for providing vertex attributes to a graphics pipeline.
+ pub max_vertex_input_bindings: usize,
+ /// Maximum vertex input attribute offset that can be added to the vertex input binding stride.
+ pub max_vertex_input_attribute_offset: usize,
+ /// Maximum vertex input binding stride that can be specified in a vertex input binding.
+ pub max_vertex_input_binding_stride: usize,
+ /// Maximum number of components of output variables which can be output by a vertex shader.
+ pub max_vertex_output_components: usize,
+
+ /// Maximum number of vertices for each patch.
+ pub max_patch_size: pso::PatchSize,
+ ///
+ pub max_geometry_shader_invocations: usize,
+ ///
+ pub max_geometry_input_components: usize,
+ ///
+ pub max_geometry_output_components: usize,
+ ///
+ pub max_geometry_output_vertices: usize,
+ ///
+ pub max_geometry_total_output_components: usize,
+ ///
+ pub max_fragment_input_components: usize,
+ ///
+ pub max_fragment_output_attachments: usize,
+ ///
+ pub max_fragment_dual_source_attachments: usize,
+ ///
+ pub max_fragment_combined_output_resources: usize,
+
+ ///
+ pub max_compute_shared_memory_size: usize,
+ ///
+ pub max_compute_work_group_count: WorkGroupCount,
+ ///
+ pub max_compute_work_group_invocations: usize,
+ ///
+ pub max_compute_work_group_size: [u32; 3],
+
+ ///
+ pub max_draw_indexed_index_value: IndexCount,
+ ///
+ pub max_draw_indirect_count: InstanceCount,
+
+ ///
+ pub max_sampler_lod_bias: f32,
+ /// Maximum degree of sampler anisotropy.
+ pub max_sampler_anisotropy: f32,
+
+ /// Maximum number of viewports.
+ pub max_viewports: usize,
+ ///
+ pub max_viewport_dimensions: [image::Size; 2],
+ ///
+ pub max_framebuffer_extent: image::Extent,
+
+ ///
+ pub min_memory_map_alignment: usize,
+ ///
+ pub buffer_image_granularity: buffer::Offset,
+ /// The alignment of the start of buffer used as a texel buffer, in bytes, non-zero.
+ pub min_texel_buffer_offset_alignment: buffer::Offset,
+ /// The alignment of the start of buffer used for uniform buffer updates, in bytes, non-zero.
+ pub min_uniform_buffer_offset_alignment: buffer::Offset,
+ /// The alignment of the start of buffer used as a storage buffer, in bytes, non-zero.
+ pub min_storage_buffer_offset_alignment: buffer::Offset,
+ /// Number of samples supported for color attachments of framebuffers (floating/fixed point).
+ pub framebuffer_color_sample_counts: image::NumSamples,
+ /// Number of samples supported for depth attachments of framebuffers.
+ pub framebuffer_depth_sample_counts: image::NumSamples,
+ /// Number of samples supported for stencil attachments of framebuffers.
+ pub framebuffer_stencil_sample_counts: image::NumSamples,
+ /// Maximum number of color attachments that can be used by a subpass in a render pass.
+ pub max_color_attachments: usize,
+ ///
+ pub standard_sample_locations: bool,
+ /// The alignment of the start of the buffer used as a GPU copy source, in bytes, non-zero.
+ pub optimal_buffer_copy_offset_alignment: buffer::Offset,
+ /// The alignment of the row pitch of the texture data stored in a buffer that is
+ /// used in a GPU copy operation, in bytes, non-zero.
+ pub optimal_buffer_copy_pitch_alignment: buffer::Offset,
+ /// Size and alignment in bytes that bounds concurrent access to host-mapped device memory.
+ pub non_coherent_atom_size: usize,
+
+ /// The alignment of the vertex buffer stride.
+ pub min_vertex_input_binding_stride_alignment: buffer::Offset,
+
+ /// The maximum number of local workgroups that can be launched by a single draw mesh tasks command
+ pub max_draw_mesh_tasks_count: u32,
+ /// The maximum total number of task shader invocations in a single local workgroup. The product of the X, Y, and
+ /// Z sizes, as specified by the LocalSize execution mode in shader modules or by the object decorated by the
+ /// WorkgroupSize decoration, must be less than or equal to this limit.
+ pub max_task_work_group_invocations: u32,
+ /// The maximum size of a local task workgroup. These three values represent the maximum local workgroup size in
+ /// the X, Y, and Z dimensions, respectively. The x, y, and z sizes, as specified by the LocalSize execution mode
+ /// or by the object decorated by the WorkgroupSize decoration in shader modules, must be less than or equal to
+ /// the corresponding limit.
+ pub max_task_work_group_size: [u32; 3],
+ /// The maximum number of bytes that the task shader can use in total for shared and output memory combined.
+ pub max_task_total_memory_size: u32,
+ /// The maximum number of output tasks a single task shader workgroup can emit.
+ pub max_task_output_count: u32,
+ /// The maximum total number of mesh shader invocations in a single local workgroup. The product of the X, Y, and
+ /// Z sizes, as specified by the LocalSize execution mode in shader modules or by the object decorated by the
+ /// WorkgroupSize decoration, must be less than or equal to this limit.
+ pub max_mesh_work_group_invocations: u32,
+ /// The maximum size of a local mesh workgroup. These three values represent the maximum local workgroup size in
+ /// the X, Y, and Z dimensions, respectively. The x, y, and z sizes, as specified by the LocalSize execution mode
+ /// or by the object decorated by the WorkgroupSize decoration in shader modules, must be less than or equal to the
+ /// corresponding limit.
+ pub max_mesh_work_group_size: [u32; 3],
+ /// The maximum number of bytes that the mesh shader can use in total for shared and output memory combined.
+ pub max_mesh_total_memory_size: u32,
+ /// The maximum number of vertices a mesh shader output can store.
+ pub max_mesh_output_vertices: u32,
+ /// The maximum number of primitives a mesh shader output can store.
+ pub max_mesh_output_primitives: u32,
+ /// The maximum number of multi-view views a mesh shader can use.
+ pub max_mesh_multiview_view_count: u32,
+ /// The granularity with which mesh vertex outputs are allocated. The value can be used to compute the memory size
+ /// used by the mesh shader, which must be less than or equal to maxMeshTotalMemorySize.
+ pub mesh_output_per_vertex_granularity: u32,
+ /// The granularity with which mesh outputs qualified as per-primitive are allocated. The value can be used to
+ /// compute the memory size used by the mesh shader, which must be less than or equal to
+ pub mesh_output_per_primitive_granularity: u32,
+}
+
+/// An enum describing the type of an index value in a slice's index buffer
+#[allow(missing_docs)]
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[repr(u8)]
+pub enum IndexType {
+ U16,
+ U32,
+}
+
+/// Error creating an instance of a backend on the platform that
+/// doesn't support this backend.
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub struct UnsupportedBackend;
+
+impl fmt::Display for UnsupportedBackend {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "UnsupportedBackend")
+ }
+}
+
+impl std::error::Error for UnsupportedBackend {}
+
+/// An instantiated backend.
+///
+/// Any startup the backend needs to perform will be done when creating the type that implements
+/// `Instance`.
+///
+/// # Examples
+///
+/// ```rust
+/// # extern crate gfx_backend_empty;
+/// # extern crate gfx_hal;
+/// use gfx_backend_empty as backend;
+/// use gfx_hal::Instance;
+///
+/// // Create a concrete instance of our backend (this is backend-dependent and may be more
+/// // complicated for some backends).
+/// let instance = backend::Instance::create("My App", 1).unwrap();
+/// // We can get a list of the available adapters, which are either physical graphics
+/// // devices, or virtual adapters. Because we are using the dummy `empty` backend,
+/// // there will be nothing in this list.
+/// for (idx, adapter) in instance.enumerate_adapters().iter().enumerate() {
+/// println!("Adapter {}: {:?}", idx, adapter.info);
+/// }
+/// ```
+pub trait Instance<B: Backend>: Any + Send + Sync + Sized {
+ /// Create a new instance.
+ ///
+ /// # Arguments
+ ///
+ /// * `name` - name of the application using the API.
+ /// * `version` - free form representation of the application's version.
+ ///
+ /// This metadata is passed further down the graphics stack.
+ ///
+ /// # Errors
+ ///
+ /// Returns an `Err` variant if the requested backend [is not supported
+ /// on the current platform][UnsupportedBackend].
+ fn create(name: &str, version: u32) -> Result<Self, UnsupportedBackend>;
+
+ /// Return all available [graphics adapters][adapter::Adapter].
+ fn enumerate_adapters(&self) -> Vec<adapter::Adapter<B>>;
+
+ /// Create a new [surface][window::Surface].
+ ///
+ /// Surfaces can be used to render to windows.
+ ///
+ /// # Safety
+ ///
+ /// This method can cause undefined behavior if `raw_window_handle` isn't
+ /// a handle to a valid window for the current platform.
+ unsafe fn create_surface(
+ &self,
+ raw_window_handle: &impl raw_window_handle::HasRawWindowHandle,
+ ) -> Result<B::Surface, window::InitError>;
+
+ /// Destroy a surface, freeing the resources associated with it and
+ /// releasing it from this graphics API.
+ ///
+ /// # Safety
+ ///
+ unsafe fn destroy_surface(&self, surface: B::Surface);
+}
+
+/// A strongly-typed index to a particular `MemoryType`.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct MemoryTypeId(pub usize);
+
+impl From<usize> for MemoryTypeId {
+ fn from(id: usize) -> Self {
+ MemoryTypeId(id)
+ }
+}
+
+struct PseudoVec<T>(Option<T>);
+
+impl<T> Extend<T> for PseudoVec<T> {
+ fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
+ let mut iter = iter.into_iter();
+ self.0 = iter.next();
+ assert!(iter.next().is_none());
+ }
+}
+
+/// Wraps together all the types needed for a graphics backend.
+///
+/// Each backend module, such as OpenGL or Metal, will implement this trait
+/// with its own concrete types.
+pub trait Backend: 'static + Sized + Eq + Clone + Hash + fmt::Debug + Any + Send + Sync {
+ /// The corresponding [instance][Instance] type for this backend.
+ type Instance: Instance<Self>;
+ /// The corresponding [physical device][adapter::PhysicalDevice] type for this backend.
+ type PhysicalDevice: adapter::PhysicalDevice<Self>;
+ /// The corresponding [logical device][device::Device] type for this backend.
+ type Device: device::Device<Self>;
+ /// The corresponding [surface][window::PresentationSurface] type for this backend.
+ type Surface: window::PresentationSurface<Self>;
+
+ /// The corresponding [queue family][queue::QueueFamily] type for this backend.
+ type QueueFamily: queue::QueueFamily;
+ /// The corresponding [command queue][queue::CommandQueue] type for this backend.
+ type CommandQueue: queue::CommandQueue<Self>;
+ /// The corresponding [command buffer][command::CommandBuffer] type for this backend.
+ type CommandBuffer: command::CommandBuffer<Self>;
+
+ /// The corresponding shader module type for this backend.
+ type ShaderModule: fmt::Debug + Any + Send + Sync;
+ /// The corresponding render pass type for this backend.
+ type RenderPass: fmt::Debug + Any + Send + Sync;
+ /// The corresponding framebuffer type for this backend.
+ type Framebuffer: fmt::Debug + Any + Send + Sync;
+
+ /// The corresponding memory type for this backend.
+ type Memory: fmt::Debug + Any + Send + Sync;
+ /// The corresponding [command pool][pool::CommandPool] type for this backend.
+ type CommandPool: pool::CommandPool<Self>;
+
+ /// The corresponding buffer type for this backend.
+ type Buffer: fmt::Debug + Any + Send + Sync;
+ /// The corresponding buffer view type for this backend.
+ type BufferView: fmt::Debug + Any + Send + Sync;
+ /// The corresponding image type for this backend.
+ type Image: fmt::Debug + Any + Send + Sync;
+ /// The corresponding image view type for this backend.
+ type ImageView: fmt::Debug + Any + Send + Sync;
+ /// The corresponding sampler type for this backend.
+ type Sampler: fmt::Debug + Any + Send + Sync;
+
+ /// The corresponding compute pipeline type for this backend.
+ type ComputePipeline: fmt::Debug + Any + Send + Sync;
+ /// The corresponding graphics pipeline type for this backend.
+ type GraphicsPipeline: fmt::Debug + Any + Send + Sync;
+ /// The corresponding pipeline cache type for this backend.
+ type PipelineCache: fmt::Debug + Any + Send + Sync;
+ /// The corresponding pipeline layout type for this backend.
+ type PipelineLayout: fmt::Debug + Any + Send + Sync;
+ /// The corresponding [descriptor pool][pso::DescriptorPool] type for this backend.
+ type DescriptorPool: pso::DescriptorPool<Self>;
+ /// The corresponding descriptor set type for this backend.
+ type DescriptorSet: fmt::Debug + Any + Send + Sync;
+ /// The corresponding descriptor set layout type for this backend.
+ type DescriptorSetLayout: fmt::Debug + Any + Send + Sync;
+
+ /// The corresponding fence type for this backend.
+ type Fence: fmt::Debug + Any + Send + Sync;
+ /// The corresponding semaphore type for this backend.
+ type Semaphore: fmt::Debug + Any + Send + Sync;
+ /// The corresponding event type for this backend.
+ type Event: fmt::Debug + Any + Send + Sync;
+ /// The corresponding query pool type for this backend.
+ type QueryPool: fmt::Debug + Any + Send + Sync;
+}
diff --git a/third_party/rust/gfx-hal/src/memory.rs b/third_party/rust/gfx-hal/src/memory.rs
new file mode 100644
index 0000000000..a4a200e90d
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/memory.rs
@@ -0,0 +1,130 @@
+//! Types to describe the properties of memory allocated for graphics resources.
+
+use crate::{buffer, image, queue, Backend};
+use std::ops::Range;
+
+bitflags!(
+ /// Memory property flags.
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct Properties: u16 {
+ /// Device local memory on the GPU.
+ const DEVICE_LOCAL = 0x1;
+
+ /// Host visible memory can be accessed by the CPU.
+ ///
+ /// Backends must provide at least one cpu visible memory.
+ const CPU_VISIBLE = 0x2;
+
+ /// CPU-GPU coherent.
+ ///
+ /// Non-coherent memory requires explicit flushing.
+ const COHERENT = 0x4;
+
+ /// Cached memory by the CPU
+ const CPU_CACHED = 0x8;
+
+ /// Memory that may be lazily allocated as needed on the GPU
+ /// and *must not* be visible to the CPU.
+ const LAZILY_ALLOCATED = 0x10;
+ }
+);
+
+bitflags!(
+ /// Memory heap flags.
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct HeapFlags: u16 {
+ /// Device local memory on the GPU.
+ const DEVICE_LOCAL = 0x1;
+ }
+);
+
+bitflags!(
+ /// Barrier dependency flags.
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct Dependencies: u32 {
+ /// Specifies the memory dependency to be framebuffer-local.
+ const BY_REGION = 0x1;
+ ///
+ const VIEW_LOCAL = 0x2;
+ ///
+ const DEVICE_GROUP = 0x4;
+ }
+);
+
+// DOC TODO: Could be better, but I don't know how to do this without
+// trying to explain the whole synchronization model.
+/// A [memory barrier](https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#synchronization-memory-barriers)
+/// type for either buffers or images.
+#[allow(missing_docs)]
+#[derive(Clone, Debug)]
+pub enum Barrier<'a, B: Backend> {
+ /// Applies the given access flags to all buffers in the range.
+ AllBuffers(Range<buffer::Access>),
+ /// Applies the given access flags to all images in the range.
+ AllImages(Range<image::Access>),
+ /// A memory barrier that defines access to a buffer.
+ Buffer {
+ /// The access flags controlling the buffer.
+ states: Range<buffer::State>,
+ /// The buffer the barrier controls.
+ target: &'a B::Buffer,
+ /// Subrange of the buffer the barrier applies to.
+ range: buffer::SubRange,
+ /// The source and destination Queue family IDs, for a [queue family ownership transfer](https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#synchronization-queue-transfers)
+ /// Can be `None` to indicate no ownership transfer.
+ families: Option<Range<queue::QueueFamilyId>>,
+ },
+ /// A memory barrier that defines access to (a subset of) an image.
+ Image {
+ /// The access flags controlling the image.
+ states: Range<image::State>,
+ /// The image the barrier controls.
+ target: &'a B::Image,
+ /// A `SubresourceRange` that defines which section of an image the barrier applies to.
+ range: image::SubresourceRange,
+ /// The source and destination Queue family IDs, for a [queue family ownership transfer](https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#synchronization-queue-transfers)
+ /// Can be `None` to indicate no ownership transfer.
+ families: Option<Range<queue::QueueFamilyId>>,
+ },
+}
+
+impl<'a, B: Backend> Barrier<'a, B> {
+ /// Create a barrier for the whole buffer between the given states.
+ pub fn whole_buffer(target: &'a B::Buffer, states: Range<buffer::State>) -> Self {
+ Barrier::Buffer {
+ states,
+ target,
+ families: None,
+ range: buffer::SubRange::WHOLE,
+ }
+ }
+}
+
+/// Memory requirements for a certain resource (buffer/image).
+#[derive(Clone, Copy, Debug)]
+pub struct Requirements {
+ /// Size in the memory.
+ pub size: u64,
+ /// Memory alignment.
+ pub alignment: u64,
+ /// Supported memory types.
+ pub type_mask: u32,
+}
+
+/// A linear segment within a memory block.
+#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct Segment {
+ /// Offset to the segment.
+ pub offset: u64,
+ /// Size of the segment, or None if unbound.
+ pub size: Option<u64>,
+}
+
+impl Segment {
+ /// All the memory available.
+ pub const ALL: Self = Segment {
+ offset: 0,
+ size: None,
+ };
+}
diff --git a/third_party/rust/gfx-hal/src/pass.rs b/third_party/rust/gfx-hal/src/pass.rs
new file mode 100644
index 0000000000..c6f2d9045b
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/pass.rs
@@ -0,0 +1,197 @@
+//! Render pass handling.
+//!
+//! A *render pass* represents a collection of
+//!
+//! - [attachments][crate::pass::Attachment]
+//! - [subpasses][crate::pass::SubpassDesc]
+//! - [dependencies][crate::pass::SubpassDependency] between the subpasses
+//!
+//! and describes how the attachments are used over the course of the subpasses.
+
+use crate::{format::Format, image, memory::Dependencies, pso::PipelineStage, Backend};
+use std::ops::Range;
+
+/// Specifies the operation to be used when reading data from a subpass attachment.
+#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum AttachmentLoadOp {
+ /// Preserve existing content in the attachment.
+ Load,
+ /// Clear the attachment.
+ Clear,
+ /// Attachment content will be undefined.
+ DontCare,
+}
+
+/// Specifies the operation to be used when writing data to a subpass attachment.
+#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum AttachmentStoreOp {
+ /// Content written to the attachment will be preserved.
+ Store,
+ /// Attachment content will be undefined.
+ DontCare,
+}
+
+/// Image layout of an attachment.
+pub type AttachmentLayout = image::Layout;
+
+/// Attachment operations.
+#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct AttachmentOps {
+ /// Indicates how the data of the attachment will be loaded at first usage at
+ /// the beginning of the subpass.
+ pub load: AttachmentLoadOp,
+ /// Whether or not data from the store operation will be preserved after the subpass.
+ pub store: AttachmentStoreOp,
+}
+
+impl AttachmentOps {
+ /// Specifies `DontCare` for both load and store op.
+ pub const DONT_CARE: Self = AttachmentOps {
+ load: AttachmentLoadOp::DontCare,
+ store: AttachmentStoreOp::DontCare,
+ };
+
+ /// Specifies `Clear` for load op and `Store` for store op.
+ pub const INIT: Self = AttachmentOps {
+ load: AttachmentLoadOp::Clear,
+ store: AttachmentStoreOp::Store,
+ };
+
+ /// Specifies `Load` for load op and `Store` for store op.
+ pub const PRESERVE: Self = AttachmentOps {
+ load: AttachmentLoadOp::Load,
+ store: AttachmentStoreOp::Store,
+ };
+
+ /// Convenience function to create a new `AttachmentOps`.
+ pub fn new(load: AttachmentLoadOp, store: AttachmentStoreOp) -> Self {
+ AttachmentOps { load, store }
+ }
+
+ /// A method to provide `AttachmentOps::DONT_CARE` to things that expect
+ /// a default function rather than a value.
+ #[cfg(feature = "serde")]
+ fn whatever() -> Self {
+ Self::DONT_CARE
+ }
+}
+
+/// An attachment is a description of a resource provided to a render subpass.
+///
+/// It includes things such as render targets, images that were produced from
+/// previous subpasses, etc.
+#[derive(Clone, Debug, Hash, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct Attachment {
+ /// Format of this attachment.
+ ///
+ /// In the most cases `format` is not `None`. It should be only used for
+ /// creating dummy renderpasses, which are used as placeholder for compatible
+ /// renderpasses.
+ pub format: Option<Format>,
+ /// Number of samples to use when loading from this attachment.
+ ///
+ /// If greater than 1, [multisampling](https://en.wikipedia.org/wiki/Multisample_anti-aliasing)
+ /// will take effect.
+ pub samples: image::NumSamples,
+ /// Load and store operations of the attachment.
+ pub ops: AttachmentOps,
+ /// Load and store operations of the stencil aspect, if any.
+ #[cfg_attr(feature = "serde", serde(default = "AttachmentOps::whatever"))]
+ pub stencil_ops: AttachmentOps,
+ /// Initial and final image layouts of the renderpass.
+ pub layouts: Range<AttachmentLayout>,
+}
+
+impl Attachment {
+ /// Returns true if this attachment has some clear operations.
+ ///
+ /// Useful when starting a render pass, since there has to be a clear value provided.
+ pub fn has_clears(&self) -> bool {
+ self.ops.load == AttachmentLoadOp::Clear || self.stencil_ops.load == AttachmentLoadOp::Clear
+ }
+}
+
+/// Index of an attachment within a framebuffer/renderpass,
+pub type AttachmentId = usize;
+/// Reference to an attachment by index and expected image layout.
+pub type AttachmentRef = (AttachmentId, AttachmentLayout);
+/// An AttachmentId that can be used instead of providing an attachment.
+pub const ATTACHMENT_UNUSED: AttachmentId = !0;
+
+/// Index of a subpass.
+pub type SubpassId = u8;
+
+/// Expresses a dependency between multiple [subpasses][SubpassDesc].
+///
+/// This is used both to describe a source or destination subpass;
+/// data either explicitly passes from this subpass to the next or from another
+/// subpass into this one.
+#[derive(Clone, Debug, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct SubpassDependency {
+ /// Other subpasses this one depends on.
+ ///
+ /// If one of the range sides is `None`, it refers to the external
+ /// scope either before or after the whole render pass.
+ pub passes: Range<Option<SubpassId>>,
+ /// Other pipeline stages this subpass depends on.
+ pub stages: Range<PipelineStage>,
+ /// Resource accesses this subpass depends on.
+ pub accesses: Range<image::Access>,
+ /// Dependency flags.
+ pub flags: Dependencies,
+}
+
+/// Description of a subpass for render pass creation.
+#[derive(Clone, Debug)]
+pub struct SubpassDesc<'a> {
+ /// Which attachments will be used as color buffers.
+ pub colors: &'a [AttachmentRef],
+ /// Which attachments will be used as depth/stencil buffers.
+ pub depth_stencil: Option<&'a AttachmentRef>,
+ /// Which attachments will be used as input attachments.
+ pub inputs: &'a [AttachmentRef],
+ /// Which attachments will be used as resolve destinations.
+ ///
+ /// The number of resolve attachments may be zero or equal to the number of color attachments.
+ ///
+ /// At the end of a subpass the color attachment will be resolved to the corresponding
+ /// resolve attachment.
+ ///
+ /// The resolve attachment must not be multisampled.
+ pub resolves: &'a [AttachmentRef],
+ /// Attachments that are not used by the subpass but must be preserved to be
+ /// passed on to subsequent passes.
+ pub preserves: &'a [AttachmentId],
+}
+
+/// A sub-pass borrow of a pass.
+#[derive(Debug)]
+pub struct Subpass<'a, B: Backend> {
+ /// Index of the subpass
+ pub index: SubpassId,
+ /// Main pass borrow.
+ pub main_pass: &'a B::RenderPass,
+}
+
+impl<'a, B: Backend> Clone for Subpass<'a, B> {
+ fn clone(&self) -> Self {
+ Subpass {
+ index: self.index,
+ main_pass: self.main_pass,
+ }
+ }
+}
+
+impl<'a, B: Backend> PartialEq for Subpass<'a, B> {
+ fn eq(&self, other: &Self) -> bool {
+ self.index == other.index && std::ptr::eq(self.main_pass, other.main_pass)
+ }
+}
+
+impl<'a, B: Backend> Copy for Subpass<'a, B> {}
+impl<'a, B: Backend> Eq for Subpass<'a, B> {}
diff --git a/third_party/rust/gfx-hal/src/pool.rs b/third_party/rust/gfx-hal/src/pool.rs
new file mode 100644
index 0000000000..f194feb3a0
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/pool.rs
@@ -0,0 +1,65 @@
+//! Command pools
+
+use crate::command::Level;
+use crate::{Backend, PseudoVec};
+
+use std::any::Any;
+use std::fmt;
+
+bitflags!(
+ /// Command pool creation flags.
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct CommandPoolCreateFlags: u8 {
+ /// Indicates short-lived command buffers.
+ /// Memory optimization hint for implementations.
+ const TRANSIENT = 0x1;
+ /// Allow command buffers to be reset individually.
+ const RESET_INDIVIDUAL = 0x2;
+ }
+);
+
+/// The allocated command buffers are associated with the creating command queue.
+pub trait CommandPool<B: Backend>: fmt::Debug + Any + Send + Sync {
+ /// Reset the command pool and the corresponding command buffers.
+ ///
+ /// # Arguments
+ ///
+ /// * `release_resources` - if `true`, this command pool will recycle all the
+ /// resources it own and give them back to the system.
+ ///
+ /// # Synchronization
+ ///
+ /// You may _not_ free the pool if a command buffer allocated from it
+ /// is still in use (pool memory still in use).
+ unsafe fn reset(&mut self, release_resources: bool);
+
+ /// Allocate a single [command buffer][crate::command::CommandBuffer] from the pool.
+ ///
+ /// # Arguments
+ ///
+ /// * `level` - whether this command buffer is primary or secondary.
+ unsafe fn allocate_one(&mut self, level: Level) -> B::CommandBuffer {
+ let mut result = PseudoVec(None);
+ self.allocate(1, level, &mut result);
+ result.0.unwrap()
+ }
+
+ /// Allocate new [command buffers][crate::command::CommandBuffer] from the pool.
+ ///
+ /// # Arguments
+ ///
+ /// * `num` - how many buffers to return
+ /// * `level` - whether to allocate primary or secondary command buffers.
+ /// * `list` - an extendable list of command buffers into which to allocate.
+ unsafe fn allocate<E>(&mut self, num: usize, level: Level, list: &mut E)
+ where
+ E: Extend<B::CommandBuffer>,
+ {
+ list.extend((0..num).map(|_| self.allocate_one(level)));
+ }
+
+ /// Free [command buffers][crate::command::CommandBuffer] allocated from this pool.
+ unsafe fn free<I>(&mut self, buffers: I)
+ where
+ I: IntoIterator<Item = B::CommandBuffer>;
+}
diff --git a/third_party/rust/gfx-hal/src/pso/compute.rs b/third_party/rust/gfx-hal/src/pso/compute.rs
new file mode 100644
index 0000000000..8757e9a4e1
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/pso/compute.rs
@@ -0,0 +1,31 @@
+//! Compute pipeline descriptor.
+
+use crate::{
+ pso::{BasePipeline, EntryPoint, PipelineCreationFlags},
+ Backend,
+};
+
+/// A description of the data needed to construct a compute pipeline.
+#[derive(Debug)]
+pub struct ComputePipelineDesc<'a, B: Backend> {
+ /// The shader entry point that performs the computation.
+ pub shader: EntryPoint<'a, B>,
+ /// Pipeline layout.
+ pub layout: &'a B::PipelineLayout,
+ /// Any flags necessary for the pipeline creation.
+ pub flags: PipelineCreationFlags,
+ /// The parent pipeline to this one, if any.
+ pub parent: BasePipeline<'a, B::ComputePipeline>,
+}
+
+impl<'a, B: Backend> ComputePipelineDesc<'a, B> {
+ /// Create a new empty PSO descriptor.
+ pub fn new(shader: EntryPoint<'a, B>, layout: &'a B::PipelineLayout) -> Self {
+ ComputePipelineDesc {
+ shader,
+ layout,
+ flags: PipelineCreationFlags::empty(),
+ parent: BasePipeline::None,
+ }
+ }
+}
diff --git a/third_party/rust/gfx-hal/src/pso/descriptor.rs b/third_party/rust/gfx-hal/src/pso/descriptor.rs
new file mode 100644
index 0000000000..c1d3a71d9e
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/pso/descriptor.rs
@@ -0,0 +1,316 @@
+//! Descriptor sets and layouts.
+//!
+//! A [`Descriptor`] is an object that describes the connection between a resource, such as
+//! an `Image` or `Buffer`, and a variable in a shader. Descriptors are organized into
+//! `DescriptorSet`s, each of which contains multiple descriptors that are bound and unbound to
+//! shaders as a single unit. The contents of each descriptor in a set is defined by a
+//! `DescriptorSetLayout` which is in turn built of [`DescriptorSetLayoutBinding`]s. A `DescriptorSet`
+//! is then allocated from a [`DescriptorPool`] using the `DescriptorSetLayout`, and specific [`Descriptor`]s are
+//! then bound to each binding point in the set using a [`DescriptorSetWrite`] and/or [`DescriptorSetCopy`].
+//! Each descriptor set may contain descriptors to multiple different sorts of resources, and a shader may
+//! use multiple descriptor sets at a time.
+//!
+//! [`Descriptor`]: enum.Descriptor.html
+//! [`DescriptorSetLayoutBinding`]: struct.DescriptorSetLayoutBinding.html
+//! [`DescriptorPool`]: trait.DescriptorPool.html
+//! [`DescriptorSetWrite`]: struct.DescriptorSetWrite.html
+//! [`DescriptorSetCopy`]: struct.DescriptorSetWrite.html
+
+use std::{borrow::Borrow, fmt, iter};
+
+use crate::{
+ buffer::SubRange, device::OutOfMemory, image::Layout, pso::ShaderStageFlags, Backend, PseudoVec,
+};
+
+///
+pub type DescriptorSetIndex = u16;
+///
+pub type DescriptorBinding = u32;
+///
+pub type DescriptorArrayIndex = usize;
+
+/// Specific type of a buffer.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum BufferDescriptorType {
+ /// Storage buffers allow load, store, and atomic operations.
+ Storage {
+ /// If true, store operations are not permitted on this buffer.
+ read_only: bool,
+ },
+ /// Uniform buffers provide constant data to be accessed in a shader.
+ Uniform,
+}
+
+/// Format of a buffer.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum BufferDescriptorFormat {
+ /// The buffer is interpreted as a structure defined in a shader.
+ Structured {
+ /// If true, the buffer is accessed by an additional offset specified in
+ /// the `offsets` parameter of `CommandBuffer::bind_*_descriptor_sets`.
+ dynamic_offset: bool,
+ },
+ /// The buffer is interpreted as a 1-D array of texels, which undergo format
+ /// conversion when loaded in a shader.
+ Texel,
+}
+
+/// Specific type of an image descriptor.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum ImageDescriptorType {
+ /// A sampled image allows sampling operations.
+ Sampled {
+ /// If true, this descriptor corresponds to both a sampled image and a
+ /// sampler to be used with that image.
+ with_sampler: bool,
+ },
+ /// A storage image allows load, store and atomic operations.
+ Storage {
+ /// If true, store operations are not permitted on this image.
+ read_only: bool,
+ },
+}
+
+/// The type of a descriptor.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum DescriptorType {
+ /// A descriptor associated with sampler.
+ Sampler,
+ /// A descriptor associated with an image.
+ Image {
+ /// The specific type of this image descriptor.
+ ty: ImageDescriptorType,
+ },
+ /// A descriptor associated with a buffer.
+ Buffer {
+ /// The type of this buffer descriptor.
+ ty: BufferDescriptorType,
+ /// The format of this buffer descriptor.
+ format: BufferDescriptorFormat,
+ },
+ /// A descriptor associated with an input attachment.
+ InputAttachment,
+}
+
+/// Information about the contents of and in which stages descriptors may be bound to a descriptor
+/// set at a certain binding point. Multiple `DescriptorSetLayoutBinding`s are assembled into
+/// a `DescriptorSetLayout`, which is then allocated into a `DescriptorSet` using a
+/// [`DescriptorPool`].
+///
+/// A descriptor set consists of multiple binding points.
+/// Each binding point contains one or multiple descriptors of a certain type.
+/// The binding point is only valid for the pipelines stages specified.
+///
+/// The binding _must_ match with the corresponding shader interface.
+///
+/// [`DescriptorPool`]: trait.DescriptorPool.html
+#[derive(Clone, Debug)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct DescriptorSetLayoutBinding {
+ /// Descriptor bindings range.
+ pub binding: DescriptorBinding,
+ /// Type of the bound descriptors.
+ pub ty: DescriptorType,
+ /// Number of descriptors in the array.
+ ///
+ /// *Note*: If count is zero, the binding point is reserved
+ /// and can't be accessed from any shader stages.
+ pub count: DescriptorArrayIndex,
+ /// Valid shader stages.
+ pub stage_flags: ShaderStageFlags,
+ /// Use the associated list of immutable samplers.
+ pub immutable_samplers: bool,
+}
+
+/// Set of descriptors of a specific type.
+#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct DescriptorRangeDesc {
+ /// Type of the stored descriptors.
+ pub ty: DescriptorType,
+ /// Amount of space.
+ pub count: usize,
+}
+
+/// An error allocating descriptor sets from a pool.
+#[derive(Clone, Debug, PartialEq)]
+pub enum AllocationError {
+ /// OutOfMemory::Host: Memory allocation on the host side failed.
+ /// OutOfMemory::Device: Memory allocation on the device side failed.
+ /// This could be caused by a lack of memory or pool fragmentation.
+ OutOfMemory(OutOfMemory),
+ /// Memory allocation failed as there is not enough in the pool.
+ /// This could be caused by too many descriptor sets being created.
+ OutOfPoolMemory,
+ /// Memory allocation failed due to pool fragmentation.
+ FragmentedPool,
+ /// Descriptor set allocation failed as the layout is incompatible with the pool.
+ IncompatibleLayout,
+}
+
+impl std::fmt::Display for AllocationError {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ AllocationError::OutOfMemory(OutOfMemory::Host) => {
+ write!(fmt, "Failed to allocate descriptor set: Out of host memory")
+ }
+ AllocationError::OutOfMemory(OutOfMemory::Device) => write!(
+ fmt,
+ "Failed to allocate descriptor set: Out of device memory"
+ ),
+ AllocationError::OutOfPoolMemory => {
+ write!(fmt, "Failed to allocate descriptor set: Out of pool memory")
+ }
+ AllocationError::FragmentedPool => {
+ write!(fmt, "Failed to allocate descriptor set: Pool is fragmented")
+ }
+ AllocationError::IncompatibleLayout => write!(
+ fmt,
+ "Failed to allocate descriptor set: Incompatible layout"
+ ),
+ }
+ }
+}
+
+impl std::error::Error for AllocationError {}
+
+/// A descriptor pool is a collection of memory from which descriptor sets are allocated.
+pub trait DescriptorPool<B: Backend>: Send + Sync + fmt::Debug {
+ /// Allocate a descriptor set from the pool.
+ ///
+ /// The descriptor set will be allocated from the pool according to the corresponding set layout. However,
+ /// specific descriptors must still be written to the set before use using a [`DescriptorSetWrite`] or
+ /// [`DescriptorSetCopy`].
+ ///
+ /// Descriptors will become invalid once the pool is reset. Usage of invalidated descriptor sets results
+ /// in undefined behavior.
+ ///
+ /// [`DescriptorSetWrite`]: struct.DescriptorSetWrite.html
+ /// [`DescriptorSetCopy`]: struct.DescriptorSetCopy.html
+ unsafe fn allocate_set(
+ &mut self,
+ layout: &B::DescriptorSetLayout,
+ ) -> Result<B::DescriptorSet, AllocationError> {
+ let mut result = PseudoVec(None);
+ self.allocate(iter::once(layout), &mut result)?;
+ Ok(result.0.unwrap())
+ }
+
+ /// Allocate multiple descriptor sets from the pool.
+ ///
+ /// The descriptor set will be allocated from the pool according to the corresponding set layout. However,
+ /// specific descriptors must still be written to the set before use using a [`DescriptorSetWrite`] or
+ /// [`DescriptorSetCopy`].
+ ///
+ /// Each descriptor set will be allocated from the pool according to the corresponding set layout.
+ /// Descriptors will become invalid once the pool is reset. Usage of invalidated descriptor sets results
+ /// in undefined behavior.
+ ///
+ /// [`DescriptorSetWrite`]: struct.DescriptorSetWrite.html
+ /// [`DescriptorSetCopy`]: struct.DescriptorSetCopy.html
+ unsafe fn allocate<I, E>(&mut self, layouts: I, list: &mut E) -> Result<(), AllocationError>
+ where
+ I: IntoIterator,
+ I::Item: Borrow<B::DescriptorSetLayout>,
+ E: Extend<B::DescriptorSet>,
+ {
+ for layout in layouts {
+ let set = self.allocate_set(layout.borrow())?;
+ list.extend(iter::once(set));
+ }
+ Ok(())
+ }
+
+ /// Free the given descriptor sets provided as an iterator.
+ unsafe fn free<I>(&mut self, descriptor_sets: I)
+ where
+ I: IntoIterator<Item = B::DescriptorSet>;
+
+ /// Resets a descriptor pool, releasing all resources from all the descriptor sets
+ /// allocated from it and freeing the descriptor sets. Invalidates all descriptor
+ /// sets allocated from the pool; trying to use one after the pool has been reset
+ /// is undefined behavior.
+ unsafe fn reset(&mut self);
+}
+
+/// Writes the actual descriptors to be bound into a descriptor set.
+///
+/// Should be provided to the `write_descriptor_sets` method of a `Device`.
+#[derive(Debug)]
+pub struct DescriptorSetWrite<'a, B: Backend, WI>
+where
+ WI: IntoIterator,
+ WI::Item: Borrow<Descriptor<'a, B>>,
+{
+ /// The descriptor set to modify.
+ pub set: &'a B::DescriptorSet,
+ /// Binding index to start writing at.
+ ///
+ /// *Note*: when there are more descriptors provided than
+ /// array elements left in the specified binding starting
+ /// at the specified offset, the updates are spilled onto
+ /// the next binding (starting with offset 0), and so on.
+ pub binding: DescriptorBinding,
+ /// Offset into the array to copy to.
+ pub array_offset: DescriptorArrayIndex,
+ /// Descriptors to write to the set.
+ pub descriptors: WI,
+}
+
+/// A handle to a specific shader resource that can be bound for use in a `DescriptorSet`.
+/// Usually provided in a [`DescriptorSetWrite`]
+///
+/// [`DescriptorSetWrite`]: struct.DescriptorSetWrite.html
+#[allow(missing_docs)]
+#[derive(Clone, Debug)]
+pub enum Descriptor<'a, B: Backend> {
+ Sampler(&'a B::Sampler),
+ Image(&'a B::ImageView, Layout),
+ CombinedImageSampler(&'a B::ImageView, Layout, &'a B::Sampler),
+ Buffer(&'a B::Buffer, SubRange),
+ TexelBuffer(&'a B::BufferView),
+}
+
+/// Copies a range of descriptors to be bound from one descriptor set to another.
+///
+/// Should be provided to the `copy_descriptor_sets` method of a `Device`.
+#[derive(Clone, Copy, Debug)]
+pub struct DescriptorSetCopy<'a, B: Backend> {
+ /// Descriptor set to copy from.
+ pub src_set: &'a B::DescriptorSet,
+ /// Binding to copy from.
+ ///
+ /// *Note*: when there are more descriptors required than
+ /// array elements left in the specified binding starting
+ /// at the specified offset, the updates are taken from
+ /// the next binding (starting with offset 0), and so on.
+ pub src_binding: DescriptorBinding,
+ /// Offset into the descriptor array to start copying from.
+ pub src_array_offset: DescriptorArrayIndex,
+ /// Descriptor set to copy to.
+ pub dst_set: &'a B::DescriptorSet,
+ /// Binding to copy to.
+ ///
+ /// *Note*: when there are more descriptors provided than
+ /// array elements left in the specified binding starting
+ /// at the specified offset, the updates are spilled onto
+ /// the next binding (starting with offset 0), and so on.
+ pub dst_binding: DescriptorBinding,
+ /// Offset into the descriptor array to copy to.
+ pub dst_array_offset: DescriptorArrayIndex,
+ /// How many descriptors to copy.
+ pub count: usize,
+}
+
+bitflags! {
+ /// Descriptor pool creation flags.
+ pub struct DescriptorPoolCreateFlags: u32 {
+ /// Specifies that descriptor sets are allowed to be freed from the pool
+ /// individually.
+ const FREE_DESCRIPTOR_SET = 0x1;
+ }
+}
diff --git a/third_party/rust/gfx-hal/src/pso/graphics.rs b/third_party/rust/gfx-hal/src/pso/graphics.rs
new file mode 100644
index 0000000000..b647b1d611
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/pso/graphics.rs
@@ -0,0 +1,298 @@
+//! Graphics pipeline descriptor.
+
+use crate::{
+ image, pass,
+ pso::{
+ input_assembler::{AttributeDesc, InputAssemblerDesc, VertexBufferDesc},
+ output_merger::{ColorBlendDesc, DepthStencilDesc, Face},
+ BasePipeline, EntryPoint, PipelineCreationFlags, State,
+ },
+ Backend,
+};
+
+use std::ops::Range;
+
+/// A simple struct describing a rect with integer coordinates.
+#[derive(Clone, Copy, Debug, Hash, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct Rect {
+ /// X position.
+ pub x: i16,
+ /// Y position.
+ pub y: i16,
+ /// Width.
+ pub w: i16,
+ /// Height.
+ pub h: i16,
+}
+
+/// A simple struct describing a rect with integer coordinates.
+#[derive(Clone, Debug, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct ClearRect {
+ /// 2D region.
+ pub rect: Rect,
+ /// Layer range.
+ pub layers: Range<image::Layer>,
+}
+
+/// A viewport, generally equating to a window on a display.
+#[derive(Clone, Debug, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct Viewport {
+ /// The viewport boundaries.
+ pub rect: Rect,
+ /// The viewport depth limits.
+ pub depth: Range<f32>,
+}
+
+/// A single RGBA float color.
+pub type ColorValue = [f32; 4];
+/// A single depth value from a depth buffer.
+pub type DepthValue = f32;
+/// A single value from a stencil buffer.
+pub type StencilValue = u32;
+/// Baked-in pipeline states.
+#[derive(Clone, Debug, Default, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct BakedStates {
+ /// Static viewport. TODO: multiple viewports
+ pub viewport: Option<Viewport>,
+ /// Static scissor. TODO: multiple scissors
+ pub scissor: Option<Rect>,
+ /// Static blend constant color.
+ pub blend_color: Option<ColorValue>,
+ /// Static depth bounds.
+ pub depth_bounds: Option<Range<f32>>,
+}
+#[derive(Debug)]
+/// Primitive Assembler describes how input data are fetched in the pipeline and formed into primitives before being sent into the fragment shader.
+pub enum PrimitiveAssemblerDesc<'a, B: Backend> {
+ /// Vertex based pipeline
+ Vertex {
+ /// Vertex buffers (IA)
+ buffers: &'a [VertexBufferDesc],
+ /// Vertex attributes (IA)
+ attributes: &'a [AttributeDesc],
+ /// Input assembler attributes, describes how
+ /// vertices are assembled into primitives (such as triangles).
+ input_assembler: InputAssemblerDesc,
+ /// A shader that outputs a vertex in a model.
+ vertex: EntryPoint<'a, B>,
+ /// Tesselation shaders consisting of:
+ ///
+ /// 1. Hull shader: takes in an input patch (values representing
+ /// a small portion of a shape, which may be actual geometry or may
+ /// be parameters for creating geometry) and produces one or more
+ /// output patches.
+ ///
+ /// 2. Domain shader: takes in domains produced from a hull shader's output
+ /// patches and computes actual vertex positions.
+ tessellation: Option<(EntryPoint<'a, B>, EntryPoint<'a, B>)>,
+ /// A shader that takes given input vertexes and outputs zero
+ /// or more output vertexes.
+ geometry: Option<EntryPoint<'a, B>>,
+ },
+ /// Mesh shading pipeline
+ Mesh {
+ /// A shader that creates a variable amount of mesh shader
+ /// invocations.
+ task: Option<EntryPoint<'a, B>>,
+ /// A shader of which each workgroup emits zero or
+ /// more output primitives and the group of vertices and their
+ /// associated data required for each output primitive.
+ mesh: EntryPoint<'a, B>,
+ },
+}
+/// A description of all the settings that can be altered
+/// when creating a graphics pipeline.
+#[derive(Debug)]
+pub struct GraphicsPipelineDesc<'a, B: Backend> {
+ /// Primitive assembler
+ pub primitive_assembler: PrimitiveAssemblerDesc<'a, B>,
+ /// Rasterizer setup
+ pub rasterizer: Rasterizer,
+ /// A shader that outputs a value for a fragment.
+ /// Usually this value is a color that is then displayed as a
+ /// pixel on a screen.
+ ///
+ /// If a fragment shader is omitted, the results of fragment
+ /// processing are undefined. Specifically, any fragment color
+ /// outputs are considered to have undefined values, and the
+ /// fragment depth is considered to be unmodified. This can
+ /// be useful for depth-only rendering.
+ pub fragment: Option<EntryPoint<'a, B>>,
+ /// Description of how blend operations should be performed.
+ pub blender: BlendDesc,
+ /// Depth stencil (DSV)
+ pub depth_stencil: DepthStencilDesc,
+ /// Multisampling.
+ pub multisampling: Option<Multisampling>,
+ /// Static pipeline states.
+ pub baked_states: BakedStates,
+ /// Pipeline layout.
+ pub layout: &'a B::PipelineLayout,
+ /// Subpass in which the pipeline can be executed.
+ pub subpass: pass::Subpass<'a, B>,
+ /// Options that may be set to alter pipeline properties.
+ pub flags: PipelineCreationFlags,
+ /// The parent pipeline, which may be
+ /// `BasePipeline::None`.
+ pub parent: BasePipeline<'a, B::GraphicsPipeline>,
+}
+
+impl<'a, B: Backend> GraphicsPipelineDesc<'a, B> {
+ /// Create a new empty PSO descriptor.
+ pub fn new(
+ primitive_assembler: PrimitiveAssemblerDesc<'a, B>,
+ rasterizer: Rasterizer,
+ fragment: Option<EntryPoint<'a, B>>,
+ layout: &'a B::PipelineLayout,
+ subpass: pass::Subpass<'a, B>,
+ ) -> Self {
+ GraphicsPipelineDesc {
+ primitive_assembler,
+ rasterizer,
+ fragment,
+ blender: BlendDesc::default(),
+ depth_stencil: DepthStencilDesc::default(),
+ multisampling: None,
+ baked_states: BakedStates::default(),
+ layout,
+ subpass,
+ flags: PipelineCreationFlags::empty(),
+ parent: BasePipeline::None,
+ }
+ }
+}
+
+/// Methods for rasterizing polygons, ie, turning the mesh
+/// into a raster image.
+#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum PolygonMode {
+ /// Rasterize as a point.
+ Point,
+ /// Rasterize as a line with the given width.
+ Line,
+ /// Rasterize as a face.
+ Fill,
+}
+
+/// The front face winding order of a set of vertices. This is
+/// the order of vertexes that define which side of a face is
+/// the "front".
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum FrontFace {
+ /// Clockwise winding order.
+ Clockwise,
+ /// Counter-clockwise winding order.
+ CounterClockwise,
+}
+
+/// A depth bias allows changing the produced depth values
+/// for fragments slightly but consistently. This permits
+/// drawing of multiple polygons in the same plane without
+/// Z-fighting, such as when trying to draw shadows on a wall.
+///
+/// For details of the algorithm and equations, see
+/// [the Vulkan spec](https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#primsrast-depthbias).
+#[derive(Copy, Clone, Debug, Default, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct DepthBias {
+ /// A constant depth value added to each fragment.
+ pub const_factor: f32,
+ /// The minimum or maximum depth bias of a fragment.
+ pub clamp: f32,
+ /// A constant bias applied to the fragment's slope.
+ pub slope_factor: f32,
+}
+
+/// Rasterization state.
+#[derive(Copy, Clone, Debug, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct Rasterizer {
+ /// How to rasterize this primitive.
+ pub polygon_mode: PolygonMode,
+ /// Which face should be culled.
+ pub cull_face: Face,
+ /// Which vertex winding is considered to be the front face for culling.
+ pub front_face: FrontFace,
+ /// Whether or not to enable depth clamping; when enabled, instead of
+ /// fragments being omitted when they are outside the bounds of the z-plane,
+ /// they will be clamped to the min or max z value.
+ pub depth_clamping: bool,
+ /// What depth bias, if any, to use for the drawn primitives.
+ pub depth_bias: Option<State<DepthBias>>,
+ /// Controls how triangles will be rasterized depending on their overlap with pixels.
+ pub conservative: bool,
+ /// Controls width of rasterized line segments.
+ pub line_width: State<f32>,
+}
+
+impl Rasterizer {
+ /// Simple polygon-filling rasterizer state
+ pub const FILL: Self = Rasterizer {
+ polygon_mode: PolygonMode::Fill,
+ cull_face: Face::NONE,
+ front_face: FrontFace::CounterClockwise,
+ depth_clamping: false,
+ depth_bias: None,
+ conservative: false,
+ line_width: State::Static(1.0),
+ };
+}
+
+/// A description of an equation for how to blend transparent, overlapping fragments.
+#[derive(Clone, Debug, Default, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct BlendDesc {
+ /// The logic operation to apply to the blending equation, if any.
+ pub logic_op: Option<LogicOp>,
+ /// Which color targets to apply the blending operation to.
+ pub targets: Vec<ColorBlendDesc>,
+}
+
+/// Logic operations used for specifying blend equations.
+#[derive(Clone, Debug, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[allow(missing_docs)]
+pub enum LogicOp {
+ Clear = 0,
+ And = 1,
+ AndReverse = 2,
+ Copy = 3,
+ AndInverted = 4,
+ NoOp = 5,
+ Xor = 6,
+ Or = 7,
+ Nor = 8,
+ Equivalent = 9,
+ Invert = 10,
+ OrReverse = 11,
+ CopyInverted = 12,
+ OrInverted = 13,
+ Nand = 14,
+ Set = 15,
+}
+
+///
+pub type SampleMask = u64;
+
+///
+#[derive(Clone, Debug, PartialEq)]
+pub struct Multisampling {
+ ///
+ pub rasterization_samples: image::NumSamples,
+ ///
+ pub sample_shading: Option<f32>,
+ ///
+ pub sample_mask: SampleMask,
+ /// Toggles alpha-to-coverage multisampling, which can produce nicer edges
+ /// when many partially-transparent polygons are overlapping.
+ /// See [here]( https://msdn.microsoft.com/en-us/library/windows/desktop/bb205072(v=vs.85).aspx#Alpha_To_Coverage) for a full description.
+ pub alpha_coverage: bool,
+ ///
+ pub alpha_to_one: bool,
+}
diff --git a/third_party/rust/gfx-hal/src/pso/input_assembler.rs b/third_party/rust/gfx-hal/src/pso/input_assembler.rs
new file mode 100644
index 0000000000..55ba01bae7
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/pso/input_assembler.rs
@@ -0,0 +1,145 @@
+//! Input Assembler (IA) stage description.
+//! The input assembler collects raw vertex and index data.
+
+use crate::{format, IndexType};
+
+/// Shader binding location.
+pub type Location = u32;
+/// Index of a vertex buffer.
+pub type BufferIndex = u32;
+/// Offset of an attribute from the start of the buffer, in bytes
+pub type ElemOffset = u32;
+/// Offset between attribute values, in bytes
+pub type ElemStride = u32;
+/// Number of instances between each advancement of the vertex buffer.
+pub type InstanceRate = u8;
+/// Number of vertices in a patch
+pub type PatchSize = u8;
+
+/// The rate at which to advance input data to shaders for the given buffer
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum VertexInputRate {
+ /// Advance the buffer after every vertex
+ Vertex,
+ /// Advance the buffer after every instance
+ Instance(InstanceRate),
+}
+
+impl VertexInputRate {
+ /// Get the numeric representation of the rate
+ pub fn as_uint(&self) -> u8 {
+ match *self {
+ VertexInputRate::Vertex => 0,
+ VertexInputRate::Instance(divisor) => divisor,
+ }
+ }
+}
+
+/// A struct element descriptor.
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct Element<F> {
+ /// Element format
+ pub format: F,
+ /// Offset from the beginning of the container, in bytes
+ pub offset: ElemOffset,
+}
+
+/// Vertex buffer description. Notably, completely separate from resource `Descriptor`s
+/// used in `DescriptorSet`s.
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct VertexBufferDesc {
+ /// Binding number of this vertex buffer. This binding number is
+ /// used only for vertex buffers, and is completely separate from
+ /// `Descriptor` and `DescriptorSet` bind points.
+ pub binding: BufferIndex,
+ /// Total container size, in bytes.
+ /// Specifies the byte distance between two consecutive elements.
+ pub stride: ElemStride,
+ /// The rate at which to advance data for the given buffer
+ ///
+ /// i.e. the rate at which data passed to shaders will get advanced by
+ /// `stride` bytes
+ pub rate: VertexInputRate,
+}
+
+/// Vertex attribute description. Notably, completely separate from resource `Descriptor`s
+/// used in `DescriptorSet`s.
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct AttributeDesc {
+ /// Attribute binding location in the shader. Attribute locations are
+ /// shared between all vertex buffers in a pipeline, meaning that even if the
+ /// data for this attribute comes from a different vertex buffer, it still cannot
+ /// share the same location with another attribute.
+ pub location: Location,
+ /// Binding number of the associated vertex buffer.
+ pub binding: BufferIndex,
+ /// Attribute element description.
+ pub element: Element<format::Format>,
+}
+
+/// Describes the type of geometric primitives,
+/// created from vertex data.
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[repr(u8)]
+pub enum Primitive {
+ /// Each vertex represents a single point.
+ PointList,
+ /// Each pair of vertices represent a single line segment. For example, with `[a, b, c, d,
+ /// e]`, `a` and `b` form a line, `c` and `d` form a line, and `e` is discarded.
+ LineList,
+ /// Every two consecutive vertices represent a single line segment. Visually forms a "path" of
+ /// lines, as they are all connected. For example, with `[a, b, c]`, `a` and `b` form a line
+ /// line, and `b` and `c` form a line.
+ LineStrip,
+ /// Each triplet of vertices represent a single triangle. For example, with `[a, b, c, d, e]`,
+ /// `a`, `b`, and `c` form a triangle, `d` and `e` are discarded.
+ TriangleList,
+ /// Every three consecutive vertices represent a single triangle. For example, with `[a, b, c,
+ /// d]`, `a`, `b`, and `c` form a triangle, and `b`, `c`, and `d` form a triangle.
+ TriangleStrip,
+ /// Patch list,
+ /// used with shaders capable of producing primitives on their own (tessellation)
+ PatchList(PatchSize),
+}
+
+/// All the information needed to create an input assembler.
+#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct InputAssemblerDesc {
+ /// Type of the primitive
+ pub primitive: Primitive,
+ /// When adjacency information is enabled, every even-numbered vertex
+ /// (every other starting from the first) represents an additional
+ /// vertex for the primitive, while odd-numbered vertices (every other starting from the
+ /// second) represent adjacent vertices.
+ ///
+ /// For example, with `[a, b, c, d, e, f, g, h]`, `[a, c,
+ /// e, g]` form a triangle strip, and `[b, d, f, h]` are the adjacent vertices, where `b`, `d`,
+ /// and `f` are adjacent to the first triangle in the strip, and `d`, `f`, and `h` are adjacent
+ /// to the second.
+ pub with_adjacency: bool,
+ /// Describes whether or not primitive restart is supported for
+ /// an input assembler. Primitive restart is a feature that
+ /// allows a mark to be placed in an index buffer where it is
+ /// is "broken" into multiple pieces of geometry.
+ ///
+ /// See <https://www.khronos.org/opengl/wiki/Vertex_Rendering#Primitive_Restart>
+ /// for more detail.
+ pub restart_index: Option<IndexType>,
+}
+
+impl InputAssemblerDesc {
+ /// Create a new IA descriptor without primitive restart or adjucency.
+ pub fn new(primitive: Primitive) -> Self {
+ InputAssemblerDesc {
+ primitive,
+ with_adjacency: false,
+ restart_index: None,
+ }
+ }
+}
diff --git a/third_party/rust/gfx-hal/src/pso/mod.rs b/third_party/rust/gfx-hal/src/pso/mod.rs
new file mode 100644
index 0000000000..981605baac
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/pso/mod.rs
@@ -0,0 +1,220 @@
+//! Raw Pipeline State Objects
+//!
+//! This module contains items used to create and manage Pipelines.
+
+use crate::{device, pass, Backend};
+
+mod compute;
+mod descriptor;
+mod graphics;
+mod input_assembler;
+mod output_merger;
+mod specialization;
+
+pub use self::{
+ compute::*, descriptor::*, graphics::*, input_assembler::*, output_merger::*, specialization::*,
+};
+
+/// Error types happening upon PSO creation on the device side.
+#[derive(Clone, Debug, PartialEq)]
+pub enum CreationError {
+ /// Unknown other error.
+ Other,
+ /// Unsupported pipeline on hardware or implementation. Example: mesh shaders on DirectX 11.
+ UnsupportedPipeline,
+ /// Invalid subpass (not part of renderpass).
+ InvalidSubpass(pass::SubpassId),
+ /// Shader compilation error.
+ Shader(device::ShaderError),
+ /// Out of either host or device memory.
+ OutOfMemory(device::OutOfMemory),
+}
+
+impl From<device::OutOfMemory> for CreationError {
+ fn from(err: device::OutOfMemory) -> Self {
+ CreationError::OutOfMemory(err)
+ }
+}
+
+impl std::fmt::Display for CreationError {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ CreationError::OutOfMemory(err) => write!(fmt, "Failed to create pipeline: {}", err),
+ CreationError::Other => write!(fmt, "Failed to create pipeline: Unsupported usage: Implementation specific error occurred"),
+ CreationError::UnsupportedPipeline => write!(fmt, "Failed to create pipeline: pipeline type is not supported"),
+ CreationError::InvalidSubpass(subpass) => write!(fmt, "Failed to create pipeline: Invalid subpass: {}", subpass),
+ CreationError::Shader(err) => write!(fmt, "Failed to create pipeline: {}", err),
+ }
+ }
+}
+
+impl std::error::Error for CreationError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self {
+ CreationError::OutOfMemory(err) => Some(err),
+ CreationError::Shader(err) => Some(err),
+ CreationError::InvalidSubpass(_) => None,
+ CreationError::Other => None,
+ CreationError::UnsupportedPipeline => None,
+ }
+ }
+}
+
+bitflags!(
+ /// Stages of the logical pipeline.
+ ///
+ /// The pipeline is structured by the ordering of the flags.
+ /// Some stages are queue type dependent.
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct PipelineStage: u32 {
+ /// Beginning of the command queue.
+ const TOP_OF_PIPE = 0x1;
+ /// Indirect data consumption.
+ const DRAW_INDIRECT = 0x2;
+ /// Vertex data consumption.
+ const VERTEX_INPUT = 0x4;
+ /// Vertex shader execution.
+ const VERTEX_SHADER = 0x8;
+ /// Hull shader execution.
+ const HULL_SHADER = 0x10;
+ /// Domain shader execution.
+ const DOMAIN_SHADER = 0x20;
+ /// Geometry shader execution.
+ const GEOMETRY_SHADER = 0x40;
+ /// Fragment shader execution.
+ const FRAGMENT_SHADER = 0x80;
+ /// Stage of early depth and stencil test.
+ const EARLY_FRAGMENT_TESTS = 0x100;
+ /// Stage of late depth and stencil test.
+ const LATE_FRAGMENT_TESTS = 0x200;
+ /// Stage of final color value calculation.
+ const COLOR_ATTACHMENT_OUTPUT = 0x400;
+ /// Compute shader execution,
+ const COMPUTE_SHADER = 0x800;
+ /// Copy/Transfer command execution.
+ const TRANSFER = 0x1000;
+ /// End of the command queue.
+ const BOTTOM_OF_PIPE = 0x2000;
+ /// Read/Write access from host.
+ /// (Not a real pipeline stage)
+ const HOST = 0x4000;
+ /// Task shader stage.
+ const TASK_SHADER = 0x80000;
+ /// Mesh shader stage.
+ const MESH_SHADER = 0x100000;
+ }
+);
+
+bitflags!(
+ /// Combination of different shader pipeline stages.
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ #[derive(Default)]
+ pub struct ShaderStageFlags: u32 {
+ /// Vertex shader stage.
+ const VERTEX = 0x1;
+ /// Hull (tessellation) shader stage.
+ const HULL = 0x2;
+ /// Domain (tessellation) shader stage.
+ const DOMAIN = 0x4;
+ /// Geometry shader stage.
+ const GEOMETRY = 0x8;
+ /// Fragment shader stage.
+ const FRAGMENT = 0x10;
+ /// Compute shader stage.
+ const COMPUTE = 0x20;
+ /// Task shader stage.
+ const TASK = 0x40;
+ /// Mesh shader stage.
+ const MESH = 0x80;
+ /// All graphics pipeline shader stages.
+ const GRAPHICS = Self::VERTEX.bits | Self::HULL.bits |
+ Self::DOMAIN.bits | Self::GEOMETRY.bits | Self::FRAGMENT.bits;
+ /// All shader stages (matches Vulkan).
+ const ALL = 0x7FFFFFFF;
+ }
+);
+
+/// Shader entry point.
+#[derive(Debug)]
+pub struct EntryPoint<'a, B: Backend> {
+ /// Entry point name.
+ pub entry: &'a str,
+ /// Reference to the shader module containing this entry point.
+ pub module: &'a B::ShaderModule,
+ /// Specialization constants to be used when creating the pipeline.
+ pub specialization: Specialization<'a>,
+}
+
+impl<'a, B: Backend> Clone for EntryPoint<'a, B> {
+ fn clone(&self) -> Self {
+ EntryPoint {
+ entry: self.entry,
+ module: self.module,
+ specialization: self.specialization.clone(),
+ }
+ }
+}
+
+bitflags!(
+ /// Pipeline creation flags.
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct PipelineCreationFlags: u32 {
+ /// Disable pipeline optimizations.
+ ///
+ /// May speedup pipeline creation.
+ const DISABLE_OPTIMIZATION = 0x1;
+ /// Allow derivatives (children) of the pipeline.
+ ///
+ /// Must be set when pipelines set the pipeline as base.
+ const ALLOW_DERIVATIVES = 0x2;
+ }
+);
+
+/// A reference to a parent pipeline. The assumption is that
+/// a parent and derivative/child pipeline have most settings
+/// in common, and one may be switched for another more quickly
+/// than entirely unrelated pipelines would be.
+#[derive(Debug)]
+pub enum BasePipeline<'a, P: 'a> {
+ /// Referencing an existing pipeline as parent.
+ Pipeline(&'a P),
+ /// A pipeline in the same create pipelines call.
+ ///
+ /// The index of the parent must be lower than the index of the child.
+ Index(usize),
+ /// No parent pipeline exists.
+ None,
+}
+
+/// Pipeline state which may be static or dynamic.
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum State<T> {
+ /// Static state that cannot be altered.
+ Static(T),
+ /// Dynamic state set through a command buffer.
+ Dynamic,
+}
+
+impl<T> State<T> {
+ /// Returns the static value or a default.
+ pub fn static_or(self, default: T) -> T {
+ match self {
+ State::Static(v) => v,
+ State::Dynamic => default,
+ }
+ }
+
+ /// Whether the state is static.
+ pub fn is_static(self) -> bool {
+ match self {
+ State::Static(_) => true,
+ State::Dynamic => false,
+ }
+ }
+
+ /// Whether the state is dynamic.
+ pub fn is_dynamic(self) -> bool {
+ !self.is_static()
+ }
+}
diff --git a/third_party/rust/gfx-hal/src/pso/output_merger.rs b/third_party/rust/gfx-hal/src/pso/output_merger.rs
new file mode 100644
index 0000000000..88fbc8a8b6
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/pso/output_merger.rs
@@ -0,0 +1,359 @@
+//! Output Merger (OM) stage description.
+//! The final stage in a pipeline that creates pixel colors from
+//! the input shader results, depth/stencil information, etc.
+
+use crate::pso::{graphics::StencilValue, State};
+
+/// A pixel-wise comparison function.
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum Comparison {
+ /// `false`
+ Never = 0,
+ /// `x < y`
+ Less = 1,
+ /// `x == y`
+ Equal = 2,
+ /// `x <= y`
+ LessEqual = 3,
+ /// `x > y`
+ Greater = 4,
+ /// `x != y`
+ NotEqual = 5,
+ /// `x >= y`
+ GreaterEqual = 6,
+ /// `true`
+ Always = 7,
+}
+
+bitflags!(
+ /// Target output color mask.
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct ColorMask: u8 {
+ /// Red mask
+ const RED = 0x1;
+ /// Green mask
+ const GREEN = 0x2;
+ /// Blue mask
+ const BLUE = 0x4;
+ /// Alpha channel mask
+ const ALPHA = 0x8;
+ /// Mask for RGB channels
+ const COLOR = 0x7;
+ /// Mask all channels
+ const ALL = 0xF;
+ /// Mask no channels.
+ const NONE = 0x0;
+ }
+);
+
+impl Default for ColorMask {
+ fn default() -> Self {
+ Self::ALL
+ }
+}
+
+/// Defines the possible blending factors.
+/// During blending, the source or destination fragment may be
+/// multiplied by a factor to produce the final result.
+#[allow(missing_docs)]
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum Factor {
+ Zero = 0,
+ One = 1,
+ SrcColor = 2,
+ OneMinusSrcColor = 3,
+ DstColor = 4,
+ OneMinusDstColor = 5,
+ SrcAlpha = 6,
+ OneMinusSrcAlpha = 7,
+ DstAlpha = 8,
+ OneMinusDstAlpha = 9,
+ ConstColor = 10,
+ OneMinusConstColor = 11,
+ ConstAlpha = 12,
+ OneMinusConstAlpha = 13,
+ SrcAlphaSaturate = 14,
+ Src1Color = 15,
+ OneMinusSrc1Color = 16,
+ Src1Alpha = 17,
+ OneMinusSrc1Alpha = 18,
+}
+
+/// Blending operations.
+#[allow(missing_docs)]
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum BlendOp {
+ /// Adds source and destination.
+ /// Source and destination are multiplied by factors before addition.
+ Add { src: Factor, dst: Factor },
+ /// Subtracts destination from source.
+ /// Source and destination are multiplied by factors before subtraction.
+ Sub { src: Factor, dst: Factor },
+ /// Subtracts source from destination.
+ /// Source and destination are multiplied by factors before subtraction.
+ RevSub { src: Factor, dst: Factor },
+ /// Component-wise minimum value of source and destination.
+ Min,
+ /// Component-wise maximum value of source and destination.
+ Max,
+}
+
+impl BlendOp {
+ /// Replace the destination value with the source.
+ pub const REPLACE: Self = BlendOp::Add {
+ src: Factor::One,
+ dst: Factor::Zero,
+ };
+ /// Add the source and destination together.
+ pub const ADD: Self = BlendOp::Add {
+ src: Factor::One,
+ dst: Factor::One,
+ };
+ /// Alpha blend the source and destination together.
+ pub const ALPHA: Self = BlendOp::Add {
+ src: Factor::SrcAlpha,
+ dst: Factor::OneMinusSrcAlpha,
+ };
+ /// Alpha blend a premultiplied-alpha source with the destination.
+ pub const PREMULTIPLIED_ALPHA: Self = BlendOp::Add {
+ src: Factor::One,
+ dst: Factor::OneMinusSrcAlpha,
+ };
+}
+
+/// Specifies whether to use blending, and if so,
+/// which operations to use for color and alpha channels.
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct BlendState {
+ /// The blend operation to use for the color channels.
+ pub color: BlendOp,
+ /// The blend operation to use for the alpha channel.
+ pub alpha: BlendOp,
+}
+
+impl BlendState {
+ /// Replace the color.
+ pub const REPLACE: Self = BlendState {
+ color: BlendOp::REPLACE,
+ alpha: BlendOp::REPLACE,
+ };
+ /// Additive blending.
+ pub const ADD: Self = BlendState {
+ color: BlendOp::ADD,
+ alpha: BlendOp::ADD,
+ };
+ /// Multiplicative blending.
+ pub const MULTIPLY: Self = BlendState {
+ color: BlendOp::Add {
+ src: Factor::Zero,
+ dst: Factor::SrcColor,
+ },
+ alpha: BlendOp::Add {
+ src: Factor::Zero,
+ dst: Factor::SrcAlpha,
+ },
+ };
+ /// Alpha blending.
+ pub const ALPHA: Self = BlendState {
+ color: BlendOp::ALPHA,
+ alpha: BlendOp::PREMULTIPLIED_ALPHA,
+ };
+ /// Pre-multiplied alpha blending.
+ pub const PREMULTIPLIED_ALPHA: Self = BlendState {
+ color: BlendOp::PREMULTIPLIED_ALPHA,
+ alpha: BlendOp::PREMULTIPLIED_ALPHA,
+ };
+}
+
+/// PSO color target descriptor.
+#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct ColorBlendDesc {
+ /// Color write mask.
+ pub mask: ColorMask,
+ /// Blend state, if enabled.
+ pub blend: Option<BlendState>,
+}
+
+impl ColorBlendDesc {
+ /// Empty blend descriptor just writes out the color without blending.
+ // this can be used because `Default::default()` isn't a const function...
+ pub const EMPTY: Self = ColorBlendDesc {
+ mask: ColorMask::ALL,
+ blend: None,
+ };
+}
+
+/// Depth test state.
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct DepthTest {
+ /// Comparison function to use.
+ pub fun: Comparison,
+ /// Specify whether to write to the depth buffer or not.
+ pub write: bool,
+}
+
+impl DepthTest {
+ /// A depth test that always fails.
+ pub const FAIL: Self = DepthTest {
+ fun: Comparison::Never,
+ write: false,
+ };
+ /// A depth test that always succeeds but doesn't
+ /// write to the depth buffer
+ // DOC TODO: Not a terribly helpful description there...
+ pub const PASS_TEST: Self = DepthTest {
+ fun: Comparison::Always,
+ write: false,
+ };
+ /// A depth test that always succeeds and writes its result
+ /// to the depth buffer.
+ pub const PASS_WRITE: Self = DepthTest {
+ fun: Comparison::Always,
+ write: true,
+ };
+}
+
+/// The operation to use for stencil masking.
+#[repr(u8)]
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum StencilOp {
+ /// Keep the current value in the stencil buffer (no change).
+ Keep = 0,
+ /// Set the value in the stencil buffer to zero.
+ Zero = 1,
+ /// Set the stencil buffer value to `reference` from `StencilFace`.
+ Replace = 2,
+ /// Increment the stencil buffer value, clamping to its maximum value.
+ IncrementClamp = 3,
+ /// Decrement the stencil buffer value, clamping to its minimum value.
+ DecrementClamp = 4,
+ /// Bitwise invert the current value in the stencil buffer.
+ Invert = 5,
+ /// Increment the stencil buffer value, wrapping around to 0 on overflow.
+ IncrementWrap = 6,
+ /// Decrement the stencil buffer value, wrapping around to the maximum value on overflow.
+ DecrementWrap = 7,
+}
+
+/// Complete stencil state for a given side of a face.
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct StencilFace {
+ /// Comparison function to use to determine if the stencil test passes.
+ pub fun: Comparison,
+ /// What operation to do if the stencil test fails.
+ pub op_fail: StencilOp,
+ /// What operation to do if the stencil test passes but the depth test fails.
+ pub op_depth_fail: StencilOp,
+ /// What operation to do if both the depth and stencil test pass.
+ pub op_pass: StencilOp,
+}
+
+impl Default for StencilFace {
+ fn default() -> StencilFace {
+ StencilFace {
+ fun: Comparison::Never,
+ op_fail: StencilOp::Keep,
+ op_depth_fail: StencilOp::Keep,
+ op_pass: StencilOp::Keep,
+ }
+ }
+}
+
+/// A generic struct holding the properties of two sides of a polygon.
+#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct Sided<T> {
+ /// Information about the front face.
+ pub front: T,
+ /// Information about the back face.
+ pub back: T,
+}
+
+impl<T: Copy> Sided<T> {
+ /// Create a new `Sided` structure with both `front` and `back` holding
+ /// the same value.
+ pub fn new(value: T) -> Self {
+ Sided {
+ front: value,
+ back: value,
+ }
+ }
+}
+
+/// Pair of stencil values that could be either baked into a graphics pipeline
+/// or provided dynamically.
+pub type StencilValues = State<Sided<StencilValue>>;
+
+/// Defines a stencil test. Stencil testing is an operation
+/// performed to cull fragments;
+/// the new fragment is tested against the value held in the
+/// stencil buffer, and if the test fails the fragment is
+/// discarded.
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct StencilTest {
+ /// Operations for stencil faces.
+ pub faces: Sided<StencilFace>,
+ /// Masks that are ANDd with both the stencil buffer value and the reference value when they
+ /// are read before doing the stencil test.
+ pub read_masks: StencilValues,
+ /// Mask that are ANDd with the stencil value before writing to the stencil buffer.
+ pub write_masks: StencilValues,
+ /// The reference values used for stencil tests.
+ pub reference_values: StencilValues,
+}
+
+impl Default for StencilTest {
+ fn default() -> Self {
+ StencilTest {
+ faces: Sided::default(),
+ read_masks: State::Static(Sided::new(!0)),
+ write_masks: State::Static(Sided::new(!0)),
+ reference_values: State::Static(Sided::new(0)),
+ }
+ }
+}
+
+/// PSO depth-stencil target descriptor.
+#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct DepthStencilDesc {
+ /// Optional depth testing/writing.
+ pub depth: Option<DepthTest>,
+ /// Enable depth bounds testing.
+ pub depth_bounds: bool,
+ /// Stencil test/write.
+ pub stencil: Option<StencilTest>,
+}
+
+impl DepthStencilDesc {
+ /// Returns true if the descriptor assumes the depth attachment.
+ pub fn uses_depth(&self) -> bool {
+ self.depth.is_some() || self.depth_bounds
+ }
+ /// Returns true if the descriptor assumes the stencil attachment.
+ pub fn uses_stencil(&self) -> bool {
+ self.stencil.is_some()
+ }
+}
+
+bitflags!(
+ /// Face.
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct Face: u32 {
+ /// Empty face. TODO: remove when constexpr are stabilized to use empty()
+ const NONE = 0x0;
+ /// Front face.
+ const FRONT = 0x1;
+ /// Back face.
+ const BACK = 0x2;
+ }
+);
diff --git a/third_party/rust/gfx-hal/src/pso/specialization.rs b/third_party/rust/gfx-hal/src/pso/specialization.rs
new file mode 100644
index 0000000000..d4c15c3d25
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/pso/specialization.rs
@@ -0,0 +1,134 @@
+//! Pipeline specialization types.
+
+use std::{borrow::Cow, ops::Range, slice};
+
+/// Description of a specialization constant for the pipeline.
+#[derive(Debug, Clone, Hash, PartialEq)]
+pub struct SpecializationConstant {
+ /// Constant identifier in shader source.
+ pub id: u32,
+ /// Value to override specialization constant.
+ pub range: Range<u16>,
+}
+
+/// Information required for pipeline specialization.
+///
+/// Specialization allows for easy configuration of multiple similar pipelines.
+/// For example, there may be a boolean exposed to the shader that switches
+/// the [specularity](https://en.wikipedia.org/wiki/Specularity) on/off,
+/// provided via a [specialization constant][SpecializationConstant].
+///
+/// That would produce separate PSO's for the "on" and "off" states
+/// but they share most of the internal stuff and are fast to produce.
+/// More importantly, they are fast to execute, since the driver
+/// can optimize out the branch on that other PSO creation.
+#[derive(Debug, Clone)]
+pub struct Specialization<'a> {
+ /// Array of descriptors of specialization constants to override.
+ pub constants: Cow<'a, [SpecializationConstant]>,
+ /// Raw data of the specialization constants
+ pub data: Cow<'a, [u8]>,
+}
+
+impl Specialization<'_> {
+ /// Empty specialization instance.
+ pub const EMPTY: Self = Specialization {
+ constants: Cow::Borrowed(&[]),
+ data: Cow::Borrowed(&[]),
+ };
+}
+
+impl Default for Specialization<'_> {
+ fn default() -> Self {
+ Specialization::EMPTY
+ }
+}
+
+#[doc(hidden)]
+#[derive(Debug, Default)]
+pub struct SpecializationStorage {
+ constants: Vec<SpecializationConstant>,
+ data: Vec<u8>,
+}
+
+/// List of specialization constants.
+#[doc(hidden)]
+pub trait SpecConstList: Sized {
+ fn fold(self, storage: &mut SpecializationStorage);
+}
+
+impl<T> From<T> for Specialization<'_>
+where
+ T: SpecConstList,
+{
+ fn from(list: T) -> Self {
+ let mut storage = SpecializationStorage::default();
+ list.fold(&mut storage);
+ Specialization {
+ data: Cow::Owned(storage.data),
+ constants: Cow::Owned(storage.constants),
+ }
+ }
+}
+
+#[doc(hidden)]
+#[derive(Debug)]
+pub struct SpecConstListNil;
+
+#[doc(hidden)]
+#[derive(Debug)]
+pub struct SpecConstListCons<H, T> {
+ pub head: (u32, H),
+ pub tail: T,
+}
+
+impl SpecConstList for SpecConstListNil {
+ fn fold(self, _storage: &mut SpecializationStorage) {}
+}
+
+impl<H, T> SpecConstList for SpecConstListCons<H, T>
+where
+ T: SpecConstList,
+{
+ fn fold(self, storage: &mut SpecializationStorage) {
+ let size = std::mem::size_of::<H>();
+ assert!(storage.data.len() + size <= u16::max_value() as usize);
+ let offset = storage.data.len() as u16;
+ storage.data.extend_from_slice(unsafe {
+ // Inspecting bytes is always safe.
+ let head_ptr: *const H = &self.head.1;
+ slice::from_raw_parts(head_ptr as *const u8, size)
+ });
+ storage.constants.push(SpecializationConstant {
+ id: self.head.0,
+ range: offset..offset + size as u16,
+ });
+ self.tail.fold(storage)
+ }
+}
+
+/// Macro for specifying list of specialization constants for `EntryPoint`.
+#[macro_export]
+macro_rules! spec_const_list {
+ (@ $(,)?) => {
+ $crate::pso::SpecConstListNil
+ };
+
+ (@ $head_id:expr => $head_constant:expr $(,$tail_id:expr => $tail_constant:expr)* $(,)?) => {
+ $crate::pso::SpecConstListCons {
+ head: ($head_id, $head_constant),
+ tail: $crate::spec_const_list!(@ $($tail_id => $tail_constant),*),
+ }
+ };
+
+ ($($id:expr => $constant:expr),* $(,)?) => {
+ $crate::spec_const_list!(@ $($id => $constant),*).into()
+ };
+
+ ($($constant:expr),* $(,)?) => {
+ {
+ let mut counter = 0;
+ $crate::spec_const_list!(@ $({ counter += 1; counter - 1 } => $constant),*).into()
+ }
+ };
+}
diff --git a/third_party/rust/gfx-hal/src/query.rs b/third_party/rust/gfx-hal/src/query.rs
new file mode 100644
index 0000000000..66023361b4
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/query.rs
@@ -0,0 +1,119 @@
+//! Commands that can be used to record statistics or other useful values
+//! as the command buffer is running.
+//!
+//! They are often intended for profiling or other introspection,
+//! providing a mechanism for the command buffer to record data about its operation
+//! as it is running.
+
+use crate::device::OutOfMemory;
+use crate::Backend;
+
+/// A query identifier.
+pub type Id = u32;
+
+/// Query creation error.
+#[derive(Clone, Debug, PartialEq)]
+pub enum CreationError {
+ /// Out of either host or device memory.
+ OutOfMemory(OutOfMemory),
+
+ /// Query type unsupported.
+ Unsupported(Type),
+}
+
+impl From<OutOfMemory> for CreationError {
+ fn from(error: OutOfMemory) -> Self {
+ CreationError::OutOfMemory(error)
+ }
+}
+
+impl std::fmt::Display for CreationError {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ CreationError::OutOfMemory(err) => write!(fmt, "Failed to create query: {}", err),
+ CreationError::Unsupported(ty) => {
+ write!(fmt, "Failed to create query: Unsupported type: {:?}", ty)
+ }
+ }
+ }
+}
+
+/// A `Query` object has a particular identifier and saves its results to a given `QueryPool`.
+/// It is passed as a parameter to the command buffer's query methods.
+#[derive(Debug)]
+pub struct Query<'a, B: Backend> {
+ ///
+ pub pool: &'a B::QueryPool,
+ ///
+ pub id: Id,
+}
+
+bitflags!(
+ /// Query control flags.
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct ControlFlags: u32 {
+ /// Occlusion queries **must** return the exact sampler number.
+ ///
+ /// Requires `precise_occlusion_query` device feature.
+ const PRECISE = 0x1;
+ }
+);
+
+bitflags!(
+ /// Query result flags.
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct ResultFlags: u32 {
+ /// Results will be written as an array of 64-bit unsigned integer values.
+ const BITS_64 = 0x1;
+ /// Wait for each query’s status to become available before retrieving its results.
+ const WAIT = 0x2;
+ /// Availability status accompanies the results.
+ const WITH_AVAILABILITY = 0x4;
+ /// Returning partial results is acceptable.
+ const PARTIAL = 0x8;
+ }
+);
+
+/// Type of queries in a query pool.
+#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
+pub enum Type {
+ /// Occlusion query. Count the number of drawn samples between
+ /// the start and end of the query command.
+ Occlusion,
+ /// Pipeline statistic query. Counts the number of pipeline stage
+ /// invocations of the given types between the start and end of
+ /// the query command.
+ PipelineStatistics(PipelineStatistic),
+ /// Timestamp query. Timestamps can be recorded to the
+ /// query pool by calling `write_timestamp()`.
+ Timestamp,
+}
+
+bitflags!(
+ /// Pipeline statistic flags
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct PipelineStatistic: u32 {
+ ///
+ const INPUT_ASSEMBLY_VERTICES = 0x1;
+ ///
+ const INPUT_ASSEMBLY_PRIMITIVES = 0x2;
+ ///
+ const VERTEX_SHADER_INVOCATIONS = 0x4;
+ ///
+ const GEOMETRY_SHADER_INVOCATIONS = 0x8;
+ ///
+ const GEOMETRY_SHADER_PRIMITIVES = 0x10;
+ ///
+ const CLIPPING_INVOCATIONS = 0x20;
+ ///
+ const CLIPPING_PRIMITIVES = 0x40;
+ ///
+ const FRAGMENT_SHADER_INVOCATIONS = 0x80;
+ ///
+ const HULL_SHADER_PATCHES = 0x100;
+ ///
+ const DOMAIN_SHADER_INVOCATIONS = 0x200;
+ ///
+ const COMPUTE_SHADER_INVOCATIONS = 0x400;
+ }
+);
diff --git a/third_party/rust/gfx-hal/src/queue/family.rs b/third_party/rust/gfx-hal/src/queue/family.rs
new file mode 100644
index 0000000000..765e54d64c
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/queue/family.rs
@@ -0,0 +1,55 @@
+//! Queue family and groups.
+
+use crate::queue::QueueType;
+use crate::Backend;
+
+use std::any::Any;
+use std::fmt::Debug;
+
+/// General information about a queue family, available upon adapter discovery.
+///
+/// Note that a backend can expose multiple queue families with the same properties.
+///
+/// Can be obtained from an [adapter][crate::adapter::Adapter] through its
+/// [`queue_families`][crate::adapter::Adapter::queue_families] field.
+pub trait QueueFamily: Debug + Any + Send + Sync {
+ /// Returns the type of queues.
+ fn queue_type(&self) -> QueueType;
+ /// Returns maximum number of queues created from this family.
+ fn max_queues(&self) -> usize;
+ /// Returns the queue family ID.
+ fn id(&self) -> QueueFamilyId;
+}
+
+/// Identifier for a queue family of a physical device.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct QueueFamilyId(pub usize);
+
+/// Bare-metal queue group.
+///
+/// Denotes all queues created from one queue family.
+#[derive(Debug)]
+pub struct QueueGroup<B: Backend> {
+ /// Family index for the queues in this group.
+ pub family: QueueFamilyId,
+ /// List of queues.
+ pub queues: Vec<B::CommandQueue>,
+}
+
+impl<B: Backend> QueueGroup<B> {
+ /// Create a new, empty queue group for a queue family.
+ pub fn new(family: QueueFamilyId) -> Self {
+ QueueGroup {
+ family,
+ queues: Vec::new(),
+ }
+ }
+
+ /// Add a command queue to the group.
+ ///
+ /// The queue needs to be created from this queue family.
+ pub fn add_queue(&mut self, queue: B::CommandQueue) {
+ self.queues.push(queue);
+ }
+}
diff --git a/third_party/rust/gfx-hal/src/queue/mod.rs b/third_party/rust/gfx-hal/src/queue/mod.rs
new file mode 100644
index 0000000000..f913664b5f
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/queue/mod.rs
@@ -0,0 +1,139 @@
+//! Command queues.
+//!
+//! Queues are the execution paths of the graphical processing units. These process
+//! submitted commands buffers.
+//!
+//! There are different types of queues, which can only handle associated command buffers.
+//! `CommandQueue<B, C>` has the capability defined by `C`: graphics, compute and transfer.
+
+pub mod family;
+
+use crate::{
+ device::OutOfMemory,
+ pso,
+ window::{PresentError, PresentationSurface, Suboptimal},
+ Backend,
+};
+use std::{any::Any, borrow::Borrow, fmt, iter};
+
+pub use self::family::{QueueFamily, QueueFamilyId, QueueGroup};
+
+/// The type of the queue, an enum encompassing `queue::Capability`
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub enum QueueType {
+ /// Supports all operations.
+ General,
+ /// Only supports graphics and transfer operations.
+ Graphics,
+ /// Only supports compute and transfer operations.
+ Compute,
+ /// Only supports transfer operations.
+ Transfer,
+}
+
+impl QueueType {
+ /// Returns true if the queue supports graphics operations.
+ pub fn supports_graphics(&self) -> bool {
+ match *self {
+ QueueType::General | QueueType::Graphics => true,
+ QueueType::Compute | QueueType::Transfer => false,
+ }
+ }
+ /// Returns true if the queue supports compute operations.
+ pub fn supports_compute(&self) -> bool {
+ match *self {
+ QueueType::General | QueueType::Graphics | QueueType::Compute => true,
+ QueueType::Transfer => false,
+ }
+ }
+ /// Returns true if the queue supports transfer operations.
+ pub fn supports_transfer(&self) -> bool {
+ true
+ }
+}
+
+/// Scheduling hint for devices about the priority of a queue. Values range from `0.0` (low) to
+/// `1.0` (high).
+pub type QueuePriority = f32;
+
+/// Submission information for a [command queue][CommandQueue].
+///
+/// The submission is sent to the device through the [`submit`][CommandQueue::submit] method.
+#[derive(Debug)]
+pub struct Submission<Ic, Iw, Is> {
+ /// Command buffers to submit.
+ pub command_buffers: Ic,
+ /// Semaphores to wait being signalled before submission.
+ pub wait_semaphores: Iw,
+ /// Semaphores to signal after all command buffers in the submission have finished execution.
+ pub signal_semaphores: Is,
+}
+
+/// Abstraction for an internal GPU execution engine.
+///
+/// Commands are executed on the the device by submitting
+/// [command buffers][crate::command::CommandBuffer].
+///
+/// Queues can also be used for presenting to a surface
+/// (that is, flip the front buffer with the next one in the chain).
+pub trait CommandQueue<B: Backend>: fmt::Debug + Any + Send + Sync {
+ /// Submit command buffers to queue for execution.
+ ///
+ /// # Arguments
+ ///
+ /// * `submission` - information about which command buffers to submit,
+ /// as well as what semaphores to wait for or to signal when done.
+ /// * `fence` - must be in unsignaled state, and will be signaled after
+ /// all command buffers in the submission have finished execution.
+ ///
+ /// # Safety
+ ///
+ /// It's not checked that the queue can process the submitted command buffers.
+ ///
+ /// For example, trying to submit compute commands to a graphics queue
+ /// will result in undefined behavior.
+ unsafe fn submit<'a, T, Ic, S, Iw, Is>(
+ &mut self,
+ submission: Submission<Ic, Iw, Is>,
+ fence: Option<&B::Fence>,
+ ) where
+ T: 'a + Borrow<B::CommandBuffer>,
+ Ic: IntoIterator<Item = &'a T>,
+ S: 'a + Borrow<B::Semaphore>,
+ Iw: IntoIterator<Item = (&'a S, pso::PipelineStage)>,
+ Is: IntoIterator<Item = &'a S>;
+
+ /// Simplified version of `submit` that doesn't expect any semaphores.
+ unsafe fn submit_without_semaphores<'a, T, Ic>(
+ &mut self,
+ command_buffers: Ic,
+ fence: Option<&B::Fence>,
+ ) where
+ T: 'a + Borrow<B::CommandBuffer>,
+ Ic: IntoIterator<Item = &'a T>,
+ {
+ let submission = Submission {
+ command_buffers,
+ wait_semaphores: iter::empty(),
+ signal_semaphores: iter::empty(),
+ };
+ self.submit::<_, _, B::Semaphore, _, _>(submission, fence)
+ }
+
+ /// Present a swapchain image directly to a surface, after waiting on `wait_semaphore`.
+ ///
+ /// # Safety
+ ///
+ /// Unsafe for the same reasons as [`submit`][CommandQueue::submit].
+ /// No checks are performed to verify that this queue supports present operations.
+ unsafe fn present(
+ &mut self,
+ surface: &mut B::Surface,
+ image: <B::Surface as PresentationSurface<B>>::SwapchainImage,
+ wait_semaphore: Option<&B::Semaphore>,
+ ) -> Result<Option<Suboptimal>, PresentError>;
+
+ /// Wait for the queue to be idle.
+ fn wait_idle(&self) -> Result<(), OutOfMemory>;
+}
diff --git a/third_party/rust/gfx-hal/src/window.rs b/third_party/rust/gfx-hal/src/window.rs
new file mode 100644
index 0000000000..b0bc6801e7
--- /dev/null
+++ b/third_party/rust/gfx-hal/src/window.rs
@@ -0,0 +1,563 @@
+//! Windowing system interoperability.
+//!
+//! Screen presentation (fullscreen or window) of images requires two objects:
+//!
+//! * [Surface][Surface] is an abstraction of a native screen or window, for graphics use.
+//! * [Swapchain][Swapchain] is a chain of multiple images, which can be presented on
+//! a surface.
+//!
+//! ## Window
+//!
+//! `gfx-hal` does not provide any methods for creating a native window or screen.
+//! This is handled exeternally, either by managing your own window or by using a
+//! library such as [winit](https://github.com/rust-windowing/winit), and providing
+//! the [raw window handle](https://github.com/rust-windowing/raw-window-handle).
+//!
+//! ## Surface
+//!
+//! Once you have a window handle, you need to [create a surface][crate::Instance::create_surface]
+//! compatible with the [instance][crate::Instance] of the graphics API you currently use.
+//!
+//! ## PresentationSurface
+//!
+//! A surface has an implicit swapchain in it.
+//!
+//! The most interesting part of a swapchain are the contained presentable images/backbuffers.
+//! Presentable images are specialized images, which can be presented on the screen. They are
+//! 2D color images with optionally associated depth-stencil images.
+//!
+//! The common steps for presentation of a frame are acquisition and presentation:
+//!
+//! ```no_run
+//! # extern crate gfx_backend_empty as empty;
+//! # extern crate gfx_hal;
+//! # fn main() {
+//! # use gfx_hal::prelude::*;
+//!
+//! # let mut surface: empty::Surface = return;
+//! # let device: empty::Device = return;
+//! # let mut present_queue: empty::CommandQueue = return;
+//! # unsafe {
+//! let render_semaphore = device.create_semaphore().unwrap();
+//!
+//! let (frame, suboptimal) = surface.acquire_image(!0).unwrap();
+//! // render the scene..
+//! // `render_semaphore` will be signalled once rendering has been finished
+//! present_queue.present(&mut surface, frame, Some(&render_semaphore));
+//! # }}
+//! ```
+//!
+//! Queues need to synchronize with the presentation engine, usually done via signalling a semaphore
+//! once a frame is available for rendering and waiting on a separate semaphore until scene rendering
+//! has finished.
+//!
+//! ### Recreation
+//!
+//! DOC TODO
+
+use crate::{device, format::Format, image, Backend};
+
+use std::{
+ any::Any,
+ borrow::Borrow,
+ cmp::{max, min},
+ fmt,
+ ops::RangeInclusive,
+};
+
+/// Default image usage for the swapchain.
+pub const DEFAULT_USAGE: image::Usage = image::Usage::COLOR_ATTACHMENT;
+/// Default image count for the swapchain.
+pub const DEFAULT_IMAGE_COUNT: SwapImageIndex = 3;
+
+/// Error occurred during swapchain creation.
+#[derive(Clone, Debug, PartialEq)]
+pub enum CreationError {
+ /// Out of either host or device memory.
+ OutOfMemory(device::OutOfMemory),
+ /// Device is lost
+ DeviceLost(device::DeviceLost),
+ /// Surface is lost
+ SurfaceLost(device::SurfaceLost),
+ /// Window in use
+ WindowInUse(device::WindowInUse),
+}
+
+impl From<device::OutOfMemory> for CreationError {
+ fn from(error: device::OutOfMemory) -> Self {
+ CreationError::OutOfMemory(error)
+ }
+}
+
+impl From<device::DeviceLost> for CreationError {
+ fn from(error: device::DeviceLost) -> Self {
+ CreationError::DeviceLost(error)
+ }
+}
+
+impl From<device::SurfaceLost> for CreationError {
+ fn from(error: device::SurfaceLost) -> Self {
+ CreationError::SurfaceLost(error)
+ }
+}
+
+impl From<device::WindowInUse> for CreationError {
+ fn from(error: device::WindowInUse) -> Self {
+ CreationError::WindowInUse(error)
+ }
+}
+
+impl std::fmt::Display for CreationError {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ CreationError::OutOfMemory(err) => {
+ write!(fmt, "Failed to create or configure swapchain: {}", err)
+ }
+ CreationError::DeviceLost(err) => {
+ write!(fmt, "Failed to create or configure swapchain: {}", err)
+ }
+ CreationError::SurfaceLost(err) => {
+ write!(fmt, "Failed to create or configure swapchain: {}", err)
+ }
+ CreationError::WindowInUse(err) => {
+ write!(fmt, "Failed to create or configure swapchain: {}", err)
+ }
+ }
+ }
+}
+
+impl std::error::Error for CreationError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self {
+ CreationError::OutOfMemory(err) => Some(err),
+ CreationError::DeviceLost(err) => Some(err),
+ CreationError::SurfaceLost(err) => Some(err),
+ CreationError::WindowInUse(err) => Some(err),
+ }
+ }
+}
+
+/// An extent describes the size of a rectangle, such as
+/// a window or texture. It is not used for referring to a
+/// sub-rectangle; for that see `command::Rect`.
+#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct Extent2D {
+ /// Width
+ pub width: image::Size,
+ /// Height
+ pub height: image::Size,
+}
+
+impl From<image::Extent> for Extent2D {
+ fn from(ex: image::Extent) -> Self {
+ Extent2D {
+ width: ex.width,
+ height: ex.height,
+ }
+ }
+}
+
+impl Extent2D {
+ /// Convert into a regular image extent.
+ pub fn to_extent(&self) -> image::Extent {
+ image::Extent {
+ width: self.width,
+ height: self.height,
+ depth: 1,
+ }
+ }
+}
+
+/// Describes information about what a `Surface`'s properties are.
+/// Fetch this with [Surface::capabilities].
+#[derive(Debug, Clone)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+pub struct SurfaceCapabilities {
+ /// Number of presentable images supported by the adapter for a swapchain
+ /// created from this surface.
+ ///
+ /// - `image_count.start` must be at least 1.
+ /// - `image_count.end` must be larger or equal to `image_count.start`.
+ pub image_count: RangeInclusive<SwapImageIndex>,
+
+ /// Current extent of the surface.
+ ///
+ /// `None` if the surface has no explicit size, depending on the swapchain extent.
+ pub current_extent: Option<Extent2D>,
+
+ /// Range of supported extents.
+ ///
+ /// `current_extent` must be inside this range.
+ pub extents: RangeInclusive<Extent2D>,
+
+ /// Maximum number of layers supported for presentable images.
+ ///
+ /// Must be at least 1.
+ pub max_image_layers: image::Layer,
+
+ /// Supported image usage flags.
+ pub usage: image::Usage,
+
+ /// A bitmask of supported presentation modes.
+ pub present_modes: PresentMode,
+
+ /// A bitmask of supported alpha composition modes.
+ pub composite_alpha_modes: CompositeAlphaMode,
+}
+
+impl SurfaceCapabilities {
+ fn clamped_extent(&self, default_extent: Extent2D) -> Extent2D {
+ match self.current_extent {
+ Some(current) => current,
+ None => {
+ let (min_width, max_width) = (self.extents.start().width, self.extents.end().width);
+ let (min_height, max_height) =
+ (self.extents.start().height, self.extents.end().height);
+
+ // clamp the default_extent to within the allowed surface sizes
+ let width = min(max_width, max(default_extent.width, min_width));
+ let height = min(max_height, max(default_extent.height, min_height));
+
+ Extent2D { width, height }
+ }
+ }
+ }
+}
+
+/// A `Surface` abstracts the surface of a native window.
+pub trait Surface<B: Backend>: fmt::Debug + Any + Send + Sync {
+ /// Check if the queue family supports presentation to this surface.
+ fn supports_queue_family(&self, family: &B::QueueFamily) -> bool;
+
+ /// Query surface capabilities for this physical device.
+ ///
+ /// Use this function for configuring swapchain creation.
+ fn capabilities(&self, physical_device: &B::PhysicalDevice) -> SurfaceCapabilities;
+
+ /// Query surface formats for this physical device.
+ ///
+ /// This function may be slow. It's typically used during the initialization only.
+ ///
+ /// Note: technically the surface support formats may change at the point
+ /// where an application needs to recreate the swapchain, e.g. when the window
+ /// is moved to a different monitor.
+ ///
+ /// If `None` is returned then the surface has no preferred format and the
+ /// application may use any desired format.
+ fn supported_formats(&self, physical_device: &B::PhysicalDevice) -> Option<Vec<Format>>;
+}
+
+/// A surface trait that exposes the ability to present images on the
+/// associtated swap chain.
+pub trait PresentationSurface<B: Backend>: Surface<B> {
+ /// An opaque type wrapping the swapchain image.
+ type SwapchainImage: Borrow<B::Image> + Borrow<B::ImageView> + fmt::Debug + Send + Sync;
+
+ /// Set up the swapchain associated with the surface to have the given format.
+ unsafe fn configure_swapchain(
+ &mut self,
+ device: &B::Device,
+ config: SwapchainConfig,
+ ) -> Result<(), CreationError>;
+
+ /// Remove the associated swapchain from this surface.
+ ///
+ /// This has to be done before the surface is dropped.
+ unsafe fn unconfigure_swapchain(&mut self, device: &B::Device);
+
+ /// Acquire a new swapchain image for rendering.
+ ///
+ /// May fail according to one of the reasons indicated in `AcquireError` enum.
+ ///
+ /// # Synchronization
+ ///
+ /// The acquired image is available to render. No synchronization is required.
+ unsafe fn acquire_image(
+ &mut self,
+ timeout_ns: u64,
+ ) -> Result<(Self::SwapchainImage, Option<Suboptimal>), AcquireError>;
+}
+
+/// Index of an image in the swapchain.
+///
+/// The swapchain is a series of one or more images, usually
+/// with one being drawn on while the other is displayed by
+/// the GPU (aka double-buffering). A `SwapImageIndex` refers
+/// to a particular image in the swapchain.
+pub type SwapImageIndex = u32;
+
+bitflags!(
+ /// Specifies the mode regulating how a swapchain presents frames.
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct PresentMode: u32 {
+ /// Don't ever wait for v-sync.
+ const IMMEDIATE = 0x1;
+ /// Wait for v-sync, overwrite the last rendered frame.
+ const MAILBOX = 0x2;
+ /// Present frames in the same order they are rendered.
+ const FIFO = 0x4;
+ /// Don't wait for the next v-sync if we just missed it.
+ const RELAXED = 0x8;
+ }
+);
+
+bitflags!(
+ /// Specifies how the alpha channel of the images should be handled during
+ /// compositing.
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+ pub struct CompositeAlphaMode: u32 {
+ /// The alpha channel, if it exists, of the images is ignored in the
+ /// compositing process. Instead, the image is treated as if it has a
+ /// constant alpha of 1.0.
+ const OPAQUE = 0x1;
+ /// The alpha channel, if it exists, of the images is respected in the
+ /// compositing process. The non-alpha channels of the image are
+ /// expected to already be multiplied by the alpha channel by the
+ /// application.
+ const PREMULTIPLIED = 0x2;
+ /// The alpha channel, if it exists, of the images is respected in the
+ /// compositing process. The non-alpha channels of the image are not
+ /// expected to already be multiplied by the alpha channel by the
+ /// application; instead, the compositor will multiply the non-alpha
+ /// channels of the image by the alpha channel during compositing.
+ const POSTMULTIPLIED = 0x4;
+ /// The way in which the presentation engine treats the alpha channel in
+ /// the images is unknown to gfx-hal. Instead, the application is
+ /// responsible for setting the composite alpha blending mode using
+ /// native window system commands. If the application does not set the
+ /// blending mode using native window system commands, then a
+ /// platform-specific default will be used.
+ const INHERIT = 0x8;
+ }
+);
+
+/// Contains all the data necessary to create a new `Swapchain`:
+/// color, depth, and number of images.
+///
+/// # Examples
+///
+/// This type implements the builder pattern, method calls can be
+/// easily chained.
+///
+/// ```no_run
+/// # extern crate gfx_hal;
+/// # fn main() {
+/// # use gfx_hal::window::SwapchainConfig;
+/// # use gfx_hal::format::Format;
+/// let config = SwapchainConfig::new(100, 100, Format::Bgra8Unorm, 2);
+/// # }
+/// ```
+#[derive(Debug, Clone)]
+pub struct SwapchainConfig {
+ /// Presentation mode.
+ pub present_mode: PresentMode,
+ /// Alpha composition mode.
+ pub composite_alpha_mode: CompositeAlphaMode,
+ /// Format of the backbuffer images.
+ pub format: Format,
+ /// Requested image extent. Must be in
+ /// `SurfaceCapabilities::extents` range.
+ pub extent: Extent2D,
+ /// Number of images in the swapchain. Must be in
+ /// `SurfaceCapabilities::image_count` range.
+ pub image_count: SwapImageIndex,
+ /// Number of image layers. Must be lower or equal to
+ /// `SurfaceCapabilities::max_image_layers`.
+ pub image_layers: image::Layer,
+ /// Image usage of the backbuffer images.
+ pub image_usage: image::Usage,
+}
+
+impl SwapchainConfig {
+ /// Create a new default configuration (color images only).
+ pub fn new(width: u32, height: u32, format: Format, image_count: SwapImageIndex) -> Self {
+ SwapchainConfig {
+ present_mode: PresentMode::FIFO,
+ composite_alpha_mode: CompositeAlphaMode::OPAQUE,
+ format,
+ extent: Extent2D { width, height },
+ image_count,
+ image_layers: 1,
+ image_usage: DEFAULT_USAGE,
+ }
+ }
+
+ /// Create a swapchain configuration based on the capabilities
+ /// returned from a physical device query. If the surface does not
+ /// specify a current size, default_extent is clamped and used instead.
+ ///
+ /// The default values are taken from `DEFAULT_USAGE` and `DEFAULT_IMAGE_COUNT`.
+ pub fn from_caps(caps: &SurfaceCapabilities, format: Format, default_extent: Extent2D) -> Self {
+ let composite_alpha_mode = if caps
+ .composite_alpha_modes
+ .contains(CompositeAlphaMode::INHERIT)
+ {
+ CompositeAlphaMode::INHERIT
+ } else if caps
+ .composite_alpha_modes
+ .contains(CompositeAlphaMode::OPAQUE)
+ {
+ CompositeAlphaMode::OPAQUE
+ } else {
+ panic!("neither INHERIT or OPAQUE CompositeAlphaMode(s) are supported")
+ };
+ let present_mode = if caps.present_modes.contains(PresentMode::MAILBOX) {
+ PresentMode::MAILBOX
+ } else if caps.present_modes.contains(PresentMode::FIFO) {
+ PresentMode::FIFO
+ } else {
+ panic!("FIFO PresentMode is not supported")
+ };
+
+ SwapchainConfig {
+ present_mode,
+ composite_alpha_mode,
+ format,
+ extent: caps.clamped_extent(default_extent),
+ image_count: DEFAULT_IMAGE_COUNT
+ .max(*caps.image_count.start())
+ .min(*caps.image_count.end()),
+ image_layers: 1,
+ image_usage: DEFAULT_USAGE,
+ }
+ }
+
+ /// Specify the presentation mode.
+ pub fn with_present_mode(mut self, mode: PresentMode) -> Self {
+ self.present_mode = mode;
+ self
+ }
+
+ /// Specify the presentation mode.
+ pub fn with_composite_alpha_mode(mut self, mode: CompositeAlphaMode) -> Self {
+ self.composite_alpha_mode = mode;
+ self
+ }
+
+ /// Specify the usage of backbuffer images.
+ pub fn with_image_usage(mut self, usage: image::Usage) -> Self {
+ self.image_usage = usage;
+ self
+ }
+
+ /// Specify the count of backbuffer image.
+ pub fn with_image_count(mut self, count: SwapImageIndex) -> Self {
+ self.image_count = count;
+ self
+ }
+
+ // TODO: depth-only, stencil-only, swapchain size, present modes, etc.
+}
+
+/// Marker value returned if the swapchain no longer matches the surface properties exactly,
+/// but can still be used to present to the surface successfully.
+#[derive(Debug)]
+pub struct Suboptimal;
+
+/// Error on acquiring the next image from a swapchain.
+#[derive(Clone, Debug, PartialEq)]
+pub enum AcquireError {
+ /// Out of either host or device memory.
+ OutOfMemory(device::OutOfMemory),
+ /// No image was ready and no timeout was specified.
+ NotReady,
+ /// No image was ready after the specified timeout expired.
+ Timeout,
+ /// The swapchain is no longer in sync with the surface, needs to be re-created.
+ OutOfDate,
+ /// The surface was lost, and the swapchain is no longer usable.
+ SurfaceLost(device::SurfaceLost),
+ /// Device is lost
+ DeviceLost(device::DeviceLost),
+}
+
+impl std::fmt::Display for AcquireError {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ AcquireError::OutOfMemory(err) => write!(fmt, "Failed to acqure image: {}", err),
+ AcquireError::NotReady => write!(
+ fmt,
+ "Failed to acqure image: No image ready (timeout wasn't specified)"
+ ),
+ AcquireError::Timeout => {
+ write!(fmt, "Failed to acqure image: No image ready (timeout)")
+ }
+ AcquireError::OutOfDate => write!(
+ fmt,
+ "Failed to acqure image: Swapchain is out of date and needs to be re-created"
+ ),
+ AcquireError::SurfaceLost(err) => write!(fmt, "Failed to acqure image: {}", err),
+ AcquireError::DeviceLost(err) => write!(fmt, "Failed to acqure image: {}", err),
+ }
+ }
+}
+
+impl std::error::Error for AcquireError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self {
+ AcquireError::OutOfMemory(err) => Some(err),
+ AcquireError::SurfaceLost(err) => Some(err),
+ AcquireError::DeviceLost(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+/// Error on acquiring the next image from a swapchain.
+#[derive(Clone, Debug, PartialEq)]
+pub enum PresentError {
+ /// Out of either host or device memory.
+ OutOfMemory(device::OutOfMemory),
+ /// The swapchain is no longer in sync with the surface, needs to be re-created.
+ OutOfDate,
+ /// The surface was lost, and the swapchain is no longer usable.
+ SurfaceLost(device::SurfaceLost),
+ /// Device is lost
+ DeviceLost(device::DeviceLost),
+}
+
+impl std::fmt::Display for PresentError {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ PresentError::OutOfMemory(err) => write!(fmt, "Failed to present image: {}", err),
+ PresentError::OutOfDate => write!(
+ fmt,
+ "Failed to present image: Swapchain is out of date and needs to be re-created"
+ ),
+ PresentError::SurfaceLost(err) => write!(fmt, "Failed to present image: {}", err),
+ PresentError::DeviceLost(err) => write!(fmt, "Failed to present image: {}", err),
+ }
+ }
+}
+
+impl std::error::Error for PresentError {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self {
+ PresentError::OutOfMemory(err) => Some(err),
+ PresentError::SurfaceLost(err) => Some(err),
+ PresentError::DeviceLost(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+/// Error occurred during surface creation.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum InitError {
+ /// Window handle is not supported by the backend.
+ UnsupportedWindowHandle,
+}
+
+impl std::fmt::Display for InitError {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ InitError::UnsupportedWindowHandle => write!(
+ fmt,
+ "Failed to create surface: Specified window handle is unsupported"
+ ),
+ }
+ }
+}
+
+impl std::error::Error for InitError {}