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