From 20cbef8e9f111769ab2bc5f3ea33ec6676564d06 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Fri, 21 Apr 2017 19:53:03 +1000 Subject: [PATCH] HiresTextures: Move the maximum mip level check from DDS to main loader This way that the mip count check occurs on .png and uncombined DDS textures as well. --- Source/Core/VideoCommon/HiresTextures.cpp | 55 +++++++++++++------ Source/Core/VideoCommon/HiresTextures.h | 2 + .../VideoCommon/HiresTextures_DDSLoader.cpp | 32 +++-------- 3 files changed, 48 insertions(+), 41 deletions(-) diff --git a/Source/Core/VideoCommon/HiresTextures.cpp b/Source/Core/VideoCommon/HiresTextures.cpp index 02c328c922..d601370fb5 100644 --- a/Source/Core/VideoCommon/HiresTextures.cpp +++ b/Source/Core/VideoCommon/HiresTextures.cpp @@ -366,6 +366,21 @@ std::string HiresTexture::GenBaseName(const u8* texture, size_t texture_size, co return name; } +u32 HiresTexture::CalculateMipCount(u32 width, u32 height) +{ + u32 mip_width = width; + u32 mip_height = height; + u32 mip_count = 1; + while (mip_width > 1 || mip_height > 1) + { + mip_width = std::max(mip_width / 2, 1u); + mip_height = std::max(mip_height / 2, 1u); + mip_count++; + } + + return mip_count; +} + std::shared_ptr HiresTexture::Search(const u8* texture, size_t texture_size, const u8* tlut, size_t tlut_size, u32 width, u32 height, int format, bool has_mipmaps) @@ -453,39 +468,45 @@ std::unique_ptr HiresTexture::Load(const std::string& base_filenam // Same deal if the custom texture isn't a multiple of the native size. if (width != 0 && height != 0 && (first_mip.width % width || first_mip.height % height)) { - WARN_LOG(VIDEO, "Invalid custom texture size %ux%u for texture %s. Please use an integer " - "upscaling factor based on the native size %ux%u.", - first_mip.width, first_mip.height, first_mip_filename.c_str(), width, height); + ERROR_LOG(VIDEO, "Invalid custom texture size %ux%u for texture %s. Please use an integer " + "upscaling factor based on the native size %ux%u.", + first_mip.width, first_mip.height, first_mip_filename.c_str(), width, height); } // Verify that each mip level is the correct size (divide by 2 each time). - u32 current_mip_width = std::max(first_mip.width / 2, 1u); - u32 current_mip_height = std::max(first_mip.height / 2, 1u); + u32 current_mip_width = first_mip.width; + u32 current_mip_height = first_mip.height; for (u32 mip_level = 1; mip_level < static_cast(ret->m_levels.size()); mip_level++) { - const Level& level = ret->m_levels[mip_level]; - if (current_mip_width == level.width && current_mip_height == level.height) + if (current_mip_width != 1 || current_mip_height != 1) { current_mip_width = std::max(current_mip_width / 2, 1u); current_mip_height = std::max(current_mip_height / 2, 1u); - continue; - } - ERROR_LOG(VIDEO, - "Invalid custom texture size %dx%d for texture %s. Mipmap level %u _must_ be %dx%d.", - level.width, level.height, first_mip_filename.c_str(), mip_level, current_mip_width, - current_mip_height); + const Level& level = ret->m_levels[mip_level]; + if (current_mip_width == level.width && current_mip_height == level.height) + continue; + + ERROR_LOG(VIDEO, + "Invalid custom texture size %dx%d for texture %s. Mipmap level %u must be %dx%d.", + level.width, level.height, first_mip_filename.c_str(), mip_level, current_mip_width, + current_mip_height); + } + else + { + // It is invalid to have more than a single 1x1 mipmap. + ERROR_LOG(VIDEO, "Custom texture %s has too many 1x1 mipmaps. Skipping extra levels.", + first_mip_filename.c_str()); + } // Drop this mip level and any others after it. while (ret->m_levels.size() > mip_level) ret->m_levels.pop_back(); - - break; } // All levels have to have the same format. - if (ret && std::any_of(ret->m_levels.begin(), ret->m_levels.end(), - [&ret](const Level& l) { return l.format != ret->m_levels[0].format; })) + if (std::any_of(ret->m_levels.begin(), ret->m_levels.end(), + [&ret](const Level& l) { return l.format != ret->m_levels[0].format; })) { ERROR_LOG(VIDEO, "Custom texture %s has inconsistent formats across mip levels.", first_mip_filename.c_str()); diff --git a/Source/Core/VideoCommon/HiresTextures.h b/Source/Core/VideoCommon/HiresTextures.h index 95ad65ce7f..30bb96d40c 100644 --- a/Source/Core/VideoCommon/HiresTextures.h +++ b/Source/Core/VideoCommon/HiresTextures.h @@ -28,6 +28,8 @@ public: size_t tlut_size, u32 width, u32 height, int format, bool has_mipmaps, bool dump = false); + static u32 CalculateMipCount(u32 width, u32 height); + ~HiresTexture(); HostTextureFormat GetFormat() const; diff --git a/Source/Core/VideoCommon/HiresTextures_DDSLoader.cpp b/Source/Core/VideoCommon/HiresTextures_DDSLoader.cpp index f1b978051a..ca0429c2a3 100644 --- a/Source/Core/VideoCommon/HiresTextures_DDSLoader.cpp +++ b/Source/Core/VideoCommon/HiresTextures_DDSLoader.cpp @@ -172,21 +172,6 @@ static u32 GetBlockCount(u32 extent, u32 block_size) return std::max(Common::AlignUp(extent, block_size) / block_size, 1u); } -static u32 CalculateMipCount(u32 width, u32 height) -{ - u32 mip_width = std::max(width / 2, 1u); - u32 mip_height = std::max(height / 2, 1u); - u32 mip_count = 1; - while (mip_width > 1 || mip_height > 1) - { - mip_width = std::max(mip_width / 2, 1u); - mip_height = std::max(mip_height / 2, 1u); - mip_count++; - } - - return mip_count; -} - static bool ParseDDSHeader(File::IOFile& file, DDSLoadInfo* info) { // Exit as early as possible for non-DDS textures, since all extensions are currently @@ -217,13 +202,11 @@ static bool ParseDDSHeader(File::IOFile& file, DDSLoadInfo* info) // Check for mip levels. if (header.dwFlags & DDS_HEADER_FLAGS_MIPMAP) { - // Miplevels = 0 means full mip chain? - // Some files may specify a number too large here, which doesn't play well with the backends. info->mip_count = header.dwMipMapCount; - if (info->mip_count != 0) - info->mip_count = std::min(info->mip_count, CalculateMipCount(info->width, info->height)); + if (header.dwMipMapCount != 0) + info->mip_count = header.dwMipMapCount; else - info->mip_count = CalculateMipCount(info->width, info->height); + info->mip_count = HiresTexture::CalculateMipCount(info->width, info->height); } else { @@ -372,10 +355,13 @@ bool HiresTexture::LoadDDSTexture(HiresTexture* tex, const std::string& filename // Read in any remaining mip levels in the file. // If the .dds file does not contain a full mip chain, we'll fall back to the old path. - u32 mip_width = std::max(info.width / 2, 1u); - u32 mip_height = std::max(info.height / 2, 1u); + u32 mip_width = info.width; + u32 mip_height = info.height; for (u32 i = 1; i < info.mip_count; i++) { + mip_width = std::max(mip_width / 2, 1u); + mip_height = std::max(mip_height / 2, 1u); + // Pitch can't be specified with each mip level, so we have to calculate it ourselves. u32 blocks_wide = GetBlockCount(mip_width, info.block_size); u32 blocks_high = GetBlockCount(mip_height, info.block_size); @@ -386,8 +372,6 @@ bool HiresTexture::LoadDDSTexture(HiresTexture* tex, const std::string& filename break; tex->m_levels.push_back(std::move(level)); - mip_width = std::max(mip_width / 2, 1u); - mip_height = std::max(mip_height / 2, 1u); } return true;