From 3754a77d87b5e746042883049dc01afc9e1b16b7 Mon Sep 17 00:00:00 2001 From: Chuck Walbourn Date: Mon, 11 Sep 2023 23:13:35 -0700 Subject: [PATCH] DDS_FLAGS_PERMISSIVE flag to allow some file variants with header bugs (#394) --- DirectXTex/DirectXTex.h | 3 +++ DirectXTex/DirectXTexDDS.cpp | 31 +++++++++++++++++++++++++++---- Texconv/texconv.cpp | 4 ++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/DirectXTex/DirectXTex.h b/DirectXTex/DirectXTex.h index eae8e62..2bc5cc4 100644 --- a/DirectXTex/DirectXTex.h +++ b/DirectXTex/DirectXTex.h @@ -226,6 +226,9 @@ namespace DirectX DDS_FLAGS_BAD_DXTN_TAILS = 0x40, // Some older DXTn DDS files incorrectly handle mipchain tails for blocks smaller than 4x4 + DDS_FLAGS_PERMISSIVE = 0x80, + // Allow some file variants due to common bugs in the header written by various leagcy DDS writers + 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) diff --git a/DirectXTex/DirectXTexDDS.cpp b/DirectXTex/DirectXTexDDS.cpp index 162308d..32eef41 100644 --- a/DirectXTex/DirectXTexDDS.cpp +++ b/DirectXTex/DirectXTexDDS.cpp @@ -346,11 +346,18 @@ namespace return E_FAIL; } - if (pHeader->ddspf.size != 0 /* Known variant */ - && pHeader->ddspf.size != 24 /* Known variant */ - && pHeader->ddspf.size != sizeof(DDS_PIXELFORMAT)) + if (flags & DDS_FLAGS_PERMISSIVE) { - return E_FAIL; + if (pHeader->ddspf.size != 0 /* Known variant */ + && pHeader->ddspf.size != 24 /* Known variant */ + && pHeader->ddspf.size != sizeof(DDS_PIXELFORMAT)) + { + return HRESULT_E_NOT_SUPPORTED; + } + } + else if (pHeader->ddspf.size != sizeof(DDS_PIXELFORMAT)) + { + return HRESULT_E_NOT_SUPPORTED; } metadata.mipLevels = pHeader->mipMapCount; @@ -460,6 +467,14 @@ namespace metadata.height = pHeader->height; metadata.depth = pHeader->depth; metadata.dimension = TEX_DIMENSION_TEXTURE3D; + + if (flags & DDS_FLAGS_PERMISSIVE) + { + // Allow cases where mipCount was computed incorrectly + size_t maxMips = 0; + std::ignore = Internal::CalculateMipLevels3D(metadata.width, metadata.height, metadata.depth, maxMips); + metadata.mipLevels = std::min(metadata.mipLevels, maxMips); + } } else { @@ -479,6 +494,14 @@ namespace metadata.dimension = TEX_DIMENSION_TEXTURE2D; // Note there's no way for a legacy Direct3D 9 DDS to express a '1D' texture + + if (flags & DDS_FLAGS_PERMISSIVE) + { + // Allow cases where mipCount was computed incorrectly + size_t maxMips = 0; + std::ignore = Internal::CalculateMipLevels(metadata.width, metadata.height, maxMips); + metadata.mipLevels = std::min(metadata.mipLevels, maxMips); + } } metadata.format = GetDXGIFormat(*pHeader, pHeader->ddspf, flags, convFlags); diff --git a/Texconv/texconv.cpp b/Texconv/texconv.cpp index f7538b3..53ece5c 100644 --- a/Texconv/texconv.cpp +++ b/Texconv/texconv.cpp @@ -94,6 +94,7 @@ namespace OPT_VFLIP, OPT_DDS_DWORD_ALIGN, OPT_DDS_BAD_DXTN_TAILS, + OPT_DDS_PERMISSIVE, OPT_USE_DX10, OPT_USE_DX9, OPT_TGA20, @@ -190,6 +191,7 @@ namespace { L"vflip", OPT_VFLIP }, { L"dword", OPT_DDS_DWORD_ALIGN }, { L"badtails", OPT_DDS_BAD_DXTN_TAILS }, + { L"permissive", OPT_DDS_PERMISSIVE }, { L"dx10", OPT_USE_DX10 }, { L"dx9", OPT_USE_DX9 }, { L"tga20", OPT_TGA20 }, @@ -2104,6 +2106,8 @@ int __cdecl wmain(_In_ int argc, _In_z_count_(argc) wchar_t* argv[]) ddsFlags |= DDS_FLAGS_EXPAND_LUMINANCE; if (dwOptions & (uint64_t(1) << OPT_DDS_BAD_DXTN_TAILS)) ddsFlags |= DDS_FLAGS_BAD_DXTN_TAILS; + if (dwOptions & (uint64_t(1) << OPT_DDS_PERMISSIVE)) + ddsFlags |= DDS_FLAGS_PERMISSIVE; hr = LoadFromDDSFile(curpath.c_str(), ddsFlags, &info, *image); if (FAILED(hr))