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