blade_graphics/
lib.rs

1#![allow(
2    // We don't use syntax sugar where it's not necessary.
3    clippy::match_like_matches_macro,
4    // Redundant matching is more explicit.
5    clippy::redundant_pattern_matching,
6    // Explicit lifetimes are often easier to reason about.
7    clippy::needless_lifetimes,
8    // No need for defaults in the internal types.
9    clippy::new_without_default,
10    // Matches are good and extendable, no need to make an exception here.
11    clippy::single_match,
12    // Push commands are more regular than macros.
13    clippy::vec_init_then_push,
14    // This is the land of unsafe.
15    clippy::missing_safety_doc,
16)]
17#![warn(
18    trivial_numeric_casts,
19    unused_extern_crates,
20    //TODO: re-enable. Currently doesn't like "mem::size_of" on newer Rust
21    //unused_qualifications,
22    // We don't match on a reference, unless required.
23    clippy::pattern_type_mismatch,
24)]
25
26pub use naga::{back::PipelineConstants, StorageAccess, VectorSize};
27pub type Transform = mint::RowMatrix3x4<f32>;
28
29pub const IDENTITY_TRANSFORM: Transform = mint::RowMatrix3x4 {
30    x: mint::Vector4 {
31        x: 1.0,
32        y: 0.0,
33        z: 0.0,
34        w: 0.0,
35    },
36    y: mint::Vector4 {
37        x: 0.0,
38        y: 1.0,
39        z: 0.0,
40        w: 0.0,
41    },
42    z: mint::Vector4 {
43        x: 0.0,
44        y: 0.0,
45        z: 1.0,
46        w: 0.0,
47    },
48};
49
50pub mod derive;
51#[cfg_attr(
52    all(not(vulkan), not(gles), any(target_os = "ios", target_os = "macos")),
53    path = "metal/mod.rs"
54)]
55#[cfg_attr(
56    all(
57        not(gles),
58        any(
59            vulkan,
60            windows,
61            target_os = "linux",
62            target_os = "android",
63            target_os = "freebsd"
64        )
65    ),
66    path = "vulkan/mod.rs"
67)]
68#[cfg_attr(any(gles, target_arch = "wasm32"), path = "gles/mod.rs")]
69mod hal;
70mod shader;
71pub mod traits;
72pub mod util;
73pub mod limits {
74    /// Max number of passes inside a command encoder.
75    pub const PASS_COUNT: usize = 100;
76    /// Max plain data size for a pipeline.
77    pub const PLAIN_DATA_SIZE: u32 = 256;
78    /// Max number of resources in a bind group.
79    pub const RESOURCES_IN_GROUP: u32 = 8;
80    /// Min storage buffer alignment.
81    pub const STORAGE_BUFFER_ALIGNMENT: u64 = 16;
82    /// Min acceleration structure scratch buffer alignment.
83    pub const ACCELERATION_STRUCTURE_SCRATCH_ALIGNMENT: u64 = 256;
84}
85
86pub use hal::*;
87
88#[cfg(target_arch = "wasm32")]
89pub const CANVAS_ID: &str = "blade";
90
91use std::{fmt, num::NonZeroU32};
92
93#[derive(Clone, Debug, Default)]
94pub struct ContextDesc {
95    /// Ability to present contents to a window.
96    pub presentation: bool,
97    /// Enable validation of the GAPI, shaders,
98    /// and insert crash markers into command buffers.
99    pub validation: bool,
100    /// Enable GPU timing of all passes.
101    pub timing: bool,
102    /// Enable capture support with GAPI tools.
103    pub capture: bool,
104    /// Enable GAPI overlay.
105    pub overlay: bool,
106    /// Force selection of a specific Device ID, unless 0.
107    pub device_id: u32,
108}
109
110#[derive(Debug)]
111pub enum NotSupportedError {
112    Platform(PlatformError),
113    NoSupportedDeviceFound,
114    PlatformNotSupported,
115}
116
117impl From<PlatformError> for NotSupportedError {
118    fn from(error: PlatformError) -> Self {
119        Self::Platform(error)
120    }
121}
122
123#[derive(Clone, Debug, Default, PartialEq)]
124pub struct Capabilities {
125    /// Which shader stages support ray queries
126    pub ray_query: ShaderVisibility,
127    /// Bit mask of supported MSAA sample counts.
128    pub sample_count_mask: u32,
129}
130
131#[derive(Clone, Debug, Default)]
132pub struct DeviceInformation {
133    /// If this is something like llvmpipe, not a real GPU
134    pub is_software_emulated: bool,
135    /// The name of the GPU device
136    pub device_name: String,
137    /// The driver used to talk to the GPU
138    pub driver_name: String,
139    /// Further information about the driver
140    pub driver_info: String,
141}
142
143impl Context {
144    pub fn create_surface_configured<
145        I: raw_window_handle::HasWindowHandle + raw_window_handle::HasDisplayHandle,
146    >(
147        &self,
148        window: &I,
149        config: SurfaceConfig,
150    ) -> Result<Surface, NotSupportedError> {
151        let mut surface = self.create_surface(window)?;
152        self.reconfigure_surface(&mut surface, config);
153        Ok(surface)
154    }
155}
156
157#[derive(Clone, Copy, Debug, PartialEq)]
158pub enum Memory {
159    /// Device-local memory. Fast for GPU operations.
160    Device,
161    /// Shared CPU-GPU memory. Not so fast for GPU.
162    Shared,
163    /// Upload memory. Can only be transferred on GPU.
164    Upload,
165    /// External memory
166    External(ExternalMemorySource),
167}
168
169/// If the source contains None it will export it otherwise it will import the value in Some
170//TODO add D3D11, D3D12 and metal support
171#[derive(Clone, Copy, Debug, PartialEq, Hash)]
172pub enum ExternalMemorySource {
173    #[cfg(target_os = "windows")]
174    Win32(Option<isize>),
175
176    #[cfg(target_os = "windows")]
177    Win32KMT(Option<isize>),
178
179    #[cfg(not(target_os = "windows"))]
180    Fd(Option<i32>),
181
182    #[cfg(target_os = "linux")]
183    Dma(Option<i32>),
184
185    /// Is a pointer cast to usize, reason being it otherwise can't be used as sync and send, you should manage memory access to this yourself
186    HostAllocation(usize),
187}
188
189impl Memory {
190    pub fn is_host_visible(&self) -> bool {
191        match *self {
192            Self::Shared
193            | Self::Upload
194            | Self::External(ExternalMemorySource::HostAllocation(_)) => true,
195            Self::Device | Self::External(_) => false,
196        }
197    }
198}
199
200#[derive(Debug)]
201pub struct BufferDesc<'a> {
202    pub name: &'a str,
203    pub size: u64,
204    pub memory: Memory,
205}
206
207#[derive(Clone, Copy, Debug)]
208pub struct BufferPiece {
209    pub buffer: Buffer,
210    pub offset: u64,
211}
212
213impl From<Buffer> for BufferPiece {
214    fn from(buffer: Buffer) -> Self {
215        Self { buffer, offset: 0 }
216    }
217}
218
219impl BufferPiece {
220    pub fn data(&self) -> *mut u8 {
221        let base = self.buffer.data();
222        assert!(!base.is_null());
223        unsafe { base.offset(self.offset as isize) }
224    }
225}
226
227impl Buffer {
228    pub fn at(self, offset: u64) -> BufferPiece {
229        BufferPiece {
230            buffer: self,
231            offset,
232        }
233    }
234}
235
236pub type ResourceIndex = u32;
237/// An array of resources to be used with shader bindings.
238/// The generic argument tells the maximum number of resources.
239pub struct ResourceArray<T, const N: ResourceIndex> {
240    data: Vec<T>,
241    free_list: Vec<ResourceIndex>,
242}
243impl<T, const N: ResourceIndex> ResourceArray<T, N> {
244    pub fn new() -> Self {
245        Self {
246            data: Vec::with_capacity(N as usize),
247            free_list: Vec::new(),
248        }
249    }
250    pub fn alloc(&mut self, value: T) -> ResourceIndex {
251        if let Some(index) = self.free_list.pop() {
252            self.data[index as usize] = value;
253            index
254        } else {
255            let index = self.data.len() as u32;
256            assert!(index < N);
257            self.data.push(value);
258            index
259        }
260    }
261    pub fn free(&mut self, index: ResourceIndex) {
262        self.free_list.push(index);
263    }
264    pub fn clear(&mut self) {
265        self.data.clear();
266        self.free_list.clear();
267    }
268}
269impl<T, const N: ResourceIndex> std::ops::Index<ResourceIndex> for ResourceArray<T, N> {
270    type Output = T;
271    fn index(&self, index: ResourceIndex) -> &T {
272        &self.data[index as usize]
273    }
274}
275impl<T, const N: ResourceIndex> std::ops::IndexMut<ResourceIndex> for ResourceArray<T, N> {
276    fn index_mut(&mut self, index: ResourceIndex) -> &mut T {
277        &mut self.data[index as usize]
278    }
279}
280pub type BufferArray<const N: ResourceIndex> = ResourceArray<BufferPiece, N>;
281pub type TextureArray<const N: ResourceIndex> = ResourceArray<TextureView, N>;
282
283#[derive(Clone, Copy, Debug)]
284pub struct TexturePiece {
285    pub texture: Texture,
286    pub mip_level: u32,
287    pub array_layer: u32,
288    pub origin: [u32; 3],
289}
290
291impl From<Texture> for TexturePiece {
292    fn from(texture: Texture) -> Self {
293        Self {
294            texture,
295            mip_level: 0,
296            array_layer: 0,
297            origin: [0; 3],
298        }
299    }
300}
301
302#[non_exhaustive]
303#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
304pub enum TextureFormat {
305    // color
306    R8Unorm,
307    Rg8Unorm,
308    Rg8Snorm,
309    Rgba8Unorm,
310    Rgba8UnormSrgb,
311    Bgra8Unorm,
312    Bgra8UnormSrgb,
313    Rgba8Snorm,
314    R16Float,
315    Rg16Float,
316    Rgba16Float,
317    R32Float,
318    Rg32Float,
319    Rgba32Float,
320    R32Uint,
321    Rg32Uint,
322    Rgba32Uint,
323    // depth and stencil
324    Depth32Float,
325    Depth32FloatStencil8Uint,
326    Stencil8Uint,
327    // S3TC block compression
328    Bc1Unorm,
329    Bc1UnormSrgb,
330    Bc2Unorm,
331    Bc2UnormSrgb,
332    Bc3Unorm,
333    Bc3UnormSrgb,
334    Bc4Unorm,
335    Bc4Snorm,
336    Bc5Unorm,
337    Bc5Snorm,
338    Bc6hUfloat,
339    Bc6hFloat,
340    Bc7Unorm,
341    Bc7UnormSrgb,
342    // packed 32-bit
343    Rgb10a2Unorm,
344    Rg11b10Ufloat,
345    Rgb9e5Ufloat,
346}
347
348#[derive(Clone, Copy, Debug)]
349pub struct TexelBlockInfo {
350    pub dimensions: (u8, u8),
351    pub size: u8,
352}
353
354bitflags::bitflags! {
355    #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
356    pub struct TexelAspects: u8 {
357        const COLOR = 0x1;
358        const DEPTH = 0x2;
359        const STENCIL = 0x4;
360    }
361}
362
363/// Dimensionality of a texture.
364#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
365pub enum TextureDimension {
366    /// 1D texture
367    D1,
368    /// 2D texture
369    D2,
370    /// 3D texture
371    D3,
372}
373
374#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
375pub enum ViewDimension {
376    D1,
377    D1Array,
378    D2,
379    D2Array,
380    Cube,
381    CubeArray,
382    D3,
383}
384
385#[repr(C)]
386#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
387pub struct Extent {
388    pub width: u32,
389    pub height: u32,
390    pub depth: u32,
391}
392impl Default for Extent {
393    fn default() -> Self {
394        Self {
395            width: 1,
396            height: 1,
397            depth: 1,
398        }
399    }
400}
401impl fmt::Display for Extent {
402    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
403        write!(f, "{}x{}x{}", self.width, self.height, self.depth)
404    }
405}
406
407impl Extent {
408    pub fn max_mip_levels(&self) -> u32 {
409        self.width
410            .max(self.height)
411            .max(self.depth)
412            .next_power_of_two()
413            .trailing_zeros()
414    }
415    pub fn at_mip_level(&self, level: u32) -> Self {
416        Self {
417            width: (self.width >> level).max(1),
418            height: (self.height >> level).max(1),
419            depth: (self.depth >> level).max(1),
420        }
421    }
422}
423
424bitflags::bitflags! {
425    #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
426    pub struct TextureUsage: u32 {
427        const COPY = 1 << 0;
428        const TARGET = 1 << 1;
429        const RESOURCE = 1 << 2;
430        const STORAGE = 1 << 3;
431    }
432}
433
434#[derive(Debug)]
435pub struct TextureDesc<'a> {
436    pub name: &'a str,
437    pub format: TextureFormat,
438    pub size: Extent,
439    pub array_layer_count: u32,
440    pub mip_level_count: u32,
441    pub sample_count: u32,
442    pub dimension: TextureDimension,
443    pub usage: TextureUsage,
444    pub external: Option<ExternalMemorySource>,
445}
446
447#[derive(Clone, Debug, Default, Eq, PartialEq)]
448pub struct TextureSubresources {
449    pub base_mip_level: u32,
450    pub mip_level_count: Option<NonZeroU32>,
451    pub base_array_layer: u32,
452    pub array_layer_count: Option<NonZeroU32>,
453}
454
455#[derive(Debug)]
456pub struct TextureViewDesc<'a> {
457    pub name: &'a str,
458    pub format: TextureFormat,
459    pub dimension: ViewDimension,
460    pub subresources: &'a TextureSubresources,
461}
462
463bitflags::bitflags! {
464    #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
465    pub struct ShaderVisibility: u32 {
466        const COMPUTE = 1 << 0;
467        const VERTEX = 1 << 1;
468        const FRAGMENT = 1 << 2;
469    }
470}
471
472/// How edges should be handled in texture addressing.
473#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
474pub enum AddressMode {
475    /// Clamp the value to the edge of the texture.
476    #[default]
477    ClampToEdge,
478    /// Repeat the texture in a tiling fashion.
479    Repeat,
480    /// Repeat the texture, mirroring it every repeat.
481    MirrorRepeat,
482    /// Clamp the value to the border of the texture.
483    ClampToBorder,
484}
485
486/// Texel mixing mode when sampling between texels.
487#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
488pub enum FilterMode {
489    /// Nearest neighbor sampling.
490    #[default]
491    Nearest,
492    /// Linear Interpolation
493    Linear,
494}
495
496/// Comparison function used for depth and stencil operations.
497#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
498pub enum CompareFunction {
499    /// Function never passes
500    Never,
501    /// Function passes if new value less than existing value
502    Less,
503    /// Function passes if new value is equal to existing value. When using
504    /// this compare function, make sure to mark your Vertex Shader's `@builtin(position)`
505    /// output as `@invariant` to prevent artifacting.
506    Equal,
507    /// Function passes if new value is less than or equal to existing value
508    LessEqual,
509    /// Function passes if new value is greater than existing value
510    Greater,
511    /// Function passes if new value is not equal to existing value. When using
512    /// this compare function, make sure to mark your Vertex Shader's `@builtin(position)`
513    /// output as `@invariant` to prevent artifacting.
514    NotEqual,
515    /// Function passes if new value is greater than or equal to existing value
516    GreaterEqual,
517    /// Function always passes
518    #[default]
519    Always,
520}
521
522#[derive(Clone, Copy, Debug)]
523pub enum TextureColor {
524    TransparentBlack,
525    OpaqueBlack,
526    White,
527}
528
529#[derive(Debug, Default)]
530pub struct SamplerDesc<'a> {
531    pub name: &'a str,
532    pub address_modes: [AddressMode; 3],
533    pub mag_filter: FilterMode,
534    pub min_filter: FilterMode,
535    pub mipmap_filter: FilterMode,
536    pub lod_min_clamp: f32,
537    pub lod_max_clamp: Option<f32>,
538    pub compare: Option<CompareFunction>,
539    pub anisotropy_clamp: u32,
540    pub border_color: Option<TextureColor>,
541}
542
543#[derive(Debug)]
544pub enum AccelerationStructureType {
545    TopLevel,
546    BottomLevel,
547}
548
549#[derive(Debug)]
550pub struct AccelerationStructureDesc<'a> {
551    pub name: &'a str,
552    pub ty: AccelerationStructureType,
553    pub size: u64,
554}
555
556#[non_exhaustive]
557#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
558pub enum VertexFormat {
559    F32,
560    F32Vec2,
561    F32Vec3,
562    F32Vec4,
563    U32,
564    U32Vec2,
565    U32Vec3,
566    U32Vec4,
567    I32,
568    I32Vec2,
569    I32Vec3,
570    I32Vec4,
571}
572
573#[derive(Clone, Debug)]
574pub struct AccelerationStructureMesh {
575    pub vertex_data: BufferPiece,
576    pub vertex_format: VertexFormat,
577    pub vertex_stride: u32,
578    pub vertex_count: u32,
579    pub index_data: BufferPiece,
580    pub index_type: Option<IndexType>,
581    pub triangle_count: u32,
582    pub transform_data: BufferPiece,
583    pub is_opaque: bool,
584}
585
586#[derive(Clone, Debug)]
587pub struct AccelerationStructureInstance {
588    pub acceleration_structure_index: u32,
589    pub transform: Transform,
590    pub mask: u32,
591    pub custom_index: u32,
592}
593
594impl Default for AccelerationStructureInstance {
595    fn default() -> Self {
596        Self {
597            acceleration_structure_index: 0,
598            transform: IDENTITY_TRANSFORM,
599            mask: 0xFF,
600            custom_index: 0,
601        }
602    }
603}
604
605#[derive(Clone, Copy, Debug, Default, PartialEq)]
606pub struct AccelerationStructureSizes {
607    /// Size of the permanent GPU data
608    pub data: u64,
609    /// Size of the scratch space
610    pub scratch: u64,
611}
612
613pub struct Shader {
614    module: naga::Module,
615    info: naga::valid::ModuleInfo,
616    source: String,
617}
618
619#[derive(Clone, Copy)]
620pub struct ShaderFunction<'a> {
621    pub shader: &'a Shader,
622    pub entry_point: &'a str,
623    pub constants: &'a PipelineConstants,
624}
625
626impl ShaderFunction<'_> {
627    fn entry_point_index(&self) -> usize {
628        self.shader
629            .module
630            .entry_points
631            .iter()
632            .position(|ep| ep.name == self.entry_point)
633            .expect("Entry point not found in the shader")
634    }
635}
636
637#[derive(Clone, Copy, Debug, PartialEq)]
638pub enum ShaderBinding {
639    Texture,
640    TextureArray { count: u32 },
641    Sampler,
642    Buffer,
643    BufferArray { count: u32 },
644    AccelerationStructure,
645    Plain { size: u32 },
646}
647
648pub trait ShaderBindable: Clone + Copy + derive::HasShaderBinding {
649    fn bind_to(&self, context: &mut PipelineContext, index: u32);
650}
651
652#[derive(Debug)]
653struct ShaderDataInfo {
654    visibility: ShaderVisibility,
655    binding_access: Box<[StorageAccess]>,
656}
657
658#[derive(Clone, Debug, Default, PartialEq)]
659pub struct ShaderDataLayout {
660    pub bindings: Vec<(&'static str, ShaderBinding)>,
661}
662impl ShaderDataLayout {
663    pub const EMPTY: &'static Self = &Self {
664        bindings: Vec::new(),
665    };
666
667    fn to_info(&self) -> ShaderDataInfo {
668        ShaderDataInfo {
669            visibility: ShaderVisibility::empty(),
670            binding_access: vec![StorageAccess::empty(); self.bindings.len()].into_boxed_slice(),
671        }
672    }
673}
674
675pub trait ShaderData {
676    fn layout() -> ShaderDataLayout;
677    fn fill(&self, context: PipelineContext);
678}
679
680#[derive(Copy, Clone, Debug, PartialEq)]
681pub struct VertexAttribute {
682    pub offset: u32,
683    pub format: VertexFormat,
684}
685
686struct VertexAttributeMapping {
687    buffer_index: usize,
688    attribute_index: usize,
689}
690
691#[derive(Clone, Debug, Default, PartialEq)]
692pub struct VertexLayout {
693    pub attributes: Vec<(&'static str, VertexAttribute)>,
694    pub stride: u32,
695}
696
697pub trait Vertex {
698    fn layout() -> VertexLayout;
699}
700
701#[derive(Clone, Debug, PartialEq)]
702pub struct VertexFetchState<'a> {
703    pub layout: &'a VertexLayout,
704    pub instanced: bool,
705}
706
707pub struct ShaderDesc<'a> {
708    pub source: &'a str,
709}
710
711#[derive(Clone, Debug, Default, PartialEq)]
712pub enum CommandType {
713    Transfer,
714    Compute,
715    #[default]
716    General,
717}
718
719pub struct CommandEncoderDesc<'a> {
720    pub name: &'a str,
721    /// Number of buffers that this encoder needs to keep alive.
722    /// For example, one buffer is being run on GPU while the
723    /// other is being actively encoded, which makes 2.
724    pub buffer_count: u32,
725}
726
727pub struct ComputePipelineDesc<'a> {
728    pub name: &'a str,
729    pub data_layouts: &'a [&'a ShaderDataLayout],
730    pub compute: ShaderFunction<'a>,
731}
732
733/// Primitive type the input mesh is composed of.
734#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
735pub enum PrimitiveTopology {
736    /// Vertex data is a list of points. Each vertex is a new point.
737    PointList,
738    /// Vertex data is a list of lines. Each pair of vertices composes a new line.
739    ///
740    /// Vertices `0 1 2 3` create two lines `0 1` and `2 3`
741    LineList,
742    /// Vertex data is a strip of lines. Each set of two adjacent vertices form a line.
743    ///
744    /// Vertices `0 1 2 3` create three lines `0 1`, `1 2`, and `2 3`.
745    LineStrip,
746    /// Vertex data is a list of triangles. Each set of 3 vertices composes a new triangle.
747    ///
748    /// Vertices `0 1 2 3 4 5` create two triangles `0 1 2` and `3 4 5`
749    #[default]
750    TriangleList,
751    /// Vertex data is a triangle strip. Each set of three adjacent vertices form a triangle.
752    ///
753    /// Vertices `0 1 2 3 4 5` creates four triangles `0 1 2`, `2 1 3`, `2 3 4`, and `4 3 5`
754    TriangleStrip,
755}
756
757/// Vertex winding order which classifies the "front" face of a triangle.
758#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
759pub enum FrontFace {
760    /// Triangles with vertices in counter clockwise order are considered the front face.
761    ///
762    /// This is the default with right handed coordinate spaces.
763    #[default]
764    Ccw,
765    /// Triangles with vertices in clockwise order are considered the front face.
766    ///
767    /// This is the default with left handed coordinate spaces.
768    Cw,
769}
770
771/// Face of a vertex.
772#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
773pub enum Face {
774    /// Front face
775    Front,
776    /// Back face
777    Back,
778}
779
780#[derive(Clone, Debug, Default)]
781pub struct PrimitiveState {
782    /// The primitive topology used to interpret vertices.
783    pub topology: PrimitiveTopology,
784    /// The face to consider the front for the purpose of culling and stencil operations.
785    pub front_face: FrontFace,
786    /// The face culling mode.
787    pub cull_mode: Option<Face>,
788    /// If set to true, the polygon depth is not clipped to 0-1 before rasterization.
789    pub unclipped_depth: bool,
790    /// If true, only the primitive edges are rasterized..
791    pub wireframe: bool,
792}
793
794/// Operation to perform on the stencil value.
795#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
796pub enum StencilOperation {
797    /// Keep stencil value unchanged.
798    #[default]
799    Keep,
800    /// Set stencil value to zero.
801    Zero,
802    /// Replace stencil value with value provided.
803    Replace,
804    /// Bitwise inverts stencil value.
805    Invert,
806    /// Increments stencil value by one, clamping on overflow.
807    IncrementClamp,
808    /// Decrements stencil value by one, clamping on underflow.
809    DecrementClamp,
810    /// Increments stencil value by one, wrapping on overflow.
811    IncrementWrap,
812    /// Decrements stencil value by one, wrapping on underflow.
813    DecrementWrap,
814}
815
816/// Describes stencil state in a render pipeline.
817///
818/// If you are not using stencil state, set this to [`StencilFaceState::IGNORE`].
819#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
820pub struct StencilFaceState {
821    /// Comparison function that determines if the fail_op or pass_op is used on the stencil buffer.
822    pub compare: CompareFunction,
823    /// Operation that is preformed when stencil test fails.
824    pub fail_op: StencilOperation,
825    /// Operation that is performed when depth test fails but stencil test succeeds.
826    pub depth_fail_op: StencilOperation,
827    /// Operation that is performed when stencil test success.
828    pub pass_op: StencilOperation,
829}
830
831impl StencilFaceState {
832    /// Ignore the stencil state for the face.
833    pub const IGNORE: Self = StencilFaceState {
834        compare: CompareFunction::Always,
835        fail_op: StencilOperation::Keep,
836        depth_fail_op: StencilOperation::Keep,
837        pass_op: StencilOperation::Keep,
838    };
839}
840
841impl Default for StencilFaceState {
842    fn default() -> Self {
843        Self::IGNORE
844    }
845}
846
847/// State of the stencil operation (fixed-pipeline stage).
848///
849/// For use in [`DepthStencilState`].
850#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
851pub struct StencilState {
852    /// Front face mode.
853    pub front: StencilFaceState,
854    /// Back face mode.
855    pub back: StencilFaceState,
856    /// Stencil values are AND'd with this mask when reading and writing from the stencil buffer. Only low 8 bits are used.
857    pub read_mask: u32,
858    /// Stencil values are AND'd with this mask when writing to the stencil buffer. Only low 8 bits are used.
859    pub write_mask: u32,
860}
861
862#[derive(Clone, Copy, Debug, Default, PartialEq)]
863pub struct DepthBiasState {
864    /// Constant depth biasing factor, in basic units of the depth format.
865    pub constant: i32,
866    /// Slope depth biasing factor.
867    pub slope_scale: f32,
868    /// Depth bias clamp value (absolute).
869    pub clamp: f32,
870}
871
872/// Describes the depth/stencil state in a render pipeline.
873#[derive(Clone, Debug)]
874pub struct DepthStencilState {
875    /// Format of the depth/stencil texture view.
876    pub format: TextureFormat,
877    /// If disabled, depth will not be written to.
878    pub depth_write_enabled: bool,
879    /// Comparison function used to compare depth values in the depth test.
880    pub depth_compare: CompareFunction,
881    /// Stencil state.
882    pub stencil: StencilState,
883    /// Depth bias state.
884    pub bias: DepthBiasState,
885}
886
887/// Alpha blend factor.
888#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
889pub enum BlendFactor {
890    /// 0.0
891    Zero,
892    /// 1.0
893    One,
894    /// S.component
895    Src,
896    /// 1.0 - S.component
897    OneMinusSrc,
898    /// S.alpha
899    SrcAlpha,
900    /// 1.0 - S.alpha
901    OneMinusSrcAlpha,
902    /// D.component
903    Dst,
904    /// 1.0 - D.component
905    OneMinusDst,
906    /// D.alpha
907    DstAlpha,
908    /// 1.0 - D.alpha
909    OneMinusDstAlpha,
910    /// min(S.alpha, 1.0 - D.alpha)
911    SrcAlphaSaturated,
912    /// Constant
913    Constant,
914    /// 1.0 - Constant
915    OneMinusConstant,
916}
917
918/// Alpha blend operation.
919#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
920pub enum BlendOperation {
921    /// Src + Dst
922    #[default]
923    Add,
924    /// Src - Dst
925    Subtract,
926    /// Dst - Src
927    ReverseSubtract,
928    /// min(Src, Dst)
929    Min,
930    /// max(Src, Dst)
931    Max,
932}
933
934/// Describes a blend component of a [`BlendState`].
935#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
936pub struct BlendComponent {
937    /// Multiplier for the source, which is produced by the fragment shader.
938    pub src_factor: BlendFactor,
939    /// Multiplier for the destination, which is stored in the target.
940    pub dst_factor: BlendFactor,
941    /// The binary operation applied to the source and destination,
942    /// multiplied by their respective factors.
943    pub operation: BlendOperation,
944}
945
946impl BlendComponent {
947    /// Default blending state that replaces destination with the source.
948    pub const REPLACE: Self = Self {
949        src_factor: BlendFactor::One,
950        dst_factor: BlendFactor::Zero,
951        operation: BlendOperation::Add,
952    };
953
954    /// Blend state of (1 * src) + ((1 - src_alpha) * dst)
955    pub const OVER: Self = Self {
956        src_factor: BlendFactor::One,
957        dst_factor: BlendFactor::OneMinusSrcAlpha,
958        operation: BlendOperation::Add,
959    };
960
961    /// Blend state of src + dst
962    pub const ADDITIVE: Self = Self {
963        src_factor: BlendFactor::One,
964        dst_factor: BlendFactor::One,
965        operation: BlendOperation::Add,
966    };
967}
968
969impl Default for BlendComponent {
970    fn default() -> Self {
971        Self::REPLACE
972    }
973}
974
975/// Describe the blend state of a render pipeline,
976/// within [`ColorTargetState`].
977#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
978pub struct BlendState {
979    /// Color equation.
980    pub color: BlendComponent,
981    /// Alpha equation.
982    pub alpha: BlendComponent,
983}
984
985impl BlendState {
986    /// Blend mode that does no color blending, just overwrites the output with the contents of the shader.
987    pub const REPLACE: Self = Self {
988        color: BlendComponent::REPLACE,
989        alpha: BlendComponent::REPLACE,
990    };
991
992    /// Blend mode that does standard alpha blending with non-premultiplied alpha.
993    pub const ALPHA_BLENDING: Self = Self {
994        color: BlendComponent {
995            src_factor: BlendFactor::SrcAlpha,
996            dst_factor: BlendFactor::OneMinusSrcAlpha,
997            operation: BlendOperation::Add,
998        },
999        alpha: BlendComponent::OVER,
1000    };
1001
1002    /// Blend mode that does standard alpha blending with premultiplied alpha.
1003    pub const PREMULTIPLIED_ALPHA_BLENDING: Self = Self {
1004        color: BlendComponent::OVER,
1005        alpha: BlendComponent::OVER,
1006    };
1007
1008    /// Blend mode that just adds the value.
1009    pub const ADDITIVE: Self = Self {
1010        color: BlendComponent::ADDITIVE,
1011        alpha: BlendComponent::ADDITIVE,
1012    };
1013}
1014
1015bitflags::bitflags! {
1016    /// Color write mask. Disabled color channels will not be written to.
1017    #[repr(transparent)]
1018    #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
1019    pub struct ColorWrites: u32 {
1020        /// Enable red channel writes
1021        const RED = 1 << 0;
1022        /// Enable green channel writes
1023        const GREEN = 1 << 1;
1024        /// Enable blue channel writes
1025        const BLUE = 1 << 2;
1026        /// Enable alpha channel writes
1027        const ALPHA = 1 << 3;
1028        /// Enable red, green, and blue channel writes
1029        const COLOR = Self::RED.bits() | Self::GREEN.bits() | Self::BLUE.bits();
1030        /// Enable writes to all channels.
1031        const ALL = Self::RED.bits() | Self::GREEN.bits() | Self::BLUE.bits() | Self::ALPHA.bits();
1032    }
1033}
1034
1035impl Default for ColorWrites {
1036    fn default() -> Self {
1037        Self::ALL
1038    }
1039}
1040
1041/// Describes the color state of a render pipeline.
1042#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1043pub struct ColorTargetState {
1044    /// The [`TextureFormat`] of the image that this pipeline will render to.
1045    pub format: TextureFormat,
1046    /// The blending that is used for this pipeline.
1047    pub blend: Option<BlendState>,
1048    /// Mask which enables/disables writes to different color/alpha channel.
1049    pub write_mask: ColorWrites,
1050}
1051
1052impl From<TextureFormat> for ColorTargetState {
1053    fn from(format: TextureFormat) -> Self {
1054        Self {
1055            format,
1056            blend: None,
1057            write_mask: ColorWrites::ALL,
1058        }
1059    }
1060}
1061
1062pub struct RenderPipelineDesc<'a> {
1063    pub name: &'a str,
1064    pub data_layouts: &'a [&'a ShaderDataLayout],
1065    pub vertex: ShaderFunction<'a>,
1066    pub vertex_fetches: &'a [VertexFetchState<'a>],
1067    pub primitive: PrimitiveState,
1068    pub depth_stencil: Option<DepthStencilState>,
1069    pub fragment: Option<ShaderFunction<'a>>,
1070    pub color_targets: &'a [ColorTargetState],
1071    pub multisample_state: MultisampleState,
1072}
1073
1074#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
1075pub struct MultisampleState {
1076    pub sample_count: u32,
1077    pub sample_mask: u64,
1078    pub alpha_to_coverage: bool,
1079}
1080
1081impl Default for MultisampleState {
1082    fn default() -> Self {
1083        Self {
1084            sample_count: 1,
1085            sample_mask: !0,
1086            alpha_to_coverage: false,
1087        }
1088    }
1089}
1090
1091#[derive(Clone, Copy, Debug)]
1092pub enum InitOp {
1093    Load,
1094    Clear(TextureColor),
1095    DontCare,
1096}
1097
1098#[derive(Clone, Copy, Debug)]
1099pub enum FinishOp {
1100    Store,
1101    Discard,
1102    /// The texture specified here will be stored but it is undefined what
1103    /// happens to the original render target
1104    ResolveTo(TextureView),
1105    Ignore,
1106}
1107
1108#[derive(Debug)]
1109pub struct RenderTarget {
1110    pub view: TextureView,
1111    pub init_op: InitOp,
1112    pub finish_op: FinishOp,
1113}
1114
1115#[derive(Debug)]
1116pub struct RenderTargetSet<'a> {
1117    pub colors: &'a [RenderTarget],
1118    pub depth_stencil: Option<RenderTarget>,
1119}
1120
1121/// Mechanism used to acquire frames and display them on screen.
1122#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
1123pub enum DisplaySync {
1124    /// Block until the oldest frame is released.
1125    #[default]
1126    Block,
1127    /// Display the most recently presented frame.
1128    /// Falls back to `Tear` if unsupported.
1129    Recent,
1130    /// Tear the currently displayed frame when presenting a new one.
1131    Tear,
1132}
1133
1134#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
1135pub enum ColorSpace {
1136    #[default]
1137    Linear,
1138    Srgb,
1139}
1140
1141#[derive(Clone, Copy, Debug, Default, PartialEq)]
1142pub struct SurfaceConfig {
1143    pub size: Extent,
1144    pub usage: TextureUsage,
1145    pub display_sync: DisplaySync,
1146    /// The color space that render output colors are expected to be in.
1147    ///
1148    /// This will affect the surface format returned by the `Context`.
1149    ///
1150    /// For example, if the display expects sRGB space and we render
1151    /// in `ColorSpace::Linear` space, the returned format will be sRGB.
1152    pub color_space: ColorSpace,
1153    pub transparent: bool,
1154    pub allow_exclusive_full_screen: bool,
1155}
1156
1157#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
1158pub enum AlphaMode {
1159    #[default]
1160    Ignored,
1161    PreMultiplied,
1162    PostMultiplied,
1163}
1164
1165#[derive(Clone, Copy, Debug, PartialEq)]
1166pub struct SurfaceInfo {
1167    pub format: TextureFormat,
1168    pub alpha: AlphaMode,
1169}
1170
1171#[derive(Clone, Copy, Debug, PartialEq)]
1172pub enum IndexType {
1173    U16,
1174    U32,
1175}
1176
1177#[derive(Clone, Debug, PartialEq)]
1178pub struct ScissorRect {
1179    pub x: i32,
1180    pub y: i32,
1181    pub w: u32,
1182    pub h: u32,
1183}
1184
1185#[derive(Clone, Debug, PartialEq)]
1186pub struct Viewport {
1187    pub x: f32,
1188    pub y: f32,
1189    pub w: f32,
1190    pub h: f32,
1191    pub depth: std::ops::Range<f32>,
1192}
1193
1194pub type Timings = Vec<(String, std::time::Duration)>;