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 = 100;
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
99impl PlatformError {
100 pub(crate) fn loading(err: impl fmt::Debug) -> Self {
101 Self(format!("failed to load: {:?}", err))
102 }
103 pub(crate) fn init(err: impl fmt::Debug) -> Self {
104 Self(format!("failed to initialize: {:?}", err))
105 }
106}
107
108impl fmt::Display for PlatformError {
109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110 f.write_str(&self.0)
111 }
112}
113
114impl std::error::Error for PlatformError {}
115
116#[cfg(not(any(
117 vulkan,
118 windows,
119 target_os = "linux",
120 target_os = "android",
121 target_os = "freebsd"
122)))]
123pub mod openxr {
124 #[derive(Clone, Debug)]
125 pub enum Instance {}
126 #[derive(Clone, Debug)]
127 pub enum SystemId {}
128}
129
130#[derive(Clone)]
131pub struct XrDesc {
132 pub instance: openxr::Instance,
133 pub system_id: openxr::SystemId,
134}
135
136impl fmt::Debug for XrDesc {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 f.debug_struct("XrDesc")
139 .field("system_id", &self.system_id)
140 .finish()
141 }
142}
143
144#[derive(Clone, Debug, Default)]
145pub struct ContextDesc {
146 pub presentation: bool,
148 pub xr: Option<XrDesc>,
150 pub ray_tracing: bool,
152 pub validation: bool,
155 pub timing: bool,
157 pub capture: bool,
159 pub overlay: bool,
161 pub device_id: Option<u32>,
163}
164
165#[derive(Debug)]
166pub enum NotSupportedError {
167 Platform(PlatformError),
168 NoSupportedDeviceFound,
169 PlatformNotSupported,
170}
171
172impl fmt::Display for NotSupportedError {
173 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174 match *self {
175 Self::Platform(ref e) => write!(f, "platform error: {}", e),
176 Self::NoSupportedDeviceFound => f.write_str("no supported device found"),
177 Self::PlatformNotSupported => f.write_str("platform not supported"),
178 }
179 }
180}
181
182impl std::error::Error for NotSupportedError {}
183
184impl From<PlatformError> for NotSupportedError {
185 fn from(error: PlatformError) -> Self {
186 Self::Platform(error)
187 }
188}
189
190#[derive(Clone, Debug, PartialEq, Eq)]
192pub enum DeviceError {
193 DeviceLost,
195 OutOfMemory,
197}
198
199impl fmt::Display for DeviceError {
200 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201 match *self {
202 Self::DeviceLost => f.write_str("device lost"),
203 Self::OutOfMemory => f.write_str("out of memory"),
204 }
205 }
206}
207
208impl std::error::Error for DeviceError {}
209
210#[derive(Clone, Copy, Debug, Default)]
212pub struct MemoryStats {
213 pub budget: u64,
216 pub usage: u64,
219}
220
221#[derive(Clone, Copy, Debug, Default, PartialEq)]
226pub struct CooperativeMatrix {
227 pub f32_tile: u32,
229 pub f16_tile: u32,
231}
232
233impl CooperativeMatrix {
234 pub fn is_supported(&self) -> bool {
236 self.f32_tile > 0 || self.f16_tile > 0
237 }
238}
239
240#[derive(Clone, Debug, Default, PartialEq)]
241pub struct Capabilities {
242 pub binding_array: bool,
244 pub ray_query: ShaderVisibility,
246 pub sample_count_mask: u32,
248 pub dual_source_blending: bool,
250 pub shader_float16: bool,
252 pub cooperative_matrix: CooperativeMatrix,
254}
255
256#[derive(Clone, Debug, Default)]
257pub struct DeviceInformation {
258 pub is_software_emulated: bool,
260 pub device_name: String,
262 pub driver_name: String,
264 pub driver_info: String,
266}
267
268impl Context {
269 pub fn create_surface_configured<
270 I: raw_window_handle::HasWindowHandle + raw_window_handle::HasDisplayHandle,
271 >(
272 &self,
273 window: &I,
274 config: SurfaceConfig,
275 ) -> Result<Surface, NotSupportedError> {
276 let mut surface = self.create_surface(window)?;
277 self.reconfigure_surface(&mut surface, config);
278 Ok(surface)
279 }
280}
281
282#[derive(Clone, Copy, Debug, PartialEq)]
283pub enum Memory {
284 Device,
286 Shared,
288 Upload,
290 External(ExternalMemorySource),
292}
293
294#[derive(Clone, Copy, Debug, PartialEq, Hash)]
297pub enum ExternalMemorySource {
298 #[cfg(target_os = "windows")]
299 Win32(Option<isize>),
300
301 #[cfg(target_os = "windows")]
302 Win32KMT(Option<isize>),
303
304 #[cfg(not(target_os = "windows"))]
305 Fd(Option<i32>),
306
307 #[cfg(target_os = "linux")]
308 Dma(Option<i32>),
309
310 HostAllocation(usize),
312}
313
314impl Memory {
315 pub fn is_host_visible(&self) -> bool {
316 match *self {
317 Self::Shared
318 | Self::Upload
319 | Self::External(ExternalMemorySource::HostAllocation(_)) => true,
320 Self::Device | Self::External(_) => false,
321 }
322 }
323}
324
325#[derive(Debug)]
326pub struct BufferDesc<'a> {
327 pub name: &'a str,
328 pub size: u64,
329 pub memory: Memory,
330}
331
332#[derive(Clone, Copy, Debug)]
333pub struct BufferPiece {
334 pub buffer: Buffer,
335 pub offset: u64,
336}
337
338impl From<Buffer> for BufferPiece {
339 fn from(buffer: Buffer) -> Self {
340 Self { buffer, offset: 0 }
341 }
342}
343
344impl BufferPiece {
345 pub fn data(&self) -> *mut u8 {
346 let base = self.buffer.data();
347 assert!(!base.is_null());
348 debug_assert!(
349 self.offset <= self.buffer.size(),
350 "BufferPiece offset {} exceeds buffer size {}",
351 self.offset,
352 self.buffer.size(),
353 );
354 unsafe { base.offset(self.offset as isize) }
355 }
356}
357
358impl Buffer {
359 pub fn at(self, offset: u64) -> BufferPiece {
360 BufferPiece {
361 buffer: self,
362 offset,
363 }
364 }
365}
366
367pub type ResourceIndex = u32;
368pub struct ResourceArray<T, const N: ResourceIndex> {
371 data: Vec<T>,
372 free_list: Vec<ResourceIndex>,
373}
374impl<T, const N: ResourceIndex> ResourceArray<T, N> {
375 pub fn new() -> Self {
376 Self {
377 data: Vec::with_capacity(N as usize),
378 free_list: Vec::new(),
379 }
380 }
381 pub fn alloc(&mut self, value: T) -> ResourceIndex {
382 if let Some(index) = self.free_list.pop() {
383 self.data[index as usize] = value;
384 index
385 } else {
386 let index = self.data.len() as u32;
387 assert!(index < N);
388 self.data.push(value);
389 index
390 }
391 }
392 pub fn free(&mut self, index: ResourceIndex) {
393 self.free_list.push(index);
394 }
395 pub fn clear(&mut self) {
396 self.data.clear();
397 self.free_list.clear();
398 }
399}
400impl<T, const N: ResourceIndex> std::ops::Index<ResourceIndex> for ResourceArray<T, N> {
401 type Output = T;
402 fn index(&self, index: ResourceIndex) -> &T {
403 &self.data[index as usize]
404 }
405}
406impl<T, const N: ResourceIndex> std::ops::IndexMut<ResourceIndex> for ResourceArray<T, N> {
407 fn index_mut(&mut self, index: ResourceIndex) -> &mut T {
408 &mut self.data[index as usize]
409 }
410}
411pub type BufferArray<const N: ResourceIndex> = ResourceArray<BufferPiece, N>;
412pub type TextureArray<const N: ResourceIndex> = ResourceArray<TextureView, N>;
413pub type AccelerationStructureArray<const N: ResourceIndex> =
414 ResourceArray<AccelerationStructure, N>;
415
416#[derive(Clone, Copy, Debug)]
417pub struct TexturePiece {
418 pub texture: Texture,
419 pub mip_level: u32,
420 pub array_layer: u32,
421 pub origin: [u32; 3],
422}
423
424impl From<Texture> for TexturePiece {
425 fn from(texture: Texture) -> Self {
426 Self {
427 texture,
428 mip_level: 0,
429 array_layer: 0,
430 origin: [0; 3],
431 }
432 }
433}
434
435#[non_exhaustive]
436#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
437pub enum TextureFormat {
438 R8Unorm,
440 Rg8Unorm,
441 Rg8Snorm,
442 Rgba8Unorm,
443 Rgba8UnormSrgb,
444 Bgra8Unorm,
445 Bgra8UnormSrgb,
446 Rgba8Snorm,
447 R16Float,
448 Rg16Float,
449 Rgba16Float,
450 R32Float,
451 Rg32Float,
452 Rgba32Float,
453 R32Uint,
454 Rg32Uint,
455 Rgba32Uint,
456 Depth32Float,
458 Depth32FloatStencil8Uint,
459 Stencil8Uint,
460 Bc1Unorm,
462 Bc1UnormSrgb,
463 Bc2Unorm,
464 Bc2UnormSrgb,
465 Bc3Unorm,
466 Bc3UnormSrgb,
467 Bc4Unorm,
468 Bc4Snorm,
469 Bc5Unorm,
470 Bc5Snorm,
471 Bc6hUfloat,
472 Bc6hFloat,
473 Bc7Unorm,
474 Bc7UnormSrgb,
475 Rgb10a2Unorm,
477 Rg11b10Ufloat,
478 Rgb9e5Ufloat,
479}
480
481#[derive(Clone, Copy, Debug)]
482pub struct TexelBlockInfo {
483 pub dimensions: (u8, u8),
484 pub size: u8,
485}
486
487bitflags::bitflags! {
488 #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
489 pub struct TexelAspects: u8 {
490 const COLOR = 0x1;
491 const DEPTH = 0x2;
492 const STENCIL = 0x4;
493 }
494}
495
496#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
498pub enum TextureDimension {
499 D1,
501 D2,
503 D3,
505}
506
507#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
508pub enum ViewDimension {
509 D1,
510 D1Array,
511 D2,
512 D2Array,
513 Cube,
514 CubeArray,
515 D3,
516}
517
518#[repr(C)]
519#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
520pub struct Extent {
521 pub width: u32,
522 pub height: u32,
523 pub depth: u32,
524}
525impl Default for Extent {
526 fn default() -> Self {
527 Self {
528 width: 1,
529 height: 1,
530 depth: 1,
531 }
532 }
533}
534impl fmt::Display for Extent {
535 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
536 write!(f, "{}x{}x{}", self.width, self.height, self.depth)
537 }
538}
539
540impl Extent {
541 pub fn max_mip_levels(&self) -> u32 {
542 self.width
543 .max(self.height)
544 .max(self.depth)
545 .next_power_of_two()
546 .trailing_zeros()
547 }
548 pub fn at_mip_level(&self, level: u32) -> Self {
549 Self {
550 width: (self.width >> level).max(1),
551 height: (self.height >> level).max(1),
552 depth: (self.depth >> level).max(1),
553 }
554 }
555}
556
557bitflags::bitflags! {
558 #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
559 pub struct TextureUsage: u32 {
560 const COPY = 1 << 0;
561 const TARGET = 1 << 1;
562 const RESOURCE = 1 << 2;
563 const STORAGE = 1 << 3;
564 }
565}
566
567#[derive(Debug)]
568pub struct TextureDesc<'a> {
569 pub name: &'a str,
570 pub format: TextureFormat,
571 pub size: Extent,
572 pub array_layer_count: u32,
573 pub mip_level_count: u32,
574 pub sample_count: u32,
575 pub dimension: TextureDimension,
576 pub usage: TextureUsage,
577 pub external: Option<ExternalMemorySource>,
578}
579
580#[derive(Clone, Debug, Default, Eq, PartialEq)]
581pub struct TextureSubresources {
582 pub base_mip_level: u32,
583 pub mip_level_count: Option<NonZeroU32>,
584 pub base_array_layer: u32,
585 pub array_layer_count: Option<NonZeroU32>,
586}
587
588#[derive(Debug)]
589pub struct TextureViewDesc<'a> {
590 pub name: &'a str,
591 pub format: TextureFormat,
592 pub dimension: ViewDimension,
593 pub subresources: &'a TextureSubresources,
594}
595
596bitflags::bitflags! {
597 #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
598 pub struct ShaderVisibility: u32 {
599 const COMPUTE = 1 << 0;
600 const VERTEX = 1 << 1;
601 const FRAGMENT = 1 << 2;
602 }
603}
604
605#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
607pub enum AddressMode {
608 #[default]
610 ClampToEdge,
611 Repeat,
613 MirrorRepeat,
615 ClampToBorder,
617}
618
619#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
621pub enum FilterMode {
622 #[default]
624 Nearest,
625 Linear,
627}
628
629#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
631pub enum CompareFunction {
632 Never,
634 Less,
636 Equal,
640 LessEqual,
642 Greater,
644 NotEqual,
648 GreaterEqual,
650 #[default]
652 Always,
653}
654
655#[derive(Clone, Copy, Debug, PartialEq)]
656pub enum TextureColor {
657 TransparentBlack,
658 OpaqueBlack,
659 White,
660}
661
662#[derive(Debug, Default)]
663pub struct SamplerDesc<'a> {
664 pub name: &'a str,
665 pub address_modes: [AddressMode; 3],
666 pub mag_filter: FilterMode,
667 pub min_filter: FilterMode,
668 pub mipmap_filter: FilterMode,
669 pub lod_min_clamp: f32,
670 pub lod_max_clamp: Option<f32>,
671 pub compare: Option<CompareFunction>,
672 pub anisotropy_clamp: u32,
673 pub border_color: Option<TextureColor>,
674}
675
676#[derive(Debug)]
677pub enum AccelerationStructureType {
678 TopLevel,
679 BottomLevel,
680}
681
682#[derive(Debug)]
683pub struct AccelerationStructureDesc<'a> {
684 pub name: &'a str,
685 pub ty: AccelerationStructureType,
686 pub size: u64,
687}
688
689#[non_exhaustive]
690#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
691pub enum VertexFormat {
692 F32,
693 F32Vec2,
694 F32Vec3,
695 F32Vec4,
696 U32,
697 U32Vec2,
698 U32Vec3,
699 U32Vec4,
700 I32,
701 I32Vec2,
702 I32Vec3,
703 I32Vec4,
704}
705
706#[derive(Clone, Debug)]
707pub struct AccelerationStructureMesh {
708 pub vertex_data: BufferPiece,
709 pub vertex_format: VertexFormat,
710 pub vertex_stride: u32,
711 pub vertex_count: u32,
712 pub index_data: BufferPiece,
713 pub index_type: Option<IndexType>,
714 pub triangle_count: u32,
715 pub transform_data: BufferPiece,
716 pub is_opaque: bool,
717}
718
719#[derive(Clone, Debug)]
720pub struct AccelerationStructureInstance {
721 pub acceleration_structure_index: u32,
722 pub transform: Transform,
723 pub mask: u32,
724 pub custom_index: u32,
725}
726
727impl Default for AccelerationStructureInstance {
728 fn default() -> Self {
729 Self {
730 acceleration_structure_index: 0,
731 transform: IDENTITY_TRANSFORM,
732 mask: 0xFF,
733 custom_index: 0,
734 }
735 }
736}
737
738#[derive(Clone, Copy, Debug, Default, PartialEq)]
739pub struct AccelerationStructureSizes {
740 pub data: u64,
742 pub scratch: u64,
744}
745
746pub struct Shader {
747 module: naga::Module,
748 info: naga::valid::ModuleInfo,
749 source: String,
750}
751
752#[derive(Clone, Copy)]
753pub struct ShaderFunction<'a> {
754 pub shader: &'a Shader,
755 pub entry_point: &'a str,
756 pub constants: &'a PipelineConstants,
757}
758
759impl ShaderFunction<'_> {
760 fn entry_point_index(&self) -> usize {
761 self.shader
762 .module
763 .entry_points
764 .iter()
765 .position(|ep| ep.name == self.entry_point)
766 .expect("Entry point not found in the shader")
767 }
768}
769
770#[derive(Clone, Copy, Debug, PartialEq)]
771pub enum ShaderBinding {
772 Texture,
773 TextureArray { count: u32 },
774 Sampler,
775 Buffer,
776 BufferArray { count: u32 },
777 AccelerationStructure,
778 AccelerationStructureArray { count: u32 },
779 Plain { size: u32 },
780}
781
782pub trait ShaderBindable: Clone + Copy + derive::HasShaderBinding {
783 fn bind_to(&self, context: &mut PipelineContext, index: u32);
784}
785
786#[derive(Debug)]
787struct ShaderDataInfo {
788 visibility: ShaderVisibility,
789 binding_access: Box<[StorageAccess]>,
790}
791
792#[derive(Clone, Debug, Default, PartialEq)]
793pub struct ShaderDataLayout {
794 pub bindings: Vec<(&'static str, ShaderBinding)>,
795}
796impl ShaderDataLayout {
797 pub const EMPTY: &'static Self = &Self {
798 bindings: Vec::new(),
799 };
800
801 fn to_info(&self) -> ShaderDataInfo {
802 ShaderDataInfo {
803 visibility: ShaderVisibility::empty(),
804 binding_access: vec![StorageAccess::empty(); self.bindings.len()].into_boxed_slice(),
805 }
806 }
807}
808
809pub trait ShaderData {
810 fn layout() -> ShaderDataLayout;
811 fn fill(&self, context: PipelineContext);
812}
813
814#[derive(Copy, Clone, Debug, PartialEq)]
815pub struct VertexAttribute {
816 pub offset: u32,
817 pub format: VertexFormat,
818}
819
820struct VertexAttributeMapping {
821 buffer_index: usize,
822 attribute_index: usize,
823}
824
825#[derive(Clone, Debug, Default, PartialEq)]
826pub struct VertexLayout {
827 pub attributes: Vec<(&'static str, VertexAttribute)>,
828 pub stride: u32,
829}
830
831pub trait Vertex {
832 fn layout() -> VertexLayout;
833}
834
835#[derive(Clone, Debug, PartialEq)]
836pub struct VertexFetchState<'a> {
837 pub layout: &'a VertexLayout,
838 pub instanced: bool,
839}
840
841pub struct ShaderDesc<'a> {
842 pub source: &'a str,
845 pub naga_module: Option<naga::Module>,
848}
849
850#[derive(Clone, Debug, Default, PartialEq)]
851pub enum CommandType {
852 Transfer,
853 Compute,
854 #[default]
855 General,
856}
857
858pub struct CommandEncoderDesc<'a> {
859 pub name: &'a str,
860 pub buffer_count: u32,
864}
865
866pub struct ComputePipelineDesc<'a> {
867 pub name: &'a str,
868 pub data_layouts: &'a [&'a ShaderDataLayout],
869 pub compute: ShaderFunction<'a>,
870}
871
872#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
874pub enum PrimitiveTopology {
875 PointList,
877 LineList,
881 LineStrip,
885 #[default]
889 TriangleList,
890 TriangleStrip,
894}
895
896#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
898pub enum FrontFace {
899 #[default]
903 Ccw,
904 Cw,
908}
909
910#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
912pub enum Face {
913 Front,
915 Back,
917}
918
919#[derive(Clone, Debug, Default)]
920pub struct PrimitiveState {
921 pub topology: PrimitiveTopology,
923 pub front_face: FrontFace,
925 pub cull_mode: Option<Face>,
927 pub unclipped_depth: bool,
929 pub wireframe: bool,
931}
932
933#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
935pub enum StencilOperation {
936 #[default]
938 Keep,
939 Zero,
941 Replace,
943 Invert,
945 IncrementClamp,
947 DecrementClamp,
949 IncrementWrap,
951 DecrementWrap,
953}
954
955#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
959pub struct StencilFaceState {
960 pub compare: CompareFunction,
962 pub fail_op: StencilOperation,
964 pub depth_fail_op: StencilOperation,
966 pub pass_op: StencilOperation,
968}
969
970impl StencilFaceState {
971 pub const IGNORE: Self = StencilFaceState {
973 compare: CompareFunction::Always,
974 fail_op: StencilOperation::Keep,
975 depth_fail_op: StencilOperation::Keep,
976 pass_op: StencilOperation::Keep,
977 };
978}
979
980impl Default for StencilFaceState {
981 fn default() -> Self {
982 Self::IGNORE
983 }
984}
985
986#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
990pub struct StencilState {
991 pub front: StencilFaceState,
993 pub back: StencilFaceState,
995 pub read_mask: u32,
997 pub write_mask: u32,
999}
1000
1001#[derive(Clone, Copy, Debug, Default, PartialEq)]
1002pub struct DepthBiasState {
1003 pub constant: i32,
1005 pub slope_scale: f32,
1007 pub clamp: f32,
1009}
1010
1011#[derive(Clone, Debug)]
1013pub struct DepthStencilState {
1014 pub format: TextureFormat,
1016 pub depth_write_enabled: bool,
1018 pub depth_compare: CompareFunction,
1020 pub stencil: StencilState,
1022 pub bias: DepthBiasState,
1024}
1025
1026#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
1028pub enum BlendFactor {
1029 Zero,
1031 One,
1033 Src,
1035 OneMinusSrc,
1037 SrcAlpha,
1039 OneMinusSrcAlpha,
1041 Dst,
1043 OneMinusDst,
1045 DstAlpha,
1047 OneMinusDstAlpha,
1049 SrcAlphaSaturated,
1051 Constant,
1053 OneMinusConstant,
1055 Src1,
1057 OneMinusSrc1,
1059 Src1Alpha,
1061 OneMinusSrc1Alpha,
1063}
1064
1065impl BlendFactor {
1066 pub const fn uses_dual_source(&self) -> bool {
1067 matches!(
1068 self,
1069 BlendFactor::Src1
1070 | BlendFactor::OneMinusSrc1
1071 | BlendFactor::Src1Alpha
1072 | BlendFactor::OneMinusSrc1Alpha
1073 )
1074 }
1075}
1076
1077#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
1079pub enum BlendOperation {
1080 #[default]
1082 Add,
1083 Subtract,
1085 ReverseSubtract,
1087 Min,
1089 Max,
1091}
1092
1093#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1095pub struct BlendComponent {
1096 pub src_factor: BlendFactor,
1098 pub dst_factor: BlendFactor,
1100 pub operation: BlendOperation,
1103}
1104
1105impl BlendComponent {
1106 pub const REPLACE: Self = Self {
1108 src_factor: BlendFactor::One,
1109 dst_factor: BlendFactor::Zero,
1110 operation: BlendOperation::Add,
1111 };
1112
1113 pub const OVER: Self = Self {
1115 src_factor: BlendFactor::One,
1116 dst_factor: BlendFactor::OneMinusSrcAlpha,
1117 operation: BlendOperation::Add,
1118 };
1119
1120 pub const ADDITIVE: Self = Self {
1122 src_factor: BlendFactor::One,
1123 dst_factor: BlendFactor::One,
1124 operation: BlendOperation::Add,
1125 };
1126
1127 pub const fn uses_dual_source(&self) -> bool {
1128 self.src_factor.uses_dual_source() || self.dst_factor.uses_dual_source()
1129 }
1130}
1131
1132impl Default for BlendComponent {
1133 fn default() -> Self {
1134 Self::REPLACE
1135 }
1136}
1137
1138#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1141pub struct BlendState {
1142 pub color: BlendComponent,
1144 pub alpha: BlendComponent,
1146}
1147
1148impl BlendState {
1149 pub const REPLACE: Self = Self {
1151 color: BlendComponent::REPLACE,
1152 alpha: BlendComponent::REPLACE,
1153 };
1154
1155 pub const ALPHA_BLENDING: Self = Self {
1157 color: BlendComponent {
1158 src_factor: BlendFactor::SrcAlpha,
1159 dst_factor: BlendFactor::OneMinusSrcAlpha,
1160 operation: BlendOperation::Add,
1161 },
1162 alpha: BlendComponent::OVER,
1163 };
1164
1165 pub const PREMULTIPLIED_ALPHA_BLENDING: Self = Self {
1167 color: BlendComponent::OVER,
1168 alpha: BlendComponent::OVER,
1169 };
1170
1171 pub const ADDITIVE: Self = Self {
1173 color: BlendComponent::ADDITIVE,
1174 alpha: BlendComponent::ADDITIVE,
1175 };
1176
1177 pub const fn uses_dual_source(&self) -> bool {
1178 self.color.uses_dual_source() || self.alpha.uses_dual_source()
1179 }
1180}
1181
1182bitflags::bitflags! {
1183 #[repr(transparent)]
1185 #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
1186 pub struct ColorWrites: u32 {
1187 const RED = 1 << 0;
1189 const GREEN = 1 << 1;
1191 const BLUE = 1 << 2;
1193 const ALPHA = 1 << 3;
1195 const COLOR = Self::RED.bits() | Self::GREEN.bits() | Self::BLUE.bits();
1197 const ALL = Self::RED.bits() | Self::GREEN.bits() | Self::BLUE.bits() | Self::ALPHA.bits();
1199 }
1200}
1201
1202impl Default for ColorWrites {
1203 fn default() -> Self {
1204 Self::ALL
1205 }
1206}
1207
1208#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1210pub struct ColorTargetState {
1211 pub format: TextureFormat,
1213 pub blend: Option<BlendState>,
1215 pub write_mask: ColorWrites,
1217}
1218
1219impl From<TextureFormat> for ColorTargetState {
1220 fn from(format: TextureFormat) -> Self {
1221 Self {
1222 format,
1223 blend: None,
1224 write_mask: ColorWrites::ALL,
1225 }
1226 }
1227}
1228
1229pub struct RenderPipelineDesc<'a> {
1230 pub name: &'a str,
1231 pub data_layouts: &'a [&'a ShaderDataLayout],
1232 pub vertex: ShaderFunction<'a>,
1233 pub vertex_fetches: &'a [VertexFetchState<'a>],
1234 pub primitive: PrimitiveState,
1235 pub depth_stencil: Option<DepthStencilState>,
1236 pub fragment: Option<ShaderFunction<'a>>,
1237 pub color_targets: &'a [ColorTargetState],
1238 pub multisample_state: MultisampleState,
1239}
1240
1241#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
1242pub struct MultisampleState {
1243 pub sample_count: u32,
1244 pub sample_mask: u64,
1245 pub alpha_to_coverage: bool,
1246}
1247
1248impl Default for MultisampleState {
1249 fn default() -> Self {
1250 Self {
1251 sample_count: 1,
1252 sample_mask: !0,
1253 alpha_to_coverage: false,
1254 }
1255 }
1256}
1257
1258#[derive(Clone, Copy, Debug)]
1259pub enum InitOp {
1260 Load,
1261 Clear(TextureColor),
1262 DontCare,
1263}
1264
1265#[derive(Clone, Copy, Debug)]
1266pub enum FinishOp {
1267 Store,
1268 Discard,
1269 ResolveTo(TextureView),
1272 Ignore,
1273}
1274
1275#[derive(Debug)]
1276pub struct RenderTarget {
1277 pub view: TextureView,
1278 pub init_op: InitOp,
1279 pub finish_op: FinishOp,
1280}
1281
1282#[derive(Debug)]
1283pub struct RenderTargetSet<'a> {
1284 pub colors: &'a [RenderTarget],
1285 pub depth_stencil: Option<RenderTarget>,
1286}
1287
1288#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
1290pub enum DisplaySync {
1291 #[default]
1293 Block,
1294 Recent,
1297 Tear,
1299}
1300
1301#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
1302pub enum ColorSpace {
1303 #[default]
1304 Linear,
1305 Srgb,
1306}
1307
1308#[derive(Clone, Copy, Debug, Default, PartialEq)]
1309pub struct SurfaceConfig {
1310 pub size: Extent,
1311 pub usage: TextureUsage,
1312 pub display_sync: DisplaySync,
1313 pub color_space: ColorSpace,
1320 pub transparent: bool,
1321 pub allow_exclusive_full_screen: bool,
1322}
1323
1324#[derive(Clone, Copy, Debug, PartialEq)]
1325pub struct XrSurfaceConfig {
1326 pub size: Extent,
1327 pub usage: TextureUsage,
1328 pub color_space: ColorSpace,
1329 pub view_count: u32,
1330}
1331
1332impl Default for XrSurfaceConfig {
1333 fn default() -> Self {
1334 Self {
1335 size: Extent::default(),
1336 usage: TextureUsage::TARGET,
1337 color_space: ColorSpace::Linear,
1338 view_count: 2,
1339 }
1340 }
1341}
1342
1343#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
1344pub enum AlphaMode {
1345 #[default]
1346 Ignored,
1347 PreMultiplied,
1348 PostMultiplied,
1349}
1350
1351#[derive(Clone, Copy, Debug, PartialEq)]
1352pub struct SurfaceInfo {
1353 pub format: TextureFormat,
1354 pub alpha: AlphaMode,
1355}
1356
1357#[derive(Clone, Copy, Debug, PartialEq)]
1358pub enum IndexType {
1359 U16,
1360 U32,
1361}
1362
1363#[derive(Clone, Debug, PartialEq)]
1364pub struct ScissorRect {
1365 pub x: i32,
1366 pub y: i32,
1367 pub w: u32,
1368 pub h: u32,
1369}
1370
1371#[derive(Clone, Debug, PartialEq)]
1372pub struct Viewport {
1373 pub x: f32,
1374 pub y: f32,
1375 pub w: f32,
1376 pub h: f32,
1377 pub depth: std::ops::Range<f32>,
1378}
1379
1380pub type Timings = Vec<(String, std::time::Duration)>;