[GPU] Document tiled texture address bits
Will be useful for calculating memory extents more precisely in the future.
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/gpu/texture_address.h"
|
||||
|
||||
namespace xe {
|
||||
namespace gpu {
|
||||
@@ -414,10 +415,10 @@ TextureGuestLayout GetGuestTextureLayout(
|
||||
uint32_t bytes_per_block_log2 = xe::log2_floor(bytes_per_block);
|
||||
if (dimension == xenos::DataDimension::k3D) {
|
||||
level_layout.array_slice_data_extent_bytes =
|
||||
GetTiledAddressUpperBound3D(
|
||||
uint32_t(GetTiledAddressUpperBound3D(
|
||||
level_layout.x_extent_blocks, level_layout.y_extent_blocks,
|
||||
level_layout.z_extent, row_pitch_blocks_tile_aligned,
|
||||
level_layout.y_extent_blocks, bytes_per_block_log2);
|
||||
level_layout.z_slice_stride_block_rows, bytes_per_block_log2));
|
||||
} else {
|
||||
level_layout.array_slice_data_extent_bytes =
|
||||
GetTiledAddressUpperBound2D(
|
||||
@@ -447,62 +448,17 @@ TextureGuestLayout GetGuestTextureLayout(
|
||||
return layout;
|
||||
}
|
||||
|
||||
int32_t GetTiledOffset2D(int32_t x, int32_t y, uint32_t pitch,
|
||||
uint32_t bytes_per_block_log2) {
|
||||
// https://github.com/gildor2/UModel/blob/de8fbd3bc922427ea056b7340202dcdcc19ccff5/Unreal/UnTexture.cpp#L489
|
||||
pitch = xe::align(pitch, xenos::kTextureTileWidthHeight);
|
||||
// Top bits of coordinates.
|
||||
int32_t macro = ((x >> 5) + (y >> 5) * int32_t(pitch >> 5))
|
||||
<< (bytes_per_block_log2 + 7);
|
||||
// Lower bits of coordinates (result is 6-bit value).
|
||||
int32_t micro = ((x & 7) + ((y & 0xE) << 2)) << bytes_per_block_log2;
|
||||
// Mix micro/macro + add few remaining x/y bits.
|
||||
int32_t offset =
|
||||
macro + ((micro & ~0xF) << 1) + (micro & 0xF) + ((y & 1) << 4);
|
||||
// Mix bits again.
|
||||
return ((offset & ~0x1FF) << 3) + ((y & 16) << 7) + ((offset & 0x1C0) << 2) +
|
||||
(((((y & 8) >> 2) + (x >> 3)) & 3) << 6) + (offset & 0x3F);
|
||||
}
|
||||
|
||||
int32_t GetTiledOffset3D(int32_t x, int32_t y, int32_t z, uint32_t pitch,
|
||||
uint32_t height, uint32_t bytes_per_block_log2) {
|
||||
// Reconstructed from disassembly of XGRAPHICS::TileVolume.
|
||||
pitch = xe::align(pitch, xenos::kTextureTileWidthHeight);
|
||||
height = xe::align(height, xenos::kTextureTileWidthHeight);
|
||||
int32_t macro_outer =
|
||||
((y >> 4) + (z >> 2) * int32_t(height >> 4)) * int32_t(pitch >> 5);
|
||||
int32_t macro =
|
||||
((((x >> 5) + macro_outer) << (bytes_per_block_log2 + 6)) & 0xFFFFFFF)
|
||||
<< 1;
|
||||
int32_t micro =
|
||||
(((x & 7) + ((y & 6) << 2)) << (bytes_per_block_log2 + 6)) >> 6;
|
||||
int32_t offset_outer = ((y >> 3) + (z >> 2)) & 1;
|
||||
int32_t offset1 =
|
||||
offset_outer + ((((x >> 3) + (offset_outer << 1)) & 3) << 1);
|
||||
int32_t offset2 = ((macro + (micro & ~15)) << 1) + (micro & 15) +
|
||||
((z & 3) << (bytes_per_block_log2 + 6)) + ((y & 1) << 4);
|
||||
int32_t address = (offset1 & 1) << 3;
|
||||
address += (offset2 >> 6) & 7;
|
||||
address <<= 3;
|
||||
address += offset1 & ~1;
|
||||
address <<= 2;
|
||||
address += offset2 & ~511;
|
||||
address <<= 3;
|
||||
address += offset2 & 63;
|
||||
return address;
|
||||
}
|
||||
|
||||
uint32_t GetTiledAddressUpperBound2D(uint32_t right, uint32_t bottom,
|
||||
uint32_t pitch,
|
||||
uint32_t pitch_aligned,
|
||||
uint32_t bytes_per_block_log2) {
|
||||
if (!right || !bottom) {
|
||||
return 0;
|
||||
}
|
||||
// Get the origin of the 32x32 tile containing the last texel.
|
||||
uint32_t upper_bound = uint32_t(GetTiledOffset2D(
|
||||
uint32_t upper_bound = uint32_t(texture_address::Tiled2D(
|
||||
int32_t((right - 1) & ~(xenos::kTextureTileWidthHeight - 1)),
|
||||
int32_t((bottom - 1) & ~(xenos::kTextureTileWidthHeight - 1)), pitch,
|
||||
bytes_per_block_log2));
|
||||
int32_t((bottom - 1) & ~(xenos::kTextureTileWidthHeight - 1)),
|
||||
pitch_aligned, bytes_per_block_log2));
|
||||
switch (bytes_per_block_log2) {
|
||||
case 0:
|
||||
// Independent addressing within 128x128 portions, but the extent is 0xA00
|
||||
@@ -521,20 +477,19 @@ uint32_t GetTiledAddressUpperBound2D(uint32_t right, uint32_t bottom,
|
||||
return upper_bound;
|
||||
}
|
||||
|
||||
uint32_t GetTiledAddressUpperBound3D(uint32_t right, uint32_t bottom,
|
||||
uint32_t back, uint32_t pitch,
|
||||
uint32_t height,
|
||||
uint64_t GetTiledAddressUpperBound3D(uint32_t right, uint32_t bottom,
|
||||
uint32_t back, uint32_t pitch_aligned,
|
||||
uint32_t height_aligned,
|
||||
uint32_t bytes_per_block_log2) {
|
||||
if (!right || !bottom || !back) {
|
||||
return 0;
|
||||
}
|
||||
// Get the origin of the 32x32x4 tile containing the last texel.
|
||||
uint32_t upper_bound = uint32_t(GetTiledOffset3D(
|
||||
uint64_t upper_bound = uint64_t(texture_address::Tiled3D(
|
||||
int32_t((right - 1) & ~(xenos::kTextureTileWidthHeight - 1)),
|
||||
int32_t((bottom - 1) & ~(xenos::kTextureTileWidthHeight - 1)),
|
||||
int32_t((back - 1) & ~(xenos::kTextureTileDepth - 1)), pitch, height,
|
||||
bytes_per_block_log2));
|
||||
uint32_t pitch_aligned = xe::align(pitch, xenos::kTextureTileWidthHeight);
|
||||
int32_t((back - 1) & ~(xenos::kTextureTileDepth - 1)), pitch_aligned,
|
||||
height_aligned, bytes_per_block_log2));
|
||||
switch (bytes_per_block_log2) {
|
||||
case 0:
|
||||
// 64x32x8 portions have independent addressing.
|
||||
|
||||
Reference in New Issue
Block a user