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