diff --git a/src/graphics/guest_gpu/tile.cpp b/src/graphics/guest_gpu/tile.cpp index 1fb33feac..4b9bbb798 100644 --- a/src/graphics/guest_gpu/tile.cpp +++ b/src/graphics/guest_gpu/tile.cpp @@ -24,7 +24,7 @@ static uint32_t ShiftCeil(uint32_t value, uint32_t shift) { } static uint32_t CalcLinearBlockWidth(uint32_t bytes_per_element) { - return std::max(1u, 256u / bytes_per_element); + return 256u / bytes_per_element; } static uint32_t CalcLinearAlignedLevelPitch(uint32_t base_width, uint32_t base_height, @@ -64,244 +64,65 @@ static uint32_t SetLinearMipChainLayout(uint32_t levels, const uint32_t* mip_pit return AlignUp(offset, 256u); } -static bool Gen5Standard4KBLayout(uint32_t format, uint32_t* bytes_per_element, - uint32_t* texels_per_element_wide, - uint32_t* texels_per_element_tall, uint32_t* block_width_log2, - uint32_t* block_height_log2) { - const auto bytes = Prospero::NumBytesPerElement(format); - switch (bytes) { - case 1: - *bytes_per_element = 1; - *texels_per_element_wide = 1; - *texels_per_element_tall = 1; - *block_width_log2 = 6; - *block_height_log2 = 6; - return true; - case 2: - *bytes_per_element = 2; - *texels_per_element_wide = 1; - *texels_per_element_tall = 1; - *block_width_log2 = 6; - *block_height_log2 = 5; - return true; - case 4: - *bytes_per_element = 4; - *texels_per_element_wide = 1; - *texels_per_element_tall = 1; - *block_width_log2 = 5; - *block_height_log2 = 5; - return true; - case 8: - *bytes_per_element = 8; - *texels_per_element_wide = 1; - *texels_per_element_tall = 1; - *block_width_log2 = 5; - *block_height_log2 = 4; - return true; - case 16: - *bytes_per_element = 16; - *texels_per_element_wide = 1; - *texels_per_element_tall = 1; - *block_width_log2 = 4; - *block_height_log2 = 4; - return true; - default: break; - } +struct Log2BlockDimensions { + uint8_t width; + uint8_t height; + uint8_t depth; +}; - switch (Prospero::BlockCompressedBytesPerBlock(format)) { - case 8: - *bytes_per_element = 8; - *texels_per_element_wide = 4; - *texels_per_element_tall = 4; - *block_width_log2 = 5; - *block_height_log2 = 4; - return true; - case 16: - *bytes_per_element = 16; - *texels_per_element_wide = 4; - *texels_per_element_tall = 4; - *block_width_log2 = 4; - *block_height_log2 = 4; - return true; - default: return false; - } -} +// Indexed by log2(bytes per element). These are the block dimensions from +// Resolve texture layout facts once and share the result with every consumer. +static constexpr Log2BlockDimensions LOG2_BLOCK_THIN_256B[] = { + {4, 4, 0}, {4, 3, 0}, {3, 3, 0}, {3, 2, 0}, {2, 2, 0}}; +static constexpr Log2BlockDimensions LOG2_BLOCK_THIN_4KB[] = { + {6, 6, 0}, {6, 5, 0}, {5, 5, 0}, {5, 4, 0}, {4, 4, 0}}; +static constexpr Log2BlockDimensions LOG2_BLOCK_THIN_64KB[] = { + {8, 8, 0}, {8, 7, 0}, {7, 7, 0}, {7, 6, 0}, {6, 6, 0}}; +static constexpr Log2BlockDimensions LOG2_BLOCK_THICK_4KB[] = { + {4, 4, 4}, {3, 4, 4}, {3, 4, 3}, {3, 3, 3}, {2, 3, 3}}; +static constexpr Log2BlockDimensions LOG2_BLOCK_THICK_64KB[] = { + {6, 5, 5}, {5, 5, 5}, {5, 5, 4}, {5, 4, 4}, {4, 4, 4}}; -static bool Gen5Standard256BLayout(uint32_t format, uint32_t* bytes_per_element, - uint32_t* texels_per_element_wide, - uint32_t* texels_per_element_tall, uint32_t* block_width_log2, - uint32_t* block_height_log2) { - const auto bytes = Prospero::NumBytesPerElement(format); - switch (bytes) { - case 1: - *bytes_per_element = 1; - *texels_per_element_wide = 1; - *texels_per_element_tall = 1; - *block_width_log2 = 4; - *block_height_log2 = 4; - return true; - case 2: - *bytes_per_element = 2; - *texels_per_element_wide = 1; - *texels_per_element_tall = 1; - *block_width_log2 = 4; - *block_height_log2 = 3; - return true; - case 4: - *bytes_per_element = 4; - *texels_per_element_wide = 1; - *texels_per_element_tall = 1; - *block_width_log2 = 3; - *block_height_log2 = 3; - return true; - case 8: - *bytes_per_element = 8; - *texels_per_element_wide = 1; - *texels_per_element_tall = 1; - *block_width_log2 = 3; - *block_height_log2 = 2; - return true; - case 16: - *bytes_per_element = 16; - *texels_per_element_wide = 1; - *texels_per_element_tall = 1; - *block_width_log2 = 2; - *block_height_log2 = 2; - return true; - default: break; - } +struct BlockFamilyInfo { + uint32_t block_size; + const Log2BlockDimensions* dimensions; + uint32_t max_bytes_per_element; +}; - switch (Prospero::BlockCompressedBytesPerBlock(format)) { - case 8: - *bytes_per_element = 8; - *texels_per_element_wide = 4; - *texels_per_element_tall = 4; - *block_width_log2 = 3; - *block_height_log2 = 2; - return true; - case 16: - *bytes_per_element = 16; - *texels_per_element_wide = 4; - *texels_per_element_tall = 4; - *block_width_log2 = 2; - *block_height_log2 = 2; - return true; - default: return false; - } -} +static constexpr BlockFamilyInfo BLOCK_FAMILIES[] = { + {256, LOG2_BLOCK_THIN_256B, 16}, {4096, LOG2_BLOCK_THIN_4KB, 16}, + {4096, LOG2_BLOCK_THICK_4KB, 16}, {65536, LOG2_BLOCK_THIN_64KB, 16}, + {65536, LOG2_BLOCK_THICK_64KB, 16}, {65536, LOG2_BLOCK_THIN_64KB, 16}, + {65536, LOG2_BLOCK_THICK_64KB, 16}, {65536, LOG2_BLOCK_THIN_64KB, 16}, + {65536, LOG2_BLOCK_THIN_64KB, 8}, +}; +static_assert(std::size(BLOCK_FAMILIES) == static_cast(TileBlockFamily::Count)); -static bool Gen5Standard64KBLayout(uint32_t format, uint32_t* bytes_per_element, - uint32_t* texels_per_element_wide, - uint32_t* texels_per_element_tall, uint32_t* block_width_log2, - uint32_t* block_height_log2) { - switch (Prospero::NumBytesPerElement(format)) { - case 1: - *bytes_per_element = 1; - *texels_per_element_wide = 1; - *texels_per_element_tall = 1; - *block_width_log2 = 8; - *block_height_log2 = 8; - return true; - case 2: - *bytes_per_element = 2; - *texels_per_element_wide = 1; - *texels_per_element_tall = 1; - *block_width_log2 = 8; - *block_height_log2 = 7; - return true; - case 4: - *bytes_per_element = 4; - *texels_per_element_wide = 1; - *texels_per_element_tall = 1; - *block_width_log2 = 7; - *block_height_log2 = 7; - return true; - case 8: - *bytes_per_element = 8; - *texels_per_element_wide = 1; - *texels_per_element_tall = 1; - *block_width_log2 = 7; - *block_height_log2 = 6; - return true; - case 16: - *bytes_per_element = 16; - *texels_per_element_wide = 1; - *texels_per_element_tall = 1; - *block_width_log2 = 6; - *block_height_log2 = 6; - return true; - default: break; - } +static constexpr Log2BlockDimensions LOG2_BLOCK_MSAA[4][5] = { + {{8, 8, 0}, {8, 7, 0}, {7, 7, 0}, {7, 6, 0}, {6, 6, 0}}, + {{7, 8, 0}, {7, 7, 0}, {6, 7, 0}, {6, 6, 0}, {5, 6, 0}}, + {{7, 7, 0}, {7, 6, 0}, {6, 6, 0}, {6, 5, 0}, {5, 5, 0}}, + {{6, 7, 0}, {6, 6, 0}, {5, 6, 0}, {5, 5, 0}, {4, 5, 0}}, +}; - switch (Prospero::BlockCompressedBytesPerBlock(format)) { - case 8: - *bytes_per_element = 8; - *texels_per_element_wide = 4; - *texels_per_element_tall = 4; - *block_width_log2 = 7; - *block_height_log2 = 6; - return true; - case 16: - *bytes_per_element = 16; - *texels_per_element_wide = 4; - *texels_per_element_tall = 4; - *block_width_log2 = 6; - *block_height_log2 = 6; - return true; - default: return false; +static void SetBlockDimensions(const Log2BlockDimensions& dimensions, uint32_t* block_width, + uint32_t* block_height, uint32_t* block_depth = nullptr) { + *block_width = 1u << dimensions.width; + *block_height = 1u << dimensions.height; + if (block_depth != nullptr) { + *block_depth = 1u << dimensions.depth; } } -static bool Gen5Thin64KBBlockSizeFromElementBytes(uint32_t bytes_per_element, uint32_t* block_width, - uint32_t* block_height) { - // Thin 64 KiB block dimensions shared by depth and render-target tiles. - switch (bytes_per_element) { - case 1: - *block_width = 256; - *block_height = 256; - return true; - case 2: - *block_width = 256; - *block_height = 128; - return true; - case 4: - *block_width = 128; - *block_height = 128; - return true; - case 8: - *block_width = 128; - *block_height = 64; - return true; - case 16: - *block_width = 64; - *block_height = 64; - return true; - default: break; - } - - return false; -} - static bool Gen5Msaa64KBBlockSizeFromElementBytes(uint32_t bytes_per_element, uint32_t num_fragments_log2, uint32_t* block_width, uint32_t* block_height) { - if (num_fragments_log2 == 0) { - return Gen5Thin64KBBlockSizeFromElementBytes(bytes_per_element, block_width, block_height); - } if (num_fragments_log2 > 3 || !std::has_single_bit(bytes_per_element) || bytes_per_element > 16) { return false; } - // Row zero is the ordinary thin layout; rows 1..3 are 2x, 4x and 8x blocks. - static constexpr uint8_t LOG2_BLOCK[4][5][2] = { - {{8, 8}, {8, 7}, {7, 7}, {7, 6}, {6, 6}}, - {{7, 8}, {7, 7}, {6, 7}, {6, 6}, {5, 6}}, - {{7, 7}, {7, 6}, {6, 6}, {6, 5}, {5, 5}}, - {{6, 7}, {6, 6}, {5, 6}, {5, 5}, {4, 5}}, - }; const auto bytes_log2 = std::countr_zero(bytes_per_element); - *block_width = 1u << LOG2_BLOCK[num_fragments_log2][bytes_log2][0]; - *block_height = 1u << LOG2_BLOCK[num_fragments_log2][bytes_log2][1]; + SetBlockDimensions(LOG2_BLOCK_MSAA[num_fragments_log2][bytes_log2], block_width, block_height); return true; } @@ -395,220 +216,231 @@ static constexpr Gen5MipTailLocation GEN5_MIP_TAIL_LOCATIONS_THICK_4KB[5][5] = { {{0, 4}, {2, 2}, {2, 0}, {0, 2}, {0, 0}}, }; -struct TextureBlockLayout { - uint32_t bytes; - uint32_t texel_width; - uint32_t texel_height; - uint32_t block_width; - uint32_t block_height; - uint32_t block_size; +struct MipTailLayout { + const Gen5MipTailLocation* locations; + uint32_t max_levels; + uint32_t width_limit; + uint32_t height_limit; }; -static bool GetTextureBlockLayout(uint32_t format, uint32_t tile, TextureBlockLayout& out) { - uint32_t width_log2 = 0, height_log2 = 0; - if (tile == 1 && Gen5Standard256BLayout(format, &out.bytes, &out.texel_width, &out.texel_height, - &width_log2, &height_log2)) { - out.block_size = 256; - } else if (tile == 5 && Gen5Standard4KBLayout(format, &out.bytes, &out.texel_width, - &out.texel_height, &width_log2, &height_log2)) { - out.block_size = 4096; - } else if ((tile == 9 || tile == 17) && - Gen5Standard64KBLayout(format, &out.bytes, &out.texel_width, &out.texel_height, - &width_log2, &height_log2)) { - out.block_size = 65536; - } else if (tile == 24 || tile == 27) { - out.bytes = Prospero::NumBytesPerElement(format); - out.texel_width = out.texel_height = 1; - if (out.bytes == 0 || (tile == 24 && out.bytes > 8) || - !Gen5Thin64KBBlockSizeFromElementBytes(out.bytes, &out.block_width, - &out.block_height)) { - return false; - } - out.block_size = 65536; +template +static MipTailLayout MakeMipTailLayout(const Gen5MipTailLocation (&locations)[Levels], + uint32_t width_limit, uint32_t height_limit) { + return {locations, static_cast(Levels), width_limit, height_limit}; +} + +static bool GetMipTailLayout(const TileBlockLayout& block, MipTailLayout& out) { + const auto index = std::countr_zero(block.bytes_per_element); + switch (block.family) { + case TileBlockFamily::Standard4KB: + out = MakeMipTailLayout(GEN5_MIP_TAIL_LOCATIONS_THIN_4KB[index], + block.block_width >> 1u, block.block_height); + return true; + case TileBlockFamily::Standard4KB3D: + out = MakeMipTailLayout(GEN5_MIP_TAIL_LOCATIONS_THICK_4KB[index], block.block_width, + block.block_height >> 1u); + return true; + case TileBlockFamily::Standard64KB3D: + case TileBlockFamily::Prt64KB3D: + out = MakeMipTailLayout(GEN5_MIP_TAIL_LOCATIONS_THICK_64KB[index], + block.block_width >> 1u, block.block_height); + return true; + case TileBlockFamily::Depth64KB: + out = MakeMipTailLayout(GEN5_MIP_TAIL_LOCATIONS_THIN_64KB[index], + block.block_width >> 1u, block.block_height); + if (block.bytes_per_element < 4) { + out.width_limit = 64; + out.height_limit = 128; + } + return true; + case TileBlockFamily::Standard64KB: + case TileBlockFamily::Prt64KB: + case TileBlockFamily::RenderTarget64KB: + out = MakeMipTailLayout(GEN5_MIP_TAIL_LOCATIONS_THIN_64KB[index], + block.block_width >> 1u, block.block_height); + return true; + case TileBlockFamily::Standard256B: + case TileBlockFamily::Count: return false; + } + return false; +} + +bool TileGetTextureElementLayout(uint32_t format, TileTextureElementLayout& out) { + if (const auto bytes = Prospero::NumBytesPerElement(format); std::has_single_bit(bytes)) { + out = {bytes, 1, 1}; return true; - } else { + } + if (const auto bytes = Prospero::BlockCompressedBytesPerBlock(format); bytes != 0) { + out = {bytes, 4, 4}; + return true; + } + return false; +} + +bool TileGetTextureBlockLayout(uint32_t format, uint32_t tile, bool volume, + TileTextureBlockLayout& out) { + TileBlockFamily family = TileBlockFamily::Count; + switch (static_cast(tile)) { + case Prospero::TileMode::kStandard256B: + if (!volume) family = TileBlockFamily::Standard256B; + break; + case Prospero::TileMode::kStandard4KB: + family = volume ? TileBlockFamily::Standard4KB3D : TileBlockFamily::Standard4KB; + break; + case Prospero::TileMode::kStandard64KB: + family = volume ? TileBlockFamily::Standard64KB3D : TileBlockFamily::Standard64KB; + break; + case Prospero::TileMode::kPrt: + family = volume ? TileBlockFamily::Prt64KB3D : TileBlockFamily::Prt64KB; + break; + case Prospero::TileMode::kDepth: family = TileBlockFamily::Depth64KB; break; + case Prospero::TileMode::kRenderTarget: family = TileBlockFamily::RenderTarget64KB; break; + default: return false; + } + if (family == TileBlockFamily::Count) { return false; } - out.block_width = 1u << width_log2; - out.block_height = 1u << height_log2; + + TileTextureElementLayout element {}; + if (!TileGetTextureElementLayout(format, element)) { + return false; + } + if ((family == TileBlockFamily::Depth64KB || family == TileBlockFamily::RenderTarget64KB) && + Prospero::RenderTargetBytesPerElement(format) != element.bytes) { + return false; + } + + TileBlockLayout block {}; + if (!TileGetBlockLayout(family, element.bytes, block)) { + return false; + } + out = {block, element.texel_width, element.texel_height}; return true; } -static void SetMicroMipLayout(const TextureBlockLayout& block, uint32_t width, uint32_t height, - uint32_t levels, TileSizeAlign* total_size, - TileSizeOffset* level_sizes, TilePaddedSize* padded_size) { - const uint32_t width0 = (width + block.texel_width - 1u) / block.texel_width; - const uint32_t height0 = (height + block.texel_height - 1u) / block.texel_height; - uint32_t offset = 0; - for (int32_t l = static_cast(levels) - 1; l >= 0; --l) { - const auto level = static_cast(l); - const uint32_t padded_width = - AlignUp(std::max(ShiftCeil(width0, level), 1u), block.block_width); - const uint32_t padded_height = - AlignUp(std::max(ShiftCeil(height0, level), 1u), block.block_height); - const uint32_t size = padded_width * padded_height * block.bytes; - if (level_sizes != nullptr) level_sizes[level] = {size, offset}; - if (padded_size != nullptr) { - padded_size[level] = {padded_width * block.texel_width, - padded_height * block.texel_height}; - } - offset += size; +bool TileGetTiledTextureLayout(const TileSurfaceDescription& description, TileSurfaceLayout& out) { + bool volume = false; + switch (description.dimension) { + case TileSurfaceDimension::Dim2D: break; + case TileSurfaceDimension::Dim3D: volume = true; break; + default: return false; } - if (total_size != nullptr) *total_size = {offset, block.block_size}; -} - -static void SetMacroMipLayout(const TextureBlockLayout& block, uint32_t tile, uint32_t width, - uint32_t height, uint32_t levels, TileSizeAlign* total_size, - TileSizeOffset* level_sizes, TilePaddedSize* padded_size) { - const uint32_t width0 = (width + block.texel_width - 1u) / block.texel_width; - const uint32_t height0 = (height + block.texel_height - 1u) / block.texel_height; - const uint32_t bytes_log2 = std::countr_zero(block.bytes); - const uint32_t max_tail = block.block_size == 4096 ? 8u : 12u; - uint32_t tail_width = block.block_width >> 1u, tail_height = block.block_height; - if (tile == 24 && block.bytes < 4) { - tail_width = 64; - tail_height = 128; + if (description.width == 0 || description.height == 0 || description.depth == 0 || + description.levels == 0 || description.levels > 16 || description.layers == 0 || + (volume ? description.layers != 1 : description.depth != 1)) { + return false; } - uint32_t first_tail = levels; - if (levels > 1) { - for (uint32_t level = 0; level < levels; ++level) { - if (ShiftCeil(width0, level) <= tail_width && - ShiftCeil(height0, level) <= tail_height && levels - level <= max_tail) { - first_tail = level; + TileTextureBlockLayout texture {}; + if (!TileGetTextureBlockLayout(description.format, description.tile_mode, volume, texture)) { + return false; + } + const auto& block = texture.block; + const auto width0 = (description.width + texture.texel_width - 1u) / texture.texel_width; + const auto height0 = (description.height + texture.texel_height - 1u) / texture.texel_height; + + TileSurfaceLayout result {}; + result.description = description; + result.texture = texture; + result.first_tail_level = description.levels; + const uint32_t block_slices = + volume ? ShiftCeil(description.depth, std::countr_zero(block.block_depth)) + : description.layers; + + MipTailLayout tail {}; + const bool has_tail = GetMipTailLayout(block, tail); + if (has_tail && description.levels > 1) { + for (uint32_t level = 0; level < description.levels; ++level) { + if (ShiftCeil(width0, level) <= tail.width_limit && + ShiftCeil(height0, level) <= tail.height_limit && + description.levels - level <= tail.max_levels) { + result.first_tail_level = level; break; } } } - uint32_t offset = first_tail < levels ? block.block_size : 0; - for (int32_t l = static_cast(first_tail) - 1; l >= 0; --l) { - const auto level = static_cast(l); - const uint32_t padded_width = - AlignUp(std::max(ShiftCeil(width0, level), 1u), block.block_width); - const uint32_t padded_height = - AlignUp(std::max(ShiftCeil(height0, level), 1u), block.block_height); - const uint32_t size = padded_width * padded_height * block.bytes; - if (level_sizes != nullptr) level_sizes[level] = {size, offset, size, offset}; - if (padded_size != nullptr) { - padded_size[level] = {padded_width * block.texel_width, - padded_height * block.texel_height}; - } - offset += size; + for (uint32_t level = 0; level < result.first_tail_level; ++level) { + auto& mip = result.mips[level]; + mip.width = std::max( + ((description.width >> level) + texture.texel_width - 1u) / texture.texel_width, 1u); + mip.height = std::max( + ((description.height >> level) + texture.texel_height - 1u) / texture.texel_height, 1u); + mip.padded_width = AlignUp(std::max(ShiftCeil(width0, level), 1u), block.block_width); + mip.padded_height = AlignUp(std::max(ShiftCeil(height0, level), 1u), block.block_height); + mip.size = static_cast(block.block_depth) * mip.padded_width * mip.padded_height * + block.bytes_per_element; + result.block_slice_size += mip.size; } - uint32_t linear_offset = 0; - for (uint32_t level = first_tail; level < levels; ++level) { - const uint32_t mip_width = - std::max(((width >> level) + block.texel_width - 1u) / block.texel_width, 1u); - const uint32_t mip_height = - std::max(((height >> level) + block.texel_height - 1u) / block.texel_height, 1u); - const auto tail = block.block_size == 4096 - ? GEN5_MIP_TAIL_LOCATIONS_THIN_4KB[bytes_log2][level - first_tail] - : GEN5_MIP_TAIL_LOCATIONS_THIN_64KB[bytes_log2][level - first_tail]; - if (level_sizes != nullptr) { - level_sizes[level] = {mip_width * mip_height * block.bytes, - linear_offset, - block.block_size, - 0, - tail.x, - tail.y}; - } - if (padded_size != nullptr) { - padded_size[level] = {block.block_width * block.texel_width, - block.block_height * block.texel_height}; - } - linear_offset += mip_width * mip_height * block.bytes; + if (result.first_tail_level < description.levels) { + result.block_slice_size += block.block_size; + } + for (uint32_t level = result.first_tail_level; level < description.levels; ++level) { + auto& mip = result.mips[level]; + mip.width = std::max( + ((description.width >> level) + texture.texel_width - 1u) / texture.texel_width, 1u); + mip.height = std::max( + ((description.height >> level) + texture.texel_height - 1u) / texture.texel_height, 1u); + mip.padded_width = block.block_width; + mip.padded_height = block.block_height; + mip.size = block.block_size; + mip.tail_x = tail.locations[level - result.first_tail_level].x; + mip.tail_y = tail.locations[level - result.first_tail_level].y; } - if (total_size != nullptr) *total_size = {offset, block.block_size}; -} -bool TileGetTextureVolumeLayout(uint32_t format, uint32_t width, uint32_t height, uint32_t depth, - uint32_t levels, uint32_t tile, TileVolumeLayout& out) { - if (width == 0 || height == 0 || depth == 0 || levels == 0 || levels > 16) { + uint64_t offset = result.first_tail_level < description.levels ? block.block_size : 0; + for (int32_t level = static_cast(result.first_tail_level) - 1; level >= 0; --level) { + result.mips[level].offset = offset; + offset += result.mips[level].size; + } + if (offset != result.block_slice_size || result.block_slice_size > UINT64_MAX / block_slices) { return false; } - TextureBlockLayout element {}; - if (!GetTextureBlockLayout(format, tile, element)) return false; + result.total_size = result.block_slice_size * block_slices; + out = result; + return true; +} - TileBlockFamily family = TileBlockFamily::Count; - switch (tile) { - case 5: family = TileBlockFamily::Standard4KB3D; break; - case 9: family = TileBlockFamily::Standard64KB3D; break; - case 17: family = TileBlockFamily::Prt64KB3D; break; - case 24: family = TileBlockFamily::Depth64KB; break; - case 27: family = TileBlockFamily::RenderTarget64KB; break; - default: return false; - } - TileBlockLayout block {}; - if (!TileGetBlockLayout(family, element.bytes, block)) return false; - - out = {}; - out.family = family; - out.bytes_per_element = element.bytes; - out.texel_width = element.texel_width; - out.texel_height = element.texel_height; - out.block_depth = block.block_depth; - out.first_tail_level = levels; - const uint32_t width0 = (width + element.texel_width - 1u) / element.texel_width; - const uint32_t height0 = (height + element.texel_height - 1u) / element.texel_height; - const bool thick4 = family == TileBlockFamily::Standard4KB3D; - const bool thick64 = - family == TileBlockFamily::Standard64KB3D || family == TileBlockFamily::Prt64KB3D; - uint32_t max_tail = 12u; - if (thick4) { - max_tail = 5u; - } else if (thick64) { - max_tail = 10u; - } - uint32_t tail_width = thick4 ? block.block_width : block.block_width >> 1u; - uint32_t tail_height = thick4 ? block.block_height >> 1u : block.block_height; - if (family == TileBlockFamily::Depth64KB && element.bytes < 4) { - tail_width = 64; - tail_height = 128; +static void SetLegacyTiledMipLayout(const TileSurfaceLayout& layout, TileSizeAlign* total_size, + TileSizeOffset* level_sizes, TilePaddedSize* padded_size) { + EXIT_NOT_IMPLEMENTED(layout.block_slice_size > UINT32_MAX); + const auto& block = layout.texture.block; + if (total_size != nullptr) { + *total_size = {static_cast(layout.block_slice_size), block.block_size}; } - for (uint32_t level = 0; level < levels; ++level) { - const uint32_t mip_width = std::max(ShiftCeil(width0, level), 1u); - const uint32_t mip_height = std::max(ShiftCeil(height0, level), 1u); - if (levels > 1 && mip_width <= tail_width && mip_height <= tail_height && - levels - level <= max_tail) { - out.first_tail_level = level; - out.block_slice_size += block.block_size; - break; + uint64_t linear_tail_offset = 0; + for (uint32_t level = 0; level < layout.description.levels; ++level) { + const auto& mip = layout.mips[level]; + const bool tail = level >= layout.first_tail_level; + EXIT_NOT_IMPLEMENTED(mip.offset > UINT32_MAX || mip.size > UINT32_MAX); + if (level_sizes != nullptr) { + if (tail) { + const uint64_t linear_size = + static_cast(mip.width) * mip.height * block.bytes_per_element; + EXIT_NOT_IMPLEMENTED(linear_size > UINT32_MAX || linear_tail_offset > UINT32_MAX); + level_sizes[level] = {static_cast(linear_size), + static_cast(linear_tail_offset), + static_cast(mip.size), + static_cast(mip.offset), + mip.tail_x, + mip.tail_y}; + linear_tail_offset += linear_size; + } else if (block.family == TileBlockFamily::Standard256B) { + level_sizes[level] = {static_cast(mip.size), + static_cast(mip.offset)}; + } else { + level_sizes[level] = { + static_cast(mip.size), static_cast(mip.offset), + static_cast(mip.size), static_cast(mip.offset)}; + } + } + if (padded_size != nullptr) { + padded_size[level] = {mip.padded_width * layout.texture.texel_width, + mip.padded_height * layout.texture.texel_height}; } - out.level_widths[level] = AlignUp(mip_width, block.block_width); - out.level_heights[level] = AlignUp(mip_height, block.block_height); - out.level_sizes[level] = static_cast(block.block_depth) * - out.level_widths[level] * out.level_heights[level] * element.bytes; - out.block_slice_size += out.level_sizes[level]; } - - const auto bytes_log2 = std::countr_zero(element.bytes); - const Gen5MipTailLocation* tail_locations = nullptr; - if (thick4) { - tail_locations = GEN5_MIP_TAIL_LOCATIONS_THICK_4KB[bytes_log2]; - } else if (thick64) { - tail_locations = GEN5_MIP_TAIL_LOCATIONS_THICK_64KB[bytes_log2]; - } else { - tail_locations = GEN5_MIP_TAIL_LOCATIONS_THIN_64KB[bytes_log2]; - } - for (uint32_t level = out.first_tail_level; level < levels; ++level) { - const auto index = level - out.first_tail_level; - const auto tail = tail_locations[index]; - out.level_sizes[level] = block.block_size; - out.level_widths[level] = block.block_width; - out.level_heights[level] = block.block_height; - out.tail_x[level] = tail.x; - out.tail_y[level] = tail.y; - } - uint64_t offset = out.first_tail_level < levels ? block.block_size : 0; - for (int32_t l = static_cast(out.first_tail_level) - 1; l >= 0; --l) { - out.level_offsets[l] = offset; - offset += out.level_sizes[l]; - } - out.total_size = out.block_slice_size * ShiftCeil(depth, std::countr_zero(block.block_depth)); - return offset == out.block_slice_size; } static uint32_t Gen5Standard4KBOffsetInBlock(uint32_t x, uint32_t y, uint32_t bytes_per_element) { @@ -744,39 +576,6 @@ static uint32_t Gen5Standard64KBVolumeOffsetInBlock(uint32_t x, uint32_t y, uint Bit(z, bits[1], 13) ^ Bit(y, bits[2], 14) ^ Bit(x, bits[3], 15); } -bool TileIsStandard4KBTextureSupported(uint32_t format) { - uint32_t bytes_per_element = 0; - uint32_t texels_per_element_wide = 0; - uint32_t texels_per_element_tall = 0; - uint32_t block_width_log2 = 0; - uint32_t block_height_log2 = 0; - - return Gen5Standard4KBLayout(format, &bytes_per_element, &texels_per_element_wide, - &texels_per_element_tall, &block_width_log2, &block_height_log2); -} - -bool TileIsStandard256BTextureSupported(uint32_t format) { - uint32_t bytes_per_element = 0; - uint32_t texels_per_element_wide = 0; - uint32_t texels_per_element_tall = 0; - uint32_t block_width_log2 = 0; - uint32_t block_height_log2 = 0; - - return Gen5Standard256BLayout(format, &bytes_per_element, &texels_per_element_wide, - &texels_per_element_tall, &block_width_log2, &block_height_log2); -} - -bool TileIsStandard64KBTextureSupported(uint32_t format) { - uint32_t bytes_per_element = 0; - uint32_t texels_per_element_wide = 0; - uint32_t texels_per_element_tall = 0; - uint32_t block_width_log2 = 0; - uint32_t block_height_log2 = 0; - - return Gen5Standard64KBLayout(format, &bytes_per_element, &texels_per_element_wide, - &texels_per_element_tall, &block_width_log2, &block_height_log2); -} - struct Uint128 { uint64_t n[2]; }; @@ -1058,85 +857,18 @@ static constexpr uint32_t Depth64KB64YOffsetBytes(uint32_t y); bool TileGetBlockLayout(TileBlockFamily family, uint32_t bytes_per_element, TileBlockLayout& layout) { - if (!std::has_single_bit(bytes_per_element) || bytes_per_element > 16) { + const auto family_index = static_cast(family); + if (family_index >= std::size(BLOCK_FAMILIES) || !std::has_single_bit(bytes_per_element)) { + return false; + } + const auto& info = BLOCK_FAMILIES[family_index]; + if (bytes_per_element > info.max_bytes_per_element) { return false; } - TileBlockLayout result {family, bytes_per_element, 0, 0, 0, 1}; - auto thin = [&] { - return Gen5Thin64KBBlockSizeFromElementBytes(bytes_per_element, &result.block_width, - &result.block_height); - }; - auto thick64 = [&] { - static constexpr uint8_t LOG2_DIMS[5][3] = { - {6, 5, 5}, {5, 5, 5}, {5, 5, 4}, {5, 4, 4}, {4, 4, 4}}; - const auto index = std::countr_zero(bytes_per_element); - result.block_width = 1u << LOG2_DIMS[index][0]; - result.block_height = 1u << LOG2_DIMS[index][1]; - result.block_depth = 1u << LOG2_DIMS[index][2]; - }; - switch (family) { - case TileBlockFamily::Standard256B: - result.block_size = 256; - if (bytes_per_element <= 2) { - result.block_width = 16; - } else if (bytes_per_element <= 8) { - result.block_width = 8; - } else { - result.block_width = 4; - } - result.block_height = result.block_size / (result.block_width * bytes_per_element); - break; - case TileBlockFamily::Standard4KB: - result.block_size = 4096; - if (bytes_per_element <= 2) { - result.block_width = 64; - } else if (bytes_per_element <= 8) { - result.block_width = 32; - } else { - result.block_width = 16; - } - result.block_height = result.block_size / (result.block_width * bytes_per_element); - break; - case TileBlockFamily::Standard4KB3D: { - static constexpr uint8_t LOG2_DIMS[5][3] = { - {4, 4, 4}, {3, 4, 4}, {3, 4, 3}, {3, 3, 3}, {2, 3, 3}}; - const auto index = std::countr_zero(bytes_per_element); - result.block_size = 4096; - result.block_width = 1u << LOG2_DIMS[index][0]; - result.block_height = 1u << LOG2_DIMS[index][1]; - result.block_depth = 1u << LOG2_DIMS[index][2]; - break; - } - case TileBlockFamily::Standard64KB: - case TileBlockFamily::Prt64KB: - result.block_size = 65536; - if (!thin()) { - return false; - } - break; - case TileBlockFamily::Standard64KB3D: - case TileBlockFamily::Prt64KB3D: - result.block_size = 65536; - thick64(); - break; - case TileBlockFamily::RenderTarget64KB: - result.block_size = 65536; - if (!thin()) { - return false; - } - break; - case TileBlockFamily::Depth64KB: - if (bytes_per_element > 8) { - return false; - } - result.block_size = 65536; - if (!thin()) { - return false; - } - break; - case TileBlockFamily::Count: return false; - } + TileBlockLayout result {family, bytes_per_element, info.block_size, 0, 0, 1}; + SetBlockDimensions(info.dimensions[std::countr_zero(bytes_per_element)], &result.block_width, + &result.block_height, &result.block_depth); if (static_cast(result.block_width) * result.block_height * result.block_depth * bytes_per_element != @@ -1382,7 +1114,7 @@ static_assert(Depth64KB32XOffsetBytes(2) == 0x0010u); static_assert(Depth64KB32YOffsetBytes(1) == 0x0008u); static_assert((Depth64KB32XOffsetBytes(3) ^ Depth64KB32YOffsetBytes(5)) == 0x009cu); -bool TileGetHtileSize(uint32_t width, uint32_t height, TileSizeAlign& htile_size) { +static bool TileGetHtileSize(uint32_t width, uint32_t height, TileSizeAlign& htile_size) { htile_size = {}; if (width == 0 || width > 16384 || height == 0 || height > 16384) { return false; @@ -1513,28 +1245,41 @@ bool TileGetRenderTargetMipLayout(uint32_t width, uint32_t height, uint32_t pitc case 16: format = Prospero::GpuEnumValue(Prospero::BufferFormat::k32_32_32_32Float); break; default: return false; } - TileGetTextureSize(format, width, height, pitch, levels, + TileGetTextureSize(format, width, height, levels, Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget), &total_size, level_sizes, padded_size); return total_size.size != 0 && total_size.align == 65536; } -void TileGetTextureSize(uint32_t format, uint32_t width, uint32_t height, uint32_t pitch, - uint32_t levels, uint32_t tile, TileSizeAlign* total_size, - TileSizeOffset* level_sizes, TilePaddedSize* padded_size) { +void TileGetTextureSize(uint32_t format, uint32_t width, uint32_t height, uint32_t levels, + uint32_t tile, TileSizeAlign* total_size, TileSizeOffset* level_sizes, + TilePaddedSize* padded_size) { KYTY_PROFILER_FUNCTION(); EXIT_IF(levels == 0 || levels > 16); - if (const uint32_t bytes_per_element = Prospero::NumBytesPerElement(format); - bytes_per_element != 0 && tile == 0) { + TileTextureElementLayout element {}; + if (static_cast(tile) == Prospero::TileMode::kLinear && + TileGetTextureElementLayout(format, element)) { uint32_t mip_pitch[16] {}; uint32_t mip_height[16] {}; uint32_t mip_size[16] {}; + const uint32_t elements_w0 = + std::max((width + element.texel_width - 1u) / element.texel_width, 1u); + const uint32_t elements_h0 = + std::max((height + element.texel_height - 1u) / element.texel_height, 1u); + const bool compressed = element.texel_width != 1 || element.texel_height != 1; for (uint32_t l = 0; l < levels; l++) { - mip_pitch[l] = CalcLinearAlignedLevelPitch(width, height, l, bytes_per_element, - &mip_height[l], &mip_size[l]); + uint32_t padded_elements_h = 0; + const uint32_t aligned_elements_w = CalcLinearAlignedLevelPitch( + elements_w0, elements_h0, l, element.bytes, &padded_elements_h, &mip_size[l]); + mip_pitch[l] = aligned_elements_w * element.texel_width; + mip_height[l] = padded_elements_h * element.texel_height; + if (compressed) { + mip_pitch[l] = std::max(mip_pitch[l], 32u); + mip_height[l] = std::max(mip_height[l], 32u); + } } const uint32_t total = SetLinearMipChainLayout(levels, mip_pitch, mip_height, mip_size, @@ -1548,42 +1293,11 @@ void TileGetTextureSize(uint32_t format, uint32_t width, uint32_t height, uint32 return; } - TextureBlockLayout block {}; - if (GetTextureBlockLayout(format, tile, block)) { - if (tile == 1) { - SetMicroMipLayout(block, width, height, levels, total_size, level_sizes, padded_size); - } else { - SetMacroMipLayout(block, tile, width, height, levels, total_size, level_sizes, - padded_size); - } - return; - } - - if (auto bytes_per_block = Prospero::BlockCompressedBytesPerBlock(format); - bytes_per_block != 0 && tile == 0) { - uint32_t mip_pitch[16] {}; - uint32_t mip_height[16] {}; - uint32_t mip_size[16] {}; - - const uint32_t blocks_w0 = std::max((width + 3u) / 4u, 1u); - const uint32_t blocks_h0 = std::max((height + 3u) / 4u, 1u); - for (uint32_t l = 0; l < levels; l++) { - uint32_t padded_blocks_h = 0; - const uint32_t aligned_blocks_w = CalcLinearAlignedLevelPitch( - blocks_w0, blocks_h0, l, bytes_per_block, &padded_blocks_h, &mip_size[l]); - - mip_pitch[l] = std::max(aligned_blocks_w * 4u, 32u); - mip_height[l] = std::max(padded_blocks_h * 4u, 32u); - } - - const uint32_t total = SetLinearMipChainLayout(levels, mip_pitch, mip_height, mip_size, - level_sizes, padded_size); - - if (total_size != nullptr) { - total_size->size = total; - total_size->align = 256; - } - + TileSurfaceLayout layout {}; + const TileSurfaceDescription description { + format, tile, TileSurfaceDimension::Dim2D, width, height, 1, levels, 1}; + if (TileGetTiledTextureLayout(description, layout)) { + SetLegacyTiledMipLayout(layout, total_size, level_sizes, padded_size); return; } if (total_size != nullptr && total_size->size == 0) { @@ -1591,7 +1305,6 @@ void TileGetTextureSize(uint32_t format, uint32_t width, uint32_t height, uint32 list.push_back(fmt::format("format = {}", format)); list.push_back(fmt::format("width = {}", width)); list.push_back(fmt::format("height = {}", height)); - list.push_back(fmt::format("pitch = {}", pitch)); list.push_back(fmt::format("levels = {}", levels)); list.push_back(fmt::format("tile = {}", tile)); EXIT("unknown format:\n%s\n", Common::Concat(list, '\n').c_str()); @@ -1599,65 +1312,53 @@ void TileGetTextureSize(uint32_t format, uint32_t width, uint32_t height, uint32 } void TileGetTextureTotalSize(uint32_t format, uint32_t width, uint32_t height, uint32_t depth, - uint32_t pitch, uint32_t levels, uint32_t tile, bool volume_texture, + uint32_t levels, uint32_t tile, bool volume_texture, TileSizeAlign& total_size) { EXIT_NOT_IMPLEMENTED(depth == 0); - if (volume_texture) { - TileVolumeLayout volume {}; - if (TileGetTextureVolumeLayout(format, width, height, depth, levels, tile, volume)) { - EXIT_NOT_IMPLEMENTED(volume.total_size > UINT32_MAX); - total_size.size = static_cast(volume.total_size); - total_size.align = tile == 5 ? 4096u : 65536u; - return; + if (volume_texture && static_cast(tile) != Prospero::TileMode::kLinear) { + TileSurfaceLayout layout {}; + const TileSurfaceDescription description { + format, tile, TileSurfaceDimension::Dim3D, width, height, depth, levels, 1}; + if (!TileGetTiledTextureLayout(description, layout)) { + EXIT("unsupported 3D texture layout: format=%u tile=%u extent=%ux%ux%u levels=%u\n", + format, tile, width, height, depth, levels); } + EXIT_NOT_IMPLEMENTED(layout.total_size > UINT32_MAX); + total_size.size = static_cast(layout.total_size); + total_size.align = layout.texture.block.block_size; + return; } TileSizeAlign slice_size {}; - TileGetTextureSize(format, width, height, pitch, levels, tile, &slice_size, nullptr, nullptr); + TileGetTextureSize(format, width, height, levels, tile, &slice_size, nullptr, nullptr); total_size = slice_size; const uint64_t total = static_cast(slice_size.size) * depth; EXIT_NOT_IMPLEMENTED(total > 0xffffffffull); total_size.size = static_cast(total); } -uint32_t TileGetTexturePitch(uint32_t format, uint32_t width, uint32_t levels, uint32_t tile) { +uint32_t TileGetTexturePitch(uint32_t format, uint32_t width, uint32_t tile) { uint32_t pitch = width; - - if (tile == 27) { - if (const uint32_t bytes_per_element = Prospero::NumBytesPerElement(format); - bytes_per_element != 0) { - uint32_t block_width = 0; - uint32_t block_height = 0; - EXIT_NOT_IMPLEMENTED(!Gen5Thin64KBBlockSizeFromElementBytes( - bytes_per_element, &block_width, &block_height)); - pitch = AlignUp(pitch, block_width); + switch (static_cast(tile)) { + case Prospero::TileMode::kLinear: { + TileTextureElementLayout element {}; + if (TileGetTextureElementLayout(format, element) && element.texel_width == 1 && + element.texel_height == 1) { + pitch = AlignUp(pitch, CalcLinearBlockWidth(element.bytes)); + } + break; } - } - - if (tile == 0) { - if (const auto bytes_per_element = Prospero::NumBytesPerElement(format); - bytes_per_element != 0) { - pitch = AlignUp(pitch * bytes_per_element, 256u) / bytes_per_element; - } - } - uint32_t bytes_per_element = 0; - uint32_t texels_per_element_wide = 0; - uint32_t texels_per_element_tall = 0; - uint32_t block_width_log2 = 0; - uint32_t block_height_log2 = 0; - if ((tile == 9 || tile == 17) && - Gen5Standard64KBLayout(format, &bytes_per_element, &texels_per_element_wide, - &texels_per_element_tall, &block_width_log2, &block_height_log2)) { - pitch = AlignUp(pitch, (1u << block_width_log2) * texels_per_element_wide); - } - if (tile == 24) { - const uint32_t bytes_per_element = Prospero::NumBytesPerElement(format); - uint32_t block_width = 0; - uint32_t block_height = 0; - if (bytes_per_element <= 8 && - Gen5Thin64KBBlockSizeFromElementBytes(bytes_per_element, &block_width, &block_height)) { - pitch = AlignUp(pitch, block_width); + case Prospero::TileMode::kStandard64KB: + case Prospero::TileMode::kPrt: + case Prospero::TileMode::kDepth: + case Prospero::TileMode::kRenderTarget: { + TileTextureBlockLayout layout {}; + if (TileGetTextureBlockLayout(format, tile, false, layout)) { + pitch = AlignUp(pitch, layout.block.block_width * layout.texel_width); + } + break; } + default: break; } return pitch; diff --git a/src/graphics/guest_gpu/tile.h b/src/graphics/guest_gpu/tile.h index dbe96058b..3e753ff10 100644 --- a/src/graphics/guest_gpu/tile.h +++ b/src/graphics/guest_gpu/tile.h @@ -39,7 +39,7 @@ enum class TileBlockFamily : uint32_t { }; struct TileBlockLayout { - TileBlockFamily family = TileBlockFamily::Standard256B; + TileBlockFamily family = TileBlockFamily::Count; uint32_t bytes_per_element = 0; uint32_t block_size = 0; uint32_t block_width = 0; @@ -47,38 +47,69 @@ struct TileBlockLayout { uint32_t block_depth = 0; }; -struct TileVolumeLayout { - TileBlockFamily family = TileBlockFamily::Count; - uint32_t bytes_per_element = 0; - uint32_t texel_width = 1; - uint32_t texel_height = 1; - uint32_t first_tail_level = 0; - uint32_t block_depth = 1; - uint64_t block_slice_size = 0; - uint64_t total_size = 0; - uint64_t level_offsets[16] = {}; - uint64_t level_sizes[16] = {}; - uint32_t tail_x[16] = {}; - uint32_t tail_y[16] = {}; - uint32_t level_widths[16] = {}; - uint32_t level_heights[16] = {}; +struct TileTextureElementLayout { + uint32_t bytes = 0; + uint32_t texel_width = 1; + uint32_t texel_height = 1; +}; + +struct TileTextureBlockLayout { + TileBlockLayout block; + uint32_t texel_width = 1; + uint32_t texel_height = 1; +}; + +enum class TileSurfaceDimension : uint32_t { + Dim2D, + Dim3D, +}; + +struct TileSurfaceDescription { + uint32_t format = 0; + uint32_t tile_mode = 0; + TileSurfaceDimension dimension = TileSurfaceDimension::Dim2D; + uint32_t width = 0; + uint32_t height = 0; + uint32_t depth = 1; + uint32_t levels = 1; + uint32_t layers = 1; +}; + +// Width/height fields are measured in addressable elements, not texture texels. +struct TileMipLayout { + uint64_t offset = 0; + uint64_t size = 0; + uint32_t width = 0; + uint32_t height = 0; + uint32_t padded_width = 0; + uint32_t padded_height = 0; + uint32_t tail_x = 0; + uint32_t tail_y = 0; +}; + +struct TileSurfaceLayout { + TileSurfaceDescription description; + TileTextureBlockLayout texture; + uint32_t first_tail_level = 0; + uint64_t block_slice_size = 0; + uint64_t total_size = 0; + TileMipLayout mips[16] = {}; }; bool TileGetBlockLayout(TileBlockFamily family, uint32_t bytes_per_element, TileBlockLayout& layout); +bool TileGetTextureElementLayout(uint32_t format, TileTextureElementLayout& layout); +bool TileGetTextureBlockLayout(uint32_t format, uint32_t tile, bool volume, + TileTextureBlockLayout& layout); +bool TileGetTiledTextureLayout(const TileSurfaceDescription& description, + TileSurfaceLayout& layout); bool TileGetBlockOffset(const TileBlockLayout& layout, uint32_t x, uint32_t y, uint32_t z, uint32_t& byte_offset); bool TileGetBlockXor(const TileBlockLayout& layout, uint32_t block_x, uint32_t block_y, uint32_t& byte_offset); bool TileGetBlockXor(const TileBlockLayout& layout, uint32_t block_x, uint32_t block_y, uint32_t block_z, uint32_t& byte_offset); -bool TileIsStandard256BTextureSupported(uint32_t format); -bool TileIsStandard4KBTextureSupported(uint32_t format); -bool TileIsStandard64KBTextureSupported(uint32_t format); -bool TileGetTextureVolumeLayout(uint32_t format, uint32_t width, uint32_t height, uint32_t depth, - uint32_t levels, uint32_t tile, TileVolumeLayout& layout); -bool TileGetHtileSize(uint32_t width, uint32_t height, TileSizeAlign& htile_size); bool TileGetDepthSize(uint32_t width, uint32_t height, uint32_t pitch, uint32_t z_format, uint32_t stencil_format, bool htile, TileSizeAlign& stencil_size, TileSizeAlign& htile_size, TileSizeAlign& depth_size, @@ -94,13 +125,13 @@ bool TileGetRenderTargetMipLayout(uint32_t width, uint32_t height, uint32_t uint32_t bytes_per_element, uint32_t levels, TileSizeAlign& total_size, TileSizeOffset* level_sizes, TilePaddedSize* padded_size); -void TileGetTextureSize(uint32_t format, uint32_t width, uint32_t height, uint32_t pitch, - uint32_t levels, uint32_t tile, TileSizeAlign* total_size, - TileSizeOffset* level_sizes, TilePaddedSize* padded_size); -void TileGetTextureTotalSize(uint32_t format, uint32_t width, uint32_t height, uint32_t depth, - uint32_t pitch, uint32_t levels, uint32_t tile, bool volume_texture, - TileSizeAlign& total_size); -uint32_t TileGetTexturePitch(uint32_t format, uint32_t width, uint32_t levels, uint32_t tile); +void TileGetTextureSize(uint32_t format, uint32_t width, uint32_t height, uint32_t levels, + uint32_t tile, TileSizeAlign* total_size, TileSizeOffset* level_sizes, + TilePaddedSize* padded_size); +void TileGetTextureTotalSize(uint32_t format, uint32_t width, uint32_t height, uint32_t depth, + uint32_t levels, uint32_t tile, bool volume_texture, + TileSizeAlign& total_size); +uint32_t TileGetTexturePitch(uint32_t format, uint32_t width, uint32_t tile); } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/cache/textureCache.cpp b/src/graphics/host_gpu/renderer/cache/textureCache.cpp index c627b576d..ab44e210d 100644 --- a/src/graphics/host_gpu/renderer/cache/textureCache.cpp +++ b/src/graphics/host_gpu/renderer/cache/textureCache.cpp @@ -911,7 +911,6 @@ TextureCache::BuildColorTransfer(const Image& image, BindingType binding, uint32_t format = info.guest_format; uint32_t layers = info.TransferLayers(); bool volume = info.IsVolume(); - bool layered = info.IsLayered(); bool allow_depth_tile = direction == TransferDirection::Upload; const char* owner = direction == TransferDirection::Upload ? "TextureCache" : "TextureCache readback"; @@ -940,7 +939,6 @@ TextureCache::BuildColorTransfer(const Image& image, BindingType binding, format = info.guest_format; layers = info.resources.layers; volume = false; - layered = layers > 1; allow_depth_tile = false; plan.swap_bgra16 = info.bgra16; owner = "VideoOut"; @@ -958,19 +956,14 @@ TextureCache::BuildColorTransfer(const Image& image, BindingType binding, plan.swap_bgra16 = info.bgra16; } - plan.layout = TextureCalcUploadLayout(format, info.extent.width, info.extent.height, - info.resources.levels, layers, info.pitch, info.tile_mode, - info.data.size, allow_depth_tile, volume, owner); - plan.regions = TextureBuildImageCopies(plan.layout, info.extent.width, info.extent.height, - layers, info.resources.levels, layered, volume); - plan.tiled = static_cast(plan.layout.tile) != Prospero::TileMode::kLinear; + plan.layout = TextureCalcUploadLayout(format, info.extent.width, info.extent.height, + info.resources.levels, layers, info.tile_mode, + info.data.size, allow_depth_tile, volume, owner); + plan.regions = TextureBuildImageCopies(plan.layout); + plan.tiled = static_cast(plan.layout.surface.description.tile_mode) != + Prospero::TileMode::kLinear; if (plan.tiled) { - // CMASK/FMASK decoding is intentionally deferred. - if (plan.layout.tile_family == TileBlockFamily::Depth64KB && - Prospero::IsFmaskTextureFormat(format)) { - return plan; - } - if (!TextureBuildGpuTileInfos(info.data.size, plan.regions, plan.layout, format, layers, + if (!TextureBuildGpuTileInfos(info.data.size, plan.regions, plan.layout, info.resources.levels, plan.tiles)) { return plan; } @@ -1017,9 +1010,10 @@ void TextureCache::UploadImage(Image& image, const ImageDesc& desc, Buffer& sour " size=0x%016" PRIx64 " format=%u tile=%u family=%u extent=%ux%ux%u " "pitch=%u levels=%u layers=%u samples=%u\n", static_cast(desc.type), info.data.address, info.data.size, - info.guest_format, info.tile_mode, static_cast(plan.layout.tile_family), - info.extent.width, info.extent.height, info.extent.depth, info.pitch, - info.resources.levels, info.resources.layers, info.samples); + info.guest_format, info.tile_mode, + static_cast(plan.layout.surface.texture.block.family), info.extent.width, + info.extent.height, info.extent.depth, info.pitch, info.resources.levels, + info.resources.layers, info.samples); } TileManager::Result linear {source.Handle(), source_offset, info.data.size}; if (plan.tiled) { @@ -1718,14 +1712,9 @@ bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, uint64_t vaddr, uin return false; } if (color.tiled) { - const auto binding = m_texture_cache.UploadBinding(image); - const auto format = - binding == TextureCache::BindingType::RenderTarget - ? ImageOps::RenderTargetTransferFormat(image.info.bytes_per_block) - : image.info.guest_format; color.tiles.clear(); - if (!TextureBuildGpuTileInfos(copy_size, color.regions, color.layout, format, - image.info.TransferLayers(), levels, color.tiles)) { + if (!TextureBuildGpuTileInfos(copy_size, color.regions, color.layout, levels, + color.tiles)) { return false; } color.linear_size = GetLinearSize(color.tiles); diff --git a/src/graphics/host_gpu/renderer/colorRenderTarget.cpp b/src/graphics/host_gpu/renderer/colorRenderTarget.cpp index b81611e57..b7a9efa63 100644 --- a/src/graphics/host_gpu/renderer/colorRenderTarget.cpp +++ b/src/graphics/host_gpu/renderer/colorRenderTarget.cpp @@ -178,10 +178,10 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, RenderCommandB pitch = (rt.pitch.pitch_div8_minus1 + 1u) << 3u; } else if (tile) { if (volume) { - pitch = TileGetTexturePitch(transfer_format, width, levels, rt.attrib3.tile_mode); + pitch = TileGetTexturePitch(transfer_format, width, rt.attrib3.tile_mode); } else if (standard64) { pitch = TileGetTexturePitch(Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float), - width, levels, rt.attrib3.tile_mode); + width, rt.attrib3.tile_mode); } else { pitch = TileGetRenderTargetPitch(width, bytes_per_element, rt.attrib.num_fragments); } @@ -192,13 +192,20 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, RenderCommandB pitch = width; } - TileSizeOffset mip_sizes[16] {}; - TilePaddedSize mip_padded[16] {}; - TileVolumeLayout volume_layout {}; - uint64_t backing_size = 0; + TileSizeOffset mip_sizes[16] {}; + TilePaddedSize mip_padded[16] {}; + TileSurfaceLayout volume_layout {}; + uint64_t backing_size = 0; if (volume) { - if (!tile || !TileGetTextureVolumeLayout(transfer_format, width, height, depth, levels, - rt.attrib3.tile_mode, volume_layout)) { + const TileSurfaceDescription description {transfer_format, + rt.attrib3.tile_mode, + TileSurfaceDimension::Dim3D, + width, + height, + depth, + levels, + 1}; + if (!tile || !TileGetTiledTextureLayout(description, volume_layout)) { EXIT("unsupported 3D render-target layout: %ux%ux%u levels=%u tile=%u\n", width, height, depth, levels, rt.attrib3.tile_mode); } @@ -209,7 +216,7 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, RenderCommandB bool valid_layout = false; if (standard64) { TileGetTextureSize(Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float), width, - height, pitch, levels, rt.attrib3.tile_mode, &layout, mip_sizes, + height, levels, rt.attrib3.tile_mode, &layout, mip_sizes, mip_padded); valid_layout = layout.size != 0 && layout.align == 65536; } else { @@ -289,11 +296,12 @@ void RenderExecutor::ResolveRenderColorTarget(uint64_t submit_id, RenderCommandB desc.info.tile_mode = rt.attrib3.tile_mode; for (uint32_t level = 0; level < levels; level++) { if (volume) { + const auto& mip = volume_layout.mips[level]; desc.info.mip_layout[level] = { - volume_layout.level_offsets[level], - volume_layout.level_sizes[level], - volume_layout.level_widths[level], - volume_layout.level_heights[level], + mip.offset, + mip.size, + mip.padded_width, + mip.padded_height, }; continue; } diff --git a/src/graphics/host_gpu/renderer/image/textureCommon.cpp b/src/graphics/host_gpu/renderer/image/textureCommon.cpp index 23be33316..3d318936c 100644 --- a/src/graphics/host_gpu/renderer/image/textureCommon.cpp +++ b/src/graphics/host_gpu/renderer/image/textureCommon.cpp @@ -168,14 +168,6 @@ RenderTargetFormatInfo TextureGetRenderTargetFormat(uint32_t raw_layout, uint32_ namespace { -static uint64_t GetLevelSrcOffset(const TileSizeOffset& level_size) { - return (level_size.src_size != 0 ? level_size.src_offset : level_size.offset); -} - -static uint64_t GetLevelSrcSize(const TileSizeOffset& level_size) { - return (level_size.src_size != 0 ? level_size.src_size : level_size.size); -} - static uint32_t GetTextureLevelDepth(uint32_t depth, uint32_t level, bool volume_texture) { return volume_texture ? std::max(depth >> level, 1u) : depth; } @@ -188,20 +180,6 @@ static size_t GetTextureRegionCount(uint32_t depth, uint64_t levels, bool volume return count; } -uint64_t TextureUploadSliceSourceOffset(const TextureUploadLayout& layout, uint32_t level, - uint32_t slice) { - if (level >= 16 || layout.level_sizes[level].size == 0) { - EXIT("invalid texture upload slice source, level=%u slice=%u\n", level, slice); - } - const auto level_offset = GetLevelSrcOffset(layout.level_sizes[level]); - const auto slice_stride = - layout.source_slice_stride != 0 ? layout.source_slice_stride : layout.slice_stride; - if (slice_stride != 0 && slice > (UINT64_MAX - level_offset) / slice_stride) { - EXIT("texture upload slice source offset overflow, level=%u slice=%u\n", level, slice); - } - return level_offset + static_cast(slice) * slice_stride; -} - vk::ComponentSwizzle TextureGetComponentSwizzle(uint8_t s) { switch (static_cast(s)) { case Prospero::CompSwizzle::kZero: return vk::ComponentSwizzle::eZero; @@ -241,12 +219,11 @@ vk::Format TextureGetFormat(uint32_t fmt) { namespace { -uint64_t CalcTextureSliceStride(const TileSizeOffset* level_sizes, uint64_t levels, +uint64_t CalcTextureSliceStride(const TextureUploadMipLayout* mips, uint64_t levels, uint64_t total_size, uint32_t depth) { uint64_t stride = 0; for (uint32_t i = 0; i < levels; i++) { - stride = - std::max(stride, static_cast(level_sizes[i].offset) + level_sizes[i].size); + stride = std::max(stride, mips[i].offset + mips[i].size); } if (depth > 1 && total_size != 0 && total_size % depth == 0) { @@ -259,39 +236,26 @@ uint64_t CalcTextureSliceStride(const TileSizeOffset* level_sizes, uint64_t leve return stride; } -uint64_t CalcLinearUploadLevelSize(uint32_t fmt, uint32_t pitch, uint32_t height) { - if (const uint32_t bytes_per_element = Prospero::NumBytesPerElement(fmt); - bytes_per_element != 0) { - return static_cast(pitch) * height * bytes_per_element; - } - - if (const uint32_t bytes_per_block = Prospero::BlockCompressedBytesPerBlock(fmt); - bytes_per_block != 0) { - const uint32_t blocks_w = std::max((pitch + 3u) / 4u, 1u); - const uint32_t blocks_h = std::max((height + 3u) / 4u, 1u); - return static_cast(blocks_w) * blocks_h * bytes_per_block; - } - - return 0; +uint64_t CalcLinearUploadLevelSize(const TileTextureElementLayout& element, uint32_t pitch, + uint32_t height) { + const uint32_t elements_w = + std::max((pitch + element.texel_width - 1u) / element.texel_width, 1u); + const uint32_t elements_h = + std::max((height + element.texel_height - 1u) / element.texel_height, 1u); + return static_cast(elements_w) * elements_h * element.bytes; } -uint64_t SetLinearUploadLevels(TileSizeOffset* level_sizes, uint32_t fmt, uint64_t height, +uint64_t SetLinearUploadLevels(TextureUploadMipLayout* mips, + const TileTextureElementLayout& element, uint64_t height, uint64_t levels, uint32_t base_pitch) { uint64_t offset = 0; auto pitch = base_pitch; auto h = static_cast(height); for (uint32_t i = 0; i < levels; i++) { - const auto size = CalcLinearUploadLevelSize(fmt, pitch, h); - EXIT_NOT_IMPLEMENTED(size > 0xffffffffull); - EXIT_NOT_IMPLEMENTED(offset > 0xffffffffull); - - level_sizes[i].size = static_cast(size); - level_sizes[i].offset = static_cast(offset); - level_sizes[i].src_size = 0; - level_sizes[i].src_offset = 0; - level_sizes[i].x = 0; - level_sizes[i].y = 0; + const auto size = CalcLinearUploadLevelSize(element, pitch, h); + mips[i].size = size; + mips[i].offset = offset; offset += size; if (pitch > 1) { @@ -307,141 +271,123 @@ uint64_t SetLinearUploadLevels(TileSizeOffset* level_sizes, uint32_t fmt, uint64 } // namespace -TextureUploadLayout TextureCalcUploadLayout(uint32_t fmt, uint64_t width, uint64_t height, - uint64_t levels, uint32_t depth, uint64_t pitch, - uint64_t tile, uint64_t upload_size, - bool allow_depth_tile, bool volume_texture, - const char* owner) { +TextureUploadLayout TextureCalcUploadLayout(uint32_t fmt, uint32_t width, uint32_t height, + uint32_t levels, uint32_t depth, uint32_t tile, + uint64_t upload_size, bool allow_depth_tile, + bool volume_texture, const char* owner) { TextureUploadLayout layout {}; - layout.tile = static_cast(tile); - layout.pitch = static_cast(pitch); - layout.texel_block = Prospero::BlockCompressedBytesPerBlock(fmt) != 0 ? 4u : 1u; - layout.volume_texture = volume_texture; + layout.surface.description = { + fmt, + tile, + volume_texture ? TileSurfaceDimension::Dim3D : TileSurfaceDimension::Dim2D, + width, + height, + volume_texture ? depth : 1u, + levels, + volume_texture ? 1u : depth, + }; + const auto& description = layout.surface.description; + const auto tile_mode = static_cast(description.tile_mode); + TileTextureElementLayout element {}; - if (fmt != 0) { - if (layout.tile != 0) { - const auto tile_mode = static_cast(layout.tile); - switch (tile_mode) { - case Prospero::TileMode::kStandard256B: - if (TileIsStandard256BTextureSupported(fmt)) { - layout.tile_family = TileBlockFamily::Standard256B; - } - break; - case Prospero::TileMode::kStandard4KB: - if (TileIsStandard4KBTextureSupported(fmt)) { - layout.tile_family = TileBlockFamily::Standard4KB; - } - break; - case Prospero::TileMode::kStandard64KB: - if (TileIsStandard64KBTextureSupported(fmt)) { - layout.tile_family = TileBlockFamily::Standard64KB; - } - break; - case Prospero::TileMode::kPrt: - if (TileIsStandard64KBTextureSupported(fmt)) { - layout.tile_family = TileBlockFamily::Prt64KB; - } - break; - case Prospero::TileMode::kRenderTarget: - if (Prospero::RenderTargetBytesPerElement(fmt) != 0) { - layout.tile_family = TileBlockFamily::RenderTarget64KB; - } - break; - case Prospero::TileMode::kDepth: - if (allow_depth_tile && Prospero::RenderTargetBytesPerElement(fmt) != 0) { - layout.tile_family = TileBlockFamily::Depth64KB; - } - break; - default: break; - } - if (layout.tile_family == TileBlockFamily::Count) { - EXIT("%s: unsupported typed tiled upload: fmt=%u tile=%u " - "size=%" PRIu64 " extent=%" PRIu64 "x%" PRIu64 " pitch=%" PRIu64 - " levels=%" PRIu64 "\n", - owner, static_cast(fmt), layout.tile, upload_size, width, height, - pitch, levels); - } - } - - layout.pitch = TileGetTexturePitch(fmt, width, levels, layout.tile); - - TileGetTextureSize(fmt, width, height, layout.pitch, levels, layout.tile, nullptr, - layout.level_sizes, layout.padded_sizes); - - if (static_cast(layout.tile) != Prospero::TileMode::kLinear) { - if (layout.volume_texture) { - layout.slice_stride = SetLinearUploadLevels(layout.level_sizes, fmt, height, levels, - static_cast(width)); - } else { - TileSizeOffset tiled_levels[16] {}; - std::copy_n(layout.level_sizes, levels, tiled_levels); - layout.source_slice_stride = - CalcTextureSliceStride(tiled_levels, levels, upload_size, depth); - SetLinearUploadLevels(layout.level_sizes, fmt, height, levels, layout.pitch); - for (uint32_t i = 0; i < levels; ++i) { - if (tiled_levels[i].src_size > tiled_levels[i].size) { - layout.first_tail_level = std::min(layout.first_tail_level, i); - } - layout.level_sizes[i].src_offset = GetLevelSrcOffset(tiled_levels[i]); - layout.level_sizes[i].src_size = GetLevelSrcSize(tiled_levels[i]); - layout.level_sizes[i].x = tiled_levels[i].x; - layout.level_sizes[i].y = tiled_levels[i].y; - } - } - } else if (layout.volume_texture) { - layout.slice_stride = - CalcTextureSliceStride(layout.level_sizes, levels, upload_size, depth); - } - } else { + if (fmt == 0) { EXIT("%s: legacy texture upload format unsupported: fmt=0 tile=%u size=%" PRIu64 - " extent=%" PRIu64 "x%" PRIu64 " pitch=%" PRIu64 " levels=%" PRIu64 "\n", - owner, layout.tile, upload_size, width, height, pitch, levels); + " extent=%ux%u levels=%u\n", + owner, description.tile_mode, upload_size, width, height, levels); } - if (!layout.volume_texture) { - layout.slice_stride = - CalcTextureSliceStride(layout.level_sizes, levels, upload_size, depth); + switch (tile_mode) { + case Prospero::TileMode::kLinear: + if (!TileGetTextureElementLayout(fmt, element)) { + EXIT("%s: unsupported linear texture format: fmt=%u\n", owner, fmt); + } + break; + case Prospero::TileMode::kDepth: + if (!allow_depth_tile || !TileGetTiledTextureLayout(description, layout.surface)) { + EXIT("%s: unsupported typed tiled upload: fmt=%u tile=%u " + "size=%" PRIu64 " extent=%ux%u levels=%u\n", + owner, static_cast(fmt), description.tile_mode, upload_size, width, + height, levels); + } + break; + default: + if (!TileGetTiledTextureLayout(description, layout.surface)) { + EXIT("%s: unsupported typed tiled upload: fmt=%u tile=%u " + "size=%" PRIu64 " extent=%ux%u levels=%u\n", + owner, static_cast(fmt), description.tile_mode, upload_size, width, + height, levels); + } + break; + } + + if (tile_mode != Prospero::TileMode::kLinear) { + element = {layout.surface.texture.block.bytes_per_element, + layout.surface.texture.texel_width, layout.surface.texture.texel_height}; + } + layout.pitch = TileGetTexturePitch(fmt, width, description.tile_mode); + if (tile_mode == Prospero::TileMode::kLinear) { + TileSizeOffset level_sizes[16] {}; + TilePaddedSize padded_sizes[16] {}; + TileGetTextureSize(fmt, width, height, levels, description.tile_mode, nullptr, level_sizes, + padded_sizes); + for (uint32_t level = 0; level < levels; ++level) { + layout.mips[level] = {level_sizes[level].offset, level_sizes[level].size, + padded_sizes[level].width, padded_sizes[level].height}; + } + } else if (volume_texture) { + layout.slice_stride = SetLinearUploadLevels(layout.mips, element, height, levels, width); + } else { + layout.source_slice_stride = layout.surface.block_slice_size; + if (depth > 1 && upload_size != 0 && upload_size % depth == 0) { + layout.source_slice_stride = std::max(layout.source_slice_stride, upload_size / depth); + } + SetLinearUploadLevels(layout.mips, element, height, levels, layout.pitch); + } + + if (!volume_texture || tile_mode == Prospero::TileMode::kLinear) { + layout.slice_stride = CalcTextureSliceStride(layout.mips, levels, upload_size, depth); } return layout; } -std::vector TextureBuildImageCopies(const TextureUploadLayout& layout, - uint32_t width, uint32_t height, - uint32_t depth, uint64_t levels, - bool array_texture, bool volume_texture) { - uint32_t mip_width = width; - uint32_t mip_height = height; - uint32_t mip_pitch = volume_texture && static_cast(layout.tile) != - Prospero::TileMode::kLinear - ? width - : layout.pitch; +std::vector TextureBuildImageCopies(const TextureUploadLayout& layout) { + const auto& description = layout.surface.description; + const bool volume_texture = description.dimension == TileSurfaceDimension::Dim3D; + const auto depth = volume_texture ? description.depth : description.layers; + uint32_t mip_width = description.width; + uint32_t mip_height = description.height; + uint32_t mip_pitch = volume_texture && static_cast(description.tile_mode) != + Prospero::TileMode::kLinear + ? description.width + : layout.pitch; std::vector regions; - regions.reserve(GetTextureRegionCount(depth, levels, volume_texture)); - for (uint32_t i = 0; i < levels; i++) { - EXIT_NOT_IMPLEMENTED(layout.level_sizes[i].size == 0); + regions.reserve(GetTextureRegionCount(depth, description.levels, volume_texture)); + for (uint32_t i = 0; i < description.levels; i++) { + EXIT_NOT_IMPLEMENTED(layout.mips[i].size == 0); const auto mip_depth = GetTextureLevelDepth(depth, i, volume_texture); for (uint32_t z = 0; z < mip_depth; z++) { const auto slice_offset = z * layout.slice_stride; vk::BufferImageCopy region {}; - region.bufferOffset = layout.level_sizes[i].offset + slice_offset; - region.imageSubresource = {vk::ImageAspectFlagBits::eColor, i, array_texture ? z : 0, + region.bufferOffset = layout.mips[i].offset + slice_offset; + region.imageSubresource = {vk::ImageAspectFlagBits::eColor, i, volume_texture ? 0u : z, 1}; region.imageOffset.z = volume_texture ? static_cast(z) : 0; region.imageExtent = {mip_width, mip_height, 1}; - const bool linear = - static_cast(layout.tile) == Prospero::TileMode::kLinear; + const bool linear = static_cast(description.tile_mode) == + Prospero::TileMode::kLinear; if (linear) { - region.bufferRowLength = layout.padded_sizes[i].width; - region.bufferImageHeight = layout.padded_sizes[i].height; + region.bufferRowLength = layout.mips[i].row_length; + region.bufferImageHeight = layout.mips[i].image_height; } else { - const auto align = [](uint32_t value, uint32_t block) { + const auto texel_width = layout.surface.texture.texel_width; + const auto align = [](uint32_t value, uint32_t block) { return ((value + block - 1u) / block) * block; }; - const auto pitch = align(mip_pitch, layout.texel_block); - region.bufferRowLength = pitch > align(mip_width, layout.texel_block) ? pitch : 0; + const auto pitch = align(mip_pitch, texel_width); + region.bufferRowLength = pitch > align(mip_width, texel_width) ? pitch : 0; } regions.push_back(region); } @@ -460,24 +406,6 @@ std::vector TextureBuildImageCopies(const TextureUploadLayo return regions; } -struct GpuTileElementLayout { - uint32_t bytes = 0; - uint32_t wide = 1; - uint32_t tall = 1; -}; - -static bool GetGpuTileElementLayout(uint32_t fmt, GpuTileElementLayout& out) { - if (const auto bytes = Prospero::NumBytesPerElement(fmt); bytes != 0) { - out = {bytes, 1, 1}; - return true; - } - if (const auto bytes = Prospero::BlockCompressedBytesPerBlock(fmt); bytes != 0) { - out = {bytes, 4, 4}; - return true; - } - return false; -} - static bool SetGpuTileSize(uint64_t offset, uint64_t length, uint64_t capacity, uint64_t& size) { if (offset > capacity || length > capacity - offset) { return false; @@ -487,42 +415,32 @@ static bool SetGpuTileSize(uint64_t offset, uint64_t length, uint64_t capacity, } bool TextureBuildGpuTileInfos(uint64_t tiled_size, const std::vector& regions, - const TextureUploadLayout& layout, uint32_t fmt, uint32_t depth, - uint64_t levels, std::vector& out_infos) { + const TextureUploadLayout& layout, uint32_t levels, + std::vector& out_infos) { + const auto& description = layout.surface.description; + const bool volume_texture = description.dimension == TileSurfaceDimension::Dim3D; + const auto depth = volume_texture ? description.depth : description.layers; if (tiled_size == 0 || levels == 0 || levels > 16 || depth == 0 || - regions.size() != GetTextureRegionCount(depth, levels, layout.volume_texture) || - Prospero::IsFmaskTextureFormat(fmt)) { + regions.size() != GetTextureRegionCount(depth, levels, volume_texture) || + Prospero::IsFmaskTextureFormat(description.format)) { return false; } - GpuTileElementLayout element {}; - if (layout.tile_family == TileBlockFamily::RenderTarget64KB || - layout.tile_family == TileBlockFamily::Depth64KB) { - element.bytes = Prospero::RenderTargetBytesPerElement(fmt); - } else if (!GetGpuTileElementLayout(fmt, element)) { - return false; - } - if (element.bytes == 0) { + const auto& surface = layout.surface; + const auto& texture = surface.texture; + const auto& block = texture.block; + if (surface.description.levels < levels || block.bytes_per_element == 0 || + block.family == TileBlockFamily::Count) { return false; } std::vector infos; infos.reserve(regions.size()); - if (layout.volume_texture) { - TileVolumeLayout volume {}; - if (!TileGetTextureVolumeLayout(fmt, regions[0].imageExtent.width, - regions[0].imageExtent.height, depth, - static_cast(levels), layout.tile, volume)) { - return false; - } - element = {volume.bytes_per_element, volume.texel_width, volume.texel_height}; - TileBlockLayout block {}; - if (!TileGetBlockLayout(volume.family, element.bytes, block)) return false; - + if (volume_texture) { size_t region_base = 0; for (uint32_t level = 0; level < levels; ++level) { const uint32_t mip_depth = GetTextureLevelDepth(depth, level, true); - const bool tail = level >= volume.first_tail_level; + const bool tail = level >= surface.first_tail_level; const uint64_t linear_stride = layout.slice_stride; for (uint32_t z = 0; z < mip_depth; z += block.block_depth) { const uint32_t copy_depth = std::min(block.block_depth, mip_depth - z); @@ -537,50 +455,43 @@ bool TextureBuildGpuTileInfos(uint64_t tiled_size, const std::vector(z / block.block_depth) * volume.block_slice_size + - volume.level_offsets[level]; + static_cast(z / block.block_depth) * surface.block_slice_size + + surface.mips[level].offset; const uint64_t linear_span = static_cast(copy_depth - 1u) * linear_stride + - layout.level_sizes[level].size; + layout.mips[level].size; if (!SetGpuTileSize(info.linear_offset, linear_span, UINT64_MAX, info.linear_size) || - !SetGpuTileSize(info.tiled_offset, volume.level_sizes[level], tiled_size, + !SetGpuTileSize(info.tiled_offset, surface.mips[level].size, tiled_size, info.tiled_size)) { return false; } info.linear_slice_stride = linear_stride; - info.width = - std::max((region.imageExtent.width + element.wide - 1u) / element.wide, 1u); - info.height = std::max((logical_height + element.tall - 1u) / element.tall, 1u); - info.depth = copy_depth; + info.width = std::max((region.imageExtent.width + texture.texel_width - 1u) / + texture.texel_width, + 1u); + info.height = std::max( + (logical_height + texture.texel_height - 1u) / texture.texel_height, 1u); + info.depth = copy_depth; info.surface_z = block.block_depth == 1 ? static_cast(region.imageOffset.z) : 0; - info.pitch = std::max((pitch + element.wide - 1u) / element.wide, 1u); - info.tail_x = tail ? volume.tail_x[level] : 0; - info.tail_y = tail ? volume.tail_y[level] : 0; + info.pitch = std::max((pitch + texture.texel_width - 1u) / texture.texel_width, 1u); + info.tail_x = tail ? surface.mips[level].tail_x : 0; + info.tail_y = tail ? surface.mips[level].tail_y : 0; info.tail = tail; - info.tiled_width = volume.level_widths[level]; - info.tiled_height = volume.level_heights[level]; + info.tiled_width = surface.mips[level].padded_width; + info.tiled_height = surface.mips[level].padded_height; infos.push_back(info); } region_base += mip_depth; } } else { - const auto base_family = layout.tile_family; - if (base_family == TileBlockFamily::Count) { - return false; - } - size_t region_index = 0; for (uint32_t level = 0; level < levels; level++) { - const auto& level_size = layout.level_sizes[level]; - const bool tail = level >= layout.first_tail_level; - const auto family = base_family; - TileBlockLayout block {}; - if (!TileGetBlockLayout(family, element.bytes, block)) { - return false; - } - const auto level_depth = GetTextureLevelDepth(depth, level, layout.volume_texture); + const auto& level_size = layout.mips[level]; + const auto& mip = surface.mips[level]; + const bool tail = level >= surface.first_tail_level; + const auto level_depth = GetTextureLevelDepth(depth, level, false); for (uint32_t z = 0; z < level_depth; z++) { const auto& region = regions[region_index++]; const auto pitch = @@ -589,39 +500,36 @@ bool TextureBuildGpuTileInfos(uint64_t tiled_size, const std::vector (UINT64_MAX - mip.offset) / source_stride) { return false; } - info.width = - std::max((region.imageExtent.width + element.wide - 1u) / element.wide, 1u); - info.height = std::max((logical_height + element.tall - 1u) / element.tall, 1u); - info.surface_z = base_family == TileBlockFamily::RenderTarget64KB || - base_family == TileBlockFamily::Depth64KB + info.tiled_offset = mip.offset + static_cast(z) * source_stride; + if (!SetGpuTileSize(info.linear_offset, level_size.size, UINT64_MAX, + info.linear_size) || + !SetGpuTileSize(info.tiled_offset, mip.size, tiled_size, info.tiled_size)) { + return false; + } + info.width = std::max((region.imageExtent.width + texture.texel_width - 1u) / + texture.texel_width, + 1u); + info.height = std::max( + (logical_height + texture.texel_height - 1u) / texture.texel_height, 1u); + info.surface_z = block.family == TileBlockFamily::RenderTarget64KB || + block.family == TileBlockFamily::Depth64KB ? region.imageSubresource.baseArrayLayer : 0; - info.pitch = std::max((pitch + element.wide - 1u) / element.wide, 1u); - info.tail = tail; - info.tail_x = tail ? level_size.x : 0; - info.tail_y = tail ? level_size.y : 0; - info.tiled_width = - layout.padded_sizes[level].width != 0 - ? std::max((layout.padded_sizes[level].width + element.wide - 1u) / - element.wide, - 1u) - : info.pitch; - info.tiled_height = - layout.padded_sizes[level].height != 0 - ? std::max((layout.padded_sizes[level].height + element.tall - 1u) / - element.tall, - 1u) - : info.height; + info.pitch = std::max((pitch + texture.texel_width - 1u) / texture.texel_width, 1u); + info.tail = tail; + info.tail_x = tail ? mip.tail_x : 0; + info.tail_y = tail ? mip.tail_y : 0; + info.tiled_width = mip.padded_width; + info.tiled_height = mip.padded_height; infos.push_back(info); } } diff --git a/src/graphics/host_gpu/renderer/image/textureCommon.h b/src/graphics/host_gpu/renderer/image/textureCommon.h index bca9b96d8..80ed3c98b 100644 --- a/src/graphics/host_gpu/renderer/image/textureCommon.h +++ b/src/graphics/host_gpu/renderer/image/textureCommon.h @@ -19,34 +19,32 @@ struct RenderTargetFormatInfo { Prospero::ColorComponentMapping export_mapping; }; +struct TextureUploadMipLayout { + uint64_t offset = 0; + uint64_t size = 0; + uint32_t row_length = 0; + uint32_t image_height = 0; +}; + struct TextureUploadLayout { - uint32_t tile = 0; - uint32_t pitch = 0; - uint32_t texel_block = 1; - uint64_t slice_stride = 0; - uint64_t source_slice_stride = 0; - uint32_t first_tail_level = 16; - TileBlockFamily tile_family = TileBlockFamily::Count; - bool volume_texture = false; - TileSizeOffset level_sizes[16] = {}; - TilePaddedSize padded_sizes[16] = {}; + uint32_t pitch = 0; + uint64_t slice_stride = 0; + uint64_t source_slice_stride = 0; + TileSurfaceLayout surface; + TextureUploadMipLayout mips[16] = {}; }; vk::ComponentMapping TextureGetComponentMapping(uint32_t swizzle); vk::Format TextureGetFormat(uint32_t fmt); RenderTargetFormatInfo TextureGetRenderTargetFormat(uint32_t layout, uint32_t type, uint32_t order); -TextureUploadLayout TextureCalcUploadLayout(uint32_t fmt, uint64_t width, uint64_t height, - uint64_t levels, uint32_t depth, uint64_t pitch, - uint64_t tile, uint64_t upload_size, - bool allow_depth_tile, bool volume_texture, - const char* owner); -std::vector TextureBuildImageCopies(const TextureUploadLayout& layout, - uint32_t width, uint32_t height, - uint32_t depth, uint64_t levels, - bool array_texture, bool volume_texture); +TextureUploadLayout TextureCalcUploadLayout(uint32_t fmt, uint32_t width, uint32_t height, + uint32_t levels, uint32_t depth, uint32_t tile, + uint64_t upload_size, bool allow_depth_tile, + bool volume_texture, const char* owner); +std::vector TextureBuildImageCopies(const TextureUploadLayout& layout); bool TextureBuildGpuTileInfos(uint64_t tiled_size, const std::vector& regions, - const TextureUploadLayout& layout, uint32_t fmt, uint32_t depth, - uint64_t levels, std::vector& infos); + const TextureUploadLayout& layout, uint32_t levels, + std::vector& infos); } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp b/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp index 10af3274d..52675038d 100644 --- a/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp +++ b/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp @@ -239,7 +239,7 @@ bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor, c const auto samples = multisampled ? 1u << descriptor.LastLevel() : 1u; const auto pitch = multisampled ? TileGetDepthPitch(width, image.info.bytes_per_block, descriptor.LastLevel()) - : TileGetTexturePitch(descriptor.Format(), width, 1, descriptor.TileMode()); + : TileGetTexturePitch(descriptor.Format(), width, descriptor.TileMode()); const bool supported_2d = type == Prospero::ImageType::kColor2D && image.info.resources.layers == 1 && descriptor.Depth() == 0 && descriptor.BaseArray5() == 0; @@ -321,7 +321,7 @@ static void ValidateDepthTargetBinding(const ShaderRecompiler::IR::ImageResource return; } const auto descriptor_pitch = - TileGetTexturePitch(descriptor.Format(), static_cast(descriptor.Width5()) + 1u, 1, + TileGetTexturePitch(descriptor.Format(), static_cast(descriptor.Width5()) + 1u, descriptor.TileMode()); EXIT("unsupported sampled depth target: resource=%d descriptor=%d encoding=%d format=%d " "kind=%u dimension=%u mip_mode=%u read=%d written=%d atomic=%d compare=%d " @@ -373,26 +373,33 @@ static bool IsSupportedStorageTextureDescriptor(const ShaderRecompiler::IR::Imag const bool is_3d = resource.dimension == ShaderRecompiler::Decoder::ImageDimension::Dim3D && descriptor.Type() == Prospero::GpuEnumValue(Prospero::ImageType::kColor3D) && descriptor.BaseArray5() == 0; - TileBlockLayout depth_block {}; - const auto depth_bpe = Prospero::RenderTargetBytesPerElement(descriptor.Format()); - const bool supported_depth_tile = - tile == Prospero::GpuEnumValue(Prospero::TileMode::kDepth) && !resource.read && - !Prospero::IsFmaskTextureFormat(descriptor.Format()) && (is_2d || is_2d_array) && - TileGetBlockLayout(TileBlockFamily::Depth64KB, depth_bpe, depth_block); - const bool supported_standard_256b = - (is_2d || is_2d_array) && - tile == Prospero::GpuEnumValue(Prospero::TileMode::kStandard256B) && - TileIsStandard256BTextureSupported(descriptor.Format()); - const bool supported_standard_tile = - (tile == Prospero::GpuEnumValue(Prospero::TileMode::kStandard4KB) && - TileIsStandard4KBTextureSupported(descriptor.Format())) || - (tile == Prospero::GpuEnumValue(Prospero::TileMode::kStandard64KB) && - TileIsStandard64KBTextureSupported(descriptor.Format())); - const bool supported_tile = tile == Prospero::GpuEnumValue(Prospero::TileMode::kLinear) || - tile == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) || - supported_depth_tile || supported_standard_256b || - supported_standard_tile; - const auto swizzle = descriptor.DstSelXYZW(); + TileTextureBlockLayout tile_layout {}; + bool supported_tile = false; + switch (static_cast(tile)) { + case Prospero::TileMode::kLinear: supported_tile = true; break; + case Prospero::TileMode::kDepth: + supported_tile = + !resource.read && !Prospero::IsFmaskTextureFormat(descriptor.Format()) && + (is_2d || is_2d_array) && + TileGetTextureBlockLayout(descriptor.Format(), tile, false, tile_layout); + break; + case Prospero::TileMode::kStandard256B: + supported_tile = + (is_2d || is_2d_array) && + TileGetTextureBlockLayout(descriptor.Format(), tile, false, tile_layout); + break; + case Prospero::TileMode::kStandard4KB: + case Prospero::TileMode::kStandard64KB: + supported_tile = + TileGetTextureBlockLayout(descriptor.Format(), tile, is_3d, tile_layout); + break; + case Prospero::TileMode::kRenderTarget: + supported_tile = + TileGetTextureBlockLayout(descriptor.Format(), tile, false, tile_layout); + break; + default: break; + } + const auto swizzle = descriptor.DstSelXYZW(); const bool supported_swizzle = IsValidImageSwizzle(swizzle) && (swizzle == DstSel(4, 5, 6, 7) || !resource.read || resource.atomic); @@ -498,18 +505,20 @@ static TextureCache::ImageDesc NullTextureDesc(const ShaderRecompiler::IR::Image static void PopulateTextureMipLayout(ImageInfo& info) { if (info.IsVolume() && info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kLinear)) { - TileVolumeLayout volume {}; - if (!TileGetTextureVolumeLayout(info.guest_format, info.extent.width, info.extent.height, - info.extent.depth, info.resources.levels, info.tile_mode, - volume)) { + TileSurfaceLayout surface {}; + const TileSurfaceDescription description { + info.guest_format, info.tile_mode, TileSurfaceDimension::Dim3D, info.extent.width, + info.extent.height, info.extent.depth, info.resources.levels, 1}; + if (!TileGetTiledTextureLayout(description, surface)) { EXIT("unsupported normalized volume texture layout\n"); } for (uint32_t level = 0; level < info.resources.levels; level++) { + const auto& mip = surface.mips[level]; info.mip_layout[level] = { - volume.level_offsets[level], - volume.level_sizes[level], - volume.level_widths[level], - volume.level_heights[level], + mip.offset, + mip.size, + mip.padded_width, + mip.padded_height, }; } return; @@ -517,7 +526,7 @@ static void PopulateTextureMipLayout(ImageInfo& info) { TileSizeOffset levels[16] {}; TilePaddedSize padded[16] {}; - TileGetTextureSize(info.guest_format, info.extent.width, info.extent.height, info.pitch, + TileGetTextureSize(info.guest_format, info.extent.width, info.extent.height, info.resources.levels, info.tile_mode, nullptr, levels, padded); for (uint32_t level = 0; level < info.resources.levels; level++) { const auto offset = @@ -675,9 +684,9 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& reso } size.size *= image_layers; } else { - pitch = TileGetTexturePitch(format, width, levels, tile); - TileGetTextureTotalSize(format, width, height, volume ? depth : image_layers, pitch, levels, - tile, volume, size); + pitch = TileGetTexturePitch(format, width, tile); + TileGetTextureTotalSize(format, width, height, volume ? depth : image_layers, levels, tile, + volume, size); } EXIT_NOT_IMPLEMENTED(size.size == 0 || size.align == 0 || (address & (static_cast(size.align) - 1u)) != 0); diff --git a/src/graphics/presentation/videoOut.cpp b/src/graphics/presentation/videoOut.cpp index ba4347a5a..eaa0fae24 100644 --- a/src/graphics/presentation/videoOut.cpp +++ b/src/graphics/presentation/videoOut.cpp @@ -537,10 +537,10 @@ Graphics::ImageInfo BufferAttributeGroup::ImageInfo(const VideoOutBuffer& buffer const auto tile_mode = Graphics::Prospero::GpuEnumValue(Graphics::Prospero::TileMode::kRenderTarget); const auto pitch = - Graphics::TileGetTexturePitch(pixel_format.guest_format, attribute.width, 1, tile_mode); + Graphics::TileGetTexturePitch(pixel_format.guest_format, attribute.width, tile_mode); Graphics::TileSizeAlign total {}; Graphics::TileGetTextureTotalSize(pixel_format.guest_format, attribute.width, attribute.height, - 1, pitch, 1, tile_mode, false, total); + 1, 1, tile_mode, false, total); if (total.size == 0 || total.align != 65536 || (buffer.data_address & (total.align - 1u)) != 0) { EXIT("invalid video-out surface footprint or alignment\n"); diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index e7022cc33..1afd57040 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -2970,11 +2970,11 @@ public: constexpr uint32_t mip_height = 1; constexpr uint32_t mip_levels = 1; const uint32_t mip_pitch = - TileGetTexturePitch(mip_format, mip_width, mip_levels, mip_tile); + TileGetTexturePitch(mip_format, mip_width, mip_tile); TileSizeAlign mip_total {}; std::array mip_sizes {}; std::array mip_padded {}; - TileGetTextureSize(mip_format, mip_width, mip_height, mip_pitch, mip_levels, mip_tile, + TileGetTextureSize(mip_format, mip_width, mip_height, mip_levels, mip_tile, &mip_total, mip_sizes.data(), mip_padded.data()); const uint64_t mip_prefix_size = mip_sizes[0].offset + mip_sizes[0].size; const uint64_t mip_guest_size = mip_total.size + 256; @@ -3866,11 +3866,10 @@ public: 0.625f, 0.75f, 0.875f, 1.0f, 0.0625f}; std::memset(memory + layered_offset, 0, layered_guest_size); const auto layered_layout = TextureCalcUploadLayout( - Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float), 2, 2, 2, 2, 2, + Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float), 2, 2, 2, 2, Prospero::GpuEnumValue(Prospero::TileMode::kLinear), layered_guest_size, true, false, "UnifiedTextureCacheFlow"); - const auto layered_upload_regions = - TextureBuildImageCopies(layered_layout, 2, 2, 2, 2, true, false); + const auto layered_upload_regions = TextureBuildImageCopies(layered_layout); Require(name, "layered guest layout", layered_upload_regions.size() == 4, "unexpected layered/mipped upload-region count"); for (const auto& region: layered_upload_regions) { @@ -5181,11 +5180,11 @@ public: { GpuResourceManager resources(m_runtime_context, scheduler); resources.MapMemory(base, allocation_size); - const uint32_t pitch = TileGetTexturePitch(format, 1, 1, tile); + const uint32_t pitch = TileGetTexturePitch(format, 1, tile); TileSizeAlign total {}; TileSizeOffset mip {}; TilePaddedSize padded {}; - TileGetTextureSize(format, 1, 1, pitch, 1, tile, &total, &mip, &padded); + TileGetTextureSize(format, 1, 1, 1, tile, &total, &mip, &padded); Require(name, "tiled layout", total.size >= 8 && total.size <= allocation_size, "BGRA16 tiled layout exceeds its guest allocation"); std::memset(mapped, 0x5a, total.size); @@ -5465,9 +5464,8 @@ public: constexpr auto stencil_format = Prospero::GpuEnumValue(Prospero::BufferFormat::k8UInt); constexpr auto linear = Prospero::GpuEnumValue(Prospero::TileMode::kLinear); - const auto stencil_pitch = TileGetTexturePitch(stencil_format, 1, 1, linear); TileSizeAlign stencil_layout {}; - TileGetTextureTotalSize(stencil_format, 1, 1, 1, stencil_pitch, 1, linear, false, + TileGetTextureTotalSize(stencil_format, 1, 1, 1, 1, linear, false, stencil_layout); Require(name, "stencil footprint", stencil_layout.size != 0 && stencil_layout.align != 0 && @@ -7717,7 +7715,7 @@ public: TileSizeAlign total {}; TileSizeOffset mip[levels] {}; TilePaddedSize padded[levels] {}; - TileGetTextureSize(format, 65, 33, 72, levels, + TileGetTextureSize(format, 65, 33, levels, Prospero::GpuEnumValue(Prospero::TileMode::kStandard256B), &total, mip, padded); constexpr u32 offsets[levels] = {0x1a00, 0xb00, 0x500, 0x300, 0x200, 0x100, 0}; @@ -7826,18 +7824,57 @@ public: struct StandardMode { u32 tile; TileBlockFamily family; - bool (*supported)(u32); }; constexpr StandardMode standard_modes[] = { {Prospero::GpuEnumValue(Prospero::TileMode::kStandard256B), - TileBlockFamily::Standard256B, TileIsStandard256BTextureSupported}, - {Prospero::GpuEnumValue(Prospero::TileMode::kStandard4KB), TileBlockFamily::Standard4KB, - TileIsStandard4KBTextureSupported}, + TileBlockFamily::Standard256B}, + {Prospero::GpuEnumValue(Prospero::TileMode::kStandard4KB), + TileBlockFamily::Standard4KB}, {Prospero::GpuEnumValue(Prospero::TileMode::kStandard64KB), - TileBlockFamily::Standard64KB, TileIsStandard64KBTextureSupported}, - {Prospero::GpuEnumValue(Prospero::TileMode::kPrt), TileBlockFamily::Prt64KB, - TileIsStandard64KBTextureSupported}, + TileBlockFamily::Standard64KB}, + {Prospero::GpuEnumValue(Prospero::TileMode::kPrt), TileBlockFamily::Prt64KB}, }; + for (const auto format: {Prospero::BufferFormat::k8Srgb, + Prospero::BufferFormat::k8_8Srgb, + Prospero::BufferFormat::k9_9_9_5Float}) { + for (const auto tile: {Prospero::TileMode::kDepth, + Prospero::TileMode::kRenderTarget}) { + TileTextureBlockLayout texture {}; + Require(name, "RT format policy", + !TileGetTextureBlockLayout(Prospero::GpuEnumValue(format), + Prospero::GpuEnumValue(tile), false, texture), + "non-render-target format admitted by an RT/depth tile family"); + } + } + { + TileSurfaceLayout invalid {}; + const TileSurfaceDescription description { + Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float), + Prospero::GpuEnumValue(Prospero::TileMode::kStandard256B), + TileSurfaceDimension::Dim3D, + 16, + 16, + 16, + 1, + 1, + }; + Require(name, "3D tile policy", !TileGetTiledTextureLayout(description, invalid), + "Standard256B volume silently fell back to a 2D array layout"); + } + { + constexpr u32 format = + Prospero::GpuEnumValue(Prospero::BufferFormat::kFmask8_S4_F4); + constexpr u32 tile = Prospero::GpuEnumValue(Prospero::TileMode::kStandard64KB); + TileSizeAlign total {}; + TileGetTextureSize(format, 128, 128, 1, tile, &total, nullptr, nullptr); + const auto layout = TextureCalcUploadLayout(format, 128, 128, 1, 1, tile, total.size, + false, false, name); + const auto regions = TextureBuildImageCopies(layout); + std::vector infos; + Require(name, "FMASK policy", + !TextureBuildGpuTileInfos(total.size, regions, layout, 1, infos), + "FMASK entered the texel tiler through a non-depth family"); + } u32 format_cases = 0; for (u32 format = 1; format <= Prospero::GpuEnumValue(Prospero::BufferFormat::kBc7Srgb); ++format) { @@ -7847,30 +7884,28 @@ public: continue; } for (const auto& mode: standard_modes) { - if (!mode.supported(format)) { + TileTextureBlockLayout texture {}; + if (!TileGetTextureBlockLayout(format, mode.tile, false, texture)) { continue; } - const u32 bpe = std::max(Prospero::NumBytesPerElement(format), - Prospero::BlockCompressedBytesPerBlock(format)); - TileBlockLayout block {}; - Require(name, "format block", TileGetBlockLayout(mode.family, bpe, block), - "CPU-supported format has no GPU family/BPE mapping"); + const u32 bpe = texture.block.bytes_per_element; + Require(name, "format block", texture.block.family == mode.family, + "CPU-supported format selected the wrong block family"); constexpr u32 width = 67; constexpr u32 height = 51; - const u32 pitch = TileGetTexturePitch(format, width, 1, mode.tile); + const u32 pitch = TileGetTexturePitch(format, width, mode.tile); TileSizeAlign total {}; - TileGetTextureSize(format, width, height, pitch, 1, mode.tile, &total, nullptr, + TileGetTextureSize(format, width, height, 1, mode.tile, &total, nullptr, nullptr); Require(name, "format size", total.size != 0, "supported format has an empty layout"); const auto layout = TextureCalcUploadLayout( - format, width, height, 1, 1, pitch, mode.tile, total.size, false, false, name); - const auto regions = - TextureBuildImageCopies(layout, width, height, 1, 1, false, false); + format, width, height, 1, 1, mode.tile, total.size, false, false, name); + const auto regions = TextureBuildImageCopies(layout); std::vector infos; - if (!TextureBuildGpuTileInfos(total.size, regions, layout, format, 1, 1, infos)) { + if (!TextureBuildGpuTileInfos(total.size, regions, layout, 1, infos)) { std::ostringstream out; out << "format=" << format << " tile=" << mode.tile << " size=" << total.size << " pitch=" << pitch; @@ -7894,27 +7929,31 @@ public: Require(name, "format coverage", format_cases != 0, "no CPU-supported standard formats were tested"); + { + constexpr u32 format = Prospero::GpuEnumValue(Prospero::BufferFormat::k32_32_32Float); + TileTextureElementLayout element {}; + Require(name, "RGB32 texture policy", !TileGetTextureElementLayout(format, element), + "12-byte texel layouts must be rejected"); + } + { constexpr u32 format = Prospero::GpuEnumValue(Prospero::BufferFormat::kBc1UNorm); constexpr u32 tile = Prospero::GpuEnumValue(Prospero::TileMode::kStandard64KB); constexpr u32 width = 256, height = 256, levels = 9; - const u32 pitch = TileGetTexturePitch(format, width, levels, tile); TileSizeAlign total {}; - TileGetTextureSize(format, width, height, pitch, levels, tile, &total, nullptr, + TileGetTextureSize(format, width, height, levels, tile, &total, nullptr, nullptr); - const auto layout = TextureCalcUploadLayout(format, width, height, levels, 1, pitch, - tile, total.size, false, false, name); - const auto regions = - TextureBuildImageCopies(layout, width, height, 1, levels, false, false); + const auto layout = TextureCalcUploadLayout(format, width, height, levels, 1, tile, + total.size, false, false, name); + const auto regions = TextureBuildImageCopies(layout); std::vector infos; - const bool built = - TextureBuildGpuTileInfos(total.size, regions, layout, format, 1, levels, infos); + const bool built = TextureBuildGpuTileInfos(total.size, regions, layout, levels, infos); uint64_t linear_size = 0; for (const auto& info: infos) { linear_size = std::max(linear_size, info.linear_offset + info.linear_size); } Require(name, "BC1 mip-tail capacities", - built && total.size == 0x10000 && layout.first_tail_level == 0 && + built && total.size == 0x10000 && layout.surface.first_tail_level == 0 && linear_size == 0x15560 && linear_size > total.size, "BC1 mip tail conflated tiled and linear capacities"); check_round_trip("BC1 mip tail", total.size, infos); @@ -7924,16 +7963,13 @@ public: constexpr u32 format = Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float); constexpr u32 tile = Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget); constexpr u32 width = 129, height = 65, layers = 3; - const u32 pitch = TileGetTexturePitch(format, width, 1, tile); TileSizeAlign total {}; - TileGetTextureTotalSize(format, width, height, layers, pitch, 1, tile, false, total); - const auto layout = TextureCalcUploadLayout(format, width, height, 1, layers, pitch, - tile, total.size, true, false, name); - const auto regions = - TextureBuildImageCopies(layout, width, height, layers, 1, true, false); + TileGetTextureTotalSize(format, width, height, layers, 1, tile, false, total); + const auto layout = TextureCalcUploadLayout(format, width, height, 1, layers, tile, + total.size, true, false, name); + const auto regions = TextureBuildImageCopies(layout); std::vector infos; - const bool built = - TextureBuildGpuTileInfos(total.size, regions, layout, format, layers, 1, infos); + const bool built = TextureBuildGpuTileInfos(total.size, regions, layout, 1, infos); Require(name, "array infos", built && infos.size() == layers && infos[0].surface_z == 0 && infos[1].surface_z == 1 && infos[2].surface_z == 2, @@ -7949,18 +7985,16 @@ public: "odd multi-mip format has no block layout"); const u32 width = block.block_width * 2u + 1u; const u32 height = block.block_height * 2u + 1u; - const u32 pitch = TileGetTexturePitch(format, width, levels, mode.tile); TileSizeAlign total {}; - TileGetTextureSize(format, width, height, pitch, levels, mode.tile, &total, nullptr, + TileGetTextureSize(format, width, height, levels, mode.tile, &total, nullptr, nullptr); - const auto layout = TextureCalcUploadLayout(format, width, height, levels, 1, pitch, - mode.tile, total.size, false, false, name); - const auto regions = - TextureBuildImageCopies(layout, width, height, 1, levels, false, false); + const auto layout = TextureCalcUploadLayout(format, width, height, levels, 1, mode.tile, + total.size, false, false, name); + const auto regions = TextureBuildImageCopies(layout); std::vector infos; Require( name, "odd mip infos", - TextureBuildGpuTileInfos(total.size, regions, layout, format, 1, levels, infos) && + TextureBuildGpuTileInfos(total.size, regions, layout, levels, infos) && infos.size() == 2 && infos[1].tiled_width >= infos[1].pitch && infos[1].tiled_height >= infos[1].height && (mode.family == TileBlockFamily::Standard256B || @@ -7992,19 +8026,16 @@ public: "2D tail mode has no block layout"); const u32 width = block.block_width * 2u; const u32 height = block.block_height * 2u; - const u32 pitch = TileGetTexturePitch(format, width, levels, mode.tile); TileSizeAlign total {}; - TileGetTextureSize(format, width, height, pitch, levels, mode.tile, &total, nullptr, + TileGetTextureSize(format, width, height, levels, mode.tile, &total, nullptr, nullptr); - const auto layout = TextureCalcUploadLayout(format, width, height, levels, 1, pitch, - mode.tile, total.size, true, false, name); - const auto regions = - TextureBuildImageCopies(layout, width, height, 1, levels, false, false); + const auto layout = TextureCalcUploadLayout(format, width, height, levels, 1, mode.tile, + total.size, true, false, name); + const auto regions = TextureBuildImageCopies(layout); std::vector infos; Require(name, "2D mip tail seam", - layout.first_tail_level == 2 && - TextureBuildGpuTileInfos(total.size, regions, layout, format, 1, levels, - infos) && + layout.surface.first_tail_level == 2 && + TextureBuildGpuTileInfos(total.size, regions, layout, levels, infos) && infos.size() == levels && !infos[0].tail && !infos[1].tail && std::all_of(infos.begin() + 2, infos.end(), [](const auto& info) { return info.tail; }), @@ -8019,16 +8050,13 @@ public: constexpr u32 height = 129; constexpr u32 depth = 17; constexpr u32 levels = 2; - const u32 pitch = TileGetTexturePitch(format, width, levels, tile); TileSizeAlign total {}; - TileGetTextureTotalSize(format, width, height, depth, pitch, levels, tile, true, total); - const auto layout = TextureCalcUploadLayout(format, width, height, levels, depth, pitch, - tile, total.size, false, true, name); - const auto regions = - TextureBuildImageCopies(layout, width, height, depth, levels, false, true); + TileGetTextureTotalSize(format, width, height, depth, levels, tile, true, total); + const auto layout = TextureCalcUploadLayout(format, width, height, levels, depth, tile, + total.size, false, true, name); + const auto regions = TextureBuildImageCopies(layout); std::vector infos; - const bool built = - TextureBuildGpuTileInfos(total.size, regions, layout, format, depth, levels, infos); + const bool built = TextureBuildGpuTileInfos(total.size, regions, layout, levels, infos); Require(name, "3D mip infos", regions.size() == depth + (depth >> 1u) && built && infos.size() == 4 && infos[0].depth == 8 && infos[1].depth == 8 && infos[2].depth == 1 && @@ -8048,17 +8076,14 @@ public: constexpr u32 height = 129; constexpr u32 depth = 17; constexpr u32 levels = 2; - const u32 pitch = TileGetTexturePitch(format, width, levels, tile); TileSizeAlign total {}; - TileGetTextureTotalSize(format, width, height, depth, pitch, levels, tile, true, total); - const auto layout = TextureCalcUploadLayout(format, width, height, levels, depth, pitch, - tile, total.size, false, true, name); - const auto regions = - TextureBuildImageCopies(layout, width, height, depth, levels, false, true); + TileGetTextureTotalSize(format, width, height, depth, levels, tile, true, total); + const auto layout = TextureCalcUploadLayout(format, width, height, levels, depth, tile, + total.size, false, true, name); + const auto regions = TextureBuildImageCopies(layout); std::vector infos; Require(name, "3D BC mip infos", - TextureBuildGpuTileInfos(total.size, regions, layout, format, depth, levels, - infos) && + TextureBuildGpuTileInfos(total.size, regions, layout, levels, infos) && infos.size() == 4 && infos[3].pitch == 8 && infos[3].height == 16 && infos[3].tiled_width == 16 && infos[3].tiled_height == 24, "block-compressed 3D mip lost its physical row or slice stride"); @@ -8069,14 +8094,12 @@ public: constexpr u32 format = Prospero::GpuEnumValue(Prospero::BufferFormat::kBc3UNorm); constexpr u32 tile = Prospero::GpuEnumValue(Prospero::TileMode::kLinear); constexpr u32 width = 8, height = 8, levels = 4; - const u32 pitch = TileGetTexturePitch(format, width, levels, tile); TileSizeAlign total {}; - TileGetTextureSize(format, width, height, pitch, levels, tile, &total, nullptr, + TileGetTextureSize(format, width, height, levels, tile, &total, nullptr, nullptr); - const auto layout = TextureCalcUploadLayout(format, width, height, levels, 1, pitch, - tile, total.size, false, false, name); - const auto regions = - TextureBuildImageCopies(layout, width, height, 1, levels, false, false); + const auto layout = TextureCalcUploadLayout(format, width, height, levels, 1, tile, + total.size, false, false, name); + const auto regions = TextureBuildImageCopies(layout); Require(name, "linear BC native regions", regions.size() == levels && std::all_of(regions.begin(), regions.end(), @@ -8114,18 +8137,15 @@ public: }; for (const auto test: volume_modes) { constexpr u32 width = 65, height = 33, depth = 37, levels = 6; - const u32 pitch = TileGetTexturePitch(test.format, width, levels, test.tile); TileSizeAlign total {}; - TileGetTextureTotalSize(test.format, width, height, depth, pitch, levels, test.tile, - true, total); + TileGetTextureTotalSize(test.format, width, height, depth, levels, test.tile, true, + total); const auto layout = - TextureCalcUploadLayout(test.format, width, height, levels, depth, pitch, test.tile, + TextureCalcUploadLayout(test.format, width, height, levels, depth, test.tile, total.size, true, true, name); - const auto regions = - TextureBuildImageCopies(layout, width, height, depth, levels, false, true); + const auto regions = TextureBuildImageCopies(layout); std::vector infos; - const bool built = TextureBuildGpuTileInfos(total.size, regions, layout, test.format, - depth, levels, infos); + const bool built = TextureBuildGpuTileInfos(total.size, regions, layout, levels, infos); const bool uses_z = test.family == TileBlockFamily::RenderTarget64KB || test.family == TileBlockFamily::Depth64KB; Require( @@ -8168,21 +8188,18 @@ public: const u32 width = block.block_width * (compressed ? 4u : 1u); const u32 height = block.block_height / 2u * (compressed ? 4u : 1u); const u32 depth = block.block_depth + 1u; - const u32 pitch = TileGetTexturePitch(tail.format, width, levels, tile); TileSizeAlign total {}; - TileGetTextureTotalSize(tail.format, width, height, depth, pitch, levels, tile, true, + TileGetTextureTotalSize(tail.format, width, height, depth, levels, tile, true, total); const auto layout = TextureCalcUploadLayout(tail.format, width, height, levels, depth, - pitch, tile, total.size, false, true, name); - const auto regions = - TextureBuildImageCopies(layout, width, height, depth, levels, false, true); + tile, total.size, false, true, name); + const auto regions = TextureBuildImageCopies(layout); std::vector infos; bool valid = total.size == 8192 && regions.size() == depth + std::max(depth >> 1u, 1u) + std::max(depth >> 2u, 1u) + std::max(depth >> 3u, 1u) + std::max(depth >> 4u, 1u) && - TextureBuildGpuTileInfos(total.size, regions, layout, tail.format, depth, levels, - infos) && + TextureBuildGpuTileInfos(total.size, regions, layout, levels, infos) && infos.size() == 6; const u32 table = std::countr_zero(tail.bytes); for (u32 level = 0; level < levels && valid; level++) { @@ -8280,15 +8297,14 @@ public: constexpr u32 volume_width = 8, volume_height = 4, volume_depth = 5; constexpr u32 volume_levels = 3; const u32 volume_pitch = - TileGetTexturePitch(volume_format, volume_width, volume_levels, volume_tile); + TileGetTexturePitch(volume_format, volume_width, volume_tile); TileSizeAlign volume_size {}; TileGetTextureTotalSize(volume_format, volume_width, volume_height, volume_depth, - volume_pitch, volume_levels, volume_tile, true, volume_size); + volume_levels, volume_tile, true, volume_size); const auto volume_layout = TextureCalcUploadLayout( - volume_format, volume_width, volume_height, volume_levels, volume_depth, volume_pitch, - volume_tile, volume_size.size, true, true, name); - const auto volume_copies = TextureBuildImageCopies( - volume_layout, volume_width, volume_height, volume_depth, volume_levels, false, true); + volume_format, volume_width, volume_height, volume_levels, volume_depth, volume_tile, + volume_size.size, true, true, name); + const auto volume_copies = TextureBuildImageCopies(volume_layout); std::vector volume_source(volume_size.size / sizeof(u32), 0); std::vector> volume_probes; for (const auto& copy: volume_copies) { @@ -8323,9 +8339,10 @@ public: volume_info.bytes_per_block = sizeof(u32); volume_info.tile_mode = volume_tile; for (u32 level = 0; level < volume_levels; level++) { - volume_info.mip_layout[level] = { - volume_layout.level_sizes[level].offset, volume_layout.level_sizes[level].size, - volume_layout.padded_sizes[level].width, volume_layout.padded_sizes[level].height}; + volume_info.mip_layout[level] = {volume_layout.mips[level].offset, + volume_layout.mips[level].size, + volume_layout.mips[level].row_length, + volume_layout.mips[level].image_height}; } Libs::Graphics::Image volume_image(m_runtime_context, scheduler, volume_info); volume_image.Upload(volume_copies, volume_upload.buffer, 0, volume_size.size); @@ -16988,12 +17005,10 @@ void CheckBasicStorageTextureDescriptor() { }}; auto standard256b_resource = BasicBgraStorageTextureResource(); standard256b_resource.kind = ShaderRecompiler::IR::ResourceKind::StorageImageUint; - const auto standard256b_pitch = TileGetTexturePitch( - standard256b.Format(), standard256b.Width5() + 1u, 1, standard256b.TileMode()); TileSizeAlign standard256b_size {}; TileGetTextureTotalSize(standard256b.Format(), standard256b.Width5() + 1u, standard256b.Height5() + 1u, standard256b.Depth() + 1u, - standard256b_pitch, 1, standard256b.TileMode(), false, + 1, standard256b.TileMode(), false, standard256b_size); Require("BasicStorageTexture", "Standard256B uint 2D descriptor", standard256b.Width5() + 1u == 2 && standard256b.Height5() + 1u == 2 && @@ -17009,10 +17024,8 @@ void CheckBasicStorageTextureDescriptor() { ValidateStorageTexture(standard256b_resource, standard256b, standard256b_size.size); const auto standard4kb_array = Standard4KBUintArrayStorageTextureDescriptor(); - const auto standard4kb_pitch = - TileGetTexturePitch(standard4kb_array.Format(), 1, 1, standard4kb_array.TileMode()); TileSizeAlign standard4kb_size {}; - TileGetTextureTotalSize(standard4kb_array.Format(), 1, 1, 1, standard4kb_pitch, 1, + TileGetTextureTotalSize(standard4kb_array.Format(), 1, 1, 1, 1, standard4kb_array.TileMode(), false, standard4kb_size); Require( "BasicStorageTexture", "Standard4KB uint 2D-array descriptor", @@ -17029,11 +17042,9 @@ void CheckBasicStorageTextureDescriptor() { auto based_standard4kb_array = standard4kb_array; based_standard4kb_array.fields[0] = 0x006c6800u; based_standard4kb_array.fields[4] = 0x00010001u; - const auto based_standard4kb_pitch = TileGetTexturePitch(based_standard4kb_array.Format(), 1, 1, - based_standard4kb_array.TileMode()); TileSizeAlign based_standard4kb_size {}; TileGetTextureTotalSize(based_standard4kb_array.Format(), 1, 1, - based_standard4kb_array.Depth() + 1u, based_standard4kb_pitch, 1, + based_standard4kb_array.Depth() + 1u, 1, based_standard4kb_array.TileMode(), false, based_standard4kb_size); Require("BasicStorageTexture", "based Standard4KB array view", based_standard4kb_array.Base40() == 0x6c680000ull && @@ -17044,12 +17055,10 @@ void CheckBasicStorageTextureDescriptor() { based_standard4kb_size.size); const auto standard64kb = Standard64KBStorageTextureDescriptor(); - const auto standard64kb_pitch = TileGetTexturePitch( - standard64kb.Format(), standard64kb.Width5() + 1u, 1, standard64kb.TileMode()); TileSizeAlign standard64kb_size {}; TileGetTextureTotalSize(standard64kb.Format(), standard64kb.Width5() + 1u, standard64kb.Height5() + 1u, standard64kb.Depth() + 1u, - standard64kb_pitch, 1, standard64kb.TileMode(), false, + 1, standard64kb.TileMode(), false, standard64kb_size); Require("BasicStorageTexture", "Standard64KB 2D descriptor", standard64kb.Type() == Prospero::GpuEnumValue(Prospero::ImageType::kColor2DArray) && @@ -17109,11 +17118,11 @@ void CheckBasicStorageTextureDescriptor() { d16_depth_tile.DstSelXYZW() == DstSel(4, 0, 0, 1), "PPSA10112 writable D16 depth-plane descriptor fixture is malformed"); const auto d16_pitch = TileGetTexturePitch( - d16_depth_tile.Format(), d16_depth_tile.Width5() + 1u, 1, d16_depth_tile.TileMode()); + d16_depth_tile.Format(), d16_depth_tile.Width5() + 1u, d16_depth_tile.TileMode()); TileSizeAlign d16_size {}; TileGetTextureTotalSize(d16_depth_tile.Format(), d16_depth_tile.Width5() + 1u, - d16_depth_tile.Height5() + 1u, d16_depth_tile.Depth() + 1u, d16_pitch, - 1, d16_depth_tile.TileMode(), false, d16_size); + d16_depth_tile.Height5() + 1u, d16_depth_tile.Depth() + 1u, 1, + d16_depth_tile.TileMode(), false, d16_size); Require("BasicStorageTexture", "PPSA10112 D16 depth-tile footprint", d16_pitch == 256 && d16_size.size == 0x20000 && d16_size.align == 0x10000, "PPSA10112 writable D16 depth-plane footprint is incorrect"); @@ -17191,16 +17200,17 @@ void CheckStorageTextureLinearUploadLayout() { constexpr uint32_t height = 2160; constexpr uint32_t depth = 1; constexpr uint32_t tile = Prospero::GpuEnumValue(Prospero::TileMode::kLinear); - const auto pitch = TileGetTexturePitch(format, width, 1, tile); + const auto pitch = TileGetTexturePitch(format, width, tile); TileSizeAlign total {}; - TileGetTextureTotalSize(format, width, height, depth, pitch, 1, tile, false, total); + TileGetTextureTotalSize(format, width, height, depth, 1, tile, false, total); const auto layout = - TextureCalcUploadLayout(format, width, height, 1, depth, pitch, tile, total.size, true, + TextureCalcUploadLayout(format, width, height, 1, depth, tile, total.size, true, false, "StorageTextureLinearTest"); - const auto regions = TextureBuildImageCopies(layout, width, height, depth, 1, false, false); + const auto regions = TextureBuildImageCopies(layout); Require("StorageTextureLinearUpload", "layout", pitch == width && total.size == 0x1fa4000 && total.align == 256 && - layout.tile == tile && layout.pitch == width && layout.slice_stride == total.size && + layout.surface.description.tile_mode == tile && layout.pitch == width && + layout.slice_stride == total.size && regions.size() == 1 && regions[0].bufferOffset == 0 && regions[0].imageExtent.width == width && regions[0].imageExtent.height == height && regions[0].bufferRowLength == width, @@ -17214,25 +17224,27 @@ void CheckStorageTextureDepthTileUploadLayout() { constexpr uint32_t height = 1; constexpr uint32_t depth = 1; constexpr uint32_t tile = Prospero::GpuEnumValue(Prospero::TileMode::kDepth); - const auto pitch = TileGetTexturePitch(format, width, 1, tile); + const auto pitch = TileGetTexturePitch(format, width, tile); TileSizeAlign slice {}; TileSizeAlign total {}; TileSizeOffset level {}; TilePaddedSize padded {}; - TileGetTextureSize(format, width, height, pitch, 1, tile, &slice, &level, &padded); - TileGetTextureTotalSize(format, width, height, depth, pitch, 1, tile, false, total); + TileGetTextureSize(format, width, height, 1, tile, &slice, &level, &padded); + TileGetTextureTotalSize(format, width, height, depth, 1, tile, false, total); const auto layout = - TextureCalcUploadLayout(format, width, height, 1, depth, pitch, tile, total.size, true, + TextureCalcUploadLayout(format, width, height, 1, depth, tile, total.size, true, false, "StorageTextureDepthTileTest"); - const auto regions = TextureBuildImageCopies(layout, width, height, depth, 1, true, false); + const auto regions = TextureBuildImageCopies(layout); Require("StorageTextureDepthTileUpload", "PPSA14053 layout", pitch == 256 && padded.width == 256 && padded.height == 256 && slice.size == 0x10000 && slice.align == 0x10000 && level.size == slice.size && level.offset == 0 && - total.size == slice.size && total.align == slice.align && layout.tile == tile && - layout.tile_family == TileBlockFamily::Depth64KB && layout.pitch == pitch && + total.size == slice.size && total.align == slice.align && + layout.surface.description.tile_mode == tile && + layout.surface.texture.block.family == TileBlockFamily::Depth64KB && + layout.pitch == pitch && layout.slice_stride == pitch && layout.source_slice_stride == total.size && - layout.level_sizes[0].size == pitch && - layout.level_sizes[0].src_size == total.size && regions.size() == 1 && + layout.mips[0].size == pitch && + layout.surface.mips[0].size == total.size && regions.size() == 1 && regions[0].bufferOffset == 0 && regions[0].imageExtent.width == width && regions[0].imageExtent.height == height && regions[0].bufferRowLength == pitch, "1x1 R8_UINT depth tile lost its 64 KiB source footprint"); @@ -17274,24 +17286,24 @@ void CheckStorageTextureVolumeUploadLayout() { constexpr uint32_t height = 33; constexpr uint32_t depth = 33; const auto pitch = TileGetTexturePitch( - format, width, 1, Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget)); + format, width, Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget)); TileSizeAlign total {}; - TileGetTextureTotalSize(format, width, height, depth, pitch, 1, + TileGetTextureTotalSize(format, width, height, depth, 1, Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget), true, total); const auto layout = - TextureCalcUploadLayout(format, width, height, 1, depth, pitch, + TextureCalcUploadLayout(format, width, height, 1, depth, Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget), total.size, true, true, "StorageTextureVolumeTest"); - const auto regions = TextureBuildImageCopies(layout, width, height, depth, 1, false, true); + const auto regions = TextureBuildImageCopies(layout); Require("StorageTextureVolumeUpload", "layout", pitch == 128 && total.size == 0x210000 && layout.slice_stride == 0x2208 && - layout.source_slice_stride == 0 && layout.level_sizes[0].size == 0x2208 && - layout.level_sizes[0].src_size == 0 && regions.size() == depth, + layout.source_slice_stride == 0 && layout.mips[0].size == 0x2208 && + layout.surface.mips[0].size == 0x10000 && regions.size() == depth, "3D render-target upload did not preserve its compact linear layout"); std::vector infos; Require("StorageTextureVolumeUpload", "GPU records", - TextureBuildGpuTileInfos(total.size, regions, layout, format, depth, 1, infos) && + TextureBuildGpuTileInfos(total.size, regions, layout, 1, infos) && infos.size() == depth, "3D render-target GPU records were not built"); for (const uint32_t z: {0u, 1u, depth - 1u}) { @@ -17311,13 +17323,12 @@ void CheckStorageTextureVolumeMipRegions() { constexpr uint32_t depth = 5; constexpr uint32_t levels = 3; constexpr uint32_t tile = Prospero::GpuEnumValue(Prospero::TileMode::kLinear); - const auto pitch = TileGetTexturePitch(format, width, levels, tile); TileSizeAlign total {}; - TileGetTextureTotalSize(format, width, height, depth, pitch, levels, tile, true, total); + TileGetTextureTotalSize(format, width, height, depth, levels, tile, true, total); const auto layout = - TextureCalcUploadLayout(format, width, height, levels, depth, pitch, tile, total.size, true, + TextureCalcUploadLayout(format, width, height, levels, depth, tile, total.size, true, true, "StorageTextureVolumeMipTest"); - const auto copies = TextureBuildImageCopies(layout, width, height, depth, levels, false, true); + const auto copies = TextureBuildImageCopies(layout); bool valid = copies.size() == 8; size_t index = 0; @@ -17331,9 +17342,9 @@ void CheckStorageTextureVolumeMipRegions() { copy.imageSubresource.mipLevel == level && copy.imageOffset.z == static_cast(z) && copy.imageExtent.width == mip_width && copy.imageExtent.height == mip_height && - copy.bufferOffset == layout.level_sizes[level].offset + z * layout.slice_stride && - copy.bufferRowLength == layout.padded_sizes[level].width && - copy.bufferImageHeight == layout.padded_sizes[level].height; + copy.bufferOffset == layout.mips[level].offset + z * layout.slice_stride && + copy.bufferRowLength == layout.mips[level].row_length && + copy.bufferImageHeight == layout.mips[level].image_height; } } valid &= index == copies.size(); @@ -17348,9 +17359,9 @@ void CheckStandard64RenderTargetTileRoundTrip() { constexpr uint32_t observed_width = 3840; constexpr uint32_t observed_height = 2160; - const auto observed_pitch = TileGetTexturePitch(format, observed_width, 1, tile); + const auto observed_pitch = TileGetTexturePitch(format, observed_width, tile); TileSizeAlign observed {}; - TileGetTextureSize(format, observed_width, observed_height, observed_pitch, 1, tile, &observed, + TileGetTextureSize(format, observed_width, observed_height, 1, tile, &observed, nullptr, nullptr); Require("Standard64RenderTarget", "observed layout", observed_pitch == 3840 && observed.size == 0x1fe0000 && observed.align == 0x10000, @@ -17358,9 +17369,9 @@ void CheckStandard64RenderTargetTileRoundTrip() { constexpr uint32_t width = 257; constexpr uint32_t height = 131; - const auto pitch = TileGetTexturePitch(format, width, 1, tile); + const auto pitch = TileGetTexturePitch(format, width, tile); TileSizeAlign storage {}; - TileGetTextureSize(format, width, height, pitch, 1, tile, &storage, nullptr, nullptr); + TileGetTextureSize(format, width, height, 1, tile, &storage, nullptr, nullptr); Require("Standard64RenderTarget", "partial layout", pitch == 384 && storage.size == 0x60000 && storage.align == 0x10000, "partial Standard64KB footprint was not padded in 128x128 blocks"); @@ -17838,11 +17849,11 @@ void CheckDepthTargetFootprints() { "non-HTile depth/stencil footprint disagrees with Prospero block rules"); const auto depth_pitch = - TileGetTexturePitch(Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float), 640, 1, + TileGetTexturePitch(Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float), 640, Prospero::GpuEnumValue(Prospero::TileMode::kDepth)); TileSizeAlign texture_depth {}; TileGetTextureTotalSize(Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float), 640, 360, 1, - depth_pitch, 1, Prospero::GpuEnumValue(Prospero::TileMode::kDepth), + 1, Prospero::GpuEnumValue(Prospero::TileMode::kDepth), false, texture_depth); Require("DepthTargetFootprints", "640x360 generic depth tile", depth_pitch == 640 && texture_depth.size == 0xf0000 && texture_depth.align == 0x10000,