hotline_rs/
gfx.rs

1use crate::os;
2use std::any::Any;
3use serde::{Deserialize, Serialize};
4use std::hash::Hash;
5use maths_rs::max;
6
7/// Implemets this interface with a Direct3D12 backend.
8#[cfg(target_os = "windows")]
9pub mod d3d12;
10
11type Error = super::Error;
12
13/// Macro to pass data!\[expression\] or data!\[\] (None) to a create function, so you don't have to deduce a 'T'.
14#[macro_export]
15macro_rules! data {
16    () => {
17        None::<&[()]>
18    };
19    ($input:expr) => {
20        Some($input)
21    }
22}
23
24/// Macro to inject debug names into gpu resources
25#[cfg(target_os = "windows")]
26#[macro_export]
27macro_rules! gfx_debug_name {
28    ($object:expr, $name:expr) => {
29        d3d12_debug_name($object, $name);
30    }
31}
32
33/// 3-Dimensional struct for compute shader thread count / thread group size.
34#[derive(Copy, Clone)]
35pub struct Size3 {
36    pub x: u32,
37    pub y: u32,
38    pub z: u32,
39}
40
41/// 3-Dimensional region used for copying resources
42#[derive(Copy, Clone)]
43pub struct Region {
44    pub left: u32,
45    pub top: u32,
46    pub front: u32,
47    pub right: u32,
48    pub bottom: u32,
49    pub back: u32
50}
51
52/// Structure to specify viewport coordinates on a `CmdBuf`.
53#[derive(Copy, Clone)]
54pub struct Viewport {
55    /// Top left x coordinate.
56    pub x: f32,
57    /// Top left y coordinate.
58    pub y: f32,
59    /// Width of the viewport rectangle.
60    pub width: f32,
61    /// Height of the viewport rectangle (Y is down).
62    pub height: f32,
63    /// Minimum depth of the viewport. Ranges between 0 and 1.
64    pub min_depth: f32,
65    /// Maximum depth of the viewport. Ranges between 0 and 1.
66    pub max_depth: f32,
67}
68
69/// Structure to specify scissor rect coordinates on a `CmdBuf`.
70#[derive(Copy, Clone)]
71pub struct ScissorRect {
72    // Left x coordinate.
73    pub left: i32,
74    // Top y coordinate.
75    pub top: i32,
76    /// Right x coordinate.
77    pub right: i32,
78    /// Bottom y coordinate.
79    pub bottom: i32,
80}
81
82/// Format for resource types (textures / buffers).
83/// n = normalised unsigned integer,
84/// u = unsigned integer,
85/// i = signed integer,
86/// f = float
87#[derive(Copy, Clone, Serialize, Deserialize, Hash, PartialEq)]
88pub enum Format {
89    Unknown,
90    R16n,
91    R16u,
92    R16i,
93    R16f,
94    R32u,
95    R32i,
96    R32f,
97    RG16f,
98    RG16u,
99    RG16i,
100    RG32u,
101    RG32i,
102    RG32f,
103    RGB32u,
104    RGB32i,
105    RGB32f,
106    RGBA8nSRGB,
107    RGBA8n,
108    RGBA8u,
109    RGBA8i,
110    BGRA8n,
111    BGRX8n,
112    BGRA8nSRGB,
113    BGRX8nSRGB,
114    RGBA16u,
115    RGBA16i,
116    RGBA16f,
117    RGBA32u,
118    RGBA32i,
119    RGBA32f,
120    D32fS8X24u,
121    D32f,
122    D24nS8u,
123    D16n,
124    BC1n,
125    BC1nSRGB,
126    BC2n,
127    BC2nSRGB,
128    BC3n,
129    BC3nSRGB,
130    BC4n,
131    BC5n,
132}
133
134/// Information to create a device, it contains default heaps for resource views
135/// resources will be automatically allocated into these heaps, you can supply custom heaps if necessary.
136#[derive(Default)]
137pub struct DeviceInfo {
138    /// optional adapter to choose a specific adapter in the scenario of a multi-adapter system
139    /// if None is supplied the first non-software emulation adapter would be selected.
140    pub adapter_name: Option<String>,
141    /// space for shader resource views, constant buffers and unordered access views.
142    pub shader_heap_size: usize,
143    /// space for colour render targets.
144    pub render_target_heap_size: usize,
145    /// space for depth stencil targets.
146    pub depth_stencil_heap_size: usize,
147}
148
149/// Information returned from `Device::get_adapter_info`.
150#[derive(Clone)]
151pub struct AdapterInfo {
152    /// The chosen adapter a device was created with.
153    pub name: String,
154    /// Description of the device.
155    pub description: String,
156    /// Dedicated video memory in bytes.
157    pub dedicated_video_memory: usize,
158    /// Dedicated system memory in bytes.
159    pub dedicated_system_memory: usize,
160    /// Shared system memory in bytes.
161    pub shared_system_memory: usize,
162    /// List of available adapter descriptons.
163    pub available: Vec<String>,
164}
165
166/// Information to create a desciptor heap... `Device` will contain default heaps, but you can create your own if required.
167pub struct HeapInfo {
168    /// ie: Shader, RenderTarget, DepthStencil, Sampler.
169    pub heap_type: HeapType,
170    /// Total size of the heap in number of resources.
171    pub num_descriptors: usize,
172}
173
174/// Options for heap types.
175#[derive(Copy, Clone, PartialEq, Eq)]
176pub enum HeapType {
177    /// For shader resource view, constant buffer or unordered access.
178    Shader,
179    /// For render targets
180    RenderTarget,
181    /// For depth stencil targets
182    DepthStencil,
183    /// For sampler states
184    Sampler,
185}
186
187/// Allows user specified heaps to be used for creating views when creating textures through `create_texture_with_heap`
188/// you can supply `None` for the heap types are not applicable and if a view is requested for a `None` heap the
189/// default device heaps will be used instead
190pub struct TextureHeapInfo<'stack, D: Device> {
191    /// Heap to allocate shader resource views and un-ordered access views
192    pub shader: Option<&'stack mut D::Heap>,
193    /// Heap to allocate render target views
194    pub render_target: Option<&'stack mut D::Heap>,
195    /// Heap to allocate depth stencil views
196    pub depth_stencil: Option<&'stack mut D::Heap>,
197}
198
199/// Information to create a query heap.
200pub struct QueryHeapInfo {
201    /// ie: Timestamp, Occlusion, PipelineStatistics
202    pub heap_type: QueryType,
203    /// Total size of the heap in number of queries.
204    pub num_queries: usize,
205}
206
207/// Options for query heap types, and queries
208#[derive(Copy, Clone, PartialEq, Eq)]
209pub enum QueryType {
210    /// Used for occlusion query heap or occlusion queries
211    Occlusion,
212    /// Can be used in the same heap as occlusion
213    BinaryOcclusion,
214    /// Create a heap to contain timestamp queries
215    Timestamp,
216    /// Create a heap to contain a structure of `PipelineStatistics`
217    PipelineStatistics,
218    /// Create video decoder statistics query and heap
219    VideoDecodeStatistics,
220}
221
222/// GPU pipeline statistics obtain by using a `PipelineStatistics` query
223pub struct PipelineStatistics {
224    pub input_assembler_vertices: u64,
225    pub input_assembler_primitives: u64,
226    pub vertex_shader_invocations: u64,
227    pub pixel_shader_primitives: u64,
228    pub compute_shader_invocations: u64
229}
230
231/// Information to pass to `Device::create_swap_chain`.
232pub struct SwapChainInfo {
233    /// Number of internal buffers to keep behind the scenes, which are swapped between each frame 
234    /// to allow overlapped CPU/GPU command buffer producer / consumer
235    pub num_buffers: u32,
236    /// Must be BGRA8n, RGBA8n or RGBA16f.
237    pub format: Format,
238    /// Colour for clearing the window when using the backbuffer pass, use None to not clear.
239    pub clear_colour: Option<ClearColour>,
240}
241
242/// Information to create a buffer through `Device::create_buffer`.
243#[derive(Copy, Clone)]
244pub struct BufferInfo {
245    /// Indicates how the buffer will be used on the GPU.
246    pub usage: BufferUsage,
247    /// Used to indicate if we want to read or write from the CPU, use NONE if possible for best performance.
248    pub cpu_access: CpuAccessFlags,
249    /// Data format of the buffer this is is only required for index buffers and can be `gfx::Format::Unknown` otherwise
250    pub format: Format,
251    /// The stride of a vertex or structure in bytes.
252    pub stride: usize,
253    /// The number of array elements.
254    pub num_elements: usize,
255    /// Initial state to start image transition barriers before state
256    pub initial_state: ResourceState,
257}
258
259/// Information to create a shader through `Device::create_shader`.
260pub struct ShaderInfo {
261    /// Type of the shader (Vertex, Fragment, Compute, etc...).
262    pub shader_type: ShaderType,
263    /// Optional info to compile from source, if this is none then
264    /// the shader will be treated as a precompiled byte code blob.
265    pub compile_info: Option<ShaderCompileInfo>,
266}
267
268/// Information required to compile a shader from source code.
269pub struct ShaderCompileInfo {
270    /// The name of the entry point function in the shader to compile.
271    pub entry_point: String,
272    /// The target you wish to compile for, this is paltform specific.
273    /// hlsl: (vs_5_0, ps_5_0, vs_6_0, ps_6_0).
274    pub target: String,
275    /// Flags to pass to the compiler.
276    pub flags: ShaderCompileFlags,
277}
278
279/// The stage to which a shader will bind itself.
280#[derive(Copy, Clone)]
281pub enum ShaderType {
282    Vertex,
283    Fragment,
284    Compute,
285}
286
287bitflags! {
288    /// Device feature flags.
289    pub struct DeviceFeatureFlags: u32 {
290        const NONE = 0;
291        const RAYTRACING = 1<<0;
292        const MESH_SAHDER = 1<<1;
293    }
294
295    /// Shader compilation flags.
296    pub struct ShaderCompileFlags: u32 {
297        /// No flags, default compilation.
298        const NONE = 0b00000000;
299        /// Generates shader with debug info
300        const DEBUG = 0b00000001;
301        /// Skips optimization for easier debuggability, deterministic results and faster compilation.
302        const SKIP_OPTIMIZATION = 0b00000010;
303    }
304
305    /// Render target write mask flags.
306    #[derive(Serialize, Deserialize)]
307    pub struct WriteMask : u8 {
308        // Write no colour channels
309        const NONE = 0;
310        /// Write the red colour channel
311        const RED = 1<<0;
312        /// Write the green colour channel
313        const GREEN = 1<<1;
314        /// Write the blue colour channel
315        const BLUE = 1<<2;
316        /// Write the alpha channel
317        const ALPHA = 1<<3;
318        /// Write (RED|GREEN|BLUE|ALPHA)
319        const ALL = (1<<4)-1;
320    }
321
322    /// CPU Access flags for buffers or textures.
323    pub struct CpuAccessFlags: u8 {
324        /// No CPUT access required, use this for best performance if you do not need to write data to a resource
325        const NONE = 1<<0;
326        /// CPU will read data from the resource
327        const READ = 1<<1;
328        /// CPU will write data to the resourc
329        const WRITE = 1<<2;
330        /// Must be used in conjunction with READ or WRITE, the resource will mapped once and never un-mapped
331        const PERSISTENTLY_MAPPED = 1<<3;
332    }
333
334    /// Textures can be used in one or more of the following ways
335    #[derive(Serialize, Deserialize)]
336    pub struct TextureUsage: u32 {
337        /// Texture will be only used for data storage and not used on any GPU pipeline stages
338        const NONE = 0;
339        /// Texture will be sampled in a shader
340        const SHADER_RESOURCE = (1 << 0);
341        /// Used as a read-writable resource in compute shaders
342        const UNORDERED_ACCESS = (1 << 1);
343        /// Used as a colour render target
344        const RENDER_TARGET = (1 << 2);
345        /// Used as a depth stencil buffer
346        const DEPTH_STENCIL = (1 << 3);
347        /// Used as a target for hardware assisted video decoding operations
348        const VIDEO_DECODE_TARGET = (1 << 4);
349        /// Indicates the texture will have mip-maps generated at run time
350        const GENERATE_MIP_MAPS = (1 << 5);
351    }
352
353    /// Describes how a buffer will be used on the GPU.
354    //#[derive(Copy, Clone, PartialEq)]
355    pub struct BufferUsage : u32 {
356        /// Used to simply store data (query results, copy buffers etc)
357        const NONE = 0;
358        /// Used as a Vertex buffer binding
359        const VERTEX = (1 << 0);
360        /// Used as a Vertex buffer binding
361        const INDEX = (1 << 1);
362        /// Used as constant buffer for shader data
363        const CONSTANT_BUFFER = (1 << 2);
364        /// Texture will be sampled in a shader
365        const SHADER_RESOURCE = (1 << 3);
366        /// Used as a read-writable resource in compute shaders
367        const UNORDERED_ACCESS = (1 << 4);
368        /// Used as indirect arguments for `execute_indirect`
369        const INDIRECT_ARGUMENT_BUFFER = (1 << 5);
370        /// Used in shader as `AppendStructuredBuffer` and contains a counter element
371        const APPEND_COUNTER = (1 << 6);
372    }
373}
374
375/// `PipelineLayout` is required to create a pipeline it describes the layout of resources for access on the GPU.
376#[derive(Default, Clone, Serialize, Deserialize)]
377pub struct PipelineLayout {
378    /// Vector of `DescriptorBinding` which are arrays of textures, samplers or structured buffers, etc
379    pub bindings: Option<Vec<DescriptorBinding>>,
380    /// Small amounts of data that can be pushed into a command buffer and available as data in shaders
381    pub push_constants: Option<Vec<PushConstantInfo>>,
382    /// Static samplers that come along with the pipeline, 
383    pub static_samplers: Option<Vec<SamplerBinding>>,
384}
385
386/// Describes a range of resources for access on the GPU.
387#[derive(Clone, Serialize, Deserialize)]
388pub struct DescriptorBinding {
389    /// The shader stage the resources will be accessible to.
390    pub visibility: ShaderVisibility,
391    /// Register index to bind to (supplied in shader).
392    pub shader_register: u32,
393    /// Register space to bind to (supplied in shader).
394    pub register_space: u32,
395    /// Type of resources in this descriptor binding.
396    pub binding_type: DescriptorType,
397    /// Number of descriptors in this table, use `None` for unbounded.
398    pub num_descriptors: Option<u32>,
399}
400
401/// Describes the type of descriptor binding to create.
402#[derive(Clone, Copy, Serialize, Deserialize, Hash)]
403pub enum DescriptorType {
404    /// Used for textures or structured buffers.
405    ShaderResource,
406    /// Used for cbuffers.
407    ConstantBuffer,
408    /// Used for read-write textures.
409    UnorderedAccess,
410    /// Used for texture samplers.
411    Sampler,
412    /// Used for push constants
413    PushConstants
414}
415
416/// Describes the visibility of which shader stages can access a descriptor.
417#[derive(Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, Default)]
418pub enum ShaderVisibility {
419    #[default]
420    All,
421    Vertex,
422    Fragment,
423    Compute,
424}
425
426/// Describes space in the shader to send data to via `CmdBuf::push_constants`. 
427#[derive(Clone, Serialize, Deserialize)]
428pub struct PushConstantInfo {
429    /// The shader stage the constants will be accessible to.
430    pub visibility: ShaderVisibility,
431    /// Register index to bind to (supplied in shader).
432    pub shader_register: u32,
433    /// Register space to bind to (supplied in shader).
434    pub register_space: u32,
435    /// Number of 32-bit values to push.
436    pub num_values: u32,
437}
438
439/// You can request this based on resource type, register and space (as specified in shader)
440#[derive(Clone)]
441pub struct PipelineSlotInfo {
442    /// The slot in the pipeline layout to bind to
443    pub index: u32,
444    /// The number of descriptors or the number of 32-bit push constant values, if `None` the table is unbounded
445    pub count: Option<u32>
446}
447
448/// Input layout describes the layout of vertex buffers bound to the input assembler.
449pub type InputLayout = Vec<InputElementInfo>;
450
451/// Describe a single element of an `InputLayoutInfo`.
452#[derive(Clone, Serialize, Deserialize)]
453pub struct InputElementInfo {
454    /// Element semantic ie. POSITION, TEXCOORD, COLOR etc.
455    pub semantic: String,
456    /// Index of the semantic ie. TEXCOORD0, TEXCOORD1 etc.
457    pub index: u32,
458    /// Format of the element size and width.
459    pub format: Format,
460    /// The vertex buffer slot this buffer will be bound to.
461    pub input_slot: u32,
462    /// Aligned byte offset of this element from the start of the struct.
463    pub aligned_byte_offset: u32,
464    /// Vertex or Instance stride.
465    pub input_slot_class: InputSlotClass,
466    /// Rate at which to step vertices.
467    pub step_rate: u32,
468}
469
470/// Describes the frequency of which elements are fetched from a vertex input element.
471#[derive(Clone, Serialize, Deserialize)]
472pub enum InputSlotClass {
473    PerVertex,
474    PerInstance,
475}
476
477/// Individual sampler state binding for use in static samplers in a `PipelineLayout`.
478#[derive(Copy, Clone, Serialize, Deserialize)]
479pub struct SamplerBinding {
480    /// The shader stage the sampler will be accessible to
481    pub visibility: ShaderVisibility,
482    /// Register index to bind to (supplied in shader)
483    pub shader_register: u32,
484    /// Register space to bind to (supplied in shader)
485    pub register_space: u32,
486    /// Sampler Info
487    pub sampler_info: SamplerInfo
488}
489
490/// Info to create a sampler state object to sample textures in shaders.
491#[derive(Copy, Clone, Serialize, Deserialize)]
492pub struct SamplerInfo {
493    pub filter: SamplerFilter,
494    pub address_u: SamplerAddressMode,
495    pub address_v: SamplerAddressMode,
496    pub address_w: SamplerAddressMode,
497    pub comparison: Option<ComparisonFunc>,
498    /// Colour is rgba8 packed into a u32
499    pub border_colour: Option<u32>,
500    pub mip_lod_bias: f32,
501    pub max_aniso: u32,
502    pub min_lod: f32,
503    pub max_lod: f32,
504}
505
506/// Filtering mode for the sampler (controls bilinear and trilinear interpolation).
507#[derive(Copy, Clone, Serialize, Deserialize)]
508pub enum SamplerFilter {
509    Point,
510    Linear,
511    Anisotropic,
512}
513
514/// Address mode for the sampler (controls wrapping and clamping).
515#[derive(Copy, Clone, Serialize, Deserialize)]
516pub enum SamplerAddressMode {
517    Wrap,
518    Mirror,
519    Clamp,
520    Border,
521    MirrorOnce,
522}
523
524/// Used for comparison ops in depth testing, samplers.
525#[derive(Copy, Clone, Serialize, Deserialize)]
526pub enum ComparisonFunc {
527    Never,
528    Less,
529    Equal,
530    LessEqual,
531    Greater,
532    NotEqual,
533    GreaterEqual,
534    Always,
535}
536
537/// Information to create a pipeline through `Device::create_render_pipeline`.
538pub struct RenderPipelineInfo<'stack, D: Device> {
539    /// Vertex Shader
540    pub vs: Option<&'stack D::Shader>,
541    /// Fragment Shader
542    pub fs: Option<&'stack D::Shader>,
543    /// Vertex shader input layout
544    pub input_layout: InputLayout,
545    /// Layout of shader resources (constant buffers, structured buffers, textures, etc)
546    pub pipeline_layout: PipelineLayout,
547    /// Control rasterisation of primitives
548    pub raster_info: RasterInfo,
549    /// Control depth test and stencil oprations
550    pub depth_stencil_info: DepthStencilInfo,
551    /// Control blending settings for the output merge stage
552    pub blend_info: BlendInfo,
553    /// Primitive topolgy oof the input assembler
554    pub topology: Topology,
555    /// Only required for Topology::PatchList use 0 as default
556    pub patch_index: u32,
557    /// Sample mask for which MSAA samples to write
558    pub sample_mask: u32,
559    /// A valid render pass, you can share pipelines across passes providing the render target
560    /// formats and sample count are the same of the passes you wish to use the pipeline on
561    pub pass: Option<&'stack D::RenderPass>,
562}
563
564/// Indicates how the pipeline interprets vertex data at the input assembler stage
565/// This will be also used to infer primitive topology types for geometry or hull shaders
566#[derive(Copy, Clone, Serialize, Deserialize)]
567pub enum Topology {
568    Undefined,
569    PointList,
570    LineList,
571    LineStrip,
572    TriangleList,
573    TriangleStrip,
574    LineListAdj,
575    LineStripAdj,
576    TriangleListAdj,
577    TriangleStripAdj,
578    PatchList,
579}
580
581/// Information to control the rasterisation mode of primitives when using a `RenderPipeline`
582#[derive(Clone, Copy, Serialize, Deserialize)]
583pub struct RasterInfo {
584    pub fill_mode: FillMode,
585    pub cull_mode: CullMode,
586    pub front_ccw: bool,
587    pub depth_bias: i32,
588    pub depth_bias_clamp: f32,
589    pub slope_scaled_depth_bias: f32,
590    pub depth_clip_enable: bool,
591    pub multisample_enable: bool,
592    pub antialiased_line_enable: bool,
593    pub forced_sample_count: u32,
594    pub conservative_raster_mode: bool,
595}
596
597/// Polygon fillmode
598#[derive(Clone, Copy, Serialize, Deserialize)]
599pub enum FillMode {
600    Wireframe,
601    Solid,
602}
603
604/// Polygon cull mode
605#[derive(Clone, Copy, Serialize, Deserialize)]
606pub enum CullMode {
607    None,
608    Front,
609    Back,
610}
611
612/// Information to control the depth and stencil testing of primitves when using a `RenderPipeline`
613#[derive(Clone, Copy, Serialize, Deserialize)]
614pub struct DepthStencilInfo {
615    /// Enable depth testing
616    pub depth_enabled: bool,
617    /// Choose to write or not write to the depth buffer
618    pub depth_write_mask: DepthWriteMask,
619    pub depth_func: ComparisonFunc,
620    /// Enable stencil testing
621    pub stencil_enabled: bool,
622    pub stencil_read_mask: u8,
623    pub stencil_write_mask: u8,
624    pub front_face: StencilInfo,
625    pub back_face: StencilInfo,
626}
627
628/// Write to the depth buffer, or omit writes and just perform depth testing
629#[derive(Clone, Copy, Serialize, Deserialize)]
630pub enum DepthWriteMask {
631    Zero,
632    All,
633}
634
635/// Stencil info for various outcomes of the depth stencil test
636#[derive(Clone, Copy, Serialize, Deserialize)]
637pub struct StencilInfo {
638    pub fail: StencilOp,
639    pub depth_fail: StencilOp,
640    pub pass: StencilOp,
641    pub func: ComparisonFunc,
642}
643
644/// Stencil operations
645#[derive(Clone, Copy, Serialize, Deserialize)]
646pub enum StencilOp {
647    Keep,
648    Zero,
649    Replace,
650    IncrSat,
651    DecrSat,
652    Invert,
653    Incr,
654    Decr,
655}
656
657/// Information to control blending operations on render targets
658#[derive(Default)]
659pub struct BlendInfo {
660    pub alpha_to_coverage_enabled: bool,
661    /// Separate blending on colour and alpha channels
662    pub independent_blend_enabled: bool,
663    /// Separate blend operations for each bout render targets
664    pub render_target: Vec<RenderTargetBlendInfo>,
665}
666
667/// Blending operations for a single render target
668#[derive(Clone, Serialize, Deserialize)]
669pub struct RenderTargetBlendInfo {
670    pub blend_enabled: bool,
671    pub logic_op_enabled: bool,
672    pub src_blend: BlendFactor,
673    pub dst_blend: BlendFactor,
674    pub blend_op: BlendOp,
675    pub src_blend_alpha: BlendFactor,
676    pub dst_blend_alpha: BlendFactor,
677    pub blend_op_alpha: BlendOp,
678    pub logic_op: LogicOp,
679    pub write_mask: WriteMask,
680}
681
682/// Controls how the source and destination terms in blend equation are derrived
683#[derive(Clone, Copy, Serialize, Deserialize)]
684pub enum BlendFactor {
685    Zero,
686    One,
687    SrcColour,
688    InvSrcColour,
689    SrcAlpha,
690    InvSrcAlpha,
691    DstAlpha,
692    InvDstAlpha,
693    DstColour,
694    InvDstColour,
695    SrcAlphaSat,
696    BlendFactor,
697    InvBlendFactor,
698    Src1Colour,
699    InvSrc1Colour,
700    Src1Alpha,
701    InvSrc1Alpha,
702}
703
704/// Controls how the source and destination terms are combined: final = src (op) dest
705#[derive(Clone, Copy, Serialize, Deserialize)]
706pub enum BlendOp {
707    Add,
708    Subtract,
709    RevSubtract,
710    Min,
711    Max,
712}
713
714/// The logical operation to configure for a render target blend with logic op enabled
715#[derive(Clone, Copy, Serialize, Deserialize)]
716pub enum LogicOp {
717    Clear,
718    Set,
719    Copy,
720    CopyInverted,
721    NoOp,
722    Invert,
723    And,
724    Nand,
725    Or,
726    Nor,
727    Xor,
728    Equiv,
729    AndReverse,
730    AndInverted,
731    OrReverse,
732    OrInverted,
733}
734
735/// Information to create a compute pipeline through `Device::create_compute_pipeline`
736pub struct ComputePipelineInfo<'stack, D: Device> {
737    /// Compute Shader
738    pub cs: &'stack D::Shader,
739    /// Describe the layout of resources we bind on the pipeline
740    pub pipeline_layout: PipelineLayout,
741}
742
743/// Information to create a pipeline through `Device::create_texture`.
744#[derive(Copy, Clone)]
745pub struct TextureInfo {
746    /// Texture type
747    pub tex_type: TextureType,
748    /// Texture format
749    pub format: Format,
750    /// Width of the image in texels
751    pub width: u64,
752    /// Height of the image in texels for `TextureType::Texture2D` and `Texture3D` use 1 for `Texture1D`
753    pub height: u64,
754    /// Depth of the image in slices of (`width` x `height`) for `TextureType::Texture3D` only (use 1 other wise)
755    pub depth: u32,
756    /// Number of array levels or slices for `Texture1D` or `Texture2D` arrays. use 1 otherwise
757    pub array_layers: u32,
758    /// Number of mip levels in the image
759    pub mip_levels: u32,
760    /// Number of MSAA samples
761    pub samples: u32,
762    /// Indicate how this texture will be used on the GPU
763    pub usage: TextureUsage,
764    /// Initial state to start image transition barriers before state
765    pub initial_state: ResourceState,
766}
767
768/// Describes the dimension of a texture
769#[derive(Copy, Clone, Debug)]
770pub enum TextureType {
771    Texture1D,
772    Texture1DArray,
773    Texture2D,
774    Texture2DArray,
775    Texture3D,
776    TextureCube,
777    TextureCubeArray
778}
779
780/// Values to clear colour render targets at the start of a `RenderPass`
781#[derive(Copy, Clone)]
782pub struct ClearColour {
783    pub r: f32,
784    pub g: f32,
785    pub b: f32,
786    pub a: f32,
787}
788
789/// Values to clear depth stencil buffers during a `RenderPass`
790pub struct ClearDepthStencil {
791    /// Clear value for the depth buffer. Use `None` to preserve existing contents.
792    pub depth: Option<f32>,
793    /// Clear value for the stencil buffer. Use `None` to preserve existing contents.
794    pub stencil: Option<u8>,
795}
796
797/// Information to create a render pass
798pub struct RenderPassInfo<'stack, D: Device> {
799    /// Array of textures which have been created with render target flags
800    pub render_targets: Vec<&'stack D::Texture>,
801    /// Colour to clear render target when the pass starts, use None to preserve previous contents
802    pub rt_clear: Option<ClearColour>,
803    /// A texture which was created with depth stencil flags
804    pub depth_stencil: Option<&'stack D::Texture>,
805    /// Depth value (in view) to clear depth stencil, use None to preserve previous contents
806    pub ds_clear: Option<ClearDepthStencil>,
807    /// Choose to resolve multi-sample AA targets,
808    pub resolve: bool,
809    /// (must also specify None to clear). This can save having to Load conents from main memory
810    pub discard: bool,
811    /// Array layer, depth slice or cubemap face to render to
812    pub array_slice: usize
813}
814
815/// Transitions are required to be performed to switch resources from reading to writing or into different formats
816pub struct TransitionBarrier<'stack, D: Device> {
817    /// A texture to perform the transition on, either `texture` xor `buffer` must be `Some`
818    pub texture: Option<&'stack D::Texture>,
819    /// A buffer to perform the transition on, either `buffer` xor `texture` must be `Some`
820    pub buffer: Option<&'stack D::Buffer>,
821    /// The state of the resource before the transition is made, this must be correct otherwise it will throw validation warnings
822    pub state_before: ResourceState,
823    /// The state we want to transition into
824    pub state_after: ResourceState,
825}
826
827/// All possible resource states, some for buffers and some for textures
828#[derive(Copy, Clone, Serialize, Deserialize, PartialEq, Debug)]
829pub enum ResourceState {
830    /// Used for texture only to be written to from fragment shaders
831    RenderTarget,
832    /// Used for a texture to be used as a depth stencil buffer
833    DepthStencil,
834    /// Used for when depth testing is enabled, but depth writes are disabled
835    DepthStencilReadOnly,
836    /// Used for swap chain textures only, required before calling swap
837    Present,
838    /// Access for read/write from shaders
839    UnorderedAccess,
840    /// Readable from shaders
841    ShaderResource,
842    /// Bindable as a vertex or constant buffer for use in shaders
843    VertexConstantBuffer,
844    /// Bindable as an index buffer
845    IndexBuffer,
846    /// Used as a source msaa texture to resolve into a non-msaa resource
847    ResolveSrc,
848    /// Used as a destination sngle sample texture to be resolved into by an msaa resource
849    ResolveDst,
850    /// Used as a source for copies from into other resources
851    CopySrc,
852    /// Used as a destination for copies from other resources or queries
853    CopyDst,
854    /// Used as destination to read back data from buffers / queries
855    GenericRead,
856    /// Used for argument buffer in `execute_indirect` calls 
857    IndirectArgument,
858}
859
860/// ome resources may contain subresources for resolving
861#[derive(Copy, Clone, Serialize, Deserialize, PartialEq)]
862pub enum Subresource {
863    /// The resource itself for example a multi-sample texture has x number of MSAA samples
864    Resource,
865    /// The sub resource for example an MSAA texture will also create a non-MSAA subresource for resolving in to.
866    ResolveResource
867}
868
869/// Info to control mapping of resources for read/write access
870#[derive(Default)]
871pub struct MapInfo {
872    /// Sub resource to map ie. mip level, cubemap face, array slice
873    pub subresource: u32,
874    /// Range start of data we wish to read, for write-only access supply 0
875    pub read_start: usize,
876    /// Range end of data we wish to read, for write only access supply 0, to read the whole resource supply usize::MAX
877    pub read_end: usize,
878}
879
880/// Info to control writing of mapped resources
881pub struct UnmapInfo {
882    /// Sub resource to map ie. mip level, cubemap face, array slice
883    pub subresource: u32,
884    /// Range start of data we have written to the buffer, supply 0 for read-only
885    pub write_start: usize,
886    /// Range end of data we have written to the buffer, supply 0 for read only
887    pub write_end: usize,
888}
889
890/// Enum to differentiate between render and compute pipelines but also still work on them generically
891pub enum PipelineType {
892    Render,
893    Compute
894}
895
896/// An opaque Shader type
897pub trait Shader<D: Device>: Send + Sync {}
898
899/// An opaque render pipeline type set blend, depth stencil, raster states on a pipeline, and bind with `CmdBuf::set_pipeline_state`
900pub trait RenderPipeline<D: Device>: Send + Sync  {}
901
902/// An opaque RenderPass containing an optional set of colour render targets and an optional depth stencil target
903pub trait RenderPass<D: Device>: Send + Sync  {
904    /// Returns a hash based on the render target format so that pipelines can be shared amonst compatible passes
905    /// hash is based on render target format, depth stencil format and MSAA sample count
906    fn get_format_hash(&self) -> u64;
907}
908/// An opaque compute pipeline type..
909pub trait ComputePipeline<D: Device>: Send + Sync  {}
910
911/// A pipeline trait for shared functionality between Compute and Render pipelines
912pub trait Pipeline {
913    /// Returns the `PipelineSlotInfo` of which slot to bind a heap to based on the reequested `register` and `descriptor_type`
914    /// if `None` is returned the pipeline does not contain bindings for the requested information
915    fn get_pipeline_slot(&self, register: u32, space: u32, descriptor_type: DescriptorType) -> Option<&PipelineSlotInfo>;
916    /// Returns a vec of all pipeline slot indices 
917    fn get_pipeline_slots(&self) -> &Vec<u32>;
918    /// Returns the pipeline type
919    fn get_pipeline_type() -> PipelineType;
920}
921
922/// A command signature is used to `execute_indirect` commands
923pub trait CommandSignature<D: Device>: Send + Sync {}
924
925/// Different types of arguments which can be changed through execute indirect calls
926#[derive(Clone, Copy)]
927pub enum IndirectArgumentType {
928    /// Used to issue indirect `draw` calls
929    Draw,
930    /// Used to issue indirect `draw_indexed` calls
931    DrawIndexed,
932    /// Used to issue indirect compute `dispatch` calls
933    Dispatch,
934    /// Used to change a vertex buffer binding
935    VertexBuffer,
936    /// Used to change an index buffer binding
937    IndexBuffer,
938    /// Used to change push constants
939    PushConstants,
940    /// Used to change constant buffer binding
941    ConstantBuffer,
942    /// Used to change a shader resource view binding
943    ShaderResource,
944    /// Userd to change an unordered access view binding
945    UnorderedAccess
946}
947
948/// Arguments to change push constants during an `execute_indirect` call when `Constant` is the `IndirectArgumentType`
949#[derive(Clone, Copy)]
950pub struct IndirectPushConstantsArguments {
951    /// The pipeline slot to modify
952    pub slot: u32,
953    /// Offset in 32bit values
954    pub offset: u32,
955    /// Number of 32bit values
956    pub num_values: u32,
957}
958
959/// Arguments to change a buffer during an `execute_indirect` call when `ConstantBuffer`, `ShaderResource` or `UnorderedAccess`
960/// are the `IndirectArgumentType`
961#[derive(Clone, Copy)]
962pub struct IndirectBufferArguments {
963    /// The pipeline layout slot or the vertex buffer / index buffer slot
964    pub slot: u32
965}
966
967/// This can be used for `Draw`, `DrawIndexed`, or `Dispatch` `IndirectArgumentType`
968#[derive(Clone, Copy)]
969pub struct IndirectNoArguments;
970
971/// Union of `IndirectArguments` where data can be selected by the `IndirectArgumentType`
972pub union IndirectTypeArguments {
973    pub push_constants: IndirectPushConstantsArguments,
974    pub buffer: IndirectBufferArguments
975}
976
977/// Pair of `IndirectArgumentType` and `IndirectTypeArguments` where the type selects the union member of data
978pub struct IndirectArgument {
979    pub argument_type: IndirectArgumentType,
980    pub arguments: Option<IndirectTypeArguments>
981}
982
983/// Structure of arguments which can be used to execute `draw_instanced` calls indirectly 
984#[repr(C)]
985#[derive(Clone, Copy)]
986pub struct DrawArguments {
987    pub vertex_count_per_instance: u32,
988    pub instance_count: u32,
989    pub start_vertex_location: u32,
990    pub start_instance_location: u32
991}
992
993/// Structure of arguments which can be used to execute `draw_indexed_instanced` calls indirectly 
994#[repr(C)]
995#[derive(Clone, Copy)]
996pub struct DrawIndexedArguments {
997    pub index_count_per_instance: u32,
998    pub instance_count: u32,
999    pub start_index_location: u32,
1000    pub base_vertex_location: i32,
1001    pub start_instance_location: u32,
1002}
1003
1004/// Structure of arguments which can be used to execute `dispatch` calls indirectly
1005#[repr(C)]
1006#[derive(Clone, Copy)]
1007pub struct DispatchArguments {
1008    pub thread_group_count_x: u32,
1009    pub thread_group_count_y: u32,
1010    pub thread_group_count_z: u32,
1011}
1012
1013/// Structure of arguments which can be used to change a vertex buffer during `execute_indirect`
1014#[repr(C)]
1015#[derive(Clone, Copy)]
1016pub struct VertexBufferView {
1017    pub location: u64,
1018    pub size_bytes: u32,
1019    pub stride_bytes: u32,
1020}
1021
1022/// Structure of arguments which can be used to change an index buffer during `execute_indirect`
1023#[repr(C)]
1024#[derive(Clone, Copy)]
1025pub struct IndexBufferView {
1026    pub location: u64,
1027    pub size_bytes: u32,
1028    pub format: u32,
1029}
1030
1031/// A GPU device is used to create GPU resources, the device also contains a single a single command queue
1032/// to which all command buffers will submitted and executed each frame. Default heaps for shader resources,
1033/// render targets and depth stencils are also provided
1034pub trait Device: 'static + Send + Sync + Sized + Any + Clone {
1035    type SwapChain: SwapChain<Self>;
1036    type CmdBuf: CmdBuf<Self>;
1037    type Buffer: Buffer<Self>;
1038    type Shader: Shader<Self>;
1039    type RenderPipeline: RenderPipeline<Self>;
1040    type Texture: Texture<Self>;
1041    type ReadBackRequest: ReadBackRequest<Self>;
1042    type RenderPass: RenderPass<Self>;
1043    type Heap: Heap<Self>;
1044    type QueryHeap: QueryHeap<Self>;
1045    type ComputePipeline: ComputePipeline<Self>;
1046    type CommandSignature: CommandSignature<Self>;
1047    /// Create a new GPU `Device` from `Device Info`
1048    fn create(info: &DeviceInfo) -> Self;
1049    /// Create a new resource `Heap` from `HeapInfo`
1050    fn create_heap(&mut self, info: &HeapInfo) -> Self::Heap;
1051    /// Create a new `QueryHeap` from `QueryHeapInfo`
1052    fn create_query_heap(&self, info: &QueryHeapInfo) -> Self::QueryHeap;
1053    /// Create a new `SwapChain` from `SwapChainInfo` and bind it to the specified `window`
1054    fn create_swap_chain<A: os::App>(
1055        &mut self,
1056        info: &SwapChainInfo,
1057        window: &A::Window,
1058    ) -> Result<Self::SwapChain, Error>;
1059    /// Create a new `CmdBuf` with `num_buffers` internal buffers, the buffers can be swapped and syncronised
1060    /// with a new `SwapChain` to allow in-flight gpu/cpu overlapped prodicer consumers 
1061    fn create_cmd_buf(&self, num_buffers: u32) -> Self::CmdBuf;
1062    /// Create a new `Shader` from `ShaderInfo`
1063    fn create_shader<T: Sized>(&self, info: &ShaderInfo, src: &[T]) -> Result<Self::Shader, Error>;
1064    /// Create a new `Buffer` from `BufferInfo` with any resource views allocated on the devices `shader_heap`
1065    fn create_buffer<T: Sized>(
1066        &mut self,
1067        info: &BufferInfo,
1068        data: Option<&[T]>,
1069    ) -> Result<Self::Buffer, Error>;
1070    /// Create a new `Buffer` from `BufferInfo` with any resource views allocated on the specified `Heap` that must be of `HeapType::Shader`
1071    fn create_buffer_with_heap<T: Sized>(
1072        &mut self,
1073        info: &BufferInfo,
1074        data: Option<&[T]>,
1075        heap: &mut Self::Heap
1076    ) -> Result<Self::Buffer, Error>;
1077    /// Create a `Buffer` specifically for reading back data from the GPU mainly for `Query` use
1078    fn create_read_back_buffer(
1079        &mut self,
1080        size: usize,
1081    ) -> Result<Self::Buffer, Error>;
1082    /// Create a new texture from `TextureInfo` and initialise it with optional data which can be any slice of a sized `T`
1083    fn create_texture<T: Sized>(
1084        &mut self,
1085        info: &TextureInfo,
1086        data: Option<&[T]>,
1087    ) -> Result<Self::Texture, Error>;
1088    /// Create a new texture from `TextureInfo` and initialise it with optional data which can be any slice of a sized `T`
1089    /// allocates requested views into the supplied heaps, if the heaps are `None` this will use the default device heaps.
1090    fn create_texture_with_heaps<T: Sized>(
1091        &mut self,
1092        info: &TextureInfo,
1093        heaps: TextureHeapInfo<Self>,
1094        data: Option<&[T]>,
1095    ) -> Result<Self::Texture, Error>;
1096    /// Create a new render pipeline state object from the supplied `RenderPipelineInfo`
1097    fn create_render_pipeline(
1098        &self,
1099        info: &RenderPipelineInfo<Self>,
1100    ) -> Result<Self::RenderPipeline, Error>;
1101    /// Create a new render pass from `RenderPassInfo`
1102    fn create_render_pass(&self, info: &RenderPassInfo<Self>) -> Result<Self::RenderPass, Error>;
1103    /// Create a new compute pipeline state object from `ComputePipelineInfo`
1104    fn create_compute_pipeline(
1105        &self,
1106        info: &ComputePipelineInfo<Self>,
1107    ) -> Result<Self::ComputePipeline, Error>;
1108    /// Creat a command signature for `execute_indirect` commands associated on the `RenderPipeline`
1109    fn create_indirect_render_command<T: Sized>(
1110        &mut self, 
1111        arguments: Vec<IndirectArgument>,
1112        pipeline: Option<&Self::RenderPipeline>
1113    ) -> Result<Self::CommandSignature, super::Error>;
1114    /// Execute a command buffer on the internal device command queue which still hold references
1115    fn execute(&self, cmd: &Self::CmdBuf);
1116    /// Borrow the internally managed shader resource heap the device creates, for binding buffers / textures in shaders
1117    fn get_shader_heap(&self) -> &Self::Heap;
1118    /// Mutably borrow the internally managed shader resource heap the device creates, for binding buffers / textures in shaders
1119    fn get_shader_heap_mut(&mut self) -> &mut Self::Heap;
1120    /// Cleans up resources which have been dropped associated with the device heaps, safeley waiting for
1121    /// any in-flight GPU operations to complete
1122    fn cleanup_dropped_resources(&mut self, swap_chain: &Self::SwapChain);
1123    /// Returns an `AdapterInfo` struct (info about GPU vendor, and HW statistics)
1124    fn get_adapter_info(&self) -> &AdapterInfo;
1125    /// Returns a `DeviceFeatureFlags` struct containing flags for supported hardware features
1126    fn get_feature_flags(&self) -> &DeviceFeatureFlags;
1127    /// Read data back from GPU buffer into CPU `ReadBackData` assumes the `Buffer` is created with `create_read_back_buffer`
1128    /// None is returned if the buffer has yet to br written on the GPU
1129    fn read_buffer(&self, swap_chain: &Self::SwapChain, buffer: &Self::Buffer, size_bytes: usize, frame_written_fence: u64) -> Option<ReadBackData>;
1130    /// Read back u64 timestamp values as values in seconds, the vector will be empty if the buffer is yet to be written
1131    /// on the GPU
1132    fn read_timestamps(&self, swap_chain: &Self::SwapChain, buffer: &Self::Buffer, size_bytes: usize, frame_written_fence: u64) -> Vec<f64>;
1133    /// Read back a single pipeline statistics query, assuming `buffer` was created with `create_read_back_buffer` 
1134    /// and is of size `get_pipeline_statistics_size_bytes()`. None is returned if the buffer is not ready
1135    fn read_pipeline_statistics(&self, swap_chain: &Self::SwapChain, buffer: &Self::Buffer, frame_written_fence: u64) -> Option<PipelineStatistics>;
1136    /// Reorts internal graphics api backend resources
1137    fn report_live_objects(&self) -> Result<(), Error>;
1138    /// Retrieve messages in the info queue since they were last drained
1139    fn get_info_queue_messages(&self) -> Result<Vec<String>, Error>;
1140    /// Size of a single timestamp query result in bytes
1141    fn get_timestamp_size_bytes() -> usize;
1142    /// Size of a single pipeline statistics query result in bytes
1143    fn get_pipeline_statistics_size_bytes() -> usize;
1144    /// Size of the indirect draw command in bytes
1145    fn get_indirect_command_size(argument_type: IndirectArgumentType) -> usize;
1146    /// Returns the alignment requirement size in bytes for counters (append buffers / uavs)
1147    fn get_counter_alignment() -> usize;
1148}
1149
1150/// A swap chain is connected to a window, controls fences and signals as we swap buffers.
1151pub trait SwapChain<D: Device>: 'static + Sized + Any + Send + Sync + Clone {
1152    /// Call to begin a new frame, to synconise with v-sync and internally swap buffers
1153    fn new_frame(&mut self);
1154    /// Update to syncornise with the window, this may require the backbuffer to resize
1155    fn update<A: os::App>(&mut self, device: &mut D, window: &A::Window, cmd: &mut D::CmdBuf);
1156    /// Waits on the CPU for the last frame that was submitted with `swap` to be completed by the GPU
1157    fn wait_for_last_frame(&self);
1158    /// Returns the fence value for the current frame, you can use this to syncronise reads
1159    fn get_frame_fence_value(&self) -> u64;
1160    /// Returns the number of buffers in the swap chain
1161    fn get_num_buffers(&self) -> u32;
1162    /// Returns the current backbuffer index, this is the buffer that will be written during
1163    /// the current frame
1164    fn get_backbuffer_index(&self) -> u32;
1165    /// Returns the current backbuffer texture
1166    fn get_backbuffer_texture(&self) -> &D::Texture;
1167    /// Returns the current backbuffer pass this is the one
1168    /// we want to render to during the current frame
1169    fn get_backbuffer_pass(&self) -> &D::RenderPass;
1170    /// Returns the current backbuffer pass mutuably
1171    fn get_backbuffer_pass_mut(&mut self) -> &mut D::RenderPass;
1172    /// Returns the current backbuffer pass without a clear
1173    fn get_backbuffer_pass_no_clear(&self) -> &D::RenderPass;
1174    /// Returns the current backbuffer pass without a clear mutably
1175    fn get_backbuffer_pass_no_clear_mut(&mut self) -> &mut D::RenderPass;
1176    /// Call swap at the end of the frame to swap the back buffer, we rotate through n-buffers
1177    fn swap(&mut self, device: &D);
1178}
1179    
1180/// Responsible for buffering graphics commands. Internally it will contain a platform specific
1181/// command list for each buffer in the associated swap chain.
1182/// At the start of each frame `reset` must be called with an associated swap chain to internally switch
1183/// which buffer we are writing to. At the end of each frame `close` must be called
1184/// and finally the `CmdBuf` can be passed to `Device::execute` to be processed on the GPU.
1185pub trait CmdBuf<D: Device>: Send + Sync + Clone {
1186    /// Reset the `CmdBuf` for use on a new frame, it will be syncronised with the `SwapChain` so that
1187    /// in-flight command buffers are not overwritten
1188    fn reset(&mut self, swap_chain: &D::SwapChain);
1189    /// Call close to the command buffer after all commands have been added and before passing to `Device::execute` 
1190    fn close(&mut self) -> Result<(), Error>;
1191    /// Internally the `CmdBuf` contains a set of buffers which it rotates through to allow inflight operations
1192    /// to complete, this value indicates the buffer number you should `write` to during the current frame 
1193    fn get_backbuffer_index(&self) -> u32;
1194    /// Begins a render pass, end must be called
1195    fn begin_render_pass(&self, render_pass: &D::RenderPass);
1196    /// End a render pass must be called after `begin_render_pass` has been called
1197    fn end_render_pass(&self);
1198    /// Begin a names marker event which will be visible in tools such as PIX or RenderDoc
1199    fn begin_event(&mut self, colour: u32, name: &str);
1200    /// End an event that was started with `begin_event`
1201    fn end_event(&mut self);
1202    /// Similar to `begin_event/end_event` except it inserts a single marker point instead of a range
1203    fn set_marker(&self, colour: u32, name: &str);
1204    /// Function to specifically insert a timestamp query and request readback into the `Buffer`
1205    /// read back the rsult with `Device::read_timestamps`
1206    fn timestamp_query(&mut self, heap: &mut D::QueryHeap, resolve_buffer: &mut D::Buffer);
1207    /// Begin a new query in the heap, it will allocate an index which is returned as `usize`
1208    fn begin_query(&mut self, heap: &mut D::QueryHeap, query_type: QueryType) -> usize;
1209    /// End a query that was made on the heap results will be pushed into the `resolve_buffer` 
1210    /// the data can be read by `Device::read_buffer` or specialisations such as `read_pipeline_statistics`
1211    fn end_query(&mut self, heap: &mut D::QueryHeap, query_type: QueryType, index: usize, resolve_buffer: &mut D::Buffer);
1212    /// Add a transition barrier for resources to change states based on info supplied in `TransitionBarrier`
1213    fn transition_barrier(&mut self, barrier: &TransitionBarrier<D>);
1214    /// Add a transition barrier for a sub resource (ie. resolve texture)
1215    fn transition_barrier_subresource(&mut self, barrier: &TransitionBarrier<D>, subresource: Subresource);
1216    /// Set the viewport on the rasterizer stage
1217    fn set_viewport(&self, viewport: &Viewport);
1218    /// Set the scissor rect on the rasterizer stage
1219    fn set_scissor_rect(&self, scissor_rect: &ScissorRect);
1220    /// Set the index `buffer` to use for draw calls, the buffer should be created with `BufferUsage::INDEX`
1221    fn set_index_buffer(&self, buffer: &D::Buffer);
1222    /// Set the index `buffer` on `slot` to use for draw calls, the buffer should be created with `BufferUsage::VERTEX`
1223    fn set_vertex_buffer(&self, buffer: &D::Buffer, slot: u32);
1224    /// Set render pipeline for `draw` commands
1225    fn set_render_pipeline(&self, pipeline: &D::RenderPipeline);
1226    /// Set a compute pipeline for `dispatch`
1227    fn set_compute_pipeline(&self, pipeline: &D::ComputePipeline);
1228    /// Set's the active shader heap for the pipeline (srv, uav and cbv) and sets all descriptor tables to the root of the heap
1229    fn set_heap<T: Pipeline>(&self, pipeline: &T, heap: &D::Heap);
1230    /// Binds the heap with offset (texture srv, uav) on to the `slot` of a pipeline.
1231    /// this is like a traditional bindful render architecture `cmd.set_binding(pipeline, heap, 0, texture1_id)`
1232    fn set_binding<T: Pipeline>(&self, pipeline: &T, heap: &D::Heap, slot: u32, offset: usize);
1233    /// Push a small amount of data into the command buffer for a render pipeline, num values and dest offset are the numbr of 32bit values
1234    fn push_render_constants<T: Sized>(&self, slot: u32, num_values: u32, dest_offset: u32, data: &[T]);
1235    /// Push a small amount of data into the command buffer for a compute pipeline, num values and dest offset are the numbr of 32bit values
1236    fn push_compute_constants<T: Sized>(&self, slot: u32, num_values: u32, dest_offset: u32, data: &[T]);
1237    /// Make a non-indexed draw call supplying vertex and instance counts
1238    fn draw_instanced(
1239        &self,
1240        vertex_count: u32,
1241        instance_count: u32,
1242        start_vertex: u32,
1243        start_instance: u32,
1244    );
1245    /// Make an indexed draw call supplying index and instance counts, an index buffer should be bound
1246    fn draw_indexed_instanced(
1247        &self,
1248        index_count: u32,
1249        instance_count: u32,
1250        start_index: u32,
1251        base_vertex: i32,
1252        start_instance: u32,
1253    );
1254    /// Thread count is required for metal, in hlsl it is specified in the shader
1255    fn dispatch(&self, group_count: Size3, numthreads: Size3);
1256    /// Issue indirect commands with signature created from `create_indirect_render_command`
1257    fn execute_indirect(
1258        &self,
1259        command: &D::CommandSignature, 
1260        max_command_count: u32, 
1261        argument_buffer: &D::Buffer, 
1262        argument_buffer_offset: usize,
1263        counter_buffer: Option<&D::Buffer>,
1264        counter_buffer_offset: usize
1265    );
1266    /// Resolves the `subresource` (mip index, 3d texture slice or array slice)
1267    fn resolve_texture_subresource(&self, texture: &D::Texture, subresource: u32) -> Result<(), Error>;
1268    /// Generates a full mip chain for the specified `texture` where `heap` is the shader heap the texture was created on 
1269    fn generate_mip_maps(&mut self, texture: &D::Texture, device: &D, heap: &D::Heap) -> Result<(), Error>;
1270    /// Read back the swapchains contents to CPU
1271    fn read_back_backbuffer(&mut self, swap_chain: &D::SwapChain) -> Result<D::ReadBackRequest, Error>;
1272    /// Copy from one buffer to another with offsets
1273    fn copy_buffer_region(
1274        &mut self, 
1275        dst_buffer: &D::Buffer, 
1276        dst_offset: usize, 
1277        src_buffer: &D::Buffer, 
1278        src_offset: usize,
1279        num_bytes: usize
1280    );
1281    /// Copy from one texture to another with offsets, if `None` is specified for `src_region`
1282    /// it will copy the full size of src 
1283    fn copy_texture_region(
1284        &mut self,
1285        dst_texture: &D::Texture,
1286        subresource_index: u32,
1287        dst_x: u32,
1288        dst_y: u32,
1289        dst_z: u32,
1290        src_texture: &D::Texture,
1291        src_region: Option<Region>
1292    );
1293}
1294
1295/// An opaque Buffer type used for vertex, index, constant or unordered access.
1296pub trait Buffer<D: Device>: Send + Sync {
1297    /// updates the buffer by mapping and copying memory, if you update while a buffer is in use on the GPU you may see tearing
1298    /// multi-buffer updates to buffer so that a buffer is never written to while in flight on the GPU.
1299    /// this function internally will map and unmap
1300    fn update<T: Sized>(&mut self, offset: usize, data: &[T]) -> Result<(), Error>; // TODO: should be mut surely?
1301    // write data directly to the buffer, the buffer is required to be persistently mapped
1302    fn write<T: Sized>(&mut self, offset: usize, data: &[T]) -> Result<(), Error>; 
1303    /// maps the entire buffer for reading or writing... see MapInfo
1304    fn map(&mut self, info: &MapInfo) -> *mut u8;
1305    /// unmap buffer... see UnmapInfo
1306    fn unmap(&mut self, info: &UnmapInfo);
1307    /// Return the index to access in a shader as a structured buffer
1308    fn get_srv_index(&self) -> Option<usize>;
1309    /// Return the index to access in a shader as a cbuffer
1310    fn get_cbv_index(&self) -> Option<usize>;
1311    /// Return the index to unorder access view for read/write from shaders...
1312    fn get_uav_index(&self) -> Option<usize>;
1313    /// Return a vertex buffer view
1314    fn get_vbv(&self) -> Option<VertexBufferView>;
1315    /// Return an index buffer view
1316    fn get_ibv(&self) -> Option<IndexBufferView>;
1317    /// Returns the offset in bytes of a counter element for an append structured buffer
1318    /// `None` is returned if the buffer was not created with `BufferUsage::APPEND_COUNTER`
1319    fn get_counter_offset(&self) -> Option<usize>;
1320}
1321
1322/// An opaque Texture type
1323pub trait Texture<D: Device>: Send + Sync {
1324    /// Return the index to access in a shader (if the resource has msaa this is the resolved view)
1325    fn get_srv_index(&self) -> Option<usize>;
1326    /// Return the index to unorderd access view for read/write from shaders...
1327    fn get_uav_index(&self) -> Option<usize>;
1328    /// Return the subresource index unorderd access view for read/write from shaders
1329    /// where subresource is the array slice * num mips + mip you want to access
1330    fn get_subresource_uav_index(&self, subresource: u32) -> Option<usize>;
1331    /// Return the index of an msaa resource to access in a shader
1332    fn get_msaa_srv_index(&self) -> Option<usize>;
1333    /// Return a clone of the internal (platform specific) resource
1334    fn clone_inner(&self) -> Self;
1335    /// Returns true if this texture has a subresource which can be resolved into
1336    fn is_resolvable(&self) -> bool;
1337    /// Return the id of the shader heap
1338    fn get_shader_heap_id(&self) -> Option<u16>;
1339}
1340
1341/// An opaque shader heap type, use to create views of resources for binding and access in shaders
1342pub trait Heap<D: Device>: Send + Sync {
1343    /// Deallocate a resource from the heap and mark space in free list for re-use
1344    fn deallocate(&mut self, index: usize);
1345    /// Cleans up resources which have been dropped associated with this heap, safeley waiting for
1346    /// any in-flight GPU operations to complete
1347    fn cleanup_dropped_resources(&mut self, swap_chain: &D::SwapChain);
1348    /// Returns the id of the heap to verify and correlate with resources
1349    fn get_heap_id(&self) -> u16;
1350}
1351
1352/// An opaque query heap type, use to create queries
1353pub trait QueryHeap<D: Device>: Send + Sync {
1354    /// Reset queries at the start of the frame, each query requested will bump the allocation index
1355    fn reset(&mut self);
1356}
1357
1358/// Used to readback data from the GPU, once the request is issued `is_complete` needs to be waited on for completion
1359/// you must poll this every frame and not block so the GPU can flush the request. Once the result is ready the
1360/// data can be obtained using `get_data`
1361pub trait ReadBackRequest<D: Device> {
1362    /// Returns true when a reload request has completed and it is safe to call map
1363    fn is_complete(&self, swap_chain: &D::SwapChain) -> bool;
1364    /// Maps the buffer to allow the CPU to read GPU mapped data
1365    fn map(&self, info: &MapInfo) -> Result<ReadBackData, Error>;
1366    /// Balance with a call to map. note: it is possible to leave buffers persitently mapped
1367    fn unmap(&self);
1368}
1369
1370/// Results from an issued ReadBackRequest
1371#[derive(Clone)]
1372pub struct ReadBackData {
1373    /// Slice of data bytes
1374    pub data: &'static [u8],
1375    /// GPU format to interperet the data
1376    pub format: Format,
1377    /// Total size of data (should be == data.len())
1378    pub size: usize,
1379    /// Pitch of a row of data
1380    pub row_pitch: usize,
1381    /// Pitch of a slice (3D texture or array level, cubemap face etc)
1382    pub slice_pitch: usize,
1383}
1384
1385/// Take any sized type and return a u8 slice. This can be useful to pass `data` to `Device::create_buffer`.
1386pub fn as_u8_slice<T: Sized>(p: &T) -> &[u8] {
1387    unsafe {
1388        ::std::slice::from_raw_parts((p as *const T) as *const u8, ::std::mem::size_of::<T>())
1389    }
1390}
1391
1392/// Take any sized silce and convert to a slice of u8
1393pub fn slice_as_u8_slice<T: Sized>(p: &[T]) -> &[u8] {
1394    unsafe {
1395        ::std::slice::from_raw_parts(
1396            (p.as_ptr() as *const T) as *const u8,
1397            ::std::mem::size_of::<T>() * p.len(),
1398        )
1399    }
1400}
1401
1402/// Returns the 'block size' (texel, compressed block of texels or single buffer element) for a given format
1403pub const fn block_size_for_format(format: Format) -> u32 {
1404    match format {
1405        Format::Unknown => 0,
1406        Format::R16n => 2,
1407        Format::R16u => 2,
1408        Format::R16i => 2,
1409        Format::R16f => 2,
1410        Format::R32u => 4,
1411        Format::R32i => 4,
1412        Format::R32f => 4,
1413        Format::RG16u => 4,
1414        Format::RG16i => 4,
1415        Format::RG16f => 4,
1416        Format::RG32u => 8,
1417        Format::RG32i => 8,
1418        Format::RG32f => 8,
1419        Format::RGBA8nSRGB => 4,
1420        Format::RGBA8n => 4,
1421        Format::RGBA8u => 4,
1422        Format::RGBA8i => 4,
1423        Format::BGRA8n => 4,
1424        Format::BGRX8n => 4,
1425        Format::BGRA8nSRGB => 4,
1426        Format::BGRX8nSRGB => 4,
1427        Format::RGB32u => 12,
1428        Format::RGB32i => 12,
1429        Format::RGB32f => 12,
1430        Format::RGBA16u => 8,
1431        Format::RGBA16i => 8,
1432        Format::RGBA16f => 8,
1433        Format::RGBA32u => 16,
1434        Format::RGBA32i => 16,
1435        Format::RGBA32f => 16,
1436        Format::D32fS8X24u => 8,
1437        Format::D32f => 16,
1438        Format::D24nS8u => 32,
1439        Format::D16n => 2,
1440        Format::BC1n => 8,
1441        Format::BC1nSRGB => 8,
1442        Format::BC2n => 4,
1443        Format::BC2nSRGB => 4,
1444        Format::BC3n => 16,
1445        Format::BC3nSRGB => 16,
1446        Format::BC4n => 8,
1447        Format::BC5n => 16,
1448    }
1449}
1450
1451/// Returns the number of texels (texel x texel) in each block for the specified texture format
1452pub const fn texels_per_block_for_format(format: Format) -> u64 {
1453    match format {
1454        Format::BC1n => 4,
1455        Format::BC1nSRGB => 4,
1456        Format::BC2n => 4,
1457        Format::BC2nSRGB => 4,
1458        Format::BC3n => 4,
1459        Format::BC3nSRGB => 4,
1460        Format::BC4n => 4,
1461        Format::BC5n => 4,
1462        _ => 1,
1463    }
1464}
1465
1466/// Returns the number of components for a given format. ie RGBA = 4 and RGB = 3
1467pub const fn components_for_format(format: Format) -> u32 {
1468    match format {
1469        Format::Unknown => 0,
1470        Format::R16n => 1,
1471        Format::R16u => 1,
1472        Format::R16i => 1,
1473        Format::R16f => 1,
1474        Format::R32u => 1,
1475        Format::R32i => 1,
1476        Format::R32f => 1,
1477        Format::RG16u => 2,
1478        Format::RG16i => 2,
1479        Format::RG16f => 2,
1480        Format::RG32u => 2,
1481        Format::RG32i => 2,
1482        Format::RG32f => 2,
1483        Format::RGBA8nSRGB => 4,
1484        Format::RGBA8n => 4,
1485        Format::RGBA8u => 4,
1486        Format::RGBA8i => 4,
1487        Format::BGRA8n => 4,
1488        Format::BGRX8n => 4,
1489        Format::BGRA8nSRGB => 4,
1490        Format::BGRX8nSRGB => 4,
1491        Format::RGB32u => 3,
1492        Format::RGB32i => 3,
1493        Format::RGB32f => 3,
1494        Format::RGBA16u => 4,
1495        Format::RGBA16i => 4,
1496        Format::RGBA16f => 4,
1497        Format::RGBA32u => 4,
1498        Format::RGBA32i => 4,
1499        Format::RGBA32f => 4,
1500        Format::D32fS8X24u => 2,
1501        Format::D32f => 1,
1502        Format::D24nS8u => 2,
1503        Format::D16n => 1,
1504        Format::BC1n => 4,
1505        Format::BC1nSRGB => 4,
1506        Format::BC2n => 3,
1507        Format::BC2nSRGB => 3,
1508        Format::BC3n => 4,
1509        Format::BC3nSRGB => 4,
1510        Format::BC4n => 1,
1511        Format::BC5n => 2,
1512    }
1513}
1514
1515/// Returns the row pitch of an image in bytes: width * block size
1516pub fn row_pitch_for_format(format: Format, width: u64) -> u64 {
1517    let tpb = texels_per_block_for_format(format);
1518    block_size_for_format(format) as u64 * (width / tpb).max(1)
1519}
1520
1521/// Returns the slice pitch of an image in bytes: width * height * block size, a slice is a single 2D image
1522/// or a single slice of a 3D texture or texture array
1523pub fn slice_pitch_for_format(format: Format, width: u64, height: u64) -> u64 {
1524    let tpb = texels_per_block_for_format(format);
1525    block_size_for_format(format) as u64 * (width / tpb).max(1) * (height / tpb).max(1)
1526}
1527
1528/// Return the size in bytes of a 3 dimensional resource: width * height * depth block size
1529pub fn size_for_format(format: Format, width: u64, height: u64, depth: u32) -> u64 {
1530    let tpb = texels_per_block_for_format(format);
1531
1532    block_size_for_format(format) as u64 * (width / tpb).max(1) * (height / tpb).max(1) * depth as u64
1533}
1534
1535/// Return the size in bytes of up to dimensional resource: width * height * depth block size
1536/// for each mip level and account for array layers
1537pub fn size_for_format_mipped(format: Format, width: u64, height: u64, depth: u32, array_layers: u32, mips: u32) -> u64 {
1538    let mut total = 0;
1539    let mut mip_width = width;
1540    let mut mip_height = height;
1541    let mut mip_depth = depth;
1542    for _ in 0..mips {
1543        total += size_for_format(format, mip_width, mip_height, mip_depth) * array_layers as u64;
1544        mip_width = max(mip_width / 2, 1);
1545        mip_height = max(mip_height / 2, 1);
1546        mip_depth = max(mip_depth / 2, 1);
1547    }
1548    total
1549}
1550
1551/// Returns the number of mip levels required for a 2D texture
1552pub fn mip_levels_for_dimension(width: u64, height: u64) -> u32 {
1553    f32::log2(width.max(height) as f32) as u32 + 1
1554}
1555
1556/// Aligns value to the alignment specified by align. value must be a power of 2
1557pub fn align_pow2(value: u64, align: u64) -> u64 {
1558    (value + (align - 1)) & !(align - 1)
1559}
1560
1561/// Aligns value to the alignment specified by align. value can be non-power of 2
1562pub fn align(value: u64, align: u64) -> u64 {
1563    let div = value / align;
1564    let rem = value % align;
1565    if rem != 0 {
1566        return (div + 1) * align;
1567    }
1568    value
1569}
1570
1571/// For the supplied sized struct `&_` returns the number of 32bit constants required for use as `push_constants`
1572pub const fn num_32bit_constants<T: Sized>(_: &T) -> u32 {
1573    (std::mem::size_of::<T>() / 4) as u32
1574}
1575
1576/// Trait for sized types where num constants is the number of 32-bit constants in type
1577trait NumConstants {
1578    fn num_constants() -> u32;
1579}
1580
1581/// Blanket implmenetation for sized `T`
1582impl<T> NumConstants for T where T: Sized {
1583    fn num_constants() -> u32 {
1584        (std::mem::size_of::<T>() / 4) as u32
1585    }
1586}
1587
1588impl From<os::Rect<i32>> for Viewport {
1589    fn from(rect: os::Rect<i32>) -> Viewport {
1590        Viewport {
1591            x: rect.x as f32,
1592            y: rect.y as f32,
1593            width: rect.width as f32,
1594            height: rect.height as f32,
1595            min_depth: 0.0,
1596            max_depth: 1.0,
1597        }
1598    }
1599}
1600
1601impl From<os::Rect<i32>> for ScissorRect {
1602    fn from(rect: os::Rect<i32>) -> ScissorRect {
1603        ScissorRect {
1604            left: rect.x,
1605            top: rect.y,
1606            right: rect.width,
1607            bottom: rect.height,
1608        }
1609    }
1610}
1611
1612/// Convert from WritMask bit mask to raw u8
1613impl From<WriteMask> for u8 {
1614    fn from(mask: WriteMask) -> u8 {
1615        mask.bits
1616    }
1617}
1618
1619/// Display for `AdapterInfo` displays as so:
1620/// hotline_rs::d3d12::Device:
1621///   NVIDIA GeForce GTX 1060 6GB
1622///   Video Memory: 6052(mb)
1623///   System Memory: 0(mb)
1624///   Shared System Memory: 8159(mb)
1625/// Available Adapters:
1626///   NVIDIA GeForce GTX 1060 6GB
1627///   Microsoft Basic Render Driver
1628impl std::fmt::Display for AdapterInfo {
1629    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1630        let mut available = String::from("");
1631        for adapter in &self.available {
1632            available += "  ";
1633            available += adapter;
1634            available += "\n";
1635        }
1636        write!(
1637            f,
1638            "{}:
1639  {}
1640  Video Memory: {}(mb)
1641  System Memory: {}(mb)
1642  Shared System Memory: {}(mb)
1643Available Adapters:
1644{}",
1645            self.name,
1646            self.description,
1647            self.dedicated_video_memory / 1024 / 1024,
1648            self.dedicated_system_memory / 1024 / 1024,
1649            self.shared_system_memory / 1024 / 1024,
1650            available
1651        )
1652    }
1653}
1654
1655/// Useful defaults for quick creation of `TextureInfo`
1656impl Default for TextureInfo {
1657    fn default() -> Self {
1658        TextureInfo {
1659            tex_type: TextureType::Texture2D,
1660            format: Format::RGBA8n,
1661            width: 1,
1662            height: 1,
1663            depth: 1,
1664            array_layers: 1,
1665            mip_levels: 1,
1666            samples: 1,
1667            usage: TextureUsage::SHADER_RESOURCE,
1668            initial_state: ResourceState::ShaderResource
1669        }
1670    }
1671}
1672
1673/// Useful defaults for raster state on a pipeline state object, efetively means no culling, solid fill
1674impl Default for RasterInfo {
1675    fn default() -> Self {
1676        RasterInfo {
1677            fill_mode: FillMode::Solid,
1678            cull_mode: CullMode::None,
1679            front_ccw: false,
1680            depth_bias: 0,
1681            depth_bias_clamp: 0.0,
1682            slope_scaled_depth_bias: 0.0,
1683            depth_clip_enable: false,
1684            multisample_enable: false,
1685            antialiased_line_enable: false,
1686            forced_sample_count: 0,
1687            conservative_raster_mode: false,
1688        }
1689    }
1690}
1691
1692///  Useful defaults for smample states, wrap linear
1693impl Default for SamplerInfo {
1694    fn default() -> Self {
1695        SamplerInfo {
1696            filter: SamplerFilter::Linear,
1697            address_u: SamplerAddressMode::Wrap,
1698            address_v: SamplerAddressMode::Wrap,
1699            address_w: SamplerAddressMode::Wrap,
1700            comparison: None,
1701            border_colour: None,
1702            mip_lod_bias: 0.0,
1703            max_aniso: 0,
1704            min_lod: -1.0,
1705            max_lod: -1.0,
1706        }
1707    }
1708}
1709
1710///  Useful defaults for depth stencil state on a pipeline state object, no depth test or write
1711impl Default for DepthStencilInfo {
1712    fn default() -> Self {
1713        DepthStencilInfo {
1714            depth_enabled: false,
1715            depth_write_mask: DepthWriteMask::Zero,
1716            depth_func: ComparisonFunc::Always,
1717            stencil_enabled: false,
1718            stencil_read_mask: 0,
1719            stencil_write_mask: 0,
1720            front_face: StencilInfo {
1721                fail: StencilOp::Keep,
1722                depth_fail: StencilOp::Keep,
1723                pass: StencilOp::Keep,
1724                func: ComparisonFunc::Always,
1725            },
1726            back_face: StencilInfo {
1727                fail: StencilOp::Keep,
1728                depth_fail: StencilOp::Keep,
1729                pass: StencilOp::Keep,
1730                func: ComparisonFunc::Always,
1731            },
1732        }
1733    }
1734}
1735
1736/// Useful defaults for blend state on a pipeline state object, no blending
1737impl Default for RenderTargetBlendInfo {
1738    fn default() -> Self {
1739        RenderTargetBlendInfo {
1740            blend_enabled: false,
1741            logic_op_enabled: false,
1742            src_blend: BlendFactor::Zero,
1743            dst_blend: BlendFactor::Zero,
1744            blend_op: BlendOp::Add,
1745            src_blend_alpha: BlendFactor::Zero,
1746            dst_blend_alpha: BlendFactor::Zero,
1747            blend_op_alpha: BlendOp::Add,
1748            logic_op: LogicOp::Clear,
1749            write_mask: WriteMask::ALL,
1750        }
1751    }
1752}
1753
1754/// Defaults for a render pipline, which would do nothing
1755impl<'stack, D> Default for RenderPipelineInfo<'stack, D> where D: Device {
1756    fn default() -> Self {
1757        Self {
1758            vs: None,
1759            fs: None,
1760            input_layout: Vec::new(),
1761            pipeline_layout: PipelineLayout::default(),
1762            raster_info: RasterInfo::default(),
1763            depth_stencil_info: DepthStencilInfo::default(),
1764            blend_info: BlendInfo::default(),
1765            topology: Topology::TriangleList,
1766            patch_index: 0,
1767            sample_mask: u32::max_value(),
1768            pass: None
1769        }
1770    }
1771}
1772
1773/// Pipeline stats initialised to zero
1774impl Default for PipelineStatistics {
1775    fn default() -> Self {
1776        PipelineStatistics {
1777            input_assembler_vertices: 0,
1778            input_assembler_primitives: 0,
1779            vertex_shader_invocations: 0,
1780            pixel_shader_primitives: 0,
1781            compute_shader_invocations: 0
1782        }
1783    }
1784}
1785
1786
1787/// Pipeline stats initialised to zero
1788impl<'stack, D> Default for TextureHeapInfo<'stack, D> where D: Device {
1789    fn default() -> Self {
1790        Self {
1791            shader: None,
1792            render_target: None,
1793            depth_stencil: None
1794        }
1795    }
1796}
1797
1798/// Ability to add 2 pipeline stats to accumulate
1799impl std::ops::Add for PipelineStatistics {
1800    type Output = Self;
1801    fn add(self, other: Self) -> Self {
1802        Self {
1803            input_assembler_vertices: self.input_assembler_vertices + other.input_assembler_vertices,
1804            input_assembler_primitives: self.input_assembler_primitives + other.input_assembler_primitives,
1805            vertex_shader_invocations: self.vertex_shader_invocations + other.vertex_shader_invocations,
1806            pixel_shader_primitives: self.pixel_shader_primitives + other.pixel_shader_primitives,
1807            compute_shader_invocations: self.compute_shader_invocations + other.compute_shader_invocations,
1808        }
1809    }
1810}
1811
1812/// Ability to add_assign 2 pipeline stats to accumulate
1813impl std::ops::AddAssign for PipelineStatistics {
1814    fn add_assign(&mut self, other: Self) {
1815        self.input_assembler_vertices += other.input_assembler_vertices;
1816        self.input_assembler_primitives += other.input_assembler_primitives;
1817        self.vertex_shader_invocations += other.vertex_shader_invocations;
1818        self.pixel_shader_primitives += other.pixel_shader_primitives;
1819        self.compute_shader_invocations += other.compute_shader_invocations;
1820    }
1821}
1822
1823/// Display for resource state enums
1824impl std::fmt::Display for ResourceState {
1825    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1826        write!(f, "{:?}", self)
1827    }
1828}