#include "d3d9_format.h" namespace dxvk { // It is also worth noting that the msb/lsb-ness is flipped between VK and D3D9. D3D9_VK_FORMAT_MAPPING ConvertFormatUnfixed(D3D9Format Format) { switch (Format) { case D3D9Format::Unknown: return {}; case D3D9Format::R8G8B8: return {}; // Unsupported case D3D9Format::A8R8G8B8: return { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::X8R8G8B8: return { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT, { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_ONE }}; case D3D9Format::R5G6B5: return { VK_FORMAT_R5G6B5_UNORM_PACK16, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT}; case D3D9Format::X1R5G5B5: return { VK_FORMAT_A1R5G5B5_UNORM_PACK16, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT, { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_ONE }}; case D3D9Format::A1R5G5B5: return { VK_FORMAT_A1R5G5B5_UNORM_PACK16, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::A4R4G4B4: return { VK_FORMAT_R4G4B4A4_UNORM_PACK16, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT, { VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_R }}; case D3D9Format::R3G3B2: return {}; // Unsupported case D3D9Format::A8: return { VK_FORMAT_R8_UNORM, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT, { VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_R }}; case D3D9Format::A8R3G3B2: return {}; // Unsupported case D3D9Format::X4R4G4B4: return { VK_FORMAT_R4G4B4A4_UNORM_PACK16, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT, { VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_ONE }}; case D3D9Format::A2B10G10R10: return { VK_FORMAT_A2B10G10R10_UNORM_PACK32, // The A2 is out of place here. This should be investigated. VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::A8B8G8R8: return { VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::X8B8G8R8: return { VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT, { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_ONE }}; case D3D9Format::G16R16: return { VK_FORMAT_R16G16_UNORM, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT, { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }}; case D3D9Format::A2R10G10B10: return { VK_FORMAT_A2R10G10B10_UNORM_PACK32, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::A16B16G16R16: return { VK_FORMAT_R16G16B16A16_UNORM, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::A8P8: return {}; // Unsupported case D3D9Format::P8: return {}; // Unsupported case D3D9Format::L8: return { VK_FORMAT_R8_UNORM, VK_FORMAT_R8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT, { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ONE }}; case D3D9Format::A8L8: return { VK_FORMAT_R8G8_UNORM, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT, { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G }}; case D3D9Format::A4L4: return { VK_FORMAT_R4G4_UNORM_PACK8, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT, { VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R }}; case D3D9Format::V8U8: return { VK_FORMAT_R8G8_SNORM, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT, { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }}; case D3D9Format::L6V5U5: return {}; // Unsupported case D3D9Format::X8L8V8U8: return {}; // Unsupported case D3D9Format::Q8W8V8U8: return { VK_FORMAT_R8G8B8A8_SNORM, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::V16U16: return { VK_FORMAT_R16G16_SNORM, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT, { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }}; case D3D9Format::A2W10V10U10: return {}; // Unsupported case D3D9Format::UYVY: return { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT, { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY }, { D3D9VideoFormat_UYVY, { 2u, 1u } } }; case D3D9Format::R8G8_B8G8: return { VK_FORMAT_G8B8G8R8_422_UNORM, // This format may have been _SCALED in DX9. VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::YUY2: return { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT, { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY }, { D3D9VideoFormat_YUY2, { 2u, 1u } } }; case D3D9Format::G8R8_G8B8: return { VK_FORMAT_B8G8R8G8_422_UNORM, // This format may have been _SCALED in DX9. VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::DXT1: return { VK_FORMAT_BC1_RGBA_UNORM_BLOCK, VK_FORMAT_BC1_RGBA_SRGB_BLOCK, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::DXT2: return { VK_FORMAT_BC2_UNORM_BLOCK, VK_FORMAT_BC2_SRGB_BLOCK, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::DXT3: return { VK_FORMAT_BC2_UNORM_BLOCK, VK_FORMAT_BC2_SRGB_BLOCK, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::DXT4: return { VK_FORMAT_BC3_UNORM_BLOCK, VK_FORMAT_BC3_SRGB_BLOCK, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::DXT5: return { VK_FORMAT_BC3_UNORM_BLOCK, VK_FORMAT_BC3_SRGB_BLOCK, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::D16_LOCKABLE: return { VK_FORMAT_D16_UNORM, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_DEPTH_BIT }; case D3D9Format::D32: return { VK_FORMAT_D32_SFLOAT, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_DEPTH_BIT }; case D3D9Format::D15S1: return {}; // Unsupported (everywhere) case D3D9Format::D24S8: return { VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT }; case D3D9Format::D24X8: return { VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_DEPTH_BIT }; case D3D9Format::D24X4S4: return {}; // Unsupported (everywhere) case D3D9Format::D16: return { VK_FORMAT_D16_UNORM, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_DEPTH_BIT }; case D3D9Format::D32F_LOCKABLE: return { VK_FORMAT_D32_SFLOAT, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_DEPTH_BIT }; case D3D9Format::D24FS8: return { VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT }; case D3D9Format::D32_LOCKABLE: return { VK_FORMAT_D32_SFLOAT, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_DEPTH_BIT }; case D3D9Format::S8_LOCKABLE: return { VK_FORMAT_S8_UINT, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_STENCIL_BIT }; case D3D9Format::L16: return { VK_FORMAT_R16_UNORM, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT, { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ONE }}; case D3D9Format::VERTEXDATA: return { VK_FORMAT_R8_UINT, VK_FORMAT_UNDEFINED, 0 }; case D3D9Format::INDEX16: return { VK_FORMAT_R16_UINT, VK_FORMAT_UNDEFINED, 0 }; case D3D9Format::INDEX32: return { VK_FORMAT_R32_UINT, VK_FORMAT_UNDEFINED, 0 }; case D3D9Format::Q16W16V16U16: return { VK_FORMAT_R16G16B16A16_SNORM, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::MULTI2_ARGB8: return {}; // Unsupported case D3D9Format::R16F: return { VK_FORMAT_R16_SFLOAT, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT, { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }}; case D3D9Format::G16R16F: return { VK_FORMAT_R16G16_SFLOAT, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT, { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }}; case D3D9Format::A16B16G16R16F: return { VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::R32F: return { VK_FORMAT_R32_SFLOAT, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT, { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }}; case D3D9Format::G32R32F: return { VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT, { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }}; case D3D9Format::A32B32G32R32F: return { VK_FORMAT_R32G32B32A32_SFLOAT, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::CxV8U8: return {}; // Unsupported case D3D9Format::A1: return {}; // Unsupported case D3D9Format::A2B10G10R10_XR_BIAS: return { VK_FORMAT_A2B10G10R10_SNORM_PACK32, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::BINARYBUFFER: return { VK_FORMAT_R8_UINT, VK_FORMAT_UNDEFINED, 0 }; case D3D9Format::ATI1: return { VK_FORMAT_BC4_UNORM_BLOCK, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT, { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ONE }}; case D3D9Format::ATI2: return { VK_FORMAT_BC5_UNORM_BLOCK, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_COLOR_BIT, { VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }}; case D3D9Format::INST: return {}; // Driver hack, handled elsewhere case D3D9Format::DF24: return { VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_DEPTH_BIT, { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ONE }}; case D3D9Format::DF16: return { VK_FORMAT_D16_UNORM, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_DEPTH_BIT, { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ONE }}; case D3D9Format::NULL_FORMAT: return {}; // Driver hack, handled elsewhere case D3D9Format::GET4: return {}; // Unsupported case D3D9Format::GET1: return {}; // Unsupported case D3D9Format::NVDB: return {}; // Driver hack, handled elsewhere case D3D9Format::A2M1: return {}; // Driver hack, handled elsewhere case D3D9Format::A2M0: return {}; // Driver hack, handled elsewhere case D3D9Format::ATOC: return {}; // Driver hack, handled elsewhere case D3D9Format::INTZ: return { VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_UNDEFINED, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R }}; case D3D9Format::RAWZ: return {}; // Unsupported default: Logger::warn(str::format("ConvertFormat: Unknown format encountered: ", Format)); return {}; // Unsupported } } D3D9VkFormatTable::D3D9VkFormatTable( const Rc& adapter, const D3D9Options& options) { m_dfSupport = options.supportDFFormats; m_x4r4g4b4Support = options.supportX4R4G4B4; m_d32supportFinal = options.supportD32; // AMD do not support 24-bit depth buffers on Vulkan, // so we have to fall back to a 32-bit depth format. m_d24s8Support = CheckImageFormatSupport(adapter, VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT); // NVIDIA do not support 16-bit depth buffers with stencil on Vulkan, // so we have to fall back to a 32-bit depth format. m_d16s8Support = CheckImageFormatSupport(adapter, VK_FORMAT_D16_UNORM_S8_UINT, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT); if (!m_d24s8Support) Logger::warn("D3D9: VK_FORMAT_D24_UNORM_S8_UINT -> VK_FORMAT_D32_SFLOAT_S8_UINT"); if (!m_d16s8Support) { if (m_d24s8Support) Logger::warn("D3D9: VK_FORMAT_D16_UNORM_S8_UINT -> VK_FORMAT_D24_UNORM_S8_UINT"); else Logger::warn("D3D9: VK_FORMAT_D16_UNORM_S8_UINT -> VK_FORMAT_D32_SFLOAT_S8_UINT"); } } D3D9_VK_FORMAT_MAPPING D3D9VkFormatTable::GetFormatMapping( D3D9Format Format) const { D3D9_VK_FORMAT_MAPPING mapping = ConvertFormatUnfixed(Format); if (Format == D3D9Format::X4R4G4B4 && !m_x4r4g4b4Support) return D3D9_VK_FORMAT_MAPPING(); if (Format == D3D9Format::DF16 && !m_dfSupport) return D3D9_VK_FORMAT_MAPPING(); if (Format == D3D9Format::DF24 && !m_dfSupport) return D3D9_VK_FORMAT_MAPPING(); if (Format == D3D9Format::D32 && !m_d32supportFinal) return D3D9_VK_FORMAT_MAPPING(); if (!m_d24s8Support && mapping.FormatColor == VK_FORMAT_D24_UNORM_S8_UINT) mapping.FormatColor = VK_FORMAT_D32_SFLOAT_S8_UINT; if (!m_d16s8Support && mapping.FormatColor == VK_FORMAT_D16_UNORM_S8_UINT) mapping.FormatColor = m_d24s8Support ? VK_FORMAT_D24_UNORM_S8_UINT : VK_FORMAT_D32_SFLOAT_S8_UINT; return mapping; } DxvkFormatInfo D3D9VkFormatTable::GetUnsupportedFormatInfo( D3D9Format Format) const { switch (Format) { case D3D9Format::R8G8B8: return { 3, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::R3G3B2: return { 1, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::A8R3G3B2: return { 2, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::A8P8: return { 2, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::P8: return { 1, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::L6V5U5: return { 2, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::X8L8V8U8: return { 4, VK_IMAGE_ASPECT_COLOR_BIT }; case D3D9Format::A2W10V10U10: return { 4, VK_IMAGE_ASPECT_COLOR_BIT }; // MULTI2_ARGB8 -> Don't have a clue what this is. case D3D9Format::CxV8U8: return { 2, VK_IMAGE_ASPECT_COLOR_BIT }; // A1 -> Doesn't map nicely here cause it's not byte aligned. // Gonna just pretend that doesn't exist until something // depends on that. default: return {}; } } bool D3D9VkFormatTable::CheckImageFormatSupport( const Rc& Adapter, VkFormat Format, VkFormatFeatureFlags Features) const { VkFormatProperties supported = Adapter->formatProperties(Format); return (supported.linearTilingFeatures & Features) == Features || (supported.optimalTilingFeatures & Features) == Features; } }