1 use crate::validate_line_width;
2 
3 use spirv_cross::spirv;
4 use std::mem;
5 
6 use winapi::{
7     shared::{
8         basetsd::UINT8,
9         dxgiformat::*,
10         minwindef::{FALSE, INT, TRUE, UINT},
11     },
12     um::{d3d12::*, d3dcommon::*},
13 };
14 
15 use auxil::ShaderStage;
16 use hal::{
17     buffer,
18     format::{Format, ImageFeature, SurfaceType, Swizzle},
19     image, pso,
20 };
21 
22 use native::ShaderVisibility;
23 
is_little_endinan() -> bool24 fn is_little_endinan() -> bool {
25     unsafe { 1 == *(&1u32 as *const _ as *const u8) }
26 }
27 
map_format(format: Format) -> Option<DXGI_FORMAT>28 pub fn map_format(format: Format) -> Option<DXGI_FORMAT> {
29     use hal::format::Format::*;
30 
31     // Handling packed formats according to the platform endianness.
32     let reverse = is_little_endinan();
33     let format = match format {
34         Bgra4Unorm if !reverse => DXGI_FORMAT_B4G4R4A4_UNORM,
35         R5g6b5Unorm if reverse => DXGI_FORMAT_B5G6R5_UNORM,
36         B5g6r5Unorm if !reverse => DXGI_FORMAT_B5G6R5_UNORM,
37         B5g5r5a1Unorm if !reverse => DXGI_FORMAT_B5G5R5A1_UNORM,
38         A1r5g5b5Unorm if reverse => DXGI_FORMAT_B5G5R5A1_UNORM,
39         R8Unorm => DXGI_FORMAT_R8_UNORM,
40         R8Snorm => DXGI_FORMAT_R8_SNORM,
41         R8Uint => DXGI_FORMAT_R8_UINT,
42         R8Sint => DXGI_FORMAT_R8_SINT,
43         Rg8Unorm => DXGI_FORMAT_R8G8_UNORM,
44         Rg8Snorm => DXGI_FORMAT_R8G8_SNORM,
45         Rg8Uint => DXGI_FORMAT_R8G8_UINT,
46         Rg8Sint => DXGI_FORMAT_R8G8_SINT,
47         Rgba8Unorm => DXGI_FORMAT_R8G8B8A8_UNORM,
48         Rgba8Snorm => DXGI_FORMAT_R8G8B8A8_SNORM,
49         Rgba8Uint => DXGI_FORMAT_R8G8B8A8_UINT,
50         Rgba8Sint => DXGI_FORMAT_R8G8B8A8_SINT,
51         Rgba8Srgb => DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
52         Bgra8Unorm => DXGI_FORMAT_B8G8R8A8_UNORM,
53         Bgra8Srgb => DXGI_FORMAT_B8G8R8A8_UNORM_SRGB,
54         Abgr8Unorm if reverse => DXGI_FORMAT_R8G8B8A8_UNORM,
55         Abgr8Snorm if reverse => DXGI_FORMAT_R8G8B8A8_SNORM,
56         Abgr8Uint if reverse => DXGI_FORMAT_R8G8B8A8_UINT,
57         Abgr8Sint if reverse => DXGI_FORMAT_R8G8B8A8_SINT,
58         Abgr8Srgb if reverse => DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
59         A2b10g10r10Unorm if reverse => DXGI_FORMAT_R10G10B10A2_UNORM,
60         A2b10g10r10Uint if reverse => DXGI_FORMAT_R10G10B10A2_UINT,
61         R16Unorm => DXGI_FORMAT_R16_UNORM,
62         R16Snorm => DXGI_FORMAT_R16_SNORM,
63         R16Uint => DXGI_FORMAT_R16_UINT,
64         R16Sint => DXGI_FORMAT_R16_SINT,
65         R16Sfloat => DXGI_FORMAT_R16_FLOAT,
66         Rg16Unorm => DXGI_FORMAT_R16G16_UNORM,
67         Rg16Snorm => DXGI_FORMAT_R16G16_SNORM,
68         Rg16Uint => DXGI_FORMAT_R16G16_UINT,
69         Rg16Sint => DXGI_FORMAT_R16G16_SINT,
70         Rg16Sfloat => DXGI_FORMAT_R16G16_FLOAT,
71         Rgba16Unorm => DXGI_FORMAT_R16G16B16A16_UNORM,
72         Rgba16Snorm => DXGI_FORMAT_R16G16B16A16_SNORM,
73         Rgba16Uint => DXGI_FORMAT_R16G16B16A16_UINT,
74         Rgba16Sint => DXGI_FORMAT_R16G16B16A16_SINT,
75         Rgba16Sfloat => DXGI_FORMAT_R16G16B16A16_FLOAT,
76         R32Uint => DXGI_FORMAT_R32_UINT,
77         R32Sint => DXGI_FORMAT_R32_SINT,
78         R32Sfloat => DXGI_FORMAT_R32_FLOAT,
79         Rg32Uint => DXGI_FORMAT_R32G32_UINT,
80         Rg32Sint => DXGI_FORMAT_R32G32_SINT,
81         Rg32Sfloat => DXGI_FORMAT_R32G32_FLOAT,
82         Rgb32Uint => DXGI_FORMAT_R32G32B32_UINT,
83         Rgb32Sint => DXGI_FORMAT_R32G32B32_SINT,
84         Rgb32Sfloat => DXGI_FORMAT_R32G32B32_FLOAT,
85         Rgba32Uint => DXGI_FORMAT_R32G32B32A32_UINT,
86         Rgba32Sint => DXGI_FORMAT_R32G32B32A32_SINT,
87         Rgba32Sfloat => DXGI_FORMAT_R32G32B32A32_FLOAT,
88         B10g11r11Ufloat if reverse => DXGI_FORMAT_R11G11B10_FLOAT,
89         E5b9g9r9Ufloat if reverse => DXGI_FORMAT_R9G9B9E5_SHAREDEXP,
90         D16Unorm => DXGI_FORMAT_D16_UNORM,
91         D24UnormS8Uint => DXGI_FORMAT_D24_UNORM_S8_UINT,
92         X8D24Unorm if reverse => DXGI_FORMAT_D24_UNORM_S8_UINT,
93         D32Sfloat => DXGI_FORMAT_D32_FLOAT,
94         D32SfloatS8Uint => DXGI_FORMAT_D32_FLOAT_S8X24_UINT,
95         Bc1RgbUnorm | Bc1RgbaUnorm => DXGI_FORMAT_BC1_UNORM,
96         Bc1RgbSrgb | Bc1RgbaSrgb => DXGI_FORMAT_BC1_UNORM_SRGB,
97         Bc2Unorm => DXGI_FORMAT_BC2_UNORM,
98         Bc2Srgb => DXGI_FORMAT_BC2_UNORM_SRGB,
99         Bc3Unorm => DXGI_FORMAT_BC3_UNORM,
100         Bc3Srgb => DXGI_FORMAT_BC3_UNORM_SRGB,
101         Bc4Unorm => DXGI_FORMAT_BC4_UNORM,
102         Bc4Snorm => DXGI_FORMAT_BC4_SNORM,
103         Bc5Unorm => DXGI_FORMAT_BC5_UNORM,
104         Bc5Snorm => DXGI_FORMAT_BC5_SNORM,
105         Bc6hUfloat => DXGI_FORMAT_BC6H_UF16,
106         Bc6hSfloat => DXGI_FORMAT_BC6H_SF16,
107         Bc7Unorm => DXGI_FORMAT_BC7_UNORM,
108         Bc7Srgb => DXGI_FORMAT_BC7_UNORM_SRGB,
109 
110         _ => return None,
111     };
112 
113     Some(format)
114 }
115 
map_format_shader_depth(surface: SurfaceType) -> Option<DXGI_FORMAT>116 pub fn map_format_shader_depth(surface: SurfaceType) -> Option<DXGI_FORMAT> {
117     match surface {
118         SurfaceType::D16 => Some(DXGI_FORMAT_R16_UNORM),
119         SurfaceType::X8D24 | SurfaceType::D24_S8 => Some(DXGI_FORMAT_R24_UNORM_X8_TYPELESS),
120         SurfaceType::D32 => Some(DXGI_FORMAT_R32_FLOAT),
121         SurfaceType::D32_S8 => Some(DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS),
122         _ => return None,
123     }
124 }
125 
map_format_shader_stencil(surface: SurfaceType) -> Option<DXGI_FORMAT>126 pub fn map_format_shader_stencil(surface: SurfaceType) -> Option<DXGI_FORMAT> {
127     match surface {
128         SurfaceType::D24_S8 => Some(DXGI_FORMAT_X24_TYPELESS_G8_UINT),
129         SurfaceType::D32_S8 => Some(DXGI_FORMAT_X32_TYPELESS_G8X24_UINT),
130         _ => None,
131     }
132 }
133 
map_format_dsv(surface: SurfaceType) -> Option<DXGI_FORMAT>134 pub fn map_format_dsv(surface: SurfaceType) -> Option<DXGI_FORMAT> {
135     match surface {
136         SurfaceType::D16 => Some(DXGI_FORMAT_D16_UNORM),
137         SurfaceType::X8D24 | SurfaceType::D24_S8 => Some(DXGI_FORMAT_D24_UNORM_S8_UINT),
138         SurfaceType::D32 => Some(DXGI_FORMAT_D32_FLOAT),
139         SurfaceType::D32_S8 => Some(DXGI_FORMAT_D32_FLOAT_S8X24_UINT),
140         _ => None,
141     }
142 }
143 
map_format_nosrgb(format: Format) -> Option<DXGI_FORMAT>144 pub fn map_format_nosrgb(format: Format) -> Option<DXGI_FORMAT> {
145     // NOTE: DXGI doesn't allow sRGB format on the swapchain, but
146     //       creating RTV of swapchain buffers with sRGB works
147     match format {
148         Format::Bgra8Srgb => Some(DXGI_FORMAT_B8G8R8A8_UNORM),
149         Format::Rgba8Srgb => Some(DXGI_FORMAT_R8G8B8A8_UNORM),
150         _ => map_format(format),
151     }
152 }
153 
map_swizzle(swizzle: Swizzle) -> UINT154 pub fn map_swizzle(swizzle: Swizzle) -> UINT {
155     use hal::format::Component::*;
156 
157     [swizzle.0, swizzle.1, swizzle.2, swizzle.3]
158         .iter()
159         .enumerate()
160         .fold(
161             D3D12_SHADER_COMPONENT_MAPPING_ALWAYS_SET_BIT_AVOIDING_ZEROMEM_MISTAKES,
162             |mapping, (i, &component)| {
163                 let value = match component {
164                     R => D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0,
165                     G => D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1,
166                     B => D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2,
167                     A => D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_3,
168                     Zero => D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
169                     One => D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1,
170                 };
171                 mapping | (value << D3D12_SHADER_COMPONENT_MAPPING_SHIFT as usize * i)
172             },
173         )
174 }
175 
swizzle_rg(swizzle: Swizzle) -> Swizzle176 pub fn swizzle_rg(swizzle: Swizzle) -> Swizzle {
177     use hal::format::Component as C;
178     fn map_component(c: C) -> C {
179         match c {
180             C::R => C::G,
181             C::G => C::R,
182             x => x,
183         }
184     }
185     Swizzle(
186         map_component(swizzle.0),
187         map_component(swizzle.1),
188         map_component(swizzle.2),
189         map_component(swizzle.3),
190     )
191 }
192 
map_surface_type(st: SurfaceType) -> Option<DXGI_FORMAT>193 pub fn map_surface_type(st: SurfaceType) -> Option<DXGI_FORMAT> {
194     use hal::format::SurfaceType::*;
195 
196     assert_eq!(1, unsafe { *(&1u32 as *const _ as *const u8) });
197     Some(match st {
198         R5_G6_B5 => DXGI_FORMAT_B5G6R5_UNORM,
199         A1_R5_G5_B5 => DXGI_FORMAT_B5G5R5A1_UNORM,
200         R8 => DXGI_FORMAT_R8_TYPELESS,
201         R8_G8 => DXGI_FORMAT_R8G8_TYPELESS,
202         R8_G8_B8_A8 => DXGI_FORMAT_R8G8B8A8_TYPELESS,
203         B8_G8_R8_A8 => DXGI_FORMAT_B8G8R8A8_TYPELESS,
204         A8_B8_G8_R8 => DXGI_FORMAT_R8G8B8A8_TYPELESS,
205         A2_B10_G10_R10 => DXGI_FORMAT_R10G10B10A2_TYPELESS,
206         R16 => DXGI_FORMAT_R16_TYPELESS,
207         R16_G16 => DXGI_FORMAT_R16G16_TYPELESS,
208         R16_G16_B16_A16 => DXGI_FORMAT_R16G16B16A16_TYPELESS,
209         R32 => DXGI_FORMAT_R32_TYPELESS,
210         R32_G32 => DXGI_FORMAT_R32G32_TYPELESS,
211         R32_G32_B32 => DXGI_FORMAT_R32G32B32_TYPELESS,
212         R32_G32_B32_A32 => DXGI_FORMAT_R32G32B32A32_TYPELESS,
213         B10_G11_R11 => DXGI_FORMAT_R11G11B10_FLOAT,
214         E5_B9_G9_R9 => DXGI_FORMAT_R9G9B9E5_SHAREDEXP,
215         D16 => DXGI_FORMAT_R16_TYPELESS,
216         X8D24 => DXGI_FORMAT_R24G8_TYPELESS,
217         D32 => DXGI_FORMAT_R32_TYPELESS,
218         D24_S8 => DXGI_FORMAT_R24G8_TYPELESS,
219         D32_S8 => DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS,
220         _ => return None,
221     })
222 }
223 
map_topology_type(primitive: pso::Primitive) -> D3D12_PRIMITIVE_TOPOLOGY_TYPE224 pub fn map_topology_type(primitive: pso::Primitive) -> D3D12_PRIMITIVE_TOPOLOGY_TYPE {
225     use hal::pso::Primitive::*;
226     match primitive {
227         PointList => D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT,
228         LineList | LineStrip => D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
229         TriangleList | TriangleStrip => D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
230         PatchList(_) => D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH,
231     }
232 }
233 
map_topology(ia: &pso::InputAssemblerDesc) -> D3D12_PRIMITIVE_TOPOLOGY234 pub fn map_topology(ia: &pso::InputAssemblerDesc) -> D3D12_PRIMITIVE_TOPOLOGY {
235     use hal::pso::Primitive::*;
236     match (ia.primitive, ia.with_adjacency) {
237         (PointList, false) => D3D_PRIMITIVE_TOPOLOGY_POINTLIST,
238         (PointList, true) => panic!("Points can't have adjacency info"),
239         (LineList, false) => D3D_PRIMITIVE_TOPOLOGY_LINELIST,
240         (LineList, true) => D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ,
241         (LineStrip, false) => D3D_PRIMITIVE_TOPOLOGY_LINESTRIP,
242         (LineStrip, true) => D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ,
243         (TriangleList, false) => D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
244         (TriangleList, true) => D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ,
245         (TriangleStrip, false) => D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
246         (TriangleStrip, true) => D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ,
247         (PatchList(num), false) => {
248             assert!(num != 0);
249             D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (num as u32) - 1
250         }
251         (_, true) => panic!("Patches can't have adjacency info"),
252     }
253 }
254 
map_rasterizer(rasterizer: &pso::Rasterizer, multisample: bool) -> D3D12_RASTERIZER_DESC255 pub fn map_rasterizer(rasterizer: &pso::Rasterizer, multisample: bool) -> D3D12_RASTERIZER_DESC {
256     use hal::pso::FrontFace::*;
257     use hal::pso::PolygonMode::*;
258 
259     let bias = match rasterizer.depth_bias {
260         //TODO: support dynamic depth bias
261         Some(pso::State::Static(db)) => db,
262         Some(_) | None => pso::DepthBias::default(),
263     };
264 
265     if let pso::State::Static(w) = rasterizer.line_width {
266         validate_line_width(w);
267     }
268 
269     D3D12_RASTERIZER_DESC {
270         FillMode: match rasterizer.polygon_mode {
271             Point => {
272                 error!("Point rasterization is not supported");
273                 D3D12_FILL_MODE_WIREFRAME
274             }
275             Line => D3D12_FILL_MODE_WIREFRAME,
276             Fill => D3D12_FILL_MODE_SOLID,
277         },
278         CullMode: match rasterizer.cull_face {
279             pso::Face::NONE => D3D12_CULL_MODE_NONE,
280             pso::Face::FRONT => D3D12_CULL_MODE_FRONT,
281             pso::Face::BACK => D3D12_CULL_MODE_BACK,
282             _ => panic!("Culling both front and back faces is not supported"),
283         },
284         FrontCounterClockwise: match rasterizer.front_face {
285             Clockwise => FALSE,
286             CounterClockwise => TRUE,
287         },
288         DepthBias: bias.const_factor as INT,
289         DepthBiasClamp: bias.clamp,
290         SlopeScaledDepthBias: bias.slope_factor,
291         DepthClipEnable: !rasterizer.depth_clamping as _,
292         MultisampleEnable: if multisample { TRUE } else { FALSE },
293         ForcedSampleCount: 0,         // TODO: currently not supported
294         AntialiasedLineEnable: FALSE, // TODO: currently not supported
295         ConservativeRaster: if rasterizer.conservative {
296             D3D12_CONSERVATIVE_RASTERIZATION_MODE_ON
297         } else {
298             D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF
299         },
300     }
301 }
302 
map_factor(factor: pso::Factor, is_alpha: bool) -> D3D12_BLEND303 fn map_factor(factor: pso::Factor, is_alpha: bool) -> D3D12_BLEND {
304     use hal::pso::Factor::*;
305     match factor {
306         Zero => D3D12_BLEND_ZERO,
307         One => D3D12_BLEND_ONE,
308         SrcColor if is_alpha => D3D12_BLEND_SRC_ALPHA,
309         SrcColor => D3D12_BLEND_SRC_COLOR,
310         OneMinusSrcColor if is_alpha => D3D12_BLEND_INV_SRC_ALPHA,
311         OneMinusSrcColor => D3D12_BLEND_INV_SRC_COLOR,
312         DstColor if is_alpha => D3D12_BLEND_DEST_ALPHA,
313         DstColor => D3D12_BLEND_DEST_COLOR,
314         OneMinusDstColor if is_alpha => D3D12_BLEND_INV_DEST_ALPHA,
315         OneMinusDstColor => D3D12_BLEND_INV_DEST_COLOR,
316         SrcAlpha => D3D12_BLEND_SRC_ALPHA,
317         OneMinusSrcAlpha => D3D12_BLEND_INV_SRC_ALPHA,
318         DstAlpha => D3D12_BLEND_DEST_ALPHA,
319         OneMinusDstAlpha => D3D12_BLEND_INV_DEST_ALPHA,
320         ConstColor | ConstAlpha => D3D12_BLEND_BLEND_FACTOR,
321         OneMinusConstColor | OneMinusConstAlpha => D3D12_BLEND_INV_BLEND_FACTOR,
322         SrcAlphaSaturate => D3D12_BLEND_SRC_ALPHA_SAT,
323         Src1Color if is_alpha => D3D12_BLEND_SRC1_ALPHA,
324         Src1Color => D3D12_BLEND_SRC1_COLOR,
325         OneMinusSrc1Color if is_alpha => D3D12_BLEND_INV_SRC1_ALPHA,
326         OneMinusSrc1Color => D3D12_BLEND_INV_SRC1_COLOR,
327         Src1Alpha => D3D12_BLEND_SRC1_ALPHA,
328         OneMinusSrc1Alpha => D3D12_BLEND_INV_SRC1_ALPHA,
329     }
330 }
331 
map_blend_op( operation: pso::BlendOp, is_alpha: bool, ) -> (D3D12_BLEND_OP, D3D12_BLEND, D3D12_BLEND)332 fn map_blend_op(
333     operation: pso::BlendOp,
334     is_alpha: bool,
335 ) -> (D3D12_BLEND_OP, D3D12_BLEND, D3D12_BLEND) {
336     use hal::pso::BlendOp::*;
337     match operation {
338         Add { src, dst } => (
339             D3D12_BLEND_OP_ADD,
340             map_factor(src, is_alpha),
341             map_factor(dst, is_alpha),
342         ),
343         Sub { src, dst } => (
344             D3D12_BLEND_OP_SUBTRACT,
345             map_factor(src, is_alpha),
346             map_factor(dst, is_alpha),
347         ),
348         RevSub { src, dst } => (
349             D3D12_BLEND_OP_REV_SUBTRACT,
350             map_factor(src, is_alpha),
351             map_factor(dst, is_alpha),
352         ),
353         Min => (D3D12_BLEND_OP_MIN, D3D12_BLEND_ZERO, D3D12_BLEND_ZERO),
354         Max => (D3D12_BLEND_OP_MAX, D3D12_BLEND_ZERO, D3D12_BLEND_ZERO),
355     }
356 }
357 
map_render_targets( color_targets: &[pso::ColorBlendDesc], ) -> [D3D12_RENDER_TARGET_BLEND_DESC; D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize]358 pub fn map_render_targets(
359     color_targets: &[pso::ColorBlendDesc],
360 ) -> [D3D12_RENDER_TARGET_BLEND_DESC; D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize] {
361     let dummy_target = D3D12_RENDER_TARGET_BLEND_DESC {
362         BlendEnable: FALSE,
363         LogicOpEnable: FALSE,
364         SrcBlend: D3D12_BLEND_ZERO,
365         DestBlend: D3D12_BLEND_ZERO,
366         BlendOp: D3D12_BLEND_OP_ADD,
367         SrcBlendAlpha: D3D12_BLEND_ZERO,
368         DestBlendAlpha: D3D12_BLEND_ZERO,
369         BlendOpAlpha: D3D12_BLEND_OP_ADD,
370         LogicOp: D3D12_LOGIC_OP_CLEAR,
371         RenderTargetWriteMask: 0,
372     };
373     let mut targets = [dummy_target; D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize];
374 
375     for (target, color_desc) in targets.iter_mut().zip(color_targets.iter()) {
376         target.RenderTargetWriteMask = color_desc.mask.bits() as UINT8;
377         if let Some(ref blend) = color_desc.blend {
378             let (color_op, color_src, color_dst) = map_blend_op(blend.color, false);
379             let (alpha_op, alpha_src, alpha_dst) = map_blend_op(blend.alpha, true);
380             target.BlendEnable = TRUE;
381             target.BlendOp = color_op;
382             target.SrcBlend = color_src;
383             target.DestBlend = color_dst;
384             target.BlendOpAlpha = alpha_op;
385             target.SrcBlendAlpha = alpha_src;
386             target.DestBlendAlpha = alpha_dst;
387         }
388     }
389 
390     targets
391 }
392 
map_depth_stencil(dsi: &pso::DepthStencilDesc) -> D3D12_DEPTH_STENCIL_DESC393 pub fn map_depth_stencil(dsi: &pso::DepthStencilDesc) -> D3D12_DEPTH_STENCIL_DESC {
394     let (depth_on, depth_write, depth_func) = match dsi.depth {
395         Some(ref depth) => (TRUE, depth.write, map_comparison(depth.fun)),
396         None => unsafe { mem::zeroed() },
397     };
398 
399     let (stencil_on, front, back, read_mask, write_mask) = match dsi.stencil {
400         Some(ref stencil) => {
401             let read_masks = stencil.read_masks.static_or(pso::Sided::new(!0));
402             let write_masks = stencil.write_masks.static_or(pso::Sided::new(!0));
403             if read_masks.front != read_masks.back || write_masks.front != write_masks.back {
404                 error!(
405                     "Different sides are specified for read ({:?} and write ({:?}) stencil masks",
406                     read_masks, write_masks
407                 );
408             }
409             (
410                 TRUE,
411                 map_stencil_side(&stencil.faces.front),
412                 map_stencil_side(&stencil.faces.back),
413                 read_masks.front,
414                 write_masks.front,
415             )
416         }
417         None => unsafe { mem::zeroed() },
418     };
419 
420     D3D12_DEPTH_STENCIL_DESC {
421         DepthEnable: depth_on,
422         DepthWriteMask: if depth_write {
423             D3D12_DEPTH_WRITE_MASK_ALL
424         } else {
425             D3D12_DEPTH_WRITE_MASK_ZERO
426         },
427         DepthFunc: depth_func,
428         StencilEnable: stencil_on,
429         StencilReadMask: read_mask as _,
430         StencilWriteMask: write_mask as _,
431         FrontFace: front,
432         BackFace: back,
433     }
434 }
435 
map_comparison(func: pso::Comparison) -> D3D12_COMPARISON_FUNC436 pub fn map_comparison(func: pso::Comparison) -> D3D12_COMPARISON_FUNC {
437     use hal::pso::Comparison::*;
438     match func {
439         Never => D3D12_COMPARISON_FUNC_NEVER,
440         Less => D3D12_COMPARISON_FUNC_LESS,
441         LessEqual => D3D12_COMPARISON_FUNC_LESS_EQUAL,
442         Equal => D3D12_COMPARISON_FUNC_EQUAL,
443         GreaterEqual => D3D12_COMPARISON_FUNC_GREATER_EQUAL,
444         Greater => D3D12_COMPARISON_FUNC_GREATER,
445         NotEqual => D3D12_COMPARISON_FUNC_NOT_EQUAL,
446         Always => D3D12_COMPARISON_FUNC_ALWAYS,
447     }
448 }
449 
map_stencil_op(op: pso::StencilOp) -> D3D12_STENCIL_OP450 fn map_stencil_op(op: pso::StencilOp) -> D3D12_STENCIL_OP {
451     use hal::pso::StencilOp::*;
452     match op {
453         Keep => D3D12_STENCIL_OP_KEEP,
454         Zero => D3D12_STENCIL_OP_ZERO,
455         Replace => D3D12_STENCIL_OP_REPLACE,
456         IncrementClamp => D3D12_STENCIL_OP_INCR_SAT,
457         IncrementWrap => D3D12_STENCIL_OP_INCR,
458         DecrementClamp => D3D12_STENCIL_OP_DECR_SAT,
459         DecrementWrap => D3D12_STENCIL_OP_DECR,
460         Invert => D3D12_STENCIL_OP_INVERT,
461     }
462 }
463 
map_stencil_side(side: &pso::StencilFace) -> D3D12_DEPTH_STENCILOP_DESC464 fn map_stencil_side(side: &pso::StencilFace) -> D3D12_DEPTH_STENCILOP_DESC {
465     D3D12_DEPTH_STENCILOP_DESC {
466         StencilFailOp: map_stencil_op(side.op_fail),
467         StencilDepthFailOp: map_stencil_op(side.op_depth_fail),
468         StencilPassOp: map_stencil_op(side.op_pass),
469         StencilFunc: map_comparison(side.fun),
470     }
471 }
472 
map_wrap(wrap: image::WrapMode) -> D3D12_TEXTURE_ADDRESS_MODE473 pub fn map_wrap(wrap: image::WrapMode) -> D3D12_TEXTURE_ADDRESS_MODE {
474     use hal::image::WrapMode::*;
475     match wrap {
476         Tile => D3D12_TEXTURE_ADDRESS_MODE_WRAP,
477         Mirror => D3D12_TEXTURE_ADDRESS_MODE_MIRROR,
478         Clamp => D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
479         Border => D3D12_TEXTURE_ADDRESS_MODE_BORDER,
480         MirrorClamp => D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE,
481     }
482 }
483 
map_filter_type(filter: image::Filter) -> D3D12_FILTER_TYPE484 fn map_filter_type(filter: image::Filter) -> D3D12_FILTER_TYPE {
485     match filter {
486         image::Filter::Nearest => D3D12_FILTER_TYPE_POINT,
487         image::Filter::Linear => D3D12_FILTER_TYPE_LINEAR,
488     }
489 }
490 
map_filter( mag_filter: image::Filter, min_filter: image::Filter, mip_filter: image::Filter, reduction: D3D12_FILTER_REDUCTION_TYPE, anisotropy_clamp: Option<u8>, ) -> D3D12_FILTER491 pub fn map_filter(
492     mag_filter: image::Filter,
493     min_filter: image::Filter,
494     mip_filter: image::Filter,
495     reduction: D3D12_FILTER_REDUCTION_TYPE,
496     anisotropy_clamp: Option<u8>,
497 ) -> D3D12_FILTER {
498     let mag = map_filter_type(mag_filter);
499     let min = map_filter_type(min_filter);
500     let mip = map_filter_type(mip_filter);
501 
502     (min & D3D12_FILTER_TYPE_MASK) << D3D12_MIN_FILTER_SHIFT
503         | (mag & D3D12_FILTER_TYPE_MASK) << D3D12_MAG_FILTER_SHIFT
504         | (mip & D3D12_FILTER_TYPE_MASK) << D3D12_MIP_FILTER_SHIFT
505         | (reduction & D3D12_FILTER_REDUCTION_TYPE_MASK) << D3D12_FILTER_REDUCTION_TYPE_SHIFT
506         | anisotropy_clamp
507             .map(|_| D3D12_FILTER_ANISOTROPIC)
508             .unwrap_or(0)
509 }
510 
map_buffer_resource_state(access: buffer::Access) -> D3D12_RESOURCE_STATES511 pub fn map_buffer_resource_state(access: buffer::Access) -> D3D12_RESOURCE_STATES {
512     use self::buffer::Access;
513     // Mutable states
514     if access.contains(Access::SHADER_WRITE) {
515         return D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
516     }
517     if access.contains(Access::TRANSFER_WRITE) {
518         // Resolve not relevant for buffers.
519         return D3D12_RESOURCE_STATE_COPY_DEST;
520     }
521 
522     // Read-only states
523     let mut state = D3D12_RESOURCE_STATE_COMMON;
524 
525     if access.contains(Access::TRANSFER_READ) {
526         state |= D3D12_RESOURCE_STATE_COPY_SOURCE;
527     }
528     if access.contains(Access::INDEX_BUFFER_READ) {
529         state |= D3D12_RESOURCE_STATE_INDEX_BUFFER;
530     }
531     if access.contains(Access::VERTEX_BUFFER_READ) || access.contains(Access::UNIFORM_READ) {
532         state |= D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
533     }
534     if access.contains(Access::INDIRECT_COMMAND_READ) {
535         state |= D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT;
536     }
537     if access.contains(Access::SHADER_READ) {
538         // SHADER_READ only allows SRV access
539         state |= D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
540             | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
541     }
542 
543     state
544 }
545 
546 /// Derive the combination of read-only states from the access flags.
derive_immutable_image_states(access: image::Access) -> D3D12_RESOURCE_STATES547 fn derive_immutable_image_states(access: image::Access) -> D3D12_RESOURCE_STATES {
548     let mut state = D3D12_RESOURCE_STATE_COMMON;
549 
550     if access.contains(image::Access::TRANSFER_READ) {
551         state |= D3D12_RESOURCE_STATE_COPY_SOURCE;
552     }
553     if access.contains(image::Access::INPUT_ATTACHMENT_READ) {
554         state |= D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
555     }
556     if access.contains(image::Access::DEPTH_STENCIL_ATTACHMENT_READ) {
557         state |= D3D12_RESOURCE_STATE_DEPTH_READ;
558     }
559     if access.contains(image::Access::SHADER_READ) {
560         state |= D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
561             | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
562     }
563 
564     state
565 }
566 
567 /// Derive the mutable or read-only states from the access flags.
derive_mutable_image_states(access: image::Access) -> D3D12_RESOURCE_STATES568 fn derive_mutable_image_states(access: image::Access) -> D3D12_RESOURCE_STATES {
569     if access.contains(image::Access::SHADER_WRITE) {
570         return D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
571     }
572     if access.contains(image::Access::COLOR_ATTACHMENT_WRITE) {
573         return D3D12_RESOURCE_STATE_RENDER_TARGET;
574     }
575     if access.contains(image::Access::DEPTH_STENCIL_ATTACHMENT_WRITE) {
576         return D3D12_RESOURCE_STATE_DEPTH_WRITE;
577     }
578     if access.contains(image::Access::TRANSFER_WRITE) {
579         return D3D12_RESOURCE_STATE_COPY_DEST;
580     }
581 
582     derive_immutable_image_states(access)
583 }
584 
map_image_resource_state( access: image::Access, layout: image::Layout, ) -> D3D12_RESOURCE_STATES585 pub fn map_image_resource_state(
586     access: image::Access,
587     layout: image::Layout,
588 ) -> D3D12_RESOURCE_STATES {
589     match layout {
590         // the same as COMMON (general state)
591         image::Layout::Present => D3D12_RESOURCE_STATE_PRESENT,
592         image::Layout::ColorAttachmentOptimal => D3D12_RESOURCE_STATE_RENDER_TARGET,
593         image::Layout::DepthStencilAttachmentOptimal => D3D12_RESOURCE_STATE_DEPTH_WRITE,
594         // `TRANSFER_WRITE` requires special handling as it requires RESOLVE_DEST | COPY_DEST
595         // but only 1 write-only allowed. We do the required translation before the commands.
596         // We currently assume that `COPY_DEST` is more common state than out of renderpass resolves.
597         // Resolve operations need to insert a barrier before and after the command to transition
598         // from and into `COPY_DEST` to have a consistent state for srcAccess.
599         image::Layout::TransferDstOptimal => D3D12_RESOURCE_STATE_COPY_DEST,
600         image::Layout::TransferSrcOptimal => D3D12_RESOURCE_STATE_COPY_SOURCE,
601         image::Layout::General => derive_mutable_image_states(access),
602         image::Layout::ShaderReadOnlyOptimal | image::Layout::DepthStencilReadOnlyOptimal => {
603             derive_immutable_image_states(access)
604         }
605         image::Layout::Undefined | image::Layout::Preinitialized => D3D12_RESOURCE_STATE_COMMON,
606     }
607 }
608 
map_shader_visibility(flags: pso::ShaderStageFlags) -> ShaderVisibility609 pub fn map_shader_visibility(flags: pso::ShaderStageFlags) -> ShaderVisibility {
610     use hal::pso::ShaderStageFlags as Ssf;
611 
612     match flags {
613         Ssf::VERTEX => ShaderVisibility::VS,
614         Ssf::GEOMETRY => ShaderVisibility::GS,
615         Ssf::HULL => ShaderVisibility::HS,
616         Ssf::DOMAIN => ShaderVisibility::DS,
617         Ssf::FRAGMENT => ShaderVisibility::PS,
618         _ => ShaderVisibility::All,
619     }
620 }
621 
map_buffer_flags(usage: buffer::Usage) -> D3D12_RESOURCE_FLAGS622 pub fn map_buffer_flags(usage: buffer::Usage) -> D3D12_RESOURCE_FLAGS {
623     let mut flags = D3D12_RESOURCE_FLAG_NONE;
624 
625     // TRANSFER_DST also used for clearing buffers, which is implemented via UAV clears.
626     if usage.contains(buffer::Usage::STORAGE) || usage.contains(buffer::Usage::TRANSFER_DST) {
627         flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
628     }
629 
630     flags
631 }
632 
map_image_flags(usage: image::Usage, features: ImageFeature) -> D3D12_RESOURCE_FLAGS633 pub fn map_image_flags(usage: image::Usage, features: ImageFeature) -> D3D12_RESOURCE_FLAGS {
634     use self::image::Usage;
635     let mut flags = D3D12_RESOURCE_FLAG_NONE;
636 
637     // Blit operations implemented via a graphics pipeline
638     if usage.contains(Usage::COLOR_ATTACHMENT) {
639         debug_assert!(features.contains(ImageFeature::COLOR_ATTACHMENT));
640         flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
641     }
642     if usage.contains(Usage::DEPTH_STENCIL_ATTACHMENT) {
643         debug_assert!(features.contains(ImageFeature::DEPTH_STENCIL_ATTACHMENT));
644         flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
645     }
646     if usage.contains(Usage::TRANSFER_DST) {
647         if features.contains(ImageFeature::COLOR_ATTACHMENT) {
648             flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET
649         };
650         if features.contains(ImageFeature::DEPTH_STENCIL_ATTACHMENT) {
651             flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL
652         };
653     }
654     if usage.contains(Usage::STORAGE) {
655         debug_assert!(features.contains(ImageFeature::STORAGE));
656         flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
657     }
658     if !features.contains(ImageFeature::SAMPLED) {
659         flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
660     }
661 
662     flags
663 }
664 
map_stage(stage: ShaderStage) -> spirv::ExecutionModel665 pub fn map_stage(stage: ShaderStage) -> spirv::ExecutionModel {
666     match stage {
667         ShaderStage::Vertex => spirv::ExecutionModel::Vertex,
668         ShaderStage::Fragment => spirv::ExecutionModel::Fragment,
669         ShaderStage::Geometry => spirv::ExecutionModel::Geometry,
670         ShaderStage::Compute => spirv::ExecutionModel::GlCompute,
671         ShaderStage::Hull => spirv::ExecutionModel::TessellationControl,
672         ShaderStage::Domain => spirv::ExecutionModel::TessellationEvaluation,
673         ShaderStage::Task | ShaderStage::Mesh => {
674             panic!("{:?} shader is not yet implemented in SPIRV-Cross", stage)
675         }
676     }
677 }
678