[GPU] Fix tiled texture memory extent calculation
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2018 Ben Vanik. All rights reserved. *
|
||||
* Copyright 2022 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
@@ -346,12 +346,10 @@ TextureGuestLayout GetGuestTextureLayout(
|
||||
uint32_t z_stride_bytes = level_layout.array_slice_stride_bytes;
|
||||
if (dimension == xenos::DataDimension::k3D) {
|
||||
level_layout.array_slice_stride_bytes *=
|
||||
xe::align(depth_or_array_size, xenos::kTextureTiledDepthGranularity);
|
||||
xe::align(depth_or_array_size, xenos::kTextureTileDepth);
|
||||
}
|
||||
uint32_t array_slice_stride_bytes_non_4kb_aligned =
|
||||
level_layout.array_slice_stride_bytes;
|
||||
level_layout.array_slice_stride_bytes =
|
||||
xe::align(array_slice_stride_bytes_non_4kb_aligned,
|
||||
xe::align(level_layout.array_slice_stride_bytes,
|
||||
xenos::kTextureSubresourceAlignmentBytes);
|
||||
|
||||
// Estimate the memory amount actually referenced by the texture, which may
|
||||
@@ -374,34 +372,68 @@ TextureGuestLayout GetGuestTextureLayout(
|
||||
xe::align(level_width_blocks, xenos::kTextureTileWidthHeight);
|
||||
level_layout.y_extent_blocks =
|
||||
xe::align(level_height_blocks, xenos::kTextureTileWidthHeight);
|
||||
uint32_t bytes_per_block_log2 = xe::log2_floor(bytes_per_block);
|
||||
if (dimension == xenos::DataDimension::k3D) {
|
||||
level_layout.z_extent =
|
||||
xe::align(level_depth, xenos::kTextureTiledDepthGranularity);
|
||||
// 3D texture addressing is pretty complex, so it's hard to determine
|
||||
// the memory extent of a subregion - just use `pitch_tiles *
|
||||
// height_tiles * depth_tiles * bytes_per_tile` at least for now, until
|
||||
// we find a case where it causes issues. `width > pitch` is a very
|
||||
// weird edge case anyway, and is extremely unlikely.
|
||||
assert_true(level_layout.x_extent_blocks <=
|
||||
row_pitch_blocks_tile_aligned);
|
||||
level_layout.array_slice_data_extent_bytes =
|
||||
array_slice_stride_bytes_non_4kb_aligned;
|
||||
xe::align(level_depth, xenos::kTextureTileDepth);
|
||||
// 32-block-row x 4 slice portions laid out sequentially (4-slice-major,
|
||||
// 32-block-row-minor), address extent within a 32x32x4 tile depends on
|
||||
// the pitch. Origins of 32x32x4 tiles grow monotonically, first along
|
||||
// Z, then along Y, then along X.
|
||||
level_layout.array_slice_data_extent_bytes = uint32_t(GetTiledOffset3D(
|
||||
int32_t(level_layout.x_extent_blocks -
|
||||
xenos::kTextureTileWidthHeight),
|
||||
int32_t(level_layout.y_extent_blocks -
|
||||
xenos::kTextureTileWidthHeight),
|
||||
int32_t(level_layout.z_extent - xenos::kTextureTileDepth),
|
||||
row_pitch_blocks_tile_aligned, level_layout.y_extent_blocks,
|
||||
bytes_per_block_log2));
|
||||
switch (bytes_per_block_log2) {
|
||||
case 0:
|
||||
// 64x32x8 portions have independent addressing.
|
||||
// Extent relative to the 32x32x4 tile origin:
|
||||
// - Pitch = 32, 96, 160...: (Pitch / 64) * 0x1000 + 0x1000
|
||||
// - Pitch = 64, 128, 192...: (Pitch / 64) * 0x1000 + 0xC00
|
||||
level_layout.array_slice_data_extent_bytes +=
|
||||
((row_pitch_blocks_tile_aligned >> 6) << 12) + 0xC00 +
|
||||
((row_pitch_blocks_tile_aligned & (1 << 5)) << (10 - 5));
|
||||
break;
|
||||
default:
|
||||
// 32x32x8 portions have independent addressing.
|
||||
// Extent: ((Pitch / 32) * 0x1000 + 0x1000) * (BPB / 2)
|
||||
// Or: ((Pitch / 32) * 0x1000 / 2 + 0x1000 / 2) * BPB
|
||||
level_layout.array_slice_data_extent_bytes +=
|
||||
((row_pitch_blocks_tile_aligned << (12 - 5 - 1)) +
|
||||
(0x1000 >> 1))
|
||||
<< bytes_per_block_log2;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
level_layout.z_extent = 1;
|
||||
// 2D 32x32-block tiles are laid out linearly in the texture.
|
||||
// Calculate the extent as ((all rows except for the last * pitch in
|
||||
// tiles + last row length in tiles) * bytes per tile).
|
||||
// FIXME(Triang3l): This is wrong for 1bpb and 2bpb. At 1bpb (32x32 is
|
||||
// 1024 bytes), offset for X + 32 minus offset for X is 512, not 1024,
|
||||
// but offset for X + 128 minus offset for X + 96 is 2560. Also, for
|
||||
// XY = 0...31, the extent of the addresses is 2560, not 1024. At 2bpb,
|
||||
// addressing repeats every 64x64, and the extent for XY = 0...31 is
|
||||
// 3072, not 2048.
|
||||
level_layout.array_slice_data_extent_bytes =
|
||||
(level_layout.y_extent_blocks - xenos::kTextureTileWidthHeight) *
|
||||
level_layout.row_pitch_bytes +
|
||||
bytes_per_block * level_layout.x_extent_blocks *
|
||||
xenos::kTextureTileWidthHeight;
|
||||
// Origins of 32x32 tiles grow monotonically, first along Y, then along
|
||||
// X.
|
||||
level_layout.array_slice_data_extent_bytes = uint32_t(GetTiledOffset2D(
|
||||
int32_t(level_layout.x_extent_blocks -
|
||||
xenos::kTextureTileWidthHeight),
|
||||
int32_t(level_layout.y_extent_blocks -
|
||||
xenos::kTextureTileWidthHeight),
|
||||
row_pitch_blocks_tile_aligned, bytes_per_block_log2));
|
||||
switch (bytes_per_block_log2) {
|
||||
case 0:
|
||||
// Independent addressing within 128x128 portions, but the extent is
|
||||
// 0xA00 bytes from the 32x32 tile origin.
|
||||
level_layout.array_slice_data_extent_bytes += 0xA00;
|
||||
break;
|
||||
case 1:
|
||||
// Independent addressing within 64x64 portions, but the extent is
|
||||
// 0xC00 bytes from the 32x32 tile origin.
|
||||
level_layout.array_slice_data_extent_bytes += 0xC00;
|
||||
break;
|
||||
default:
|
||||
level_layout.array_slice_data_extent_bytes +=
|
||||
UINT32_C(0x400) << bytes_per_block_log2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (level == layout.packed_level) {
|
||||
|
||||
Reference in New Issue
Block a user