1#![allow(
2 clippy::match_like_matches_macro,
4 clippy::redundant_pattern_matching,
6 clippy::needless_lifetimes,
8 clippy::new_without_default,
10 clippy::single_match,
12 clippy::vec_init_then_push,
14 clippy::missing_safety_doc,
16 clippy::too_many_arguments,
18)]
19#![warn(
20 trivial_numeric_casts,
21 unused_extern_crates,
22 clippy::pattern_type_mismatch,
26)]
27
28pub use naga::{StorageAccess, VectorSize, back::PipelineConstants};
29pub type Transform = mint::RowMatrix3x4<f32>;
30
31pub const IDENTITY_TRANSFORM: Transform = mint::RowMatrix3x4 {
32 x: mint::Vector4 {
33 x: 1.0,
34 y: 0.0,
35 z: 0.0,
36 w: 0.0,
37 },
38 y: mint::Vector4 {
39 x: 0.0,
40 y: 1.0,
41 z: 0.0,
42 w: 0.0,
43 },
44 z: mint::Vector4 {
45 x: 0.0,
46 y: 0.0,
47 z: 1.0,
48 w: 0.0,
49 },
50};
51
52pub mod derive;
53#[cfg_attr(
54 all(not(vulkan), not(gles), any(target_os = "ios", target_os = "macos")),
55 path = "metal/mod.rs"
56)]
57#[cfg_attr(
58 all(
59 not(gles),
60 any(
61 vulkan,
62 windows,
63 target_os = "linux",
64 target_os = "android",
65 target_os = "freebsd"
66 )
67 ),
68 path = "vulkan/mod.rs"
69)]
70#[cfg_attr(any(gles, target_arch = "wasm32"), path = "gles/mod.rs")]
71mod hal;
72mod shader;
73pub mod traits;
74pub mod util;
75pub mod limits {
76 pub const PASS_COUNT: usize = 1000;
78 pub const PLAIN_DATA_SIZE: u32 = 256;
80 pub const RESOURCES_IN_GROUP: u32 = 8;
82 pub const STORAGE_BUFFER_ALIGNMENT: u64 = 16;
84 pub const ACCELERATION_STRUCTURE_SCRATCH_ALIGNMENT: u64 = 256;
86}
87
88pub use hal::*;
89
90#[cfg(target_arch = "wasm32")]
91pub const CANVAS_ID: &str = "blade";
92
93use std::{fmt, num::NonZeroU32};
94
95#[derive(Debug)]
97pub struct PlatformError(String);
98
99#[allow(unused)]
101impl PlatformError {
102 pub fn loading(err: impl fmt::Debug) -> Self {
103 Self(format!("failed to load: {:?}", err))
104 }
105 pub fn init(err: impl fmt::Debug) -> Self {
106 Self(format!("failed to initialize: {:?}", err))
107 }
108}
109
110impl fmt::Display for PlatformError {
111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 f.write_str(&self.0)
113 }
114}
115
116impl std::error::Error for PlatformError {}
117
118#[cfg(not(any(
119 vulkan,
120 windows,
121 target_os = "linux",
122 target_os = "android",
123 target_os = "freebsd"
124)))]
125pub mod openxr {
126 #[derive(Clone, Debug)]
127 pub enum Instance {}
128 #[derive(Clone, Debug)]
129 pub enum SystemId {}
130}
131
132#[derive(Clone)]
133pub struct XrDesc {
134 pub instance: openxr::Instance,
135 pub system_id: openxr::SystemId,
136}
137
138impl fmt::Debug for XrDesc {
139 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140 f.debug_struct("XrDesc")
141 .field("system_id", &self.system_id)
142 .finish()
143 }
144}
145
146#[derive(Clone, Debug, Default)]
147pub struct ContextDesc {
148 pub presentation: bool,
150 pub xr: Option<XrDesc>,
152 pub ray_tracing: bool,
154 pub validation: bool,
157 pub timing: bool,
159 pub capture: bool,
161 pub overlay: bool,
163 pub device_id: Option<u32>,
165}
166
167#[derive(Debug)]
168pub enum NotSupportedError {
169 Platform(PlatformError),
170 NoSupportedDeviceFound,
171 PlatformNotSupported,
172}
173
174impl fmt::Display for NotSupportedError {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 match *self {
177 Self::Platform(ref e) => write!(f, "platform error: {}", e),
178 Self::NoSupportedDeviceFound => f.write_str("no supported device found"),
179 Self::PlatformNotSupported => f.write_str("platform not supported"),
180 }
181 }
182}
183
184impl std::error::Error for NotSupportedError {}
185
186impl From<PlatformError> for NotSupportedError {
187 fn from(error: PlatformError) -> Self {
188 Self::Platform(error)
189 }
190}
191
192#[derive(Clone, Debug, PartialEq, Eq)]
194pub enum DeviceError {
195 DeviceLost,
197 OutOfMemory,
199}
200
201impl fmt::Display for DeviceError {
202 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203 match *self {
204 Self::DeviceLost => f.write_str("device lost"),
205 Self::OutOfMemory => f.write_str("out of memory"),
206 }
207 }
208}
209
210impl std::error::Error for DeviceError {}
211
212#[derive(Clone, Copy, Debug, Default)]
214pub struct MemoryStats {
215 pub budget: u64,
218 pub usage: u64,
221}
222
223#[derive(Clone, Copy, Debug, Default, PartialEq)]
228pub struct CooperativeMatrix {
229 pub f32_tile: u32,
231 pub f16_tile: u32,
233}
234
235impl CooperativeMatrix {
236 pub fn is_supported(&self) -> bool {
238 self.f32_tile > 0 || self.f16_tile > 0
239 }
240}
241
242#[derive(Clone, Debug, Default, PartialEq)]
243pub struct Capabilities {
244 pub binding_array: bool,
246 pub ray_query: ShaderVisibility,
248 pub sample_count_mask: u32,
250 pub dual_source_blending: bool,
252 pub shader_float16: bool,
254 pub cooperative_matrix: CooperativeMatrix,
256}
257
258#[derive(Clone, Debug)]
259pub enum DeviceReportStatus {
260 Available {
262 is_default: bool,
263 caps: Capabilities,
264 },
265 Rejected(String),
267}
268
269#[derive(Clone, Debug)]
270pub struct DeviceReport {
271 pub device_id: u32,
273 pub information: DeviceInformation,
275 pub status: DeviceReportStatus,
277}
278
279#[derive(Clone, Debug, Default)]
280pub struct DeviceInformation {
281 pub is_software_emulated: bool,
283 pub device_name: String,
285 pub driver_name: String,
287 pub driver_info: String,
289}
290
291impl Context {
292 pub fn create_surface_configured<
293 I: raw_window_handle::HasWindowHandle + raw_window_handle::HasDisplayHandle,
294 >(
295 &self,
296 window: &I,
297 config: SurfaceConfig,
298 ) -> Result<Surface, NotSupportedError> {
299 let mut surface = self.create_surface(window)?;
300 self.reconfigure_surface(&mut surface, config);
301 Ok(surface)
302 }
303}
304
305#[derive(Clone, Copy, Debug, PartialEq)]
306pub enum Memory {
307 Device,
309 Shared,
311 Upload,
313 External(ExternalMemorySource),
315}
316
317#[derive(Clone, Copy, Debug, PartialEq, Hash)]
320pub enum ExternalMemorySource {
321 #[cfg(target_os = "windows")]
322 Win32(Option<isize>),
323
324 #[cfg(target_os = "windows")]
325 Win32KMT(Option<isize>),
326
327 #[cfg(not(target_os = "windows"))]
328 Fd(Option<i32>),
329
330 #[cfg(target_os = "linux")]
331 Dma(Option<i32>),
332
333 HostAllocation(usize),
335}
336
337impl Memory {
338 pub fn is_host_visible(&self) -> bool {
339 match *self {
340 Self::Shared
341 | Self::Upload
342 | Self::External(ExternalMemorySource::HostAllocation(_)) => true,
343 Self::Device | Self::External(_) => false,
344 }
345 }
346}
347
348#[derive(Debug)]
349pub struct BufferDesc<'a> {
350 pub name: &'a str,
351 pub size: u64,
352 pub memory: Memory,
353}
354
355#[derive(Clone, Copy, Debug)]
356pub struct BufferPiece {
357 pub buffer: Buffer,
358 pub offset: u64,
359}
360
361impl From<Buffer> for BufferPiece {
362 fn from(buffer: Buffer) -> Self {
363 Self { buffer, offset: 0 }
364 }
365}
366
367impl BufferPiece {
368 pub fn data(&self) -> *mut u8 {
369 let base = self.buffer.data();
370 assert!(!base.is_null());
371 debug_assert!(
372 self.offset <= self.buffer.size(),
373 "BufferPiece offset {} exceeds buffer size {}",
374 self.offset,
375 self.buffer.size(),
376 );
377 unsafe { base.offset(self.offset as isize) }
378 }
379}
380
381impl Buffer {
382 pub fn at(self, offset: u64) -> BufferPiece {
383 BufferPiece {
384 buffer: self,
385 offset,
386 }
387 }
388}
389
390pub type ResourceIndex = u32;
391pub struct ResourceArray<T, const N: ResourceIndex> {
394 data: Vec<T>,
395 free_list: Vec<ResourceIndex>,
396}
397impl<T, const N: ResourceIndex> ResourceArray<T, N> {
398 pub fn new() -> Self {
399 Self {
400 data: Vec::with_capacity(N as usize),
401 free_list: Vec::new(),
402 }
403 }
404 pub fn alloc(&mut self, value: T) -> ResourceIndex {
405 if let Some(index) = self.free_list.pop() {
406 self.data[index as usize] = value;
407 index
408 } else {
409 let index = self.data.len() as u32;
410 assert!(index < N);
411 self.data.push(value);
412 index
413 }
414 }
415 pub fn free(&mut self, index: ResourceIndex) {
416 self.free_list.push(index);
417 }
418 pub fn clear(&mut self) {
419 self.data.clear();
420 self.free_list.clear();
421 }
422}
423impl<T, const N: ResourceIndex> std::ops::Index<ResourceIndex> for ResourceArray<T, N> {
424 type Output = T;
425 fn index(&self, index: ResourceIndex) -> &T {
426 &self.data[index as usize]
427 }
428}
429impl<T, const N: ResourceIndex> std::ops::IndexMut<ResourceIndex> for ResourceArray<T, N> {
430 fn index_mut(&mut self, index: ResourceIndex) -> &mut T {
431 &mut self.data[index as usize]
432 }
433}
434pub type BufferArray<const N: ResourceIndex> = ResourceArray<BufferPiece, N>;
435pub type TextureArray<const N: ResourceIndex> = ResourceArray<TextureView, N>;
436pub type AccelerationStructureArray<const N: ResourceIndex> =
437 ResourceArray<AccelerationStructure, N>;
438
439#[derive(Clone, Copy, Debug)]
440pub struct TexturePiece {
441 pub texture: Texture,
442 pub mip_level: u32,
443 pub array_layer: u32,
444 pub origin: [u32; 3],
445}
446
447impl From<Texture> for TexturePiece {
448 fn from(texture: Texture) -> Self {
449 Self {
450 texture,
451 mip_level: 0,
452 array_layer: 0,
453 origin: [0; 3],
454 }
455 }
456}
457
458#[non_exhaustive]
459#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
460pub enum TextureFormat {
461 R8Unorm,
463 Rg8Unorm,
464 Rg8Snorm,
465 Rgba8Unorm,
466 Rgba8UnormSrgb,
467 Bgra8Unorm,
468 Bgra8UnormSrgb,
469 Rgba8Snorm,
470 R16Float,
471 Rg16Float,
472 Rgba16Float,
473 R32Float,
474 Rg32Float,
475 Rgba32Float,
476 R32Uint,
477 Rg32Uint,
478 Rgba32Uint,
479 Depth32Float,
481 Depth32FloatStencil8Uint,
482 Stencil8Uint,
483 Bc1Unorm,
485 Bc1UnormSrgb,
486 Bc2Unorm,
487 Bc2UnormSrgb,
488 Bc3Unorm,
489 Bc3UnormSrgb,
490 Bc4Unorm,
491 Bc4Snorm,
492 Bc5Unorm,
493 Bc5Snorm,
494 Bc6hUfloat,
495 Bc6hFloat,
496 Bc7Unorm,
497 Bc7UnormSrgb,
498 Rgb10a2Unorm,
500 Rg11b10Ufloat,
501 Rgb9e5Ufloat,
502}
503
504#[derive(Clone, Copy, Debug)]
505pub struct TexelBlockInfo {
506 pub dimensions: (u8, u8),
507 pub size: u8,
508}
509
510bitflags::bitflags! {
511 #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
512 pub struct TexelAspects: u8 {
513 const COLOR = 0x1;
514 const DEPTH = 0x2;
515 const STENCIL = 0x4;
516 }
517}
518
519#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
521pub enum TextureDimension {
522 D1,
524 D2,
526 D3,
528}
529
530#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
531pub enum ViewDimension {
532 D1,
533 D1Array,
534 D2,
535 D2Array,
536 Cube,
537 CubeArray,
538 D3,
539}
540
541#[repr(C)]
542#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
543pub struct Extent {
544 pub width: u32,
545 pub height: u32,
546 pub depth: u32,
547}
548impl Default for Extent {
549 fn default() -> Self {
550 Self {
551 width: 1,
552 height: 1,
553 depth: 1,
554 }
555 }
556}
557impl fmt::Display for Extent {
558 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
559 write!(f, "{}x{}x{}", self.width, self.height, self.depth)
560 }
561}
562
563impl Extent {
564 pub fn max_mip_levels(&self) -> u32 {
565 self.width
566 .max(self.height)
567 .max(self.depth)
568 .next_power_of_two()
569 .trailing_zeros()
570 }
571 pub fn at_mip_level(&self, level: u32) -> Self {
572 Self {
573 width: (self.width >> level).max(1),
574 height: (self.height >> level).max(1),
575 depth: (self.depth >> level).max(1),
576 }
577 }
578}
579
580bitflags::bitflags! {
581 #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
582 pub struct TextureUsage: u32 {
583 const COPY = 1 << 0;
584 const TARGET = 1 << 1;
585 const RESOURCE = 1 << 2;
586 const STORAGE = 1 << 3;
587 }
588}
589
590#[derive(Debug)]
591pub struct TextureDesc<'a> {
592 pub name: &'a str,
593 pub format: TextureFormat,
594 pub size: Extent,
595 pub array_layer_count: u32,
596 pub mip_level_count: u32,
597 pub sample_count: u32,
598 pub dimension: TextureDimension,
599 pub usage: TextureUsage,
600 pub external: Option<ExternalMemorySource>,
601}
602
603#[derive(Clone, Debug, Default, Eq, PartialEq)]
604pub struct TextureSubresources {
605 pub base_mip_level: u32,
606 pub mip_level_count: Option<NonZeroU32>,
607 pub base_array_layer: u32,
608 pub array_layer_count: Option<NonZeroU32>,
609}
610
611#[derive(Debug)]
612pub struct TextureViewDesc<'a> {
613 pub name: &'a str,
614 pub format: TextureFormat,
615 pub dimension: ViewDimension,
616 pub subresources: &'a TextureSubresources,
617}
618
619bitflags::bitflags! {
620 #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
621 pub struct ShaderVisibility: u32 {
622 const COMPUTE = 1 << 0;
623 const VERTEX = 1 << 1;
624 const FRAGMENT = 1 << 2;
625 }
626}
627
628#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
630pub enum AddressMode {
631 #[default]
633 ClampToEdge,
634 Repeat,
636 MirrorRepeat,
638 ClampToBorder,
640}
641
642#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
644pub enum FilterMode {
645 #[default]
647 Nearest,
648 Linear,
650}
651
652#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
654pub enum CompareFunction {
655 Never,
657 Less,
659 Equal,
663 LessEqual,
665 Greater,
667 NotEqual,
671 GreaterEqual,
673 #[default]
675 Always,
676}
677
678#[derive(Clone, Copy, Debug, PartialEq)]
679pub enum TextureColor {
680 TransparentBlack,
681 OpaqueBlack,
682 White,
683}
684
685#[derive(Debug, Default)]
686pub struct SamplerDesc<'a> {
687 pub name: &'a str,
688 pub address_modes: [AddressMode; 3],
689 pub mag_filter: FilterMode,
690 pub min_filter: FilterMode,
691 pub mipmap_filter: FilterMode,
692 pub lod_min_clamp: f32,
693 pub lod_max_clamp: Option<f32>,
694 pub compare: Option<CompareFunction>,
695 pub anisotropy_clamp: u32,
696 pub border_color: Option<TextureColor>,
697}
698
699#[derive(Debug)]
700pub enum AccelerationStructureType {
701 TopLevel,
702 BottomLevel,
703}
704
705#[derive(Debug)]
706pub struct AccelerationStructureDesc<'a> {
707 pub name: &'a str,
708 pub ty: AccelerationStructureType,
709 pub size: u64,
710}
711
712#[non_exhaustive]
713#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
714pub enum VertexFormat {
715 F32,
716 F32Vec2,
717 F32Vec3,
718 F32Vec4,
719 U32,
720 U32Vec2,
721 U32Vec3,
722 U32Vec4,
723 I32,
724 I32Vec2,
725 I32Vec3,
726 I32Vec4,
727}
728
729#[derive(Clone, Debug)]
730pub struct AccelerationStructureMesh {
731 pub vertex_data: BufferPiece,
732 pub vertex_format: VertexFormat,
733 pub vertex_stride: u32,
734 pub vertex_count: u32,
735 pub index_data: BufferPiece,
736 pub index_type: Option<IndexType>,
737 pub triangle_count: u32,
738 pub transform_data: BufferPiece,
739 pub is_opaque: bool,
740}
741
742#[derive(Clone, Debug)]
743pub struct AccelerationStructureInstance {
744 pub acceleration_structure_index: u32,
745 pub transform: Transform,
746 pub mask: u32,
747 pub custom_index: u32,
748}
749
750impl Default for AccelerationStructureInstance {
751 fn default() -> Self {
752 Self {
753 acceleration_structure_index: 0,
754 transform: IDENTITY_TRANSFORM,
755 mask: 0xFF,
756 custom_index: 0,
757 }
758 }
759}
760
761#[derive(Clone, Copy, Debug, Default, PartialEq)]
762pub struct AccelerationStructureSizes {
763 pub data: u64,
765 pub scratch: u64,
767}
768
769pub struct Shader {
770 module: naga::Module,
771 info: naga::valid::ModuleInfo,
772 source: String,
773}
774
775#[derive(Clone, Copy)]
776pub struct ShaderFunction<'a> {
777 pub shader: &'a Shader,
778 pub entry_point: &'a str,
779 pub constants: &'a PipelineConstants,
780}
781
782impl ShaderFunction<'_> {
783 fn entry_point_index(&self) -> usize {
784 self.shader
785 .module
786 .entry_points
787 .iter()
788 .position(|ep| ep.name == self.entry_point)
789 .expect("Entry point not found in the shader")
790 }
791}
792
793#[derive(Clone, Copy, Debug, PartialEq)]
794pub enum ShaderBinding {
795 Texture,
796 TextureArray { count: u32 },
797 Sampler,
798 Buffer,
799 BufferArray { count: u32 },
800 AccelerationStructure,
801 AccelerationStructureArray { count: u32 },
802 Plain { size: u32 },
803}
804
805pub trait ShaderBindable: Clone + Copy + derive::HasShaderBinding {
806 fn bind_to(&self, context: &mut PipelineContext, index: u32);
807}
808
809#[derive(Debug)]
810struct ShaderDataInfo {
811 visibility: ShaderVisibility,
812 binding_access: Box<[StorageAccess]>,
813}
814
815#[derive(Clone, Debug, Default, PartialEq)]
816pub struct ShaderDataLayout {
817 pub bindings: Vec<(&'static str, ShaderBinding)>,
818}
819impl ShaderDataLayout {
820 pub const EMPTY: &'static Self = &Self {
821 bindings: Vec::new(),
822 };
823
824 fn to_info(&self) -> ShaderDataInfo {
825 ShaderDataInfo {
826 visibility: ShaderVisibility::empty(),
827 binding_access: vec![StorageAccess::empty(); self.bindings.len()].into_boxed_slice(),
828 }
829 }
830}
831
832pub trait ShaderData {
833 fn layout() -> ShaderDataLayout;
834 fn fill(&self, context: PipelineContext);
835}
836
837#[derive(Copy, Clone, Debug, PartialEq)]
838pub struct VertexAttribute {
839 pub offset: u32,
840 pub format: VertexFormat,
841}
842
843struct VertexAttributeMapping {
844 buffer_index: usize,
845 attribute_index: usize,
846}
847
848#[derive(Clone, Debug, Default, PartialEq)]
849pub struct VertexLayout {
850 pub attributes: Vec<(&'static str, VertexAttribute)>,
851 pub stride: u32,
852}
853
854pub trait Vertex {
855 fn layout() -> VertexLayout;
856}
857
858#[derive(Clone, Debug, PartialEq)]
859pub struct VertexFetchState<'a> {
860 pub layout: &'a VertexLayout,
861 pub instanced: bool,
862}
863
864pub struct ShaderDesc<'a> {
865 pub source: &'a str,
868 pub naga_module: Option<naga::Module>,
871}
872
873#[derive(Clone, Debug, Default, PartialEq)]
874pub enum CommandType {
875 Transfer,
876 Compute,
877 #[default]
878 General,
879}
880
881pub struct CommandEncoderDesc<'a> {
882 pub name: &'a str,
883 pub buffer_count: u32,
887}
888
889pub struct ComputePipelineDesc<'a> {
890 pub name: &'a str,
891 pub data_layouts: &'a [&'a ShaderDataLayout],
892 pub compute: ShaderFunction<'a>,
893}
894
895#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
897pub enum PrimitiveTopology {
898 PointList,
900 LineList,
904 LineStrip,
908 #[default]
912 TriangleList,
913 TriangleStrip,
917}
918
919#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
921pub enum FrontFace {
922 #[default]
926 Ccw,
927 Cw,
931}
932
933#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
935pub enum Face {
936 Front,
938 Back,
940}
941
942#[derive(Clone, Debug, Default)]
943pub struct PrimitiveState {
944 pub topology: PrimitiveTopology,
946 pub front_face: FrontFace,
948 pub cull_mode: Option<Face>,
950 pub unclipped_depth: bool,
952 pub wireframe: bool,
954}
955
956#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
958pub enum StencilOperation {
959 #[default]
961 Keep,
962 Zero,
964 Replace,
966 Invert,
968 IncrementClamp,
970 DecrementClamp,
972 IncrementWrap,
974 DecrementWrap,
976}
977
978#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
982pub struct StencilFaceState {
983 pub compare: CompareFunction,
985 pub fail_op: StencilOperation,
987 pub depth_fail_op: StencilOperation,
989 pub pass_op: StencilOperation,
991}
992
993impl StencilFaceState {
994 pub const IGNORE: Self = StencilFaceState {
996 compare: CompareFunction::Always,
997 fail_op: StencilOperation::Keep,
998 depth_fail_op: StencilOperation::Keep,
999 pass_op: StencilOperation::Keep,
1000 };
1001}
1002
1003impl Default for StencilFaceState {
1004 fn default() -> Self {
1005 Self::IGNORE
1006 }
1007}
1008
1009#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
1013pub struct StencilState {
1014 pub front: StencilFaceState,
1016 pub back: StencilFaceState,
1018 pub read_mask: u32,
1020 pub write_mask: u32,
1022}
1023
1024#[derive(Clone, Copy, Debug, Default, PartialEq)]
1025pub struct DepthBiasState {
1026 pub constant: i32,
1028 pub slope_scale: f32,
1030 pub clamp: f32,
1032}
1033
1034#[derive(Clone, Debug)]
1036pub struct DepthStencilState {
1037 pub format: TextureFormat,
1039 pub depth_write_enabled: bool,
1041 pub depth_compare: CompareFunction,
1043 pub stencil: StencilState,
1045 pub bias: DepthBiasState,
1047}
1048
1049#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
1051pub enum BlendFactor {
1052 Zero,
1054 One,
1056 Src,
1058 OneMinusSrc,
1060 SrcAlpha,
1062 OneMinusSrcAlpha,
1064 Dst,
1066 OneMinusDst,
1068 DstAlpha,
1070 OneMinusDstAlpha,
1072 SrcAlphaSaturated,
1074 Constant,
1076 OneMinusConstant,
1078 Src1,
1080 OneMinusSrc1,
1082 Src1Alpha,
1084 OneMinusSrc1Alpha,
1086}
1087
1088impl BlendFactor {
1089 pub const fn uses_dual_source(&self) -> bool {
1090 matches!(
1091 self,
1092 BlendFactor::Src1
1093 | BlendFactor::OneMinusSrc1
1094 | BlendFactor::Src1Alpha
1095 | BlendFactor::OneMinusSrc1Alpha
1096 )
1097 }
1098}
1099
1100#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
1102pub enum BlendOperation {
1103 #[default]
1105 Add,
1106 Subtract,
1108 ReverseSubtract,
1110 Min,
1112 Max,
1114}
1115
1116#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1118pub struct BlendComponent {
1119 pub src_factor: BlendFactor,
1121 pub dst_factor: BlendFactor,
1123 pub operation: BlendOperation,
1126}
1127
1128impl BlendComponent {
1129 pub const REPLACE: Self = Self {
1131 src_factor: BlendFactor::One,
1132 dst_factor: BlendFactor::Zero,
1133 operation: BlendOperation::Add,
1134 };
1135
1136 pub const OVER: Self = Self {
1138 src_factor: BlendFactor::One,
1139 dst_factor: BlendFactor::OneMinusSrcAlpha,
1140 operation: BlendOperation::Add,
1141 };
1142
1143 pub const ADDITIVE: Self = Self {
1145 src_factor: BlendFactor::One,
1146 dst_factor: BlendFactor::One,
1147 operation: BlendOperation::Add,
1148 };
1149
1150 pub const fn uses_dual_source(&self) -> bool {
1151 self.src_factor.uses_dual_source() || self.dst_factor.uses_dual_source()
1152 }
1153}
1154
1155impl Default for BlendComponent {
1156 fn default() -> Self {
1157 Self::REPLACE
1158 }
1159}
1160
1161#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1164pub struct BlendState {
1165 pub color: BlendComponent,
1167 pub alpha: BlendComponent,
1169}
1170
1171impl BlendState {
1172 pub const REPLACE: Self = Self {
1174 color: BlendComponent::REPLACE,
1175 alpha: BlendComponent::REPLACE,
1176 };
1177
1178 pub const ALPHA_BLENDING: Self = Self {
1180 color: BlendComponent {
1181 src_factor: BlendFactor::SrcAlpha,
1182 dst_factor: BlendFactor::OneMinusSrcAlpha,
1183 operation: BlendOperation::Add,
1184 },
1185 alpha: BlendComponent::OVER,
1186 };
1187
1188 pub const PREMULTIPLIED_ALPHA_BLENDING: Self = Self {
1190 color: BlendComponent::OVER,
1191 alpha: BlendComponent::OVER,
1192 };
1193
1194 pub const ADDITIVE: Self = Self {
1196 color: BlendComponent::ADDITIVE,
1197 alpha: BlendComponent::ADDITIVE,
1198 };
1199
1200 pub const fn uses_dual_source(&self) -> bool {
1201 self.color.uses_dual_source() || self.alpha.uses_dual_source()
1202 }
1203}
1204
1205bitflags::bitflags! {
1206 #[repr(transparent)]
1208 #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
1209 pub struct ColorWrites: u32 {
1210 const RED = 1 << 0;
1212 const GREEN = 1 << 1;
1214 const BLUE = 1 << 2;
1216 const ALPHA = 1 << 3;
1218 const COLOR = Self::RED.bits() | Self::GREEN.bits() | Self::BLUE.bits();
1220 const ALL = Self::RED.bits() | Self::GREEN.bits() | Self::BLUE.bits() | Self::ALPHA.bits();
1222 }
1223}
1224
1225impl Default for ColorWrites {
1226 fn default() -> Self {
1227 Self::ALL
1228 }
1229}
1230
1231#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1233pub struct ColorTargetState {
1234 pub format: TextureFormat,
1236 pub blend: Option<BlendState>,
1238 pub write_mask: ColorWrites,
1240}
1241
1242impl From<TextureFormat> for ColorTargetState {
1243 fn from(format: TextureFormat) -> Self {
1244 Self {
1245 format,
1246 blend: None,
1247 write_mask: ColorWrites::ALL,
1248 }
1249 }
1250}
1251
1252pub struct RenderPipelineDesc<'a> {
1253 pub name: &'a str,
1254 pub data_layouts: &'a [&'a ShaderDataLayout],
1255 pub vertex: ShaderFunction<'a>,
1256 pub vertex_fetches: &'a [VertexFetchState<'a>],
1257 pub primitive: PrimitiveState,
1258 pub depth_stencil: Option<DepthStencilState>,
1259 pub fragment: Option<ShaderFunction<'a>>,
1260 pub color_targets: &'a [ColorTargetState],
1261 pub multisample_state: MultisampleState,
1262}
1263
1264#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
1265pub struct MultisampleState {
1266 pub sample_count: u32,
1267 pub sample_mask: u64,
1268 pub alpha_to_coverage: bool,
1269}
1270
1271impl Default for MultisampleState {
1272 fn default() -> Self {
1273 Self {
1274 sample_count: 1,
1275 sample_mask: !0,
1276 alpha_to_coverage: false,
1277 }
1278 }
1279}
1280
1281#[derive(Clone, Copy, Debug)]
1282pub enum InitOp {
1283 Load,
1284 Clear(TextureColor),
1285 DontCare,
1286}
1287
1288#[derive(Clone, Copy, Debug)]
1289pub enum FinishOp {
1290 Store,
1291 Discard,
1292 ResolveTo(TextureView),
1295 Ignore,
1296}
1297
1298#[derive(Debug)]
1299pub struct RenderTarget {
1300 pub view: TextureView,
1301 pub init_op: InitOp,
1302 pub finish_op: FinishOp,
1303}
1304
1305#[derive(Debug)]
1306pub struct RenderTargetSet<'a> {
1307 pub colors: &'a [RenderTarget],
1308 pub depth_stencil: Option<RenderTarget>,
1309}
1310
1311#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
1313pub enum DisplaySync {
1314 #[default]
1316 Block,
1317 Recent,
1320 Tear,
1322}
1323
1324#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
1325pub enum ColorSpace {
1326 #[default]
1327 Linear,
1328 Srgb,
1329}
1330
1331#[derive(Clone, Copy, Debug, Default, PartialEq)]
1332pub struct SurfaceConfig {
1333 pub size: Extent,
1334 pub usage: TextureUsage,
1335 pub display_sync: DisplaySync,
1336 pub color_space: ColorSpace,
1343 pub transparent: bool,
1344 pub allow_exclusive_full_screen: bool,
1345}
1346
1347#[derive(Clone, Copy, Debug, PartialEq)]
1348pub struct XrSurfaceConfig {
1349 pub size: Extent,
1350 pub usage: TextureUsage,
1351 pub color_space: ColorSpace,
1352 pub view_count: u32,
1353}
1354
1355impl Default for XrSurfaceConfig {
1356 fn default() -> Self {
1357 Self {
1358 size: Extent::default(),
1359 usage: TextureUsage::TARGET,
1360 color_space: ColorSpace::Linear,
1361 view_count: 2,
1362 }
1363 }
1364}
1365
1366#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
1367pub enum AlphaMode {
1368 #[default]
1369 Ignored,
1370 PreMultiplied,
1371 PostMultiplied,
1372}
1373
1374#[derive(Clone, Copy, Debug, PartialEq)]
1375pub struct SurfaceInfo {
1376 pub format: TextureFormat,
1377 pub alpha: AlphaMode,
1378}
1379
1380#[derive(Clone, Copy, Debug, PartialEq)]
1381pub enum IndexType {
1382 U16,
1383 U32,
1384}
1385
1386#[derive(Clone, Debug, PartialEq)]
1387pub struct ScissorRect {
1388 pub x: i32,
1389 pub y: i32,
1390 pub w: u32,
1391 pub h: u32,
1392}
1393
1394#[derive(Clone, Debug, PartialEq)]
1395pub struct Viewport {
1396 pub x: f32,
1397 pub y: f32,
1398 pub w: f32,
1399 pub h: f32,
1400 pub depth: std::ops::Range<f32>,
1401}
1402
1403pub type Timings = Vec<(String, std::time::Duration)>;