1 //! Pipeline state 2 3 use crate::{com::WeakPtr, Blob, D3DResult, Error}; 4 use std::{ffi, ops::Deref, ptr}; 5 use winapi::um::{d3d12, d3dcompiler}; 6 7 bitflags! { 8 pub struct PipelineStateFlags: u32 { 9 const TOOL_DEBUG = d3d12::D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG; 10 } 11 } 12 13 bitflags! { 14 pub struct ShaderCompileFlags: u32 { 15 const DEBUG = d3dcompiler::D3DCOMPILE_DEBUG; 16 const SKIP_VALIDATION = d3dcompiler::D3DCOMPILE_SKIP_VALIDATION; 17 const SKIP_OPTIMIZATION = d3dcompiler::D3DCOMPILE_SKIP_OPTIMIZATION; 18 const PACK_MATRIX_ROW_MAJOR = d3dcompiler::D3DCOMPILE_PACK_MATRIX_ROW_MAJOR; 19 const PACK_MATRIX_COLUMN_MAJOR = d3dcompiler::D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR; 20 const PARTIAL_PRECISION = d3dcompiler::D3DCOMPILE_PARTIAL_PRECISION; 21 // TODO: add missing flags 22 } 23 } 24 25 #[derive(Copy, Clone)] 26 pub struct Shader(d3d12::D3D12_SHADER_BYTECODE); 27 impl Shader { null() -> Self28 pub fn null() -> Self { 29 Shader(d3d12::D3D12_SHADER_BYTECODE { 30 BytecodeLength: 0, 31 pShaderBytecode: ptr::null(), 32 }) 33 } 34 from_raw(data: &[u8]) -> Self35 pub fn from_raw(data: &[u8]) -> Self { 36 Shader(d3d12::D3D12_SHADER_BYTECODE { 37 BytecodeLength: data.len() as _, 38 pShaderBytecode: data.as_ptr() as _, 39 }) 40 } 41 42 // `blob` may not be null. from_blob(blob: Blob) -> Self43 pub fn from_blob(blob: Blob) -> Self { 44 Shader(d3d12::D3D12_SHADER_BYTECODE { 45 BytecodeLength: unsafe { blob.GetBufferSize() }, 46 pShaderBytecode: unsafe { blob.GetBufferPointer() }, 47 }) 48 } 49 50 /// Compile a shader from raw HLSL. 51 /// 52 /// * `target`: example format: `ps_5_1`. compile( code: &[u8], target: &ffi::CStr, entry: &ffi::CStr, flags: ShaderCompileFlags, ) -> D3DResult<(Blob, Error)>53 pub fn compile( 54 code: &[u8], 55 target: &ffi::CStr, 56 entry: &ffi::CStr, 57 flags: ShaderCompileFlags, 58 ) -> D3DResult<(Blob, Error)> { 59 let mut shader = Blob::null(); 60 let mut error = Error::null(); 61 62 let hr = unsafe { 63 d3dcompiler::D3DCompile( 64 code.as_ptr() as *const _, 65 code.len(), 66 ptr::null(), // defines 67 ptr::null(), // include 68 ptr::null_mut(), 69 entry.as_ptr() as *const _, 70 target.as_ptr() as *const _, 71 flags.bits(), 72 0, 73 shader.mut_void() as *mut *mut _, 74 error.mut_void() as *mut *mut _, 75 ) 76 }; 77 78 ((shader, error), hr) 79 } 80 } 81 82 impl Deref for Shader { 83 type Target = d3d12::D3D12_SHADER_BYTECODE; deref(&self) -> &Self::Target84 fn deref(&self) -> &Self::Target { 85 &self.0 86 } 87 } 88 89 impl From<Option<Blob>> for Shader { from(blob: Option<Blob>) -> Self90 fn from(blob: Option<Blob>) -> Self { 91 match blob { 92 Some(b) => Shader::from_blob(b), 93 None => Shader::null(), 94 } 95 } 96 } 97 98 #[derive(Copy, Clone)] 99 pub struct CachedPSO(d3d12::D3D12_CACHED_PIPELINE_STATE); 100 impl CachedPSO { null() -> Self101 pub fn null() -> Self { 102 CachedPSO(d3d12::D3D12_CACHED_PIPELINE_STATE { 103 CachedBlobSizeInBytes: 0, 104 pCachedBlob: ptr::null(), 105 }) 106 } 107 108 // `blob` may not be null. from_blob(blob: Blob) -> Self109 pub fn from_blob(blob: Blob) -> Self { 110 CachedPSO(d3d12::D3D12_CACHED_PIPELINE_STATE { 111 CachedBlobSizeInBytes: unsafe { blob.GetBufferSize() }, 112 pCachedBlob: unsafe { blob.GetBufferPointer() }, 113 }) 114 } 115 } 116 117 impl Deref for CachedPSO { 118 type Target = d3d12::D3D12_CACHED_PIPELINE_STATE; deref(&self) -> &Self::Target119 fn deref(&self) -> &Self::Target { 120 &self.0 121 } 122 } 123 124 pub type PipelineState = WeakPtr<d3d12::ID3D12PipelineState>; 125 126 #[repr(u32)] 127 pub enum Subobject { 128 RootSignature = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE, 129 VS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS, 130 PS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS, 131 DS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS, 132 HS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS, 133 GS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS, 134 CS = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS, 135 StreamOutput = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_STREAM_OUTPUT, 136 Blend = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND, 137 SampleMask = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK, 138 Rasterizer = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER, 139 DepthStencil = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL, 140 InputLayout = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT, 141 IBStripCut = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE, 142 PrimitiveTopology = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY, 143 RTFormats = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS, 144 DSFormat = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT, 145 SampleDesc = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC, 146 NodeMask = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK, 147 CachedPSO = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO, 148 Flags = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS, 149 DepthStencil1 = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL1, 150 // ViewInstancing = d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING, 151 } 152 153 /// Subobject of a pipeline stream description 154 #[repr(C)] 155 pub struct PipelineStateSubobject<T> { 156 subobject_align: [usize; 0], // Subobjects must have the same alignment as pointers. 157 subobject_type: d3d12::D3D12_PIPELINE_STATE_SUBOBJECT_TYPE, 158 subobject: T, 159 } 160 161 impl<T> PipelineStateSubobject<T> { new(subobject_type: Subobject, subobject: T) -> Self162 pub fn new(subobject_type: Subobject, subobject: T) -> Self { 163 PipelineStateSubobject { 164 subobject_align: [], 165 subobject_type: subobject_type as _, 166 subobject, 167 } 168 } 169 } 170