mirror of
https://github.com/microsoft/DirectXTex.git
synced 2025-07-09 19:50:13 +02:00
badtails flag to enable loading of legacy DXTn DDS files with incomplete mipchain tails
This commit is contained in:
parent
04143d621c
commit
7275893dbe
@ -70,6 +70,7 @@ namespace DirectX
|
|||||||
CP_FLAGS_YMM = 0x4, // Assume pitch is 32-byte aligned instead of BYTE aligned
|
CP_FLAGS_YMM = 0x4, // Assume pitch is 32-byte aligned instead of BYTE aligned
|
||||||
CP_FLAGS_ZMM = 0x8, // Assume pitch is 64-byte aligned instead of BYTE aligned
|
CP_FLAGS_ZMM = 0x8, // Assume pitch is 64-byte aligned instead of BYTE aligned
|
||||||
CP_FLAGS_PAGE4K = 0x200, // Assume pitch is 4096-byte aligned instead of BYTE aligned
|
CP_FLAGS_PAGE4K = 0x200, // Assume pitch is 4096-byte aligned instead of BYTE aligned
|
||||||
|
CP_FLAGS_BAD_DXTN_TAILS = 0x1000, // BC formats with malformed mipchain blocks smaller than 4x4
|
||||||
CP_FLAGS_24BPP = 0x10000, // Override with a legacy 24 bits-per-pixel format size
|
CP_FLAGS_24BPP = 0x10000, // Override with a legacy 24 bits-per-pixel format size
|
||||||
CP_FLAGS_16BPP = 0x20000, // Override with a legacy 16 bits-per-pixel format size
|
CP_FLAGS_16BPP = 0x20000, // Override with a legacy 16 bits-per-pixel format size
|
||||||
CP_FLAGS_8BPP = 0x40000, // Override with a legacy 8 bits-per-pixel format size
|
CP_FLAGS_8BPP = 0x40000, // Override with a legacy 8 bits-per-pixel format size
|
||||||
@ -164,6 +165,9 @@ namespace DirectX
|
|||||||
DDS_FLAGS_EXPAND_LUMINANCE = 0x20,
|
DDS_FLAGS_EXPAND_LUMINANCE = 0x20,
|
||||||
// When loading legacy luminance formats expand replicating the color channels rather than leaving them packed (L8, L16, A8L8)
|
// When loading legacy luminance formats expand replicating the color channels rather than leaving them packed (L8, L16, A8L8)
|
||||||
|
|
||||||
|
DDS_FLAGS_BAD_DXTN_TAILS = 0x40,
|
||||||
|
// Some older DXTn DDS files incorrectly handle mipchain tails for blocks smaller than 4x4
|
||||||
|
|
||||||
DDS_FLAGS_FORCE_DX10_EXT = 0x10000,
|
DDS_FLAGS_FORCE_DX10_EXT = 0x10000,
|
||||||
// Always use the 'DX10' header extension for DDS writer (i.e. don't try to write DX9 compatible DDS files)
|
// Always use the 'DX10' header extension for DDS writer (i.e. don't try to write DX9 compatible DDS files)
|
||||||
|
|
||||||
|
@ -1068,7 +1068,7 @@ namespace
|
|||||||
|
|
||||||
if (pixelSize > size)
|
if (pixelSize > size)
|
||||||
{
|
{
|
||||||
return E_FAIL;
|
return HRESULT_FROM_WIN32( ERROR_HANDLE_EOF );
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Image[]> timages(new (std::nothrow) Image[nimages]);
|
std::unique_ptr<Image[]> timages(new (std::nothrow) Image[nimages]);
|
||||||
@ -1077,7 +1077,7 @@ namespace
|
|||||||
return E_OUTOFMEMORY;
|
return E_OUTOFMEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_SetupImageArray((uint8_t*)pPixels, size, metadata, cpFlags, timages.get(), nimages))
|
if (!_SetupImageArray((uint8_t*)pPixels, pixelSize, metadata, cpFlags, timages.get(), nimages))
|
||||||
{
|
{
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
}
|
}
|
||||||
@ -1105,6 +1105,7 @@ namespace
|
|||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
for (size_t item = 0; item < metadata.arraySize; ++item)
|
for (size_t item = 0; item < metadata.arraySize; ++item)
|
||||||
{
|
{
|
||||||
|
size_t lastgood = 0;
|
||||||
for (size_t level = 0; level < metadata.mipLevels; ++level, ++index)
|
for (size_t level = 0; level < metadata.mipLevels; ++level, ++index)
|
||||||
{
|
{
|
||||||
if (index >= nimages)
|
if (index >= nimages)
|
||||||
@ -1128,6 +1129,19 @@ namespace
|
|||||||
{
|
{
|
||||||
size_t csize = std::min<size_t>(images[index].slicePitch, timages[index].slicePitch);
|
size_t csize = std::min<size_t>(images[index].slicePitch, timages[index].slicePitch);
|
||||||
memcpy_s(pDest, images[index].slicePitch, pSrc, csize);
|
memcpy_s(pDest, images[index].slicePitch, pSrc, csize);
|
||||||
|
|
||||||
|
if (cpFlags & CP_FLAGS_BAD_DXTN_TAILS)
|
||||||
|
{
|
||||||
|
if (images[index].width < 4 || images[index].height < 4)
|
||||||
|
{
|
||||||
|
csize = std::min<size_t>(images[index].slicePitch, timages[lastgood].slicePitch);
|
||||||
|
memcpy_s(pDest, images[index].slicePitch, timages[lastgood].pixels, csize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lastgood = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (IsPlanar(metadata.format))
|
else if (IsPlanar(metadata.format))
|
||||||
{
|
{
|
||||||
@ -1191,6 +1205,7 @@ namespace
|
|||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
size_t d = metadata.depth;
|
size_t d = metadata.depth;
|
||||||
|
|
||||||
|
size_t lastgood = 0;
|
||||||
for (size_t level = 0; level < metadata.mipLevels; ++level)
|
for (size_t level = 0; level < metadata.mipLevels; ++level)
|
||||||
{
|
{
|
||||||
for (size_t slice = 0; slice < d; ++slice, ++index)
|
for (size_t slice = 0; slice < d; ++slice, ++index)
|
||||||
@ -1216,6 +1231,19 @@ namespace
|
|||||||
{
|
{
|
||||||
size_t csize = std::min<size_t>(images[index].slicePitch, timages[index].slicePitch);
|
size_t csize = std::min<size_t>(images[index].slicePitch, timages[index].slicePitch);
|
||||||
memcpy_s(pDest, images[index].slicePitch, pSrc, csize);
|
memcpy_s(pDest, images[index].slicePitch, pSrc, csize);
|
||||||
|
|
||||||
|
if (cpFlags & CP_FLAGS_BAD_DXTN_TAILS)
|
||||||
|
{
|
||||||
|
if (images[index].width < 4 || images[index].height < 4)
|
||||||
|
{
|
||||||
|
csize = std::min<size_t>(images[index].slicePitch, timages[lastgood + slice].slicePitch);
|
||||||
|
memcpy_s(pDest, images[index].slicePitch, timages[lastgood + slice].pixels, csize);
|
||||||
|
}
|
||||||
|
else if (!slice)
|
||||||
|
{
|
||||||
|
lastgood = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (IsPlanar(metadata.format))
|
else if (IsPlanar(metadata.format))
|
||||||
{
|
{
|
||||||
@ -1438,10 +1466,25 @@ HRESULT DirectX::LoadFromDDSMemory(
|
|||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
return hr;
|
return hr;
|
||||||
|
|
||||||
|
DWORD cflags = CP_FLAGS_NONE;
|
||||||
|
if (flags & DDS_FLAGS_LEGACY_DWORD)
|
||||||
|
{
|
||||||
|
cflags |= CP_FLAGS_LEGACY_DWORD;
|
||||||
|
}
|
||||||
|
if (flags & DDS_FLAGS_BAD_DXTN_TAILS)
|
||||||
|
{
|
||||||
|
cflags |= CP_FLAGS_BAD_DXTN_TAILS;
|
||||||
|
}
|
||||||
|
|
||||||
auto pPixels = reinterpret_cast<const void*>(reinterpret_cast<const uint8_t*>(pSource) + offset);
|
auto pPixels = reinterpret_cast<const void*>(reinterpret_cast<const uint8_t*>(pSource) + offset);
|
||||||
assert(pPixels);
|
assert(pPixels);
|
||||||
hr = CopyImage(pPixels, size - offset, mdata,
|
hr = CopyImage(pPixels,
|
||||||
(flags & DDS_FLAGS_LEGACY_DWORD) ? CP_FLAGS_LEGACY_DWORD : CP_FLAGS_NONE, convFlags, pal8, image);
|
size - offset,
|
||||||
|
mdata,
|
||||||
|
cflags,
|
||||||
|
convFlags,
|
||||||
|
pal8,
|
||||||
|
image);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
image.Release();
|
image.Release();
|
||||||
@ -1560,7 +1603,7 @@ HRESULT DirectX::LoadFromDDSFile(
|
|||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
return hr;
|
return hr;
|
||||||
|
|
||||||
if ((convFlags & CONV_FLAGS_EXPAND) || (flags & DDS_FLAGS_LEGACY_DWORD))
|
if ((convFlags & CONV_FLAGS_EXPAND) || (flags & (DDS_FLAGS_LEGACY_DWORD | DDS_FLAGS_BAD_DXTN_TAILS)))
|
||||||
{
|
{
|
||||||
std::unique_ptr<uint8_t[]> temp(new (std::nothrow) uint8_t[remaining]);
|
std::unique_ptr<uint8_t[]> temp(new (std::nothrow) uint8_t[remaining]);
|
||||||
if (!temp)
|
if (!temp)
|
||||||
@ -1581,9 +1624,23 @@ HRESULT DirectX::LoadFromDDSFile(
|
|||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = CopyImage(temp.get(), remaining, mdata,
|
DWORD cflags = CP_FLAGS_NONE;
|
||||||
(flags & DDS_FLAGS_LEGACY_DWORD) ? CP_FLAGS_LEGACY_DWORD : CP_FLAGS_NONE,
|
if (flags & DDS_FLAGS_LEGACY_DWORD)
|
||||||
convFlags, pal8.get(), image);
|
{
|
||||||
|
cflags |= CP_FLAGS_LEGACY_DWORD;
|
||||||
|
}
|
||||||
|
if (flags & DDS_FLAGS_BAD_DXTN_TAILS)
|
||||||
|
{
|
||||||
|
cflags |= CP_FLAGS_BAD_DXTN_TAILS;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = CopyImage(temp.get(),
|
||||||
|
remaining,
|
||||||
|
mdata,
|
||||||
|
cflags,
|
||||||
|
convFlags,
|
||||||
|
pal8.get(),
|
||||||
|
image);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
{
|
{
|
||||||
image.Release();
|
image.Release();
|
||||||
@ -1595,7 +1652,7 @@ HRESULT DirectX::LoadFromDDSFile(
|
|||||||
if (remaining < image.GetPixelsSize())
|
if (remaining < image.GetPixelsSize())
|
||||||
{
|
{
|
||||||
image.Release();
|
image.Release();
|
||||||
return E_FAIL;
|
return HRESULT_FROM_WIN32( ERROR_HANDLE_EOF );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ReadFile(hFile.get(), image.GetPixels(), static_cast<DWORD>(image.GetPixelsSize()), &bytesRead, nullptr))
|
if (!ReadFile(hFile.get(), image.GetPixels(), static_cast<DWORD>(image.GetPixelsSize()), &bytesRead, nullptr))
|
||||||
|
@ -881,11 +881,20 @@ void DirectX::ComputePitch(DXGI_FORMAT fmt, size_t width, size_t height,
|
|||||||
case DXGI_FORMAT_BC4_SNORM:
|
case DXGI_FORMAT_BC4_SNORM:
|
||||||
assert(IsCompressed(fmt));
|
assert(IsCompressed(fmt));
|
||||||
{
|
{
|
||||||
size_t nbw = std::max<size_t>(1, (width + 3) / 4);
|
if (flags & CP_FLAGS_BAD_DXTN_TAILS)
|
||||||
size_t nbh = std::max<size_t>(1, (height + 3) / 4);
|
{
|
||||||
rowPitch = nbw * 8;
|
size_t nbw = width >> 2;
|
||||||
|
size_t nbh = height >> 2;
|
||||||
slicePitch = rowPitch * nbh;
|
rowPitch = std::max<size_t>(1, nbw * 8);
|
||||||
|
slicePitch = std::max<size_t>(1, rowPitch * nbh);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t nbw = std::max<size_t>(1, (width + 3) / 4);
|
||||||
|
size_t nbh = std::max<size_t>(1, (height + 3) / 4);
|
||||||
|
rowPitch = nbw * 8;
|
||||||
|
slicePitch = rowPitch * nbh;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -906,11 +915,20 @@ void DirectX::ComputePitch(DXGI_FORMAT fmt, size_t width, size_t height,
|
|||||||
case DXGI_FORMAT_BC7_UNORM_SRGB:
|
case DXGI_FORMAT_BC7_UNORM_SRGB:
|
||||||
assert(IsCompressed(fmt));
|
assert(IsCompressed(fmt));
|
||||||
{
|
{
|
||||||
size_t nbw = std::max<size_t>(1, (width + 3) / 4);
|
if (flags & CP_FLAGS_BAD_DXTN_TAILS)
|
||||||
size_t nbh = std::max<size_t>(1, (height + 3) / 4);
|
{
|
||||||
rowPitch = nbw * 16;
|
size_t nbw = width >> 2;
|
||||||
|
size_t nbh = height >> 2;
|
||||||
slicePitch = rowPitch * nbh;
|
rowPitch = std::max<size_t>(1, nbw * 16);
|
||||||
|
slicePitch = std::max<size_t>(1, rowPitch * nbh);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t nbw = std::max<size_t>(1, (width + 3) / 4);
|
||||||
|
size_t nbh = std::max<size_t>(1, (height + 3) / 4);
|
||||||
|
rowPitch = nbw * 16;
|
||||||
|
slicePitch = rowPitch * nbh;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -55,6 +55,7 @@ enum OPTIONS // Note: dwOptions below assumes 64 or less options.
|
|||||||
OPT_HFLIP,
|
OPT_HFLIP,
|
||||||
OPT_VFLIP,
|
OPT_VFLIP,
|
||||||
OPT_DDS_DWORD_ALIGN,
|
OPT_DDS_DWORD_ALIGN,
|
||||||
|
OPT_DDS_BAD_DXTN_TAILS,
|
||||||
OPT_USE_DX10,
|
OPT_USE_DX10,
|
||||||
OPT_NOLOGO,
|
OPT_NOLOGO,
|
||||||
OPT_TIMING,
|
OPT_TIMING,
|
||||||
@ -116,6 +117,7 @@ SValue g_pOptions[] =
|
|||||||
{ L"hflip", OPT_HFLIP },
|
{ L"hflip", OPT_HFLIP },
|
||||||
{ L"vflip", OPT_VFLIP },
|
{ L"vflip", OPT_VFLIP },
|
||||||
{ L"dword", OPT_DDS_DWORD_ALIGN },
|
{ L"dword", OPT_DDS_DWORD_ALIGN },
|
||||||
|
{ L"badtails", OPT_DDS_BAD_DXTN_TAILS },
|
||||||
{ L"dx10", OPT_USE_DX10 },
|
{ L"dx10", OPT_USE_DX10 },
|
||||||
{ L"nologo", OPT_NOLOGO },
|
{ L"nologo", OPT_NOLOGO },
|
||||||
{ L"timing", OPT_TIMING },
|
{ L"timing", OPT_TIMING },
|
||||||
@ -529,6 +531,7 @@ void PrintUsage()
|
|||||||
wprintf( L"\n (DDS input only)\n");
|
wprintf( L"\n (DDS input only)\n");
|
||||||
wprintf( L" -t{u|f} TYPELESS format is treated as UNORM or FLOAT\n");
|
wprintf( L" -t{u|f} TYPELESS format is treated as UNORM or FLOAT\n");
|
||||||
wprintf( L" -dword Use DWORD instead of BYTE alignment\n");
|
wprintf( L" -dword Use DWORD instead of BYTE alignment\n");
|
||||||
|
wprintf( L" -badtails Fix for older DXTn with bad mipchain tails\n");
|
||||||
wprintf( L" -xlum expand legacy L8, L16, and A8P8 formats\n");
|
wprintf( L" -xlum expand legacy L8, L16, and A8P8 formats\n");
|
||||||
wprintf( L"\n (DDS output only)\n");
|
wprintf( L"\n (DDS output only)\n");
|
||||||
wprintf( L" -dx10 Force use of 'DX10' extended header\n");
|
wprintf( L" -dx10 Force use of 'DX10' extended header\n");
|
||||||
@ -1178,6 +1181,8 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[])
|
|||||||
ddsFlags |= DDS_FLAGS_LEGACY_DWORD;
|
ddsFlags |= DDS_FLAGS_LEGACY_DWORD;
|
||||||
if ( dwOptions & (DWORD64(1) << OPT_EXPAND_LUMINANCE) )
|
if ( dwOptions & (DWORD64(1) << OPT_EXPAND_LUMINANCE) )
|
||||||
ddsFlags |= DDS_FLAGS_EXPAND_LUMINANCE;
|
ddsFlags |= DDS_FLAGS_EXPAND_LUMINANCE;
|
||||||
|
if ( dwOptions & (DWORD64(1) << OPT_DDS_BAD_DXTN_TAILS) )
|
||||||
|
ddsFlags |= DDS_FLAGS_BAD_DXTN_TAILS;
|
||||||
|
|
||||||
hr = LoadFromDDSFile( pConv->szSrc, ddsFlags, &info, *image );
|
hr = LoadFromDDSFile( pConv->szSrc, ddsFlags, &info, *image );
|
||||||
if ( FAILED(hr) )
|
if ( FAILED(hr) )
|
||||||
|
Loading…
x
Reference in New Issue
Block a user