From ace217008a332f1fe65db047e07507301ce22429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 20 Jul 2023 19:44:00 +0200 Subject: [PATCH] In D3D11, force block compressed textures to have dimensions divisible by 4 Fixes #17745 (crash when loading certain texture packs in D3D11) This is an old unfortunate limitation. Only applies to the top mip level, which makes it obvious that it's kinda unnecessary for the hardware and indeed, Vulkan and OpenGL don't have this limitation. --- GPU/Common/ReplacedTexture.cpp | 10 ++++++++++ GPU/Common/TextureReplacer.cpp | 3 +++ GPU/D3D11/TextureCacheD3D11.cpp | 8 ++++++++ assets/lang/en_US.ini | 1 + 4 files changed, 22 insertions(+) diff --git a/GPU/Common/ReplacedTexture.cpp b/GPU/Common/ReplacedTexture.cpp index 53668c89c189..d95ee297fbe4 100644 --- a/GPU/Common/ReplacedTexture.cpp +++ b/GPU/Common/ReplacedTexture.cpp @@ -513,6 +513,10 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference bool bc = Draw::DataFormatIsBlockCompressed(*pixelFormat, &blockSize); _dbg_assert_(bc || *pixelFormat == Draw::DataFormat::R8G8B8A8_UNORM); + if (bc && (level.w & 3) != 0 || (level.h & 3) != 0) { + WARN_LOG(G3D, "Block compressed replacement texture '%s' not divisible by 4x4 (%dx%d). In D3D11 (only!) we will have to expand (potentially causing glitches).", filename.c_str(), level.w, level.h); + } + data_.resize(numMips); basist::ktx2_transcoder_state transcodeState; // Each thread needs one of these. @@ -546,6 +550,7 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference } transcoder.clear(); vfs_->CloseFile(openFile); + return LoadLevelResult::DONE; // don't read more levels } else if (imageType == ReplacedImageType::DDS) { // TODO: Do better with alphaStatus, it's possible. @@ -562,6 +567,10 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference bool bc = Draw::DataFormatIsBlockCompressed(*pixelFormat, &blockSize); _dbg_assert_(bc); + if (bc && (level.w & 3) != 0 || (level.h & 3) != 0) { + WARN_LOG(G3D, "Block compressed replacement texture '%s' not divisible by 4x4 (%dx%d). In D3D11 (only!) we will have to expand (potentially causing glitches).", filename.c_str(), level.w, level.h); + } + data_.resize(numMips); // A DDS File can contain multiple mipmaps. @@ -583,6 +592,7 @@ ReplacedTexture::LoadLevelResult ReplacedTexture::LoadLevelData(VFSFileReference level.fileRef = nullptr; // We only provide a fileref on level 0 if we have mipmaps. } vfs_->CloseFile(openFile); + return LoadLevelResult::DONE; // don't read more levels } else if (imageType == ReplacedImageType::ZIM) { diff --git a/GPU/Common/TextureReplacer.cpp b/GPU/Common/TextureReplacer.cpp index da0f94401c17..5e7b471c62ff 100644 --- a/GPU/Common/TextureReplacer.cpp +++ b/GPU/Common/TextureReplacer.cpp @@ -337,6 +337,9 @@ bool TextureReplacer::LoadIniValues(IniFile &ini, VFSBackend *dir, bool isOverri } } + auto gr = GetI18NCategory(I18NCat::GRAPHICS); + + g_OSD.Show(OSDType::MESSAGE_SUCCESS, gr->T("Texture replacement pack activated")); return true; } diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index d658d19a0106..465981e67379 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -348,6 +348,14 @@ void TextureCacheD3D11::BuildTexture(TexCacheEntry *const entry) { if (th > 16384) th = 16384; + // NOTE: For block-compressed textures, we'll force the size up to the closest 4x4. This is due to an + // unfortunate restriction in D3D11 (and early D3D12). We'll warn about it in the log to give texture pack + // authors notice to fix it. + if (plan.doReplace && Draw::DataFormatIsBlockCompressed(plan.replaced->Format(), nullptr)) { + tw = (tw + 3) & ~3; + th = (th + 3) & ~3; + } + if (plan.depth == 1) { // We don't yet have mip generation, so clamp the number of levels to the ones we can load directly. levels = std::min(plan.levelsToCreate, plan.levelsToLoad); diff --git a/assets/lang/en_US.ini b/assets/lang/en_US.ini index 3462f24c2f0e..7c0999fe1dd3 100644 --- a/assets/lang/en_US.ini +++ b/assets/lang/en_US.ini @@ -630,6 +630,7 @@ Stereo rendering = Stereo rendering Stretch = Stretch Texture Filter = Texture filtering Texture Filtering = Texture filtering +Texture replacement pack activated = Texture replacement pack activated Texture Scaling = Texture scaling Texture Shader = Texture shader Turn off Hardware Tessellation - unsupported = Turn off "hardware tessellation": unsupported