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