[Vulkan] Handle MIPs with non-power-of-two dimensions

This commit is contained in:
Dr. Chat 2018-05-03 17:54:09 -05:00
parent 04748b4a0d
commit f45cd398ef
3 changed files with 29 additions and 14 deletions

View File

@ -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 *

View File

@ -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);

View File

@ -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;