use windows::Win32::Graphics::{Direct3D, Direct3D12, Dxgi}; pub fn map_buffer_usage_to_resource_flags( usage: wgt::BufferUses, ) -> Direct3D12::D3D12_RESOURCE_FLAGS { let mut flags = Direct3D12::D3D12_RESOURCE_FLAG_NONE; if usage.contains(wgt::BufferUses::STORAGE_READ_WRITE) || usage.contains(wgt::BufferUses::ACCELERATION_STRUCTURE_QUERY) { flags |= Direct3D12::D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; } flags } pub fn map_buffer_descriptor( desc: &crate::BufferDescriptor<'_>, ) -> Direct3D12::D3D12_RESOURCE_DESC { Direct3D12::D3D12_RESOURCE_DESC { Dimension: Direct3D12::D3D12_RESOURCE_DIMENSION_BUFFER, Alignment: 0, Width: desc.size, Height: 1, DepthOrArraySize: 1, MipLevels: 1, Format: Dxgi::Common::DXGI_FORMAT_UNKNOWN, SampleDesc: Dxgi::Common::DXGI_SAMPLE_DESC { Count: 1, Quality: 0, }, Layout: Direct3D12::D3D12_TEXTURE_LAYOUT_ROW_MAJOR, Flags: map_buffer_usage_to_resource_flags(desc.usage), } } pub fn map_texture_dimension(dim: wgt::TextureDimension) -> Direct3D12::D3D12_RESOURCE_DIMENSION { match dim { wgt::TextureDimension::D1 => Direct3D12::D3D12_RESOURCE_DIMENSION_TEXTURE1D, wgt::TextureDimension::D2 => Direct3D12::D3D12_RESOURCE_DIMENSION_TEXTURE2D, wgt::TextureDimension::D3 => Direct3D12::D3D12_RESOURCE_DIMENSION_TEXTURE3D, } } pub fn map_texture_usage_to_resource_flags( usage: wgt::TextureUses, ) -> Direct3D12::D3D12_RESOURCE_FLAGS { let mut flags = Direct3D12::D3D12_RESOURCE_FLAG_NONE; if usage.contains(wgt::TextureUses::COLOR_TARGET) { flags |= Direct3D12::D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; } if usage .intersects(wgt::TextureUses::DEPTH_STENCIL_READ | wgt::TextureUses::DEPTH_STENCIL_WRITE) { flags |= Direct3D12::D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; if !usage.contains(wgt::TextureUses::RESOURCE) { flags |= Direct3D12::D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE; } } if usage.intersects( wgt::TextureUses::STORAGE_READ_ONLY | wgt::TextureUses::STORAGE_WRITE_ONLY | wgt::TextureUses::STORAGE_READ_WRITE, ) { flags |= Direct3D12::D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; } flags } pub fn map_address_mode(mode: wgt::AddressMode) -> Direct3D12::D3D12_TEXTURE_ADDRESS_MODE { use wgt::AddressMode as Am; match mode { Am::Repeat => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_WRAP, Am::MirrorRepeat => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_MIRROR, Am::ClampToEdge => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_CLAMP, Am::ClampToBorder => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_BORDER, //Am::MirrorClamp => Direct3D12::D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE, } } pub fn map_filter_mode(mode: wgt::FilterMode) -> Direct3D12::D3D12_FILTER_TYPE { match mode { wgt::FilterMode::Nearest => Direct3D12::D3D12_FILTER_TYPE_POINT, wgt::FilterMode::Linear => Direct3D12::D3D12_FILTER_TYPE_LINEAR, } } pub fn map_comparison(func: wgt::CompareFunction) -> Direct3D12::D3D12_COMPARISON_FUNC { use wgt::CompareFunction as Cf; match func { Cf::Never => Direct3D12::D3D12_COMPARISON_FUNC_NEVER, Cf::Less => Direct3D12::D3D12_COMPARISON_FUNC_LESS, Cf::LessEqual => Direct3D12::D3D12_COMPARISON_FUNC_LESS_EQUAL, Cf::Equal => Direct3D12::D3D12_COMPARISON_FUNC_EQUAL, Cf::GreaterEqual => Direct3D12::D3D12_COMPARISON_FUNC_GREATER_EQUAL, Cf::Greater => Direct3D12::D3D12_COMPARISON_FUNC_GREATER, Cf::NotEqual => Direct3D12::D3D12_COMPARISON_FUNC_NOT_EQUAL, Cf::Always => Direct3D12::D3D12_COMPARISON_FUNC_ALWAYS, } } pub fn map_border_color(border_color: Option) -> [f32; 4] { use wgt::SamplerBorderColor as Sbc; match border_color { Some(Sbc::TransparentBlack) | Some(Sbc::Zero) | None => [0.0; 4], Some(Sbc::OpaqueBlack) => [0.0, 0.0, 0.0, 1.0], Some(Sbc::OpaqueWhite) => [1.0; 4], } } pub fn map_visibility(visibility: wgt::ShaderStages) -> Direct3D12::D3D12_SHADER_VISIBILITY { match visibility { wgt::ShaderStages::VERTEX => Direct3D12::D3D12_SHADER_VISIBILITY_VERTEX, wgt::ShaderStages::FRAGMENT => Direct3D12::D3D12_SHADER_VISIBILITY_PIXEL, _ => Direct3D12::D3D12_SHADER_VISIBILITY_ALL, } } pub fn map_binding_type(ty: &wgt::BindingType) -> Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE { use wgt::BindingType as Bt; match *ty { Bt::Sampler { .. } => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, Bt::Buffer { ty: wgt::BufferBindingType::Uniform, .. } => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_CBV, Bt::Buffer { ty: wgt::BufferBindingType::Storage { read_only: true }, .. } | Bt::Texture { .. } => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_SRV, Bt::Buffer { ty: wgt::BufferBindingType::Storage { read_only: false }, .. } | Bt::StorageTexture { .. } => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_UAV, Bt::AccelerationStructure { .. } => Direct3D12::D3D12_DESCRIPTOR_RANGE_TYPE_SRV, // External textures require multiple bindings and therefore cannot // be mapped to a single descriptor range type. They must be handled // separately by the caller. Bt::ExternalTexture => unreachable!("External textures must be handled separately"), } } pub fn map_buffer_usage_to_state(usage: wgt::BufferUses) -> Direct3D12::D3D12_RESOURCE_STATES { use wgt::BufferUses as Bu; let mut state = Direct3D12::D3D12_RESOURCE_STATE_COMMON; if usage.intersects(Bu::COPY_SRC) { state |= Direct3D12::D3D12_RESOURCE_STATE_COPY_SOURCE; } if usage.intersects(Bu::COPY_DST) { state |= Direct3D12::D3D12_RESOURCE_STATE_COPY_DEST; } if usage.intersects(Bu::INDEX) { state |= Direct3D12::D3D12_RESOURCE_STATE_INDEX_BUFFER; } if usage.intersects(Bu::VERTEX | Bu::UNIFORM) { state |= Direct3D12::D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER; } if usage.intersects(Bu::STORAGE_READ_WRITE) { state |= Direct3D12::D3D12_RESOURCE_STATE_UNORDERED_ACCESS; } else if usage.intersects(Bu::STORAGE_READ_ONLY) { state |= Direct3D12::D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | Direct3D12::D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; } if usage.intersects(Bu::INDIRECT) { state |= Direct3D12::D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT; } if usage.intersects(Bu::ACCELERATION_STRUCTURE_QUERY) { state |= Direct3D12::D3D12_RESOURCE_STATE_UNORDERED_ACCESS; } state } pub fn map_texture_usage_to_state(usage: wgt::TextureUses) -> Direct3D12::D3D12_RESOURCE_STATES { use wgt::TextureUses as Tu; let mut state = Direct3D12::D3D12_RESOURCE_STATE_COMMON; //Note: `RESOLVE_SOURCE` and `RESOLVE_DEST` are not used here //Note: `PRESENT` is the same as `COMMON` if usage == wgt::TextureUses::UNINITIALIZED { return state; } if usage.intersects(Tu::COPY_SRC) { state |= Direct3D12::D3D12_RESOURCE_STATE_COPY_SOURCE; } if usage.intersects(Tu::COPY_DST) { state |= Direct3D12::D3D12_RESOURCE_STATE_COPY_DEST; } if usage.intersects(Tu::RESOURCE) { state |= Direct3D12::D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | Direct3D12::D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; } if usage.intersects(Tu::COLOR_TARGET) { state |= Direct3D12::D3D12_RESOURCE_STATE_RENDER_TARGET; } if usage.intersects(Tu::DEPTH_STENCIL_READ) { state |= Direct3D12::D3D12_RESOURCE_STATE_DEPTH_READ; } if usage.intersects(Tu::DEPTH_STENCIL_WRITE) { state |= Direct3D12::D3D12_RESOURCE_STATE_DEPTH_WRITE; } if usage.intersects(Tu::STORAGE_READ_ONLY | Tu::STORAGE_WRITE_ONLY | Tu::STORAGE_READ_WRITE) { state |= Direct3D12::D3D12_RESOURCE_STATE_UNORDERED_ACCESS; } state } pub fn map_topology( topology: wgt::PrimitiveTopology, ) -> ( Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE, Direct3D::D3D_PRIMITIVE_TOPOLOGY, ) { match topology { wgt::PrimitiveTopology::PointList => ( Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT, Direct3D::D3D_PRIMITIVE_TOPOLOGY_POINTLIST, ), wgt::PrimitiveTopology::LineList => ( Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE, Direct3D::D3D_PRIMITIVE_TOPOLOGY_LINELIST, ), wgt::PrimitiveTopology::LineStrip => ( Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE, Direct3D::D3D_PRIMITIVE_TOPOLOGY_LINESTRIP, ), wgt::PrimitiveTopology::TriangleList => ( Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, Direct3D::D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST, ), wgt::PrimitiveTopology::TriangleStrip => ( Direct3D12::D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, Direct3D::D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, ), } } pub fn map_polygon_mode(mode: wgt::PolygonMode) -> Direct3D12::D3D12_FILL_MODE { match mode { wgt::PolygonMode::Fill => Direct3D12::D3D12_FILL_MODE_SOLID, wgt::PolygonMode::Line => Direct3D12::D3D12_FILL_MODE_WIREFRAME, wgt::PolygonMode::Point => panic!( "{:?} is not enabled for this backend", wgt::Features::POLYGON_MODE_POINT ), } } /// D3D12 doesn't support passing factors ending in `_COLOR` for alpha blending /// (see ). /// Therefore this function takes an additional `is_alpha` argument /// which if set will return an equivalent `_ALPHA` factor. fn map_blend_factor(factor: wgt::BlendFactor, is_alpha: bool) -> Direct3D12::D3D12_BLEND { use wgt::BlendFactor as Bf; match factor { Bf::Zero => Direct3D12::D3D12_BLEND_ZERO, Bf::One => Direct3D12::D3D12_BLEND_ONE, Bf::Src if is_alpha => Direct3D12::D3D12_BLEND_SRC_ALPHA, Bf::Src => Direct3D12::D3D12_BLEND_SRC_COLOR, Bf::OneMinusSrc if is_alpha => Direct3D12::D3D12_BLEND_INV_SRC_ALPHA, Bf::OneMinusSrc => Direct3D12::D3D12_BLEND_INV_SRC_COLOR, Bf::Dst if is_alpha => Direct3D12::D3D12_BLEND_DEST_ALPHA, Bf::Dst => Direct3D12::D3D12_BLEND_DEST_COLOR, Bf::OneMinusDst if is_alpha => Direct3D12::D3D12_BLEND_INV_DEST_ALPHA, Bf::OneMinusDst => Direct3D12::D3D12_BLEND_INV_DEST_COLOR, Bf::SrcAlpha => Direct3D12::D3D12_BLEND_SRC_ALPHA, Bf::OneMinusSrcAlpha => Direct3D12::D3D12_BLEND_INV_SRC_ALPHA, Bf::DstAlpha => Direct3D12::D3D12_BLEND_DEST_ALPHA, Bf::OneMinusDstAlpha => Direct3D12::D3D12_BLEND_INV_DEST_ALPHA, Bf::Constant => Direct3D12::D3D12_BLEND_BLEND_FACTOR, Bf::OneMinusConstant => Direct3D12::D3D12_BLEND_INV_BLEND_FACTOR, Bf::SrcAlphaSaturated => Direct3D12::D3D12_BLEND_SRC_ALPHA_SAT, Bf::Src1 if is_alpha => Direct3D12::D3D12_BLEND_SRC1_ALPHA, Bf::Src1 => Direct3D12::D3D12_BLEND_SRC1_COLOR, Bf::OneMinusSrc1 if is_alpha => Direct3D12::D3D12_BLEND_INV_SRC1_ALPHA, Bf::OneMinusSrc1 => Direct3D12::D3D12_BLEND_INV_SRC1_COLOR, Bf::Src1Alpha => Direct3D12::D3D12_BLEND_SRC1_ALPHA, Bf::OneMinusSrc1Alpha => Direct3D12::D3D12_BLEND_INV_SRC1_ALPHA, } } fn map_blend_component( component: &wgt::BlendComponent, is_alpha: bool, ) -> ( Direct3D12::D3D12_BLEND_OP, Direct3D12::D3D12_BLEND, Direct3D12::D3D12_BLEND, ) { let raw_op = match component.operation { wgt::BlendOperation::Add => Direct3D12::D3D12_BLEND_OP_ADD, wgt::BlendOperation::Subtract => Direct3D12::D3D12_BLEND_OP_SUBTRACT, wgt::BlendOperation::ReverseSubtract => Direct3D12::D3D12_BLEND_OP_REV_SUBTRACT, wgt::BlendOperation::Min => Direct3D12::D3D12_BLEND_OP_MIN, wgt::BlendOperation::Max => Direct3D12::D3D12_BLEND_OP_MAX, }; let raw_src = map_blend_factor(component.src_factor, is_alpha); let raw_dst = map_blend_factor(component.dst_factor, is_alpha); (raw_op, raw_src, raw_dst) } pub fn map_render_targets( color_targets: &[Option], ) -> [Direct3D12::D3D12_RENDER_TARGET_BLEND_DESC; Direct3D12::D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize] { let dummy_target = Direct3D12::D3D12_RENDER_TARGET_BLEND_DESC { BlendEnable: false.into(), LogicOpEnable: false.into(), SrcBlend: Direct3D12::D3D12_BLEND_ZERO, DestBlend: Direct3D12::D3D12_BLEND_ZERO, BlendOp: Direct3D12::D3D12_BLEND_OP_ADD, SrcBlendAlpha: Direct3D12::D3D12_BLEND_ZERO, DestBlendAlpha: Direct3D12::D3D12_BLEND_ZERO, BlendOpAlpha: Direct3D12::D3D12_BLEND_OP_ADD, LogicOp: Direct3D12::D3D12_LOGIC_OP_CLEAR, RenderTargetWriteMask: 0, }; let mut raw_targets = [dummy_target; Direct3D12::D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT as usize]; for (raw, ct) in raw_targets.iter_mut().zip(color_targets.iter()) { if let Some(ct) = ct.as_ref() { raw.RenderTargetWriteMask = ct.write_mask.bits() as u8; if let Some(ref blend) = ct.blend { let (color_op, color_src, color_dst) = map_blend_component(&blend.color, false); let (alpha_op, alpha_src, alpha_dst) = map_blend_component(&blend.alpha, true); raw.BlendEnable = true.into(); raw.BlendOp = color_op; raw.SrcBlend = color_src; raw.DestBlend = color_dst; raw.BlendOpAlpha = alpha_op; raw.SrcBlendAlpha = alpha_src; raw.DestBlendAlpha = alpha_dst; } } } raw_targets } fn map_stencil_op(op: wgt::StencilOperation) -> Direct3D12::D3D12_STENCIL_OP { use wgt::StencilOperation as So; match op { So::Keep => Direct3D12::D3D12_STENCIL_OP_KEEP, So::Zero => Direct3D12::D3D12_STENCIL_OP_ZERO, So::Replace => Direct3D12::D3D12_STENCIL_OP_REPLACE, So::IncrementClamp => Direct3D12::D3D12_STENCIL_OP_INCR_SAT, So::IncrementWrap => Direct3D12::D3D12_STENCIL_OP_INCR, So::DecrementClamp => Direct3D12::D3D12_STENCIL_OP_DECR_SAT, So::DecrementWrap => Direct3D12::D3D12_STENCIL_OP_DECR, So::Invert => Direct3D12::D3D12_STENCIL_OP_INVERT, } } fn map_stencil_face(face: &wgt::StencilFaceState) -> Direct3D12::D3D12_DEPTH_STENCILOP_DESC { Direct3D12::D3D12_DEPTH_STENCILOP_DESC { StencilFailOp: map_stencil_op(face.fail_op), StencilDepthFailOp: map_stencil_op(face.depth_fail_op), StencilPassOp: map_stencil_op(face.pass_op), StencilFunc: map_comparison(face.compare), } } pub fn map_depth_stencil(ds: &wgt::DepthStencilState) -> Direct3D12::D3D12_DEPTH_STENCIL_DESC { Direct3D12::D3D12_DEPTH_STENCIL_DESC { DepthEnable: ds.is_depth_enabled().into(), DepthWriteMask: if ds.depth_write_enabled { Direct3D12::D3D12_DEPTH_WRITE_MASK_ALL } else { Direct3D12::D3D12_DEPTH_WRITE_MASK_ZERO }, DepthFunc: map_comparison(ds.depth_compare), StencilEnable: ds.stencil.is_enabled().into(), StencilReadMask: ds.stencil.read_mask as u8, StencilWriteMask: ds.stencil.write_mask as u8, FrontFace: map_stencil_face(&ds.stencil.front), BackFace: map_stencil_face(&ds.stencil.back), } } pub(crate) fn map_acceleration_structure_build_flags( flags: wgt::AccelerationStructureFlags, mode: Option, ) -> Direct3D12::D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS { let mut d3d_flags = Default::default(); if flags.contains(wgt::AccelerationStructureFlags::ALLOW_COMPACTION) { d3d_flags |= Direct3D12::D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_ALLOW_COMPACTION; } if flags.contains(wgt::AccelerationStructureFlags::ALLOW_UPDATE) { d3d_flags |= Direct3D12::D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_ALLOW_UPDATE; } if flags.contains(wgt::AccelerationStructureFlags::LOW_MEMORY) { d3d_flags |= Direct3D12::D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_MINIMIZE_MEMORY; } if flags.contains(wgt::AccelerationStructureFlags::PREFER_FAST_BUILD) { d3d_flags |= Direct3D12::D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_BUILD; } if flags.contains(wgt::AccelerationStructureFlags::PREFER_FAST_TRACE) { d3d_flags |= Direct3D12::D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE; } if let Some(crate::AccelerationStructureBuildMode::Update) = mode { d3d_flags |= Direct3D12::D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PERFORM_UPDATE } d3d_flags } pub(crate) fn map_acceleration_structure_geometry_flags( flags: wgt::AccelerationStructureGeometryFlags, ) -> Direct3D12::D3D12_RAYTRACING_GEOMETRY_FLAGS { let mut d3d_flags = Default::default(); if flags.contains(wgt::AccelerationStructureGeometryFlags::OPAQUE) { d3d_flags |= Direct3D12::D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE; } if flags.contains(wgt::AccelerationStructureGeometryFlags::NO_DUPLICATE_ANY_HIT_INVOCATION) { d3d_flags |= Direct3D12::D3D12_RAYTRACING_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT_INVOCATION; } d3d_flags } pub(crate) fn map_acceleration_structure_copy_mode( mode: wgt::AccelerationStructureCopy, ) -> Direct3D12::D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE { match mode { wgt::AccelerationStructureCopy::Clone => { Direct3D12::D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE_CLONE } wgt::AccelerationStructureCopy::Compact => { Direct3D12::D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE_COMPACT } } }