1
0
mirror of https://github.com/microsoft/DirectXTex synced 2024-09-19 15:19:56 +00:00

Add support for new DXGI 16bpp format (#348)

This commit is contained in:
Chuck Walbourn 2023-05-11 09:58:28 -07:00 committed by GitHub
parent 37a3733912
commit e0a7be5a4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 212 additions and 72 deletions

View File

@ -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<size_t>(fmt) >= 1 && static_cast<size_t>(fmt) <= 190);
return (static_cast<size_t>(fmt) >= 1 && static_cast<size_t>(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

View File

@ -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<uint16_t*>(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<size_t>(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<uint16_t*>(pDestination);
for (size_t count = 0; count < (outSize - 1); count += 2)
{
*(dPtr++) |= 0xF000;
}
}
else
{
const uint16_t * __restrict sPtr = static_cast<const uint16_t*>(pSource);
uint16_t * __restrict dPtr = static_cast<uint16_t*>(pDestination);
const size_t size = std::min<size_t>(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<int>(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<const uint16_t*>(pSource);
uint32_t * __restrict dPtr = static_cast<uint32_t*>(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<const XMUNIBBLE4*>(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<XMUNIBBLE4*>(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<uintptr_t>(pSource) & 0xF) == 0);
switch (format)
switch (static_cast<int>(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<int>(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<XMUNIBBLE4*>(pDestination);
for (size_t i = 0; i < count; ++i)
{
auto index = static_cast<ptrdiff_t>((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<uint8_t>(tmp.x) & 0xF);
dPtr->y = uint8_t(static_cast<uint8_t>(tmp.y) & 0xF);
dPtr->z = uint8_t(static_cast<uint8_t>(tmp.z) & 0xF);
dPtr->w = uint8_t(static_cast<uint8_t>(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)

View File

@ -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<int>(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,

View File

@ -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<HRESULT>(0x8000000BL)
#endif

View File

@ -454,6 +454,30 @@ bool DirectX::IsDepthStencil(DXGI_FORMAT fmt) noexcept
}
//-------------------------------------------------------------------------------------
_Use_decl_annotations_
bool DirectX::IsBGR(DXGI_FORMAT fmt) noexcept
{
switch (static_cast<int>(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:

View File

@ -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 }
};

View File

@ -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 }
};

View File

@ -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 }
};