diff --git a/DirectXTex/DirectXTex.inl b/DirectXTex/DirectXTex.inl index 7fef321..0b8be4c 100644 --- a/DirectXTex/DirectXTex.inl +++ b/DirectXTex/DirectXTex.inl @@ -46,7 +46,7 @@ constexpr TEX_COMPRESS_FLAGS operator|(TEX_FILTER_FLAGS a, TEX_COMPRESS_FLAGS b) _Use_decl_annotations_ constexpr bool __cdecl IsValid(DXGI_FORMAT fmt) noexcept { - return (static_cast(fmt) >= 1 && static_cast(fmt) <= 190); + return (static_cast(fmt) >= 1 && static_cast(fmt) <= 191); } _Use_decl_annotations_ @@ -117,27 +117,6 @@ inline bool __cdecl IsSRGB(DXGI_FORMAT fmt) noexcept } } -_Use_decl_annotations_ -inline bool __cdecl IsBGR(DXGI_FORMAT fmt) noexcept -{ - switch (fmt) - { - case DXGI_FORMAT_B5G6R5_UNORM: - case DXGI_FORMAT_B5G5R5A1_UNORM: - case DXGI_FORMAT_B8G8R8A8_UNORM: - case DXGI_FORMAT_B8G8R8X8_UNORM: - case DXGI_FORMAT_B8G8R8A8_TYPELESS: - case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: - case DXGI_FORMAT_B8G8R8X8_TYPELESS: - case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: - case DXGI_FORMAT_B4G4R4A4_UNORM: - return true; - - default: - return false; - } -} - //===================================================================================== // Image I/O diff --git a/DirectXTex/DirectXTexConvert.cpp b/DirectXTex/DirectXTexConvert.cpp index 1625bef..2c6b28d 100644 --- a/DirectXTex/DirectXTexConvert.cpp +++ b/DirectXTex/DirectXTexConvert.cpp @@ -378,14 +378,24 @@ void DirectX::Internal::CopyScanline( //----------------------------------------------------------------------------- case DXGI_FORMAT_B5G5R5A1_UNORM: + case DXGI_FORMAT_B4G4R4A4_UNORM: + case WIN11_DXGI_FORMAT_A4B4G4R4_UNORM: if (inSize >= 2 && outSize >= 2) { + uint16_t alpha; + if (format == DXGI_FORMAT_B4G4R4A4_UNORM) + alpha = 0xF000; + else if (format == WIN11_DXGI_FORMAT_A4B4G4R4_UNORM) + alpha = 0x000F; + else + alpha = 0x8000; + if (pDestination == pSource) { auto dPtr = static_cast(pDestination); for (size_t count = 0; count < (outSize - 1); count += 2) { - *(dPtr++) |= 0x8000; + *(dPtr++) |= alpha; } } else @@ -395,7 +405,7 @@ void DirectX::Internal::CopyScanline( const size_t size = std::min(outSize, inSize); for (size_t count = 0; count < (size - 1); count += 2) { - *(dPtr++) = uint16_t(*(sPtr++) | 0x8000); + *(dPtr++) = uint16_t(*(sPtr++) | alpha); } } } @@ -405,31 +415,6 @@ void DirectX::Internal::CopyScanline( case DXGI_FORMAT_A8_UNORM: memset(pDestination, 0xff, outSize); return; - - //----------------------------------------------------------------------------- - case DXGI_FORMAT_B4G4R4A4_UNORM: - if (inSize >= 2 && outSize >= 2) - { - if (pDestination == pSource) - { - auto dPtr = static_cast(pDestination); - for (size_t count = 0; count < (outSize - 1); count += 2) - { - *(dPtr++) |= 0xF000; - } - } - else - { - const uint16_t * __restrict sPtr = static_cast(pSource); - uint16_t * __restrict dPtr = static_cast(pDestination); - const size_t size = std::min(outSize, inSize); - for (size_t count = 0; count < (size - 1); count += 2) - { - *(dPtr++) = uint16_t(*(sPtr++) | 0xF000); - } - } - } - return; } } @@ -631,7 +616,7 @@ bool DirectX::Internal::ExpandScanline( assert(IsValid(outFormat) && !IsPlanar(outFormat) && !IsPalettized(outFormat)); assert(IsValid(inFormat) && !IsPlanar(inFormat) && !IsPalettized(inFormat)); - switch (inFormat) + switch (static_cast(inFormat)) { case DXGI_FORMAT_B5G6R5_UNORM: if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM) @@ -707,6 +692,31 @@ bool DirectX::Internal::ExpandScanline( } return false; + case WIN11_DXGI_FORMAT_A4B4G4R4_UNORM: + if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM) + return false; + + // DXGI_FORMAT_A4B4G4R4_UNORM -> DXGI_FORMAT_R8G8B8A8_UNORM + if (inSize >= 2 && outSize >= 4) + { + const uint16_t * __restrict sPtr = static_cast(pSource); + uint32_t * __restrict dPtr = static_cast(pDestination); + + for (size_t ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4) + { + const uint16_t t = *(sPtr++); + + uint32_t t1 = uint32_t(((t & 0xf000) >> 8) | ((t & 0xf000) >> 12)); + uint32_t t2 = uint32_t((t & 0x0f00) | ((t & 0x0f00) << 4)); + uint32_t t3 = uint32_t(((t & 0x00f0) << 16) | ((t & 0x00f0) << 12)); + uint32_t ta = (tflags & TEXP_SCANLINE_SETALPHA) ? 0xff000000 : uint32_t(((t & 0x000f) << 28) | ((t & 0x000f) << 24)); + + *(dPtr++) = t1 | t2 | t3 | ta; + } + return true; + } + return false; + default: return false; } @@ -1506,6 +1516,22 @@ _Use_decl_annotations_ bool DirectX::Internal::LoadScanline( } return false; + case WIN11_DXGI_FORMAT_A4B4G4R4_UNORM: + if (size >= sizeof(XMUNIBBLE4)) + { + static const XMVECTORF32 s_Scale = { { { 1.f / 15.f, 1.f / 15.f, 1.f / 15.f, 1.f / 15.f } } }; + const XMUNIBBLE4 * __restrict sPtr = static_cast(pSource); + for (size_t icount = 0; icount < (size - sizeof(XMUNIBBLE4) + 1); icount += sizeof(XMUNIBBLE4)) + { + XMVECTOR v = XMLoadUNibble4(sPtr++); + v = XMVectorMultiply(v, s_Scale); + if (dPtr >= ePtr) break; + *(dPtr++) = XMVectorSwizzle<3, 2, 1, 0>(v); + } + return true; + } + return false; + case XBOX_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT: // Xbox One specific 7e3 format if (size >= sizeof(XMUDECN4)) @@ -2382,6 +2408,26 @@ bool DirectX::Internal::StoreScanline( } return false; + case WIN11_DXGI_FORMAT_A4B4G4R4_UNORM: + if (size >= sizeof(XMUNIBBLE4)) + { + static const XMVECTORF32 s_Scale = { { { 15.f, 15.f, 15.f, 15.f } } }; + XMUNIBBLE4 * __restrict dPtr = static_cast(pDestination); + for (size_t icount = 0; icount < (size - sizeof(XMUNIBBLE4) + 1); icount += sizeof(XMUNIBBLE4)) + { + if (sPtr >= ePtr) break; + XMVECTOR v = XMVectorSwizzle<3, 2, 1, 0>(*sPtr++); +#if defined(_M_ARM) || defined(_M_ARM64) || defined(_M_HYBRID_X86_ARM64) || defined(_M_ARM64EC) || __arm__ || __aarch64__ + v = XMVectorMultiplyAdd(v, s_Scale, g_XMOneHalf); +#else + v = XMVectorMultiply(v, s_Scale); +#endif + XMStoreUNibble4(dPtr++, v); + } + return true; + } + return false; + case XBOX_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT: // Xbox One specific 7e3 format with alpha if (size >= sizeof(XMUDECN4)) @@ -2760,7 +2806,7 @@ bool DirectX::Internal::StoreScanlineLinear( assert((reinterpret_cast(pSource) & 0xF) == 0); - switch (format) + switch (static_cast(format)) { case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: @@ -2791,6 +2837,7 @@ bool DirectX::Internal::StoreScanlineLinear( case DXGI_FORMAT_B8G8R8A8_UNORM: case DXGI_FORMAT_B8G8R8X8_UNORM: case DXGI_FORMAT_B4G4R4A4_UNORM: + case WIN11_DXGI_FORMAT_A4B4G4R4_UNORM: break; default: @@ -2831,7 +2878,7 @@ bool DirectX::Internal::LoadScanlineLinear( DXGI_FORMAT format, TEX_FILTER_FLAGS flags) noexcept { - switch (format) + switch (static_cast(format)) { case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: @@ -2862,6 +2909,7 @@ bool DirectX::Internal::LoadScanlineLinear( case DXGI_FORMAT_B8G8R8A8_UNORM: case DXGI_FORMAT_B8G8R8X8_UNORM: case DXGI_FORMAT_B4G4R4A4_UNORM: + case WIN11_DXGI_FORMAT_A4B4G4R4_UNORM: break; default: @@ -2987,6 +3035,7 @@ namespace { XBOX_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT, 10, CONVF_FLOAT | CONVF_POS_ONLY | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, { XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM,10, CONVF_SNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, { XBOX_DXGI_FORMAT_R4G4_UNORM, 4, CONVF_UNORM | CONVF_R | CONVF_G }, + { WIN11_DXGI_FORMAT_A4B4G4R4_UNORM, 4, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, }; #pragma prefast( suppress : 25004, "Signature must match bsearch" ); @@ -4328,6 +4377,56 @@ bool DirectX::Internal::StoreScanlineDither( case DXGI_FORMAT_B4G4R4A4_UNORM: STORE_SCANLINE(XMUNIBBLE4, g_Scale4pc, true, true, uint8_t, 0xF, y, true) + case WIN11_DXGI_FORMAT_A4B4G4R4_UNORM: + if (size >= sizeof(XMUNIBBLE4)) + { + XMUNIBBLE4 * __restrict dest = static_cast(pDestination); + for (size_t i = 0; i < count; ++i) + { + auto index = static_cast((y & 1) ? (count - i - 1) : i); + ptrdiff_t delta = (y & 1) ? -2 : 0; + + XMVECTOR v = XMVectorSaturate(sPtr[index]); + v = XMVectorSwizzle<3, 2, 1, 0>(v); + v = XMVectorAdd(v, vError); + v = XMVectorMultiply(v, g_Scale4pc); + + XMVECTOR target; + if (pDiffusionErrors) + { + target = XMVectorRound(v); + vError = XMVectorSubtract(v, target); + vError = XMVectorDivide(vError, g_Scale4pc); + + // Distribute error to next scanline and next pixel + pDiffusionErrors[index - delta] = XMVectorMultiplyAdd(g_ErrorWeight3, vError, pDiffusionErrors[index - delta]); + pDiffusionErrors[index + 1] = XMVectorMultiplyAdd(g_ErrorWeight5, vError, pDiffusionErrors[index + 1]); + pDiffusionErrors[index + 2 + delta] = XMVectorMultiplyAdd(g_ErrorWeight1, vError, pDiffusionErrors[index + 2 + delta]); + vError = XMVectorMultiply(vError, g_ErrorWeight7); + } + else + { + // Applied ordered dither + target = XMVectorAdd(v, ordered[index & 3]); + target = XMVectorRound(target); + } + + target = XMVectorClamp(target, g_XMZero, g_Scale4pc); + + XMFLOAT4A tmp; + XMStoreFloat4A(&tmp, target); + + auto dPtr = &dest[index]; + if (dPtr >= ePtr) break; + dPtr->x = uint8_t(static_cast(tmp.x) & 0xF); + dPtr->y = uint8_t(static_cast(tmp.y) & 0xF); + dPtr->z = uint8_t(static_cast(tmp.z) & 0xF); + dPtr->w = uint8_t(static_cast(tmp.w) & 0xF); + } + return true; + } + return false; + case XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM: STORE_SCANLINE(XMXDECN4, g_Scale9pc, false, true, uint16_t, 0x3FF, y, false) diff --git a/DirectXTex/DirectXTexDDS.cpp b/DirectXTex/DirectXTexDDS.cpp index a3888f3..054b674 100644 --- a/DirectXTex/DirectXTexDDS.cpp +++ b/DirectXTex/DirectXTexDDS.cpp @@ -30,23 +30,24 @@ namespace enum CONVERSION_FLAGS : uint32_t { CONV_FLAGS_NONE = 0x0, - CONV_FLAGS_EXPAND = 0x1, // Conversion requires expanded pixel size - CONV_FLAGS_NOALPHA = 0x2, // Conversion requires setting alpha to known value - CONV_FLAGS_SWIZZLE = 0x4, // BGR/RGB order swizzling required - CONV_FLAGS_PAL8 = 0x8, // Has an 8-bit palette - CONV_FLAGS_888 = 0x10, // Source is an 8:8:8 (24bpp) format - CONV_FLAGS_565 = 0x20, // Source is a 5:6:5 (16bpp) format - CONV_FLAGS_5551 = 0x40, // Source is a 5:5:5:1 (16bpp) format - CONV_FLAGS_4444 = 0x80, // Source is a 4:4:4:4 (16bpp) format - CONV_FLAGS_44 = 0x100, // Source is a 4:4 (8bpp) format - CONV_FLAGS_332 = 0x200, // Source is a 3:3:2 (8bpp) format - CONV_FLAGS_8332 = 0x400, // Source is a 8:3:3:2 (16bpp) format - CONV_FLAGS_A8P8 = 0x800, // Has an 8-bit palette with an alpha channel - CONV_FLAGS_DX10 = 0x10000, // Has the 'DX10' extension header - CONV_FLAGS_PMALPHA = 0x20000, // Contains premultiplied alpha data - CONV_FLAGS_L8 = 0x40000, // Source is a 8 luminance format - CONV_FLAGS_L16 = 0x80000, // Source is a 16 luminance format - CONV_FLAGS_A8L8 = 0x100000, // Source is a 8:8 luminance format + CONV_FLAGS_EXPAND = 0x1, // Conversion requires expanded pixel size + CONV_FLAGS_NOALPHA = 0x2, // Conversion requires setting alpha to known value + CONV_FLAGS_SWIZZLE = 0x4, // BGR/RGB order swizzling required + CONV_FLAGS_PAL8 = 0x8, // Has an 8-bit palette + CONV_FLAGS_888 = 0x10, // Source is an 8:8:8 (24bpp) format + CONV_FLAGS_565 = 0x20, // Source is a 5:6:5 (16bpp) format + CONV_FLAGS_5551 = 0x40, // Source is a 5:5:5:1 (16bpp) format + CONV_FLAGS_4444 = 0x80, // Source is a 4:4:4:4 (16bpp) format + CONV_FLAGS_44 = 0x100, // Source is a 4:4 (8bpp) format + CONV_FLAGS_332 = 0x200, // Source is a 3:3:2 (8bpp) format + CONV_FLAGS_8332 = 0x400, // Source is a 8:3:3:2 (16bpp) format + CONV_FLAGS_A8P8 = 0x800, // Has an 8-bit palette with an alpha channel + CONF_FLAGS_11ON12 = 0x1000, // D3D11on12 format + CONV_FLAGS_DX10 = 0x10000, // Has the 'DX10' extension header + CONV_FLAGS_PMALPHA = 0x20000, // Contains premultiplied alpha data + CONV_FLAGS_L8 = 0x40000, // Source is a 8 luminance format + CONV_FLAGS_L16 = 0x80000, // Source is a 16 luminance format + CONV_FLAGS_A8L8 = 0x100000, // Source is a 8:8 luminance format }; struct LegacyDDS @@ -507,13 +508,20 @@ namespace // Special flag for handling 16bpp formats if (flags & DDS_FLAGS_NO_16BPP) { - switch (metadata.format) + switch (static_cast(metadata.format)) { case DXGI_FORMAT_B5G6R5_UNORM: case DXGI_FORMAT_B5G5R5A1_UNORM: case DXGI_FORMAT_B4G4R4A4_UNORM: + case WIN11_DXGI_FORMAT_A4B4G4R4_UNORM: if (metadata.format == DXGI_FORMAT_B5G6R5_UNORM) + { convFlags |= CONV_FLAGS_NOALPHA; + } + if (metadata.format == WIN11_DXGI_FORMAT_A4B4G4R4_UNORM) + { + convFlags |= CONV_FLAGS_4444 | CONF_FLAGS_11ON12; + } metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM; convFlags |= CONV_FLAGS_EXPAND; break; @@ -1368,7 +1376,15 @@ namespace { if (convFlags & CONV_FLAGS_EXPAND) { - if (convFlags & (CONV_FLAGS_565 | CONV_FLAGS_5551 | CONV_FLAGS_4444)) + if (convFlags & CONV_FLAGS_4444) + { + if (!ExpandScanline(pDest, dpitch, DXGI_FORMAT_R8G8B8A8_UNORM, + pSrc, spitch, + (convFlags & CONF_FLAGS_11ON12) ? WIN11_DXGI_FORMAT_A4B4G4R4_UNORM : DXGI_FORMAT_B4G4R4A4_UNORM, + tflags)) + return E_FAIL; + } + else if (convFlags & (CONV_FLAGS_565 | CONV_FLAGS_5551)) { if (!ExpandScanline(pDest, dpitch, DXGI_FORMAT_R8G8B8A8_UNORM, pSrc, spitch, @@ -1461,7 +1477,15 @@ namespace { if (convFlags & CONV_FLAGS_EXPAND) { - if (convFlags & (CONV_FLAGS_565 | CONV_FLAGS_5551 | CONV_FLAGS_4444)) + if (convFlags & CONV_FLAGS_4444) + { + if (!ExpandScanline(pDest, dpitch, DXGI_FORMAT_R8G8B8A8_UNORM, + pSrc, spitch, + (convFlags & CONF_FLAGS_11ON12) ? WIN11_DXGI_FORMAT_A4B4G4R4_UNORM : DXGI_FORMAT_B4G4R4A4_UNORM, + tflags)) + return E_FAIL; + } + else if (convFlags & (CONV_FLAGS_565 | CONV_FLAGS_5551)) { if (!ExpandScanline(pDest, dpitch, DXGI_FORMAT_R8G8B8A8_UNORM, pSrc, spitch, diff --git a/DirectXTex/DirectXTexP.h b/DirectXTex/DirectXTexP.h index 461d8a2..7615a82 100644 --- a/DirectXTex/DirectXTexP.h +++ b/DirectXTex/DirectXTexP.h @@ -187,6 +187,8 @@ using WICPixelFormatGUID = GUID; #define XBOX_DXGI_FORMAT_R4G4_UNORM DXGI_FORMAT(190) +#define WIN11_DXGI_FORMAT_A4B4G4R4_UNORM DXGI_FORMAT(191) + #if defined(__MINGW32__) && !defined(E_BOUNDS) #define E_BOUNDS static_cast(0x8000000BL) #endif diff --git a/DirectXTex/DirectXTexUtil.cpp b/DirectXTex/DirectXTexUtil.cpp index 3133c07..4b9bd81 100644 --- a/DirectXTex/DirectXTexUtil.cpp +++ b/DirectXTex/DirectXTexUtil.cpp @@ -454,6 +454,30 @@ bool DirectX::IsDepthStencil(DXGI_FORMAT fmt) noexcept } +//------------------------------------------------------------------------------------- +_Use_decl_annotations_ +bool DirectX::IsBGR(DXGI_FORMAT fmt) noexcept +{ + switch (static_cast(fmt)) + { + case DXGI_FORMAT_B5G6R5_UNORM: + case DXGI_FORMAT_B5G5R5A1_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8X8_UNORM: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + case DXGI_FORMAT_B4G4R4A4_UNORM: + case WIN11_DXGI_FORMAT_A4B4G4R4_UNORM: + return true; + + default: + return false; + } +} + + //------------------------------------------------------------------------------------- _Use_decl_annotations_ bool DirectX::IsTypeless(DXGI_FORMAT fmt, bool partialTypeless) noexcept @@ -551,6 +575,7 @@ bool DirectX::HasAlpha(DXGI_FORMAT fmt) noexcept case XBOX_DXGI_FORMAT_R10G10B10_7E3_A2_FLOAT: case XBOX_DXGI_FORMAT_R10G10B10_6E4_A2_FLOAT: case XBOX_DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM: + case WIN11_DXGI_FORMAT_A4B4G4R4_UNORM: return true; default: @@ -667,6 +692,7 @@ size_t DirectX::BitsPerPixel(DXGI_FORMAT fmt) noexcept case DXGI_FORMAT_B4G4R4A4_UNORM: case WIN10_DXGI_FORMAT_P208: case WIN10_DXGI_FORMAT_V208: + case WIN11_DXGI_FORMAT_A4B4G4R4_UNORM: return 16; case DXGI_FORMAT_NV12: @@ -867,6 +893,7 @@ size_t DirectX::BitsPerColor(DXGI_FORMAT fmt) noexcept case DXGI_FORMAT_B4G4R4A4_UNORM: case XBOX_DXGI_FORMAT_R4G4_UNORM: + case WIN11_DXGI_FORMAT_A4B4G4R4_UNORM: return 4; case DXGI_FORMAT_R1_UNORM: diff --git a/Texassemble/texassemble.cpp b/Texassemble/texassemble.cpp index 49dc12a..08d824c 100644 --- a/Texassemble/texassemble.cpp +++ b/Texassemble/texassemble.cpp @@ -265,6 +265,9 @@ namespace // No support for legacy paletted video formats (AI44, IA44, P8, A8P8) DEFFMT(B4G4R4A4_UNORM), + // D3D11on12 format + { L"A4B4G4R4_UNORM", DXGI_FORMAT(191) }, + { nullptr, DXGI_FORMAT_UNKNOWN } }; diff --git a/Texconv/texconv.cpp b/Texconv/texconv.cpp index ec87fcb..6d89cdc 100644 --- a/Texconv/texconv.cpp +++ b/Texconv/texconv.cpp @@ -309,6 +309,9 @@ namespace // No support for legacy paletted video formats (AI44, IA44, P8, A8P8) DEFFMT(B4G4R4A4_UNORM), + // D3D11on12 format + { L"A4B4G4R4_UNORM", DXGI_FORMAT(191) }, + { nullptr, DXGI_FORMAT_UNKNOWN } }; diff --git a/Texdiag/texdiag.cpp b/Texdiag/texdiag.cpp index 5a4cc1b..ef7605b 100644 --- a/Texdiag/texdiag.cpp +++ b/Texdiag/texdiag.cpp @@ -218,6 +218,9 @@ const SValue g_pFormats[] = DEFFMT(Y216), DEFFMT(B4G4R4A4_UNORM), + // D3D11on12 format + { L"A4B4G4R4_UNORM", DXGI_FORMAT(191) }, + { nullptr, DXGI_FORMAT_UNKNOWN } };