summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDr. Chat <arkolbed@gmail.com>2018-05-03 17:54:09 -0500
committerDr. Chat <arkolbed@gmail.com>2018-05-03 17:54:09 -0500
commitf45cd398efffc166f9d00fd9e260104c38ee69fb (patch)
treebd3b25f9ae1cf6ffc0a661d71e272087715a3a81
parent04748b4a0da431613823157e112017a5bdcd4c8e (diff)
[Vulkan] Handle MIPs with non-power-of-two dimensions
-rw-r--r--src/xenia/gpu/texture_info.cc34
-rw-r--r--src/xenia/gpu/texture_info.h2
-rw-r--r--src/xenia/gpu/vulkan/texture_cache.cc7
3 files changed, 29 insertions, 14 deletions
diff --git a/src/xenia/gpu/texture_info.cc b/src/xenia/gpu/texture_info.cc
index 9c93a7872..abcdc8163 100644
--- a/src/xenia/gpu/texture_info.cc
+++ b/src/xenia/gpu/texture_info.cc
@@ -337,12 +337,6 @@ uint32_t TextureInfo::GetMipLocation(const TextureInfo& src, uint32_t mip,
return src.guest_address;
}
- // One tile is 32x32 blocks
- const uint32_t tile_size = src.format_info()->block_width *
- src.format_info()->block_height * 32 * 32 *
- src.format_info()->bits_per_pixel / 8;
-
- // Walk forward to find the address of the mip
// If the texture is <= 16 pixels w/h, the mips are packed with the base
// texture. Otherwise, they're stored beginning from mip_address.
uint32_t address_base = std::min(src.width, src.height) < 16
@@ -350,17 +344,22 @@ uint32_t TextureInfo::GetMipLocation(const TextureInfo& src, uint32_t mip,
: src.mip_address;
uint32_t address_offset = 0;
- uint32_t logical_width = std::max((src.width + 1) >> mip, 1u);
- uint32_t logical_height = std::max((src.height + 1) >> mip, 1u);
+ // Walk forward to find the address of the mip.
for (uint32_t i = 1; i < mip; i++) {
- if (std::min(logical_width, logical_height) < 16) {
+ uint32_t logical_width = std::max(xe::next_pow2(src.width + 1) >> i, 1u);
+ uint32_t logical_height = std::max(xe::next_pow2(src.height + 1) >> i, 1u);
+ if (std::min(logical_width, logical_height) <= 16) {
// We've reached the point where the mips are packed into a single tile.
break;
}
- address_offset += std::max(src.input_length >> (i * 2), tile_size);
+ address_offset += GetMipSize(src, i);
}
+ // Now, check if the mip is packed at an offset.
+ uint32_t logical_width = std::max(xe::next_pow2(src.width + 1) >> mip, 1u);
+ uint32_t logical_height = std::max(xe::next_pow2(src.height + 1) >> mip, 1u);
+
*offset_x = 0;
*offset_y = 0;
if (std::min(logical_width, logical_height) <= 16) {
@@ -381,6 +380,21 @@ uint32_t TextureInfo::GetMipLocation(const TextureInfo& src, uint32_t mip,
return address_base + address_offset;
}
+uint32_t TextureInfo::GetMipSize(const TextureInfo& src, uint32_t mip) {
+ uint32_t size = src.format_info()->block_width *
+ src.format_info()->block_height *
+ (xe::next_pow2(src.width + 1) >> mip) *
+ (xe::next_pow2(src.height + 1) >> mip) *
+ src.format_info()->bits_per_pixel / 8;
+
+ // One tile is 32x32 blocks
+ uint32_t tile_size = src.format_info()->block_width *
+ src.format_info()->block_height * 32 * 32 *
+ src.format_info()->bits_per_pixel / 8;
+
+ return std::max(size, tile_size);
+}
+
uint32_t TextureInfo::GetMipLinearSize(const TextureInfo& src, uint32_t mip) {
uint32_t bytes_per_block = src.format_info()->block_width *
src.format_info()->block_height *
diff --git a/src/xenia/gpu/texture_info.h b/src/xenia/gpu/texture_info.h
index 930eff292..6b7bbfecb 100644
--- a/src/xenia/gpu/texture_info.h
+++ b/src/xenia/gpu/texture_info.h
@@ -318,6 +318,8 @@ struct TextureInfo {
// Get the memory location of a mip. offset_x and offset_y are in blocks.
static uint32_t GetMipLocation(const TextureInfo& src, uint32_t mip,
uint32_t* offset_x, uint32_t* offset_y);
+ static uint32_t GetMipSize(const TextureInfo& src, uint32_t mip);
+
// Get the byte size of a MIP when stored linearly.
static uint32_t GetMipLinearSize(const TextureInfo& src, uint32_t mip);
diff --git a/src/xenia/gpu/vulkan/texture_cache.cc b/src/xenia/gpu/vulkan/texture_cache.cc
index eac942b2e..6a602d287 100644
--- a/src/xenia/gpu/vulkan/texture_cache.cc
+++ b/src/xenia/gpu/vulkan/texture_cache.cc
@@ -888,12 +888,11 @@ bool TextureCache::ConvertTexture2D(uint8_t* dest,
uint32_t input_width = src.size_2d.input_width >> mip;
uint32_t input_height = src.size_2d.input_height >> mip;
- // All dimensions must be at least one block w/h
+ // All dimensions must be a multiple of block w/h
logical_width = std::max(logical_width, src.format_info()->block_width);
logical_height = std::max(logical_height, src.format_info()->block_height);
- block_width = std::max(block_width, src.format_info()->block_width);
- input_width = std::max(input_width, src.format_info()->block_width);
- input_height = std::max(input_height, src.format_info()->block_height);
+ input_width = xe::round_up(input_width, src.format_info()->block_width);
+ input_height = xe::round_up(input_height, src.format_info()->block_height);
if (!src.is_tiled) {
uint32_t offset_x, offset_y;