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