summaryrefslogtreecommitdiffstats
path: root/third_party/rust/gfx-backend-dx12/src/conv.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/gfx-backend-dx12/src/conv.rs')
-rw-r--r--third_party/rust/gfx-backend-dx12/src/conv.rs690
1 files changed, 690 insertions, 0 deletions
diff --git a/third_party/rust/gfx-backend-dx12/src/conv.rs b/third_party/rust/gfx-backend-dx12/src/conv.rs
new file mode 100644
index 0000000000..5181d9c866
--- /dev/null
+++ b/third_party/rust/gfx-backend-dx12/src/conv.rs
@@ -0,0 +1,690 @@
+use crate::validate_line_width;
+
+use spirv_cross::spirv;
+use std::mem;
+
+use winapi::{
+ shared::{
+ basetsd::UINT8,
+ dxgiformat::*,
+ minwindef::{FALSE, INT, TRUE, UINT},
+ },
+ um::{d3d12::*, d3dcommon::*},
+};
+
+use auxil::ShaderStage;
+use hal::{
+ buffer,
+ format::{Format, ImageFeature, SurfaceType, Swizzle},
+ image, pso,
+};
+
+use native::ShaderVisibility;
+
+fn is_little_endinan() -> bool {
+ unsafe { 1 == *(&1u32 as *const _ as *const u8) }
+}
+
+pub fn map_format(format: Format) -> Option<DXGI_FORMAT> {
+ use hal::format::Format::*;
+
+ // Handling packed formats according to the platform endianness.
+ let reverse = is_little_endinan();
+ let format = match format {
+ Bgra4Unorm if !reverse => DXGI_FORMAT_B4G4R4A4_UNORM,
+ R5g6b5Unorm if reverse => DXGI_FORMAT_B5G6R5_UNORM,
+ B5g6r5Unorm if !reverse => DXGI_FORMAT_B5G6R5_UNORM,
+ B5g5r5a1Unorm if !reverse => DXGI_FORMAT_B5G5R5A1_UNORM,
+ A1r5g5b5Unorm if reverse => DXGI_FORMAT_B5G5R5A1_UNORM,
+ R8Unorm => DXGI_FORMAT_R8_UNORM,
+ R8Snorm => DXGI_FORMAT_R8_SNORM,
+ R8Uint => DXGI_FORMAT_R8_UINT,
+ R8Sint => DXGI_FORMAT_R8_SINT,
+ Rg8Unorm => DXGI_FORMAT_R8G8_UNORM,
+ Rg8Snorm => DXGI_FORMAT_R8G8_SNORM,
+ Rg8Uint => DXGI_FORMAT_R8G8_UINT,
+ Rg8Sint => DXGI_FORMAT_R8G8_SINT,
+ Rgba8Unorm => DXGI_FORMAT_R8G8B8A8_UNORM,
+ Rgba8Snorm => DXGI_FORMAT_R8G8B8A8_SNORM,
+ Rgba8Uint => DXGI_FORMAT_R8G8B8A8_UINT,
+ Rgba8Sint => DXGI_FORMAT_R8G8B8A8_SINT,
+ Rgba8Srgb => DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
+ Bgra8Unorm => DXGI_FORMAT_B8G8R8A8_UNORM,
+ Bgra8Srgb => DXGI_FORMAT_B8G8R8A8_UNORM_SRGB,
+ Abgr8Unorm if reverse => DXGI_FORMAT_R8G8B8A8_UNORM,
+ Abgr8Snorm if reverse => DXGI_FORMAT_R8G8B8A8_SNORM,
+ Abgr8Uint if reverse => DXGI_FORMAT_R8G8B8A8_UINT,
+ Abgr8Sint if reverse => DXGI_FORMAT_R8G8B8A8_SINT,
+ Abgr8Srgb if reverse => DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
+ A2b10g10r10Unorm if reverse => DXGI_FORMAT_R10G10B10A2_UNORM,
+ A2b10g10r10Uint if reverse => DXGI_FORMAT_R10G10B10A2_UINT,
+ R16Unorm => DXGI_FORMAT_R16_UNORM,
+ R16Snorm => DXGI_FORMAT_R16_SNORM,
+ R16Uint => DXGI_FORMAT_R16_UINT,
+ R16Sint => DXGI_FORMAT_R16_SINT,
+ R16Sfloat => DXGI_FORMAT_R16_FLOAT,
+ Rg16Unorm => DXGI_FORMAT_R16G16_UNORM,
+ Rg16Snorm => DXGI_FORMAT_R16G16_SNORM,
+ Rg16Uint => DXGI_FORMAT_R16G16_UINT,
+ Rg16Sint => DXGI_FORMAT_R16G16_SINT,
+ Rg16Sfloat => DXGI_FORMAT_R16G16_FLOAT,
+ Rgba16Unorm => DXGI_FORMAT_R16G16B16A16_UNORM,
+ Rgba16Snorm => DXGI_FORMAT_R16G16B16A16_SNORM,
+ Rgba16Uint => DXGI_FORMAT_R16G16B16A16_UINT,
+ Rgba16Sint => DXGI_FORMAT_R16G16B16A16_SINT,
+ Rgba16Sfloat => DXGI_FORMAT_R16G16B16A16_FLOAT,
+ R32Uint => DXGI_FORMAT_R32_UINT,
+ R32Sint => DXGI_FORMAT_R32_SINT,
+ R32Sfloat => DXGI_FORMAT_R32_FLOAT,
+ Rg32Uint => DXGI_FORMAT_R32G32_UINT,
+ Rg32Sint => DXGI_FORMAT_R32G32_SINT,
+ Rg32Sfloat => DXGI_FORMAT_R32G32_FLOAT,
+ Rgb32Uint => DXGI_FORMAT_R32G32B32_UINT,
+ Rgb32Sint => DXGI_FORMAT_R32G32B32_SINT,
+ Rgb32Sfloat => DXGI_FORMAT_R32G32B32_FLOAT,
+ Rgba32Uint => DXGI_FORMAT_R32G32B32A32_UINT,
+ Rgba32Sint => DXGI_FORMAT_R32G32B32A32_SINT,
+ Rgba32Sfloat => DXGI_FORMAT_R32G32B32A32_FLOAT,
+ B10g11r11Ufloat if reverse => DXGI_FORMAT_R11G11B10_FLOAT,
+ E5b9g9r9Ufloat if reverse => DXGI_FORMAT_R9G9B9E5_SHAREDEXP,
+ D16Unorm => DXGI_FORMAT_D16_UNORM,
+ D24UnormS8Uint => DXGI_FORMAT_D24_UNORM_S8_UINT,
+ X8D24Unorm if reverse => DXGI_FORMAT_D24_UNORM_S8_UINT,
+ D32Sfloat => DXGI_FORMAT_D32_FLOAT,
+ D32SfloatS8Uint => DXGI_FORMAT_D32_FLOAT_S8X24_UINT,
+ Bc1RgbUnorm | Bc1RgbaUnorm => DXGI_FORMAT_BC1_UNORM,
+ Bc1RgbSrgb | Bc1RgbaSrgb => DXGI_FORMAT_BC1_UNORM_SRGB,
+ Bc2Unorm => DXGI_FORMAT_BC2_UNORM,
+ Bc2Srgb => DXGI_FORMAT_BC2_UNORM_SRGB,
+ Bc3Unorm => DXGI_FORMAT_BC3_UNORM,
+ Bc3Srgb => DXGI_FORMAT_BC3_UNORM_SRGB,
+ Bc4Unorm => DXGI_FORMAT_BC4_UNORM,
+ Bc4Snorm => DXGI_FORMAT_BC4_SNORM,
+ Bc5Unorm => DXGI_FORMAT_BC5_UNORM,
+ Bc5Snorm => DXGI_FORMAT_BC5_SNORM,
+ Bc6hUfloat => DXGI_FORMAT_BC6H_UF16,
+ Bc6hSfloat => DXGI_FORMAT_BC6H_SF16,
+ Bc7Unorm => DXGI_FORMAT_BC7_UNORM,
+ Bc7Srgb => DXGI_FORMAT_BC7_UNORM_SRGB,
+
+ _ => return None,
+ };
+
+ Some(format)
+}
+
+pub fn map_format_shader_depth(surface: SurfaceType) -> Option<DXGI_FORMAT> {
+ match surface {
+ SurfaceType::D16 => Some(DXGI_FORMAT_R16_UNORM),
+ SurfaceType::X8D24 | SurfaceType::D24_S8 => Some(DXGI_FORMAT_R24_UNORM_X8_TYPELESS),
+ SurfaceType::D32 => Some(DXGI_FORMAT_R32_FLOAT),
+ SurfaceType::D32_S8 => Some(DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS),
+ _ => return None,
+ }
+}
+
+pub fn map_format_shader_stencil(surface: SurfaceType) -> Option<DXGI_FORMAT> {
+ match surface {
+ SurfaceType::D24_S8 => Some(DXGI_FORMAT_X24_TYPELESS_G8_UINT),
+ SurfaceType::D32_S8 => Some(DXGI_FORMAT_X32_TYPELESS_G8X24_UINT),
+ _ => None,
+ }
+}
+
+pub fn map_format_dsv(surface: SurfaceType) -> Option<DXGI_FORMAT> {
+ match surface {
+ SurfaceType::D16 => Some(DXGI_FORMAT_D16_UNORM),
+ SurfaceType::X8D24 | SurfaceType::D24_S8 => Some(DXGI_FORMAT_D24_UNORM_S8_UINT),
+ SurfaceType::D32 => Some(DXGI_FORMAT_D32_FLOAT),
+ SurfaceType::D32_S8 => Some(DXGI_FORMAT_D32_FLOAT_S8X24_UINT),
+ _ => None,
+ }
+}
+
+pub fn map_format_nosrgb(format: Format) -> Option<DXGI_FORMAT> {
+ // NOTE: DXGI doesn't allow sRGB format on the swapchain, but
+ // creating RTV of swapchain buffers with sRGB works
+ match format {
+ Format::Bgra8Srgb => Some(DXGI_FORMAT_B8G8R8A8_UNORM),
+ Format::Rgba8Srgb => Some(DXGI_FORMAT_R8G8B8A8_UNORM),
+ _ => map_format(format),
+ }
+}
+
+pub fn map_swizzle(swizzle: Swizzle) -> UINT {
+ use hal::format::Component::*;
+
+ [swizzle.0, swizzle.1, swizzle.2, swizzle.3]
+ .iter()
+ .enumerate()
+ .fold(
+ D3D12_SHADER_COMPONENT_MAPPING_ALWAYS_SET_BIT_AVOIDING_ZEROMEM_MISTAKES,
+ |mapping, (i, &component)| {
+ let value = match component {
+ R => D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0,
+ G => D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1,
+ B => D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2,
+ A => D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_3,
+ Zero => D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
+ One => D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1,
+ };
+ mapping | (value << D3D12_SHADER_COMPONENT_MAPPING_SHIFT as usize * i)
+ },
+ )
+}
+
+pub fn swizzle_rg(swizzle: Swizzle) -> Swizzle {
+ use hal::format::Component as C;
+ fn map_component(c: C) -> C {
+ match c {
+ C::R => C::G,
+ C::G => C::R,
+ x => x,
+ }
+ }
+ Swizzle(
+ map_component(swizzle.0),
+ map_component(swizzle.1),
+ map_component(swizzle.2),
+ map_component(swizzle.3),
+ )
+}
+
+pub fn map_surface_type(st: SurfaceType) -> Option<DXGI_FORMAT> {
+ use hal::format::SurfaceType::*;
+
+ assert_eq!(1, unsafe { *(&1u32 as *const _ as *const u8) });
+ Some(match st {
+ R5_G6_B5 => DXGI_FORMAT_B5G6R5_UNORM,
+ A1_R5_G5_B5 => DXGI_FORMAT_B5G5R5A1_UNORM,
+ R8 => DXGI_FORMAT_R8_TYPELESS,
+ R8_G8 => DXGI_FORMAT_R8G8_TYPELESS,
+ R8_G8_B8_A8 => DXGI_FORMAT_R8G8B8A8_TYPELESS,
+ B8_G8_R8_A8 => DXGI_FORMAT_B8G8R8A8_TYPELESS,
+ A8_B8_G8_R8 => DXGI_FORMAT_R8G8B8A8_TYPELESS,
+ A2_B10_G10_R10 => DXGI_FORMAT_R10G10B10A2_TYPELESS,
+ R16 => DXGI_FORMAT_R16_TYPELESS,
+ R16_G16 => DXGI_FORMAT_R16G16_TYPELESS,
+ R16_G16_B16_A16 => DXGI_FORMAT_R16G16B16A16_TYPELESS,
+ R32 => DXGI_FORMAT_R32_TYPELESS,
+ R32_G32 => DXGI_FORMAT_R32G32_TYPELESS,
+ R32_G32_B32 => DXGI_FORMAT_R32G32B32_TYPELESS,
+ R32_G32_B32_A32 => DXGI_FORMAT_R32G32B32A32_TYPELESS,
+ B10_G11_R11 => DXGI_FORMAT_R11G11B10_FLOAT,
+ E5_B9_G9_R9 => DXGI_FORMAT_R9G9B9E5_SHAREDEXP,
+ D16 => DXGI_FORMAT_R16_TYPELESS,
+ X8D24 => DXGI_FORMAT_R24G8_TYPELESS,
+ D32 => DXGI_FORMAT_R32_TYPELESS,
+ D24_S8 => DXGI_FORMAT_R24G8_TYPELESS,
+ D32_S8 => DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS,
+ _ => return None,
+ })
+}
+
+pub fn map_topology_type(primitive: pso::Primitive) -> D3D12_PRIMITIVE_TOPOLOGY_TYPE {
+ use hal::pso::Primitive::*;
+ match primitive {
+ PointList => D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT,
+ LineList | LineStrip => D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
+ TriangleList | TriangleStrip => D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
+ PatchList(_) => D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH,
+ }
+}
+
+pub fn map_topology(ia: &pso::InputAssemblerDesc) -> D3D12_PRIMITIVE_TOPOLOGY {
+ use hal::pso::Primitive::*;
+ match (ia.primitive, ia.with_adjacency) {
+ (PointList, false) => D3D_PRIMITIVE_TOPOLOGY_POINTLIST,
+ (PointList, true) => panic!("Points can't have adjacency info"),
+ (LineList, false) => D3D_PRIMITIVE_TOPOLOGY_LINELIST,
+ (LineList, true) => D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ,
+ (LineStrip, false) => D3D_PRIMITIVE_TOPOLOGY_LINESTRIP,
+ (LineStrip, true) => D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ,
+ (TriangleList, false) => D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
+ (TriangleList, true) => D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ,
+ (TriangleStrip, false) => D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
+ (TriangleStrip, true) => D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ,
+ (PatchList(num), false) => {
+ assert!(num != 0);
+ D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + (num as u32) - 1
+ }
+ (_, true) => panic!("Patches can't have adjacency info"),
+ }
+}
+
+pub fn map_rasterizer(rasterizer: &pso::Rasterizer, multisample: bool) -> D3D12_RASTERIZER_DESC {
+ use hal::pso::FrontFace::*;
+ use hal::pso::PolygonMode::*;
+
+ let bias = match rasterizer.depth_bias {
+ //TODO: support dynamic depth bias
+ Some(pso::State::Static(db)) => db,
+ Some(_) | None => pso::DepthBias::default(),
+ };
+
+ if let pso::State::Static(w) = rasterizer.line_width {
+ validate_line_width(w);
+ }
+
+ D3D12_RASTERIZER_DESC {
+ FillMode: match rasterizer.polygon_mode {
+ Point => {
+ error!("Point rasterization is not supported");
+ D3D12_FILL_MODE_WIREFRAME
+ }
+ Line => D3D12_FILL_MODE_WIREFRAME,
+ Fill => D3D12_FILL_MODE_SOLID,
+ },
+ CullMode: match rasterizer.cull_face {
+ pso::Face::NONE => D3D12_CULL_MODE_NONE,
+ pso::Face::FRONT => D3D12_CULL_MODE_FRONT,
+ pso::Face::BACK => D3D12_CULL_MODE_BACK,
+ _ => panic!("Culling both front and back faces is not supported"),
+ },
+ FrontCounterClockwise: match rasterizer.front_face {
+ Clockwise => FALSE,
+ CounterClockwise => TRUE,
+ },
+ DepthBias: bias.const_factor as INT,
+ DepthBiasClamp: bias.clamp,
+ SlopeScaledDepthBias: bias.slope_factor,
+ DepthClipEnable: !rasterizer.depth_clamping as _,
+ MultisampleEnable: if multisample { TRUE } else { FALSE },
+ ForcedSampleCount: 0, // TODO: currently not supported
+ AntialiasedLineEnable: FALSE, // TODO: currently not supported
+ ConservativeRaster: if rasterizer.conservative {
+ // TODO: check support
+ D3D12_CONSERVATIVE_RASTERIZATION_MODE_ON
+ } else {
+ D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF
+ },
+ }
+}
+
+fn map_factor(factor: pso::Factor, is_alpha: bool) -> D3D12_BLEND {
+ use hal::pso::Factor::*;
+ match factor {
+ Zero => D3D12_BLEND_ZERO,
+ One => D3D12_BLEND_ONE,
+ SrcColor if is_alpha => D3D12_BLEND_SRC_ALPHA,
+ SrcColor => D3D12_BLEND_SRC_COLOR,
+ OneMinusSrcColor if is_alpha => D3D12_BLEND_INV_SRC_ALPHA,
+ OneMinusSrcColor => D3D12_BLEND_INV_SRC_COLOR,
+ DstColor if is_alpha => D3D12_BLEND_DEST_ALPHA,
+ DstColor => D3D12_BLEND_DEST_COLOR,
+ OneMinusDstColor if is_alpha => D3D12_BLEND_INV_DEST_ALPHA,
+ OneMinusDstColor => D3D12_BLEND_INV_DEST_COLOR,
+ SrcAlpha => D3D12_BLEND_SRC_ALPHA,
+ OneMinusSrcAlpha => D3D12_BLEND_INV_SRC_ALPHA,
+ DstAlpha => D3D12_BLEND_DEST_ALPHA,
+ OneMinusDstAlpha => D3D12_BLEND_INV_DEST_ALPHA,
+ ConstColor | ConstAlpha => D3D12_BLEND_BLEND_FACTOR,
+ OneMinusConstColor | OneMinusConstAlpha => D3D12_BLEND_INV_BLEND_FACTOR,
+ SrcAlphaSaturate => D3D12_BLEND_SRC_ALPHA_SAT,
+ Src1Color if is_alpha => D3D12_BLEND_SRC1_ALPHA,
+ Src1Color => D3D12_BLEND_SRC1_COLOR,
+ OneMinusSrc1Color if is_alpha => D3D12_BLEND_INV_SRC1_ALPHA,
+ OneMinusSrc1Color => D3D12_BLEND_INV_SRC1_COLOR,
+ Src1Alpha => D3D12_BLEND_SRC1_ALPHA,
+ OneMinusSrc1Alpha => D3D12_BLEND_INV_SRC1_ALPHA,
+ }
+}
+
+fn map_blend_op(
+ operation: pso::BlendOp,
+ is_alpha: bool,
+) -> (D3D12_BLEND_OP, D3D12_BLEND, D3D12_BLEND) {
+ use hal::pso::BlendOp::*;
+ match operation {
+ Add { src, dst } => (
+ D3D12_BLEND_OP_ADD,
+ map_factor(src, is_alpha),
+ map_factor(dst, is_alpha),
+ ),
+ Sub { src, dst } => (
+ D3D12_BLEND_OP_SUBTRACT,
+ map_factor(src, is_alpha),
+ map_factor(dst, is_alpha),
+ ),
+ RevSub { src, dst } => (
+ D3D12_BLEND_OP_REV_SUBTRACT,
+ map_factor(src, is_alpha),
+ map_factor(dst, is_alpha),
+ ),
+ Min => (D3D12_BLEND_OP_MIN, D3D12_BLEND_ZERO, D3D12_BLEND_ZERO),
+ Max => (D3D12_BLEND_OP_MAX, D3D12_BLEND_ZERO, D3D12_BLEND_ZERO),
+ }
+}
+
+pub fn map_render_targets(
+ color_targets: &[pso::ColorBlendDesc],
+) -> [D3D12_RENDER_TARGET_BLEND_DESC; D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize] {
+ let dummy_target = D3D12_RENDER_TARGET_BLEND_DESC {
+ BlendEnable: FALSE,
+ LogicOpEnable: FALSE,
+ SrcBlend: D3D12_BLEND_ZERO,
+ DestBlend: D3D12_BLEND_ZERO,
+ BlendOp: D3D12_BLEND_OP_ADD,
+ SrcBlendAlpha: D3D12_BLEND_ZERO,
+ DestBlendAlpha: D3D12_BLEND_ZERO,
+ BlendOpAlpha: D3D12_BLEND_OP_ADD,
+ LogicOp: D3D12_LOGIC_OP_CLEAR,
+ RenderTargetWriteMask: 0,
+ };
+ let mut targets = [dummy_target; D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize];
+
+ for (target, color_desc) in targets.iter_mut().zip(color_targets.iter()) {
+ target.RenderTargetWriteMask = color_desc.mask.bits() as UINT8;
+ if let Some(ref blend) = color_desc.blend {
+ let (color_op, color_src, color_dst) = map_blend_op(blend.color, false);
+ let (alpha_op, alpha_src, alpha_dst) = map_blend_op(blend.alpha, true);
+ target.BlendEnable = TRUE;
+ target.BlendOp = color_op;
+ target.SrcBlend = color_src;
+ target.DestBlend = color_dst;
+ target.BlendOpAlpha = alpha_op;
+ target.SrcBlendAlpha = alpha_src;
+ target.DestBlendAlpha = alpha_dst;
+ }
+ }
+
+ targets
+}
+
+pub fn map_depth_stencil(dsi: &pso::DepthStencilDesc) -> D3D12_DEPTH_STENCIL_DESC {
+ let (depth_on, depth_write, depth_func) = match dsi.depth {
+ Some(ref depth) => (TRUE, depth.write, map_comparison(depth.fun)),
+ None => unsafe { mem::zeroed() },
+ };
+
+ let (stencil_on, front, back, read_mask, write_mask) = match dsi.stencil {
+ Some(ref stencil) => {
+ let read_masks = stencil.read_masks.static_or(pso::Sided::new(!0));
+ let write_masks = stencil.write_masks.static_or(pso::Sided::new(!0));
+ if read_masks.front != read_masks.back || write_masks.front != write_masks.back {
+ error!(
+ "Different sides are specified for read ({:?} and write ({:?}) stencil masks",
+ read_masks, write_masks
+ );
+ }
+ (
+ TRUE,
+ map_stencil_side(&stencil.faces.front),
+ map_stencil_side(&stencil.faces.back),
+ read_masks.front,
+ write_masks.front,
+ )
+ }
+ None => unsafe { mem::zeroed() },
+ };
+
+ D3D12_DEPTH_STENCIL_DESC {
+ DepthEnable: depth_on,
+ DepthWriteMask: if depth_write {
+ D3D12_DEPTH_WRITE_MASK_ALL
+ } else {
+ D3D12_DEPTH_WRITE_MASK_ZERO
+ },
+ DepthFunc: depth_func,
+ StencilEnable: stencil_on,
+ StencilReadMask: read_mask as _,
+ StencilWriteMask: write_mask as _,
+ FrontFace: front,
+ BackFace: back,
+ }
+}
+
+pub fn map_comparison(func: pso::Comparison) -> D3D12_COMPARISON_FUNC {
+ use hal::pso::Comparison::*;
+ match func {
+ Never => D3D12_COMPARISON_FUNC_NEVER,
+ Less => D3D12_COMPARISON_FUNC_LESS,
+ LessEqual => D3D12_COMPARISON_FUNC_LESS_EQUAL,
+ Equal => D3D12_COMPARISON_FUNC_EQUAL,
+ GreaterEqual => D3D12_COMPARISON_FUNC_GREATER_EQUAL,
+ Greater => D3D12_COMPARISON_FUNC_GREATER,
+ NotEqual => D3D12_COMPARISON_FUNC_NOT_EQUAL,
+ Always => D3D12_COMPARISON_FUNC_ALWAYS,
+ }
+}
+
+fn map_stencil_op(op: pso::StencilOp) -> D3D12_STENCIL_OP {
+ use hal::pso::StencilOp::*;
+ match op {
+ Keep => D3D12_STENCIL_OP_KEEP,
+ Zero => D3D12_STENCIL_OP_ZERO,
+ Replace => D3D12_STENCIL_OP_REPLACE,
+ IncrementClamp => D3D12_STENCIL_OP_INCR_SAT,
+ IncrementWrap => D3D12_STENCIL_OP_INCR,
+ DecrementClamp => D3D12_STENCIL_OP_DECR_SAT,
+ DecrementWrap => D3D12_STENCIL_OP_DECR,
+ Invert => D3D12_STENCIL_OP_INVERT,
+ }
+}
+
+fn map_stencil_side(side: &pso::StencilFace) -> D3D12_DEPTH_STENCILOP_DESC {
+ D3D12_DEPTH_STENCILOP_DESC {
+ StencilFailOp: map_stencil_op(side.op_fail),
+ StencilDepthFailOp: map_stencil_op(side.op_depth_fail),
+ StencilPassOp: map_stencil_op(side.op_pass),
+ StencilFunc: map_comparison(side.fun),
+ }
+}
+
+pub fn map_wrap(wrap: image::WrapMode) -> D3D12_TEXTURE_ADDRESS_MODE {
+ use hal::image::WrapMode::*;
+ match wrap {
+ Tile => D3D12_TEXTURE_ADDRESS_MODE_WRAP,
+ Mirror => D3D12_TEXTURE_ADDRESS_MODE_MIRROR,
+ Clamp => D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
+ Border => D3D12_TEXTURE_ADDRESS_MODE_BORDER,
+ MirrorClamp => D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE,
+ }
+}
+
+fn map_filter_type(filter: image::Filter) -> D3D12_FILTER_TYPE {
+ match filter {
+ image::Filter::Nearest => D3D12_FILTER_TYPE_POINT,
+ image::Filter::Linear => D3D12_FILTER_TYPE_LINEAR,
+ }
+}
+
+pub fn map_filter(
+ mag_filter: image::Filter,
+ min_filter: image::Filter,
+ mip_filter: image::Filter,
+ reduction: D3D12_FILTER_REDUCTION_TYPE,
+ anisotropy_clamp: Option<u8>,
+) -> D3D12_FILTER {
+ let mag = map_filter_type(mag_filter);
+ let min = map_filter_type(min_filter);
+ let mip = map_filter_type(mip_filter);
+
+ (min & D3D12_FILTER_TYPE_MASK) << D3D12_MIN_FILTER_SHIFT
+ | (mag & D3D12_FILTER_TYPE_MASK) << D3D12_MAG_FILTER_SHIFT
+ | (mip & D3D12_FILTER_TYPE_MASK) << D3D12_MIP_FILTER_SHIFT
+ | (reduction & D3D12_FILTER_REDUCTION_TYPE_MASK) << D3D12_FILTER_REDUCTION_TYPE_SHIFT
+ | anisotropy_clamp
+ .map(|_| D3D12_FILTER_ANISOTROPIC)
+ .unwrap_or(0)
+}
+
+pub fn map_buffer_resource_state(access: buffer::Access) -> D3D12_RESOURCE_STATES {
+ use self::buffer::Access;
+ // Mutable states
+ if access.contains(Access::SHADER_WRITE) {
+ return D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
+ }
+ if access.contains(Access::TRANSFER_WRITE) {
+ // Resolve not relevant for buffers.
+ return D3D12_RESOURCE_STATE_COPY_DEST;
+ }
+
+ // Read-only states
+ let mut state = D3D12_RESOURCE_STATE_COMMON;
+
+ if access.contains(Access::TRANSFER_READ) {
+ state |= D3D12_RESOURCE_STATE_COPY_SOURCE;
+ }
+ if access.contains(Access::INDEX_BUFFER_READ) {
+ state |= D3D12_RESOURCE_STATE_INDEX_BUFFER;
+ }
+ if access.contains(Access::VERTEX_BUFFER_READ) || access.contains(Access::UNIFORM_READ) {
+ state |= D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
+ }
+ if access.contains(Access::INDIRECT_COMMAND_READ) {
+ state |= D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT;
+ }
+ if access.contains(Access::SHADER_READ) {
+ // SHADER_READ only allows SRV access
+ state |= D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
+ | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
+ }
+
+ state
+}
+
+/// Derive the combination of read-only states from the access flags.
+fn derive_immutable_image_states(access: image::Access) -> D3D12_RESOURCE_STATES {
+ let mut state = D3D12_RESOURCE_STATE_COMMON;
+
+ if access.contains(image::Access::TRANSFER_READ) {
+ state |= D3D12_RESOURCE_STATE_COPY_SOURCE;
+ }
+ if access.contains(image::Access::INPUT_ATTACHMENT_READ) {
+ state |= D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
+ }
+ if access.contains(image::Access::DEPTH_STENCIL_ATTACHMENT_READ) {
+ state |= D3D12_RESOURCE_STATE_DEPTH_READ;
+ }
+ if access.contains(image::Access::SHADER_READ) {
+ state |= D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
+ | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
+ }
+
+ state
+}
+
+/// Derive the mutable or read-only states from the access flags.
+fn derive_mutable_image_states(access: image::Access) -> D3D12_RESOURCE_STATES {
+ if access.contains(image::Access::SHADER_WRITE) {
+ return D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
+ }
+ if access.contains(image::Access::COLOR_ATTACHMENT_WRITE) {
+ return D3D12_RESOURCE_STATE_RENDER_TARGET;
+ }
+ if access.contains(image::Access::DEPTH_STENCIL_ATTACHMENT_WRITE) {
+ return D3D12_RESOURCE_STATE_DEPTH_WRITE;
+ }
+ if access.contains(image::Access::TRANSFER_WRITE) {
+ return D3D12_RESOURCE_STATE_COPY_DEST;
+ }
+
+ derive_immutable_image_states(access)
+}
+
+pub fn map_image_resource_state(
+ access: image::Access,
+ layout: image::Layout,
+) -> D3D12_RESOURCE_STATES {
+ match layout {
+ // the same as COMMON (general state)
+ image::Layout::Present => D3D12_RESOURCE_STATE_PRESENT,
+ image::Layout::ColorAttachmentOptimal => D3D12_RESOURCE_STATE_RENDER_TARGET,
+ image::Layout::DepthStencilAttachmentOptimal => D3D12_RESOURCE_STATE_DEPTH_WRITE,
+ // `TRANSFER_WRITE` requires special handling as it requires RESOLVE_DEST | COPY_DEST
+ // but only 1 write-only allowed. We do the required translation before the commands.
+ // We currently assume that `COPY_DEST` is more common state than out of renderpass resolves.
+ // Resolve operations need to insert a barrier before and after the command to transition
+ // from and into `COPY_DEST` to have a consistent state for srcAccess.
+ image::Layout::TransferDstOptimal => D3D12_RESOURCE_STATE_COPY_DEST,
+ image::Layout::TransferSrcOptimal => D3D12_RESOURCE_STATE_COPY_SOURCE,
+ image::Layout::General => derive_mutable_image_states(access),
+ image::Layout::ShaderReadOnlyOptimal | image::Layout::DepthStencilReadOnlyOptimal => {
+ derive_immutable_image_states(access)
+ }
+ image::Layout::Undefined | image::Layout::Preinitialized => D3D12_RESOURCE_STATE_COMMON,
+ }
+}
+
+pub fn map_shader_visibility(flags: pso::ShaderStageFlags) -> ShaderVisibility {
+ use hal::pso::ShaderStageFlags as Ssf;
+
+ match flags {
+ Ssf::VERTEX => ShaderVisibility::VS,
+ Ssf::GEOMETRY => ShaderVisibility::GS,
+ Ssf::HULL => ShaderVisibility::HS,
+ Ssf::DOMAIN => ShaderVisibility::DS,
+ Ssf::FRAGMENT => ShaderVisibility::PS,
+ _ => ShaderVisibility::All,
+ }
+}
+
+pub fn map_buffer_flags(usage: buffer::Usage) -> D3D12_RESOURCE_FLAGS {
+ let mut flags = D3D12_RESOURCE_FLAG_NONE;
+
+ // TRANSFER_DST also used for clearing buffers, which is implemented via UAV clears.
+ if usage.contains(buffer::Usage::STORAGE) || usage.contains(buffer::Usage::TRANSFER_DST) {
+ flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
+ }
+
+ flags
+}
+
+pub fn map_image_flags(usage: image::Usage, features: ImageFeature) -> D3D12_RESOURCE_FLAGS {
+ use self::image::Usage;
+ let mut flags = D3D12_RESOURCE_FLAG_NONE;
+
+ // Blit operations implemented via a graphics pipeline
+ if usage.contains(Usage::COLOR_ATTACHMENT) {
+ debug_assert!(features.contains(ImageFeature::COLOR_ATTACHMENT));
+ flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
+ }
+ if usage.contains(Usage::DEPTH_STENCIL_ATTACHMENT) {
+ debug_assert!(features.contains(ImageFeature::DEPTH_STENCIL_ATTACHMENT));
+ flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
+ }
+ if usage.contains(Usage::TRANSFER_DST) {
+ if features.contains(ImageFeature::COLOR_ATTACHMENT) {
+ flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET
+ };
+ if features.contains(ImageFeature::DEPTH_STENCIL_ATTACHMENT) {
+ flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL
+ };
+ }
+ if usage.contains(Usage::STORAGE) {
+ debug_assert!(features.contains(ImageFeature::STORAGE));
+ flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
+ }
+ if !features.contains(ImageFeature::SAMPLED) {
+ flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
+ }
+
+ flags
+}
+
+pub fn map_execution_model(model: spirv::ExecutionModel) -> ShaderStage {
+ match model {
+ spirv::ExecutionModel::Vertex => ShaderStage::Vertex,
+ spirv::ExecutionModel::Fragment => ShaderStage::Fragment,
+ spirv::ExecutionModel::Geometry => ShaderStage::Geometry,
+ spirv::ExecutionModel::GlCompute => ShaderStage::Compute,
+ spirv::ExecutionModel::TessellationControl => ShaderStage::Hull,
+ spirv::ExecutionModel::TessellationEvaluation => ShaderStage::Domain,
+ spirv::ExecutionModel::Kernel => panic!("Kernel is not a valid execution model"),
+ }
+}
+
+pub fn map_stage(stage: ShaderStage) -> spirv::ExecutionModel {
+ match stage {
+ ShaderStage::Vertex => spirv::ExecutionModel::Vertex,
+ ShaderStage::Fragment => spirv::ExecutionModel::Fragment,
+ ShaderStage::Geometry => spirv::ExecutionModel::Geometry,
+ ShaderStage::Compute => spirv::ExecutionModel::GlCompute,
+ ShaderStage::Hull => spirv::ExecutionModel::TessellationControl,
+ ShaderStage::Domain => spirv::ExecutionModel::TessellationEvaluation,
+ ShaderStage::Task | ShaderStage::Mesh => {
+ panic!("{:?} shader is not yet implemented in SPIRV-Cross", stage)
+ }
+ }
+}