summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon
diff options
context:
space:
mode:
authorMarkus Wick <degasus@users.noreply.github.com>2018-05-22 09:57:26 +0200
committerGitHub <noreply@github.com>2018-05-22 09:57:26 +0200
commit0979febe7805fe2d4e6669ea233bf6af9fc9680d (patch)
tree0ca3e1ddf25754e906ba0a4b39ac3f95a29577c2 /Source/Core/VideoCommon
parent7eaba154a41c72826d4c660753386421f21336d7 (diff)
parentf7a0cae7f47c6fb9a80bf22ffd55281331c3aaef (diff)
Merge pull request #6941 from stenzek/unaligned-texture-load
HiresTextures: Do not load compressed textures with unaligned dimensions
Diffstat (limited to 'Source/Core/VideoCommon')
-rw-r--r--Source/Core/VideoCommon/HiresTextures.cpp2
-rw-r--r--Source/Core/VideoCommon/HiresTextures.h2
-rw-r--r--Source/Core/VideoCommon/HiresTextures_DDSLoader.cpp31
3 files changed, 25 insertions, 10 deletions
diff --git a/Source/Core/VideoCommon/HiresTextures.cpp b/Source/Core/VideoCommon/HiresTextures.cpp
index adca2551db..79e71fa32b 100644
--- a/Source/Core/VideoCommon/HiresTextures.cpp
+++ b/Source/Core/VideoCommon/HiresTextures.cpp
@@ -335,7 +335,7 @@ std::unique_ptr<HiresTexture> HiresTexture::Load(const std::string& base_filenam
// Try loading DDS textures first, that way we maintain compression of DXT formats.
// TODO: Reduce the number of open() calls here. We could use one fd.
Level level;
- if (!LoadDDSTexture(level, filename_iter->second.path))
+ if (!LoadDDSTexture(level, filename_iter->second.path, mip_level))
{
File::IOFile file;
file.Open(filename_iter->second.path, "rb");
diff --git a/Source/Core/VideoCommon/HiresTextures.h b/Source/Core/VideoCommon/HiresTextures.h
index af79a02d53..6d814b42a9 100644
--- a/Source/Core/VideoCommon/HiresTextures.h
+++ b/Source/Core/VideoCommon/HiresTextures.h
@@ -49,7 +49,7 @@ private:
static std::unique_ptr<HiresTexture> Load(const std::string& base_filename, u32 width,
u32 height);
static bool LoadDDSTexture(HiresTexture* tex, const std::string& filename);
- static bool LoadDDSTexture(Level& level, const std::string& filename);
+ static bool LoadDDSTexture(Level& level, const std::string& filename, u32 mip_level);
static bool LoadTexture(Level& level, const std::vector<u8>& buffer);
static void Prefetch();
diff --git a/Source/Core/VideoCommon/HiresTextures_DDSLoader.cpp b/Source/Core/VideoCommon/HiresTextures_DDSLoader.cpp
index 5a3d7788ca..182f6fcbd5 100644
--- a/Source/Core/VideoCommon/HiresTextures_DDSLoader.cpp
+++ b/Source/Core/VideoCommon/HiresTextures_DDSLoader.cpp
@@ -12,6 +12,7 @@
#include "Common/Align.h"
#include "Common/File.h"
+#include "Common/Logging/Log.h"
#include "Common/Swap.h"
#include "VideoCommon/VideoConfig.h"
@@ -400,9 +401,22 @@ bool ParseDDSHeader(File::IOFile& file, DDSLoadInfo* info)
return true;
}
-bool ReadMipLevel(HiresTexture::Level* level, File::IOFile& file, const DDSLoadInfo& info,
- u32 width, u32 height, u32 row_length, size_t size)
+bool ReadMipLevel(HiresTexture::Level* level, File::IOFile& file, const std::string& filename,
+ u32 mip_level, const DDSLoadInfo& info, u32 width, u32 height, u32 row_length,
+ size_t size)
{
+ // D3D11 cannot handle block compressed textures where the first mip level is
+ // not a multiple of the block size.
+ if (mip_level == 0 && info.block_size > 1 &&
+ ((width % info.block_size) != 0 || (height % info.block_size) != 0))
+ {
+ ERROR_LOG(VIDEO,
+ "Invalid dimensions for DDS texture %s. For compressed textures of this format, "
+ "the width/height of the first mip level must be a multiple of %u.",
+ filename.c_str(), info.block_size);
+ return false;
+ }
+
// Copy to the final storage location.
level->width = width;
level->height = height;
@@ -435,8 +449,8 @@ bool HiresTexture::LoadDDSTexture(HiresTexture* tex, const std::string& filename
// Read first mip level, as it may have a custom pitch.
Level first_level;
if (!file.Seek(info.first_mip_offset, SEEK_SET) ||
- !ReadMipLevel(&first_level, file, info, info.width, info.height, info.first_mip_row_length,
- info.first_mip_size))
+ !ReadMipLevel(&first_level, file, filename, 0, info, info.width, info.height,
+ info.first_mip_row_length, info.first_mip_size))
{
return false;
}
@@ -458,7 +472,8 @@ bool HiresTexture::LoadDDSTexture(HiresTexture* tex, const std::string& filename
u32 mip_row_length = blocks_wide * info.block_size;
size_t mip_size = blocks_wide * static_cast<size_t>(info.bytes_per_block) * blocks_high;
Level level;
- if (!ReadMipLevel(&level, file, info, mip_width, mip_height, mip_row_length, mip_size))
+ if (!ReadMipLevel(&level, file, filename, i, info, mip_width, mip_height, mip_row_length,
+ mip_size))
break;
tex->m_levels.push_back(std::move(level));
@@ -467,7 +482,7 @@ bool HiresTexture::LoadDDSTexture(HiresTexture* tex, const std::string& filename
return true;
}
-bool HiresTexture::LoadDDSTexture(Level& level, const std::string& filename)
+bool HiresTexture::LoadDDSTexture(Level& level, const std::string& filename, u32 mip_level)
{
// Only loading a single mip level.
File::IOFile file;
@@ -479,6 +494,6 @@ bool HiresTexture::LoadDDSTexture(Level& level, const std::string& filename)
if (!ParseDDSHeader(file, &info))
return false;
- return ReadMipLevel(&level, file, info, info.width, info.height, info.first_mip_row_length,
- info.first_mip_size);
+ return ReadMipLevel(&level, file, filename, mip_level, info, info.width, info.height,
+ info.first_mip_row_length, info.first_mip_size);
}