#include "d3d9_util.h" namespace dxvk { typedef HRESULT (STDMETHODCALLTYPE *D3DXDisassembleShader) ( const void* pShader, BOOL EnableColorCode, char* pComments, ID3DBlob** ppDisassembly); // ppDisassembly is actually a D3DXBUFFER, but it has the exact same vtable as a ID3DBlob at the start. D3DXDisassembleShader g_pfnDisassembleShader = nullptr; HRESULT DisassembleShader( const void* pShader, BOOL EnableColorCode, char* pComments, ID3DBlob** ppDisassembly) { if (g_pfnDisassembleShader == nullptr) { HMODULE d3d9x = LoadLibraryA("d3dx9.dll"); if (d3d9x == nullptr) d3d9x = LoadLibraryA("d3dx9_43.dll"); g_pfnDisassembleShader = reinterpret_cast(GetProcAddress(d3d9x, "D3DXDisassembleShader")); } if (g_pfnDisassembleShader == nullptr) return D3DERR_INVALIDCALL; return g_pfnDisassembleShader( pShader, EnableColorCode, pComments, ppDisassembly); } HRESULT DecodeMultiSampleType( D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, VkSampleCountFlagBits* pCount) { uint32_t sampleCount = std::max(MultiSample, 1u); // Check if this is a power of two... if (sampleCount & (sampleCount - 1)) return D3DERR_INVALIDCALL; if (MultiSample == D3DMULTISAMPLE_NONMASKABLE) sampleCount = 1u << MultisampleQuality; if (pCount != nullptr) *pCount = VkSampleCountFlagBits(sampleCount); return D3D_OK; } VkFormat GetPackedDepthStencilFormat(D3D9Format Format) { switch (Format) { case D3D9Format::D15S1: return VK_FORMAT_D16_UNORM_S8_UINT; // This should never happen! case D3D9Format::D16: case D3D9Format::D16_LOCKABLE: case D3D9Format::DF16: return VK_FORMAT_D16_UNORM; case D3D9Format::D24X8: case D3D9Format::DF24: return VK_FORMAT_X8_D24_UNORM_PACK32; case D3D9Format::D24X4S4: case D3D9Format::D24FS8: case D3D9Format::D24S8: case D3D9Format::INTZ: return VK_FORMAT_D24_UNORM_S8_UINT; case D3D9Format::D32: case D3D9Format::D32_LOCKABLE: case D3D9Format::D32F_LOCKABLE: return VK_FORMAT_D32_SFLOAT; case D3D9Format::S8_LOCKABLE: return VK_FORMAT_S8_UINT; default: return VK_FORMAT_UNDEFINED; } } VkFormatFeatureFlags GetImageFormatFeatures(DWORD Usage) { VkFormatFeatureFlags features = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT; if (Usage & D3DUSAGE_DEPTHSTENCIL) features |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT; if (Usage & D3DUSAGE_RENDERTARGET) features |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT; return features; } VkImageUsageFlags GetImageUsageFlags(DWORD Usage) { VkImageUsageFlags usage = VK_IMAGE_USAGE_SAMPLED_BIT; if (Usage & D3DUSAGE_DEPTHSTENCIL) usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; if (Usage & D3DUSAGE_RENDERTARGET) usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; return usage; } uint32_t GetVertexCount(D3DPRIMITIVETYPE type, UINT count) { switch (type) { default: case D3DPT_TRIANGLELIST: return count * 3; case D3DPT_POINTLIST: return count; case D3DPT_LINELIST: return count * 2; case D3DPT_LINESTRIP: return count + 1; case D3DPT_TRIANGLESTRIP: return count + 2; case D3DPT_TRIANGLEFAN: return count + 2; } } DxvkInputAssemblyState DecodeInputAssemblyState(D3DPRIMITIVETYPE type) { switch (type) { default: case D3DPT_TRIANGLELIST: return { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_FALSE, 0 }; case D3DPT_POINTLIST: return { VK_PRIMITIVE_TOPOLOGY_POINT_LIST, VK_FALSE, 0 }; case D3DPT_LINELIST: return { VK_PRIMITIVE_TOPOLOGY_LINE_LIST, VK_FALSE, 0 }; case D3DPT_LINESTRIP: return { VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_FALSE, 0 }; case D3DPT_TRIANGLESTRIP: return { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, VK_FALSE, 0 }; case D3DPT_TRIANGLEFAN: return { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, VK_FALSE, 0 }; } } VkBlendFactor DecodeBlendFactor(D3DBLEND BlendFactor, bool IsAlpha) { switch (BlendFactor) { default: case D3DBLEND_ZERO: return VK_BLEND_FACTOR_ZERO; case D3DBLEND_ONE: return VK_BLEND_FACTOR_ONE; case D3DBLEND_SRCCOLOR: return VK_BLEND_FACTOR_SRC_COLOR; case D3DBLEND_INVSRCCOLOR: return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR; case D3DBLEND_SRCALPHA: return VK_BLEND_FACTOR_SRC_ALPHA; case D3DBLEND_INVSRCALPHA: return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; case D3DBLEND_DESTALPHA: return VK_BLEND_FACTOR_DST_ALPHA; case D3DBLEND_INVDESTALPHA: return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA; case D3DBLEND_DESTCOLOR: return VK_BLEND_FACTOR_DST_COLOR; case D3DBLEND_INVDESTCOLOR: return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR; case D3DBLEND_SRCALPHASAT: return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE; case D3DBLEND_BOTHSRCALPHA: return VK_BLEND_FACTOR_SRC_ALPHA; case D3DBLEND_BOTHINVSRCALPHA: return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; case D3DBLEND_BLENDFACTOR: return IsAlpha ? VK_BLEND_FACTOR_CONSTANT_ALPHA : VK_BLEND_FACTOR_CONSTANT_COLOR; case D3DBLEND_INVBLENDFACTOR: return IsAlpha ? VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA : VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR; case D3DBLEND_SRCCOLOR2: return VK_BLEND_FACTOR_SRC1_COLOR; case D3DBLEND_INVSRCCOLOR2: return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR; } } VkBlendOp DecodeBlendOp(D3DBLENDOP BlendOp) { switch (BlendOp) { default: case D3DBLENDOP_ADD: return VK_BLEND_OP_ADD; case D3DBLENDOP_SUBTRACT: return VK_BLEND_OP_SUBTRACT; case D3DBLENDOP_REVSUBTRACT: return VK_BLEND_OP_REVERSE_SUBTRACT; case D3DBLENDOP_MIN: return VK_BLEND_OP_MIN; case D3DBLENDOP_MAX: return VK_BLEND_OP_MAX; } } VkFilter DecodeFilter(D3DTEXTUREFILTERTYPE Filter) { switch (Filter) { case D3DTEXF_NONE: case D3DTEXF_POINT: return VK_FILTER_NEAREST; default: return VK_FILTER_LINEAR; } } D3D9MipFilter DecodeMipFilter(D3DTEXTUREFILTERTYPE Filter) { D3D9MipFilter filter; filter.MipsEnabled = Filter != D3DTEXF_NONE; switch (Filter) { case D3DTEXF_POINT: case D3DTEXF_NONE: filter.MipFilter = VK_SAMPLER_MIPMAP_MODE_NEAREST; break; default: filter.MipFilter = VK_SAMPLER_MIPMAP_MODE_LINEAR; break; } return filter; } bool IsAnisotropic(D3DTEXTUREFILTERTYPE Filter) { return Filter == D3DTEXF_ANISOTROPIC; } VkSamplerAddressMode DecodeAddressMode(D3DTEXTUREADDRESS Mode) { switch (Mode) { default: case D3DTADDRESS_WRAP: return VK_SAMPLER_ADDRESS_MODE_REPEAT; case D3DTADDRESS_MIRROR: return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; case D3DTADDRESS_CLAMP: return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; case D3DTADDRESS_BORDER: return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; case D3DTADDRESS_MIRRORONCE: return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; } } VkCompareOp DecodeCompareOp(D3DCMPFUNC Func) { switch (Func) { default: case D3DCMP_NEVER: return VK_COMPARE_OP_NEVER; case D3DCMP_LESS: return VK_COMPARE_OP_LESS; case D3DCMP_EQUAL: return VK_COMPARE_OP_EQUAL; case D3DCMP_LESSEQUAL: return VK_COMPARE_OP_LESS_OR_EQUAL; case D3DCMP_GREATER: return VK_COMPARE_OP_GREATER; case D3DCMP_NOTEQUAL: return VK_COMPARE_OP_NOT_EQUAL; case D3DCMP_GREATEREQUAL: return VK_COMPARE_OP_GREATER_OR_EQUAL; case D3DCMP_ALWAYS: return VK_COMPARE_OP_ALWAYS; } } VkStencilOp DecodeStencilOp(D3DSTENCILOP Op) { switch (Op) { default: case D3DSTENCILOP_KEEP: return VK_STENCIL_OP_KEEP; case D3DSTENCILOP_ZERO: return VK_STENCIL_OP_ZERO; case D3DSTENCILOP_REPLACE: return VK_STENCIL_OP_REPLACE; case D3DSTENCILOP_INCRSAT: return VK_STENCIL_OP_INCREMENT_AND_CLAMP; case D3DSTENCILOP_DECRSAT: return VK_STENCIL_OP_DECREMENT_AND_CLAMP; case D3DSTENCILOP_INVERT: return VK_STENCIL_OP_INVERT; case D3DSTENCILOP_INCR: return VK_STENCIL_OP_INCREMENT_AND_WRAP; case D3DSTENCILOP_DECR: return VK_STENCIL_OP_DECREMENT_AND_WRAP; } } VkCullModeFlags DecodeCullMode(D3DCULL Mode) { switch (Mode) { case D3DCULL_CW: return VK_CULL_MODE_FRONT_BIT; case D3DCULL_CCW: return VK_CULL_MODE_BACK_BIT; default: case D3DCULL_NONE: return VK_CULL_MODE_NONE; } } VkPolygonMode DecodeFillMode(D3DFILLMODE Mode) { switch (Mode) { case D3DFILL_POINT: return VK_POLYGON_MODE_POINT; case D3DFILL_WIREFRAME: return VK_POLYGON_MODE_LINE; default: case D3DFILL_SOLID: return VK_POLYGON_MODE_FILL; } } VkIndexType DecodeIndexType(D3D9Format Format) { return Format == D3D9Format::INDEX16 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32; } VkFormat DecodeDecltype(D3DDECLTYPE Type) { switch (Type) { case D3DDECLTYPE_FLOAT1: return VK_FORMAT_R32_SFLOAT; case D3DDECLTYPE_FLOAT2: return VK_FORMAT_R32G32_SFLOAT; case D3DDECLTYPE_FLOAT3: return VK_FORMAT_R32G32B32_SFLOAT; case D3DDECLTYPE_FLOAT4: return VK_FORMAT_R32G32B32A32_SFLOAT; case D3DDECLTYPE_D3DCOLOR: return VK_FORMAT_B8G8R8A8_UNORM; case D3DDECLTYPE_UBYTE4: return VK_FORMAT_R8G8B8A8_USCALED; case D3DDECLTYPE_SHORT2: return VK_FORMAT_R16G16_SSCALED; case D3DDECLTYPE_SHORT4: return VK_FORMAT_R16G16B16A16_SSCALED; case D3DDECLTYPE_UBYTE4N: return VK_FORMAT_R8G8B8A8_UNORM; case D3DDECLTYPE_SHORT2N: return VK_FORMAT_R16G16_SNORM; case D3DDECLTYPE_SHORT4N: return VK_FORMAT_R16G16B16A16_SNORM; case D3DDECLTYPE_USHORT2N: return VK_FORMAT_R16G16_UNORM; case D3DDECLTYPE_USHORT4N: return VK_FORMAT_R16G16B16A16_UNORM; case D3DDECLTYPE_UDEC3: return VK_FORMAT_A2B10G10R10_USCALED_PACK32; case D3DDECLTYPE_FLOAT16_2: return VK_FORMAT_R16G16_SFLOAT; case D3DDECLTYPE_FLOAT16_4: return VK_FORMAT_R16G16B16A16_SFLOAT; case D3DDECLTYPE_DEC3N: return VK_FORMAT_A2B10G10R10_SNORM_PACK32; case D3DDECLTYPE_UNUSED: default: return VK_FORMAT_UNDEFINED; } } void ConvertBox(D3DBOX box, VkOffset3D& offset, VkExtent3D& extent) { offset.x = box.Left; offset.y = box.Top; offset.z = box.Front; extent.width = box.Right - box.Left; extent.height = box.Bottom - box.Top; extent.depth = box.Back - box.Front; } void ConvertRect(RECT rect, VkOffset3D& offset, VkExtent3D& extent) { offset.x = rect.left; offset.y = rect.top; offset.z = 0; extent.width = rect.right - rect.left; extent.height = rect.bottom - rect.top; extent.depth = 1; } void ConvertRect(RECT rect, VkOffset2D& offset, VkExtent2D& extent) { offset.x = rect.left; offset.y = rect.top; extent.width = rect.right - rect.left; extent.height = rect.bottom - rect.top; } uint32_t GetDecltypeSize(D3DDECLTYPE Type) { switch (Type) { case D3DDECLTYPE_FLOAT1: return 1 * sizeof(float); case D3DDECLTYPE_FLOAT2: return 2 * sizeof(float); case D3DDECLTYPE_FLOAT3: return 3 * sizeof(float); case D3DDECLTYPE_FLOAT4: return 4 * sizeof(float); case D3DDECLTYPE_D3DCOLOR: return 1 * sizeof(DWORD); case D3DDECLTYPE_UBYTE4: return 4 * sizeof(BYTE); case D3DDECLTYPE_SHORT2: return 2 * sizeof(short); case D3DDECLTYPE_SHORT4: return 4 * sizeof(short); case D3DDECLTYPE_UBYTE4N: return 4 * sizeof(BYTE); case D3DDECLTYPE_SHORT2N: return 2 * sizeof(short); case D3DDECLTYPE_SHORT4N: return 4 * sizeof(short); case D3DDECLTYPE_USHORT2N: return 2 * sizeof(short); case D3DDECLTYPE_USHORT4N: return 4 * sizeof(short); case D3DDECLTYPE_UDEC3: return 4; case D3DDECLTYPE_DEC3N: return 4; case D3DDECLTYPE_FLOAT16_2: return 2 * 2; case D3DDECLTYPE_FLOAT16_4: return 4 * 2; default: return 0; } } uint32_t GetDecltypeCount(D3DDECLTYPE Type) { switch (Type) { case D3DDECLTYPE_FLOAT1: return 1; case D3DDECLTYPE_FLOAT2: return 2; case D3DDECLTYPE_FLOAT3: return 3; case D3DDECLTYPE_FLOAT4: return 4; case D3DDECLTYPE_D3DCOLOR: return 4; case D3DDECLTYPE_UBYTE4: return 4; case D3DDECLTYPE_SHORT2: return 2; case D3DDECLTYPE_SHORT4: return 4; case D3DDECLTYPE_UBYTE4N: return 4; case D3DDECLTYPE_SHORT2N: return 2; case D3DDECLTYPE_SHORT4N: return 4; case D3DDECLTYPE_USHORT2N: return 2; case D3DDECLTYPE_USHORT4N: return 4; case D3DDECLTYPE_UDEC3: return 3; case D3DDECLTYPE_DEC3N: return 3; case D3DDECLTYPE_FLOAT16_2: return 2; case D3DDECLTYPE_FLOAT16_4: return 4; default: return 0; } } bool IsDepthFormat(D3D9Format Format) { return Format == D3D9Format::D16_LOCKABLE || Format == D3D9Format::D32 || Format == D3D9Format::D15S1 || Format == D3D9Format::D24S8 || Format == D3D9Format::D24X8 || Format == D3D9Format::D24X4S4 || Format == D3D9Format::D16 || Format == D3D9Format::D32F_LOCKABLE || Format == D3D9Format::D24FS8 || Format == D3D9Format::D32_LOCKABLE || Format == D3D9Format::DF16 || Format == D3D9Format::DF24 || Format == D3D9Format::INTZ; } }