summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTriang3l <triang3l@yandex.ru>2026-01-15 11:56:45 +0300
committerTriang3l <triang3l@yandex.ru>2026-01-15 11:56:45 +0300
commit88f95a8bd6e2e41c188693b0b4dc5e1d6157b212 (patch)
tree6ddae9edeb94fdc23b18e6272fa65f4349e4a005
parentc4e1242fa26f55c260f2b030e43ffc8a5ac5d0b7 (diff)
[GPU] Change "element" name back to "block" in texture addressing
The 32_32_32_FLOAT format seems to be vertex-only, so it looks like there can't be storage elements smaller than a single texel. So, use a more precise name that can't be confused with "picture element" (pixel) or "texture element" (texel) that represents a single logical pixel rather than a storage block of pixels.
-rw-r--r--src/xenia/gpu/draw_util.cc4
-rw-r--r--src/xenia/gpu/shaders/resolve.xesli17
-rw-r--r--src/xenia/gpu/shaders/texture_address.xesli132
-rw-r--r--src/xenia/gpu/shaders/texture_load.xesli18
-rw-r--r--src/xenia/gpu/texture_address.h87
5 files changed, 124 insertions, 134 deletions
diff --git a/src/xenia/gpu/draw_util.cc b/src/xenia/gpu/draw_util.cc
index 94e2abe37..9d54e2afc 100644
--- a/src/xenia/gpu/draw_util.cc
+++ b/src/xenia/gpu/draw_util.cc
@@ -1005,12 +1005,12 @@ bool GetResolveInfo(const RegisterFile& regs, const Memory& memory,
auto rb_copy_dest_pitch = regs.Get<reg::RB_COPY_DEST_PITCH>();
const uint32_t copy_dest_pitch_aligned =
xe::align(rb_copy_dest_pitch.copy_dest_pitch,
- texture_address::kStoragePitchHeightAlignmentElements);
+ texture_address::kStoragePitchHeightAlignmentBlocks);
info_out.copy_dest_coordinate_info.pitch_aligned_div_32 =
copy_dest_pitch_aligned >> 5;
const uint32_t copy_dest_height_aligned =
xe::align(rb_copy_dest_pitch.copy_dest_height,
- texture_address::kStoragePitchHeightAlignmentElements);
+ texture_address::kStoragePitchHeightAlignmentBlocks);
info_out.copy_dest_coordinate_info.height_aligned_div_32 =
copy_dest_height_aligned >> 5;
const FormatInfo& dest_format_info = *FormatInfo::Get(dest_format);
diff --git a/src/xenia/gpu/shaders/resolve.xesli b/src/xenia/gpu/shaders/resolve.xesli
index 18e64d6e1..397bb7281 100644
--- a/src/xenia/gpu/shaders/resolve.xesli
+++ b/src/xenia/gpu/shaders/resolve.xesli
@@ -161,7 +161,7 @@ uint XeResolveEdramPixelStrideInts(XeResolveInfo resolve_info) {
#ifndef XE_RESOLVE_CLEAR
uint XeResolveDestPixelAddress(const XeResolveInfo resolve_info,
uint2_xe host_position,
- const uint bytes_per_element_log2) {
+ const uint bytes_per_block_log2) {
host_position += resolve_info.dest_xy_offset_scaled;
uint address;
uint2_xe guest_position = host_position;
@@ -170,19 +170,18 @@ uint XeResolveEdramPixelStrideInts(XeResolveInfo resolve_info) {
resolution_scaled_addressing =
XeniaTextureGetResolutionScaledAddressing(
host_position.xy, resolve_info.resolution_scale,
- bytes_per_element_log2);
+ bytes_per_block_log2);
guest_position = resolution_scaled_addressing.guest_group_origin;
#endif
dont_flatten_xe if (resolve_info.dest_is_array) {
address = uint(XenosTextureTiledAddress3D(
int3_xe(uint3_xe(guest_position, resolve_info.dest_slice)),
resolve_info.dest_row_pitch_macro_tiles,
- resolve_info.dest_slice_pitch_3d_macro_tiles,
- bytes_per_element_log2));
+ resolve_info.dest_slice_pitch_3d_macro_tiles, bytes_per_block_log2));
} else {
address = uint(XenosTextureTiledAddress2D(
int2_xe(guest_position), resolve_info.dest_row_pitch_macro_tiles,
- bytes_per_element_log2));
+ bytes_per_block_log2));
}
#ifdef XE_RESOLVE_RESOLUTION_SCALED
address = address * (resolve_info.resolution_scale.x *
@@ -195,18 +194,18 @@ uint XeResolveEdramPixelStrideInts(XeResolveInfo resolve_info) {
// XOR to apply to the byte address to flip the bits corresponding to the
// given X coordinate bits within the macro tile width, or with resolution
- // scaling, within XeniaTextureResolutionScaledGroupElements.x.
+ // scaling, within XeniaTextureResolutionScaledGroupBlocks.x.
// Addition is recommended instead of XOR if the bits are known to be 0 in the
// original address, so the host GPU driver can optimize it into a constant
// store offset if available in the host hardware shader instruction set
// architecture.
uint XeResolveLocalXAddressXor(const uint x,
- const uint bytes_per_element_log2) {
+ const uint bytes_per_block_log2) {
#ifdef XE_RESOLVE_RESOLUTION_SCALED
- return x << bytes_per_element_log2;
+ return x << bytes_per_block_log2;
#else
return uint(XenosTextureTiledAddressXInMacroXor(int(x),
- bytes_per_element_log2));
+ bytes_per_block_log2));
#endif
}
diff --git a/src/xenia/gpu/shaders/texture_address.xesli b/src/xenia/gpu/shaders/texture_address.xesli
index a555c4642..3b5851540 100644
--- a/src/xenia/gpu/shaders/texture_address.xesli
+++ b/src/xenia/gpu/shaders/texture_address.xesli
@@ -26,15 +26,15 @@ int XenosTextureTiledAddressCombine(const int outer_inner_bytes, const int bank,
}
int XenosTextureTiledAddress2D(const int2_xe p, const uint pitch_macro_tiles,
- const uint bytes_per_element_log2) {
- const int outer_elements =
+ const uint bytes_per_block_log2) {
+ const int outer_blocks =
((p.y >> XENOS_TEXTURE_MACRO_TILE_HEIGHT_2D_LOG2) *
int(pitch_macro_tiles) +
(p.x >> XENOS_TEXTURE_MACRO_TILE_WIDTH_LOG2))
<< 6;
- const int inner_elements = (((p.y >> 1) & 0x7) << 3) | (p.x & 0x7);
- const int outer_inner_bytes =
- (outer_elements | inner_elements) << bytes_per_element_log2;
+ const int inner_blocks = (((p.y >> 1) & 0x7) << 3) | (p.x & 0x7);
+ const int outer_inner_bytes = (outer_blocks | inner_blocks)
+ << bytes_per_block_log2;
const int bank = (p.y >> 4) & 0x1;
const int pipe = ((p.x >> 3) & 0x3) ^ (((p.y >> 3) & 0x1) << 1);
return XenosTextureTiledAddressCombine(outer_inner_bytes, bank, pipe,
@@ -43,18 +43,18 @@ int XenosTextureTiledAddress2D(const int2_xe p, const uint pitch_macro_tiles,
int XenosTextureTiledAddress3D(const int3_xe p, const uint pitch_macro_tiles,
const uint height_macro_tiles,
- const uint bytes_per_element_log2) {
- const int outer_elements =
+ const uint bytes_per_block_log2) {
+ const int outer_blocks =
((((p.z >> XENOS_TEXTURE_MACRO_TILE_DEPTH_LOG2) *
int(height_macro_tiles) +
(p.y >> XENOS_TEXTURE_MACRO_TILE_HEIGHT_3D_LOG2)) *
int(pitch_macro_tiles)) +
(p.x >> XENOS_TEXTURE_MACRO_TILE_WIDTH_LOG2))
<< 7;
- const int inner_elements =
+ const int inner_blocks =
((p.z & 0x3) << 5) | (((p.y >> 1) & 0x3) << 3) | (p.x & 0x7);
- const int outer_inner_bytes =
- (outer_elements | inner_elements) << bytes_per_element_log2;
+ const int outer_inner_bytes = (outer_blocks | inner_blocks)
+ << bytes_per_block_log2;
const int bank = ((p.y >> 3) ^ (p.z >> 2)) & 0x1;
const int pipe = ((p.x >> 3) & 0x3) ^ (bank << 1);
return XenosTextureTiledAddressCombine(outer_inner_bytes, bank, pipe,
@@ -65,49 +65,49 @@ int XenosTextureTiledAddress3D(const int3_xe p, const uint pitch_macro_tiles,
// X coordinate bits within the width of a macro tile.
// Note that in a tiled address, bit 7 is X[4] ^ Y[3] ^ Z[2], not X[4] alone.
int XenosTextureTiledAddressXInMacroXor(const int x,
- const uint bytes_per_element_log2) {
- return XenosTextureTiledAddressCombine((x & 0x7) << bytes_per_element_log2,
+ const uint bytes_per_block_log2) {
+ return XenosTextureTiledAddressCombine((x & 0x7) << bytes_per_block_log2,
0, (x >> 3) & 0x3, 0);
}
-// The lowest bits of an element index within a micro tile are X[2:0].
+// The lowest bits of an block index within a micro tile are X[2:0].
// In a tiled address, the bit 4 is always Y[0].
-// However, the bits [3:0] are the lower bits of the micro tile element index
-// times the number of bytes per element.
-// Because of this, a number of elements, that depends on the count of bytes per
-// element, along the X axis (aligned to this amount) is stored consecutively in
+// However, the bits [3:0] are the lower bits of the micro tile block index
+// times the number of bytes per block.
+// Because of this, a number of blocks, that depends on the count of bytes per
+// block, along the X axis (aligned to this amount) is stored consecutively in
// guest memory:
-// - 1bpe: 8 elements (8 bytes - limited by address bit 3 being Y[1] for 1bpe).
-// - 2bpe: 8 elements (16 bytes - limited by address bit 4 always being Y[0]).
-// - 4bpe: 4 elements.
-// - 8bpe: 2 elements.
-// - 16bpe: 1 element.
-// This makes it possible to access multiple elements in a single row using
-// 8-byte or (for >= 2bpe) 16-byte loads and stores, and that's particularly
-// useful when transferring texture data between tiled and linear storage.
+// - 1bpe: 8 blocks (8 bytes - limited by address bit 3 being Y[1] for 1bpe).
+// - 2bpe: 8 blocks (16 bytes - limited by address bit 4 always being Y[0]).
+// - 4bpe: 4 blocks.
+// - 8bpe: 2 blocks.
+// - 16bpe: 1 block.
+// This makes it possible to access multiple blocks in a single row using 8-byte
+// or (for >= 2bpe) 16-byte loads and stores, and that's particularly useful
+// when transferring texture data between tiled and linear storage.
// With resolution scaling, one scaled group of bytes in guest addresses
// corresponds to `scale.x * scale.y` groups of the same size on the host.
//
-// A single group contains a full rectangular region of elements. This means
-// that, for instance, if the Y[1] tiled address bit is within the group size,
-// Y[0] must be within it too, so division is enough to go from host to guest
+// A single group contains a full rectangular region of blocks. This means that,
+// for instance, if the Y[1] tiled address bit is within the group size, Y[0]
+// must be within it too, so division is enough to go from host to guest
// coordinates for the origin of the group.
//
// The address of the guest group on the host is the guest tiled address of its
// origin in guest coordinates multiplied by `scale.x * scale.y`.
//
-// Within a guest group, the addressing of elements is controlled by the host.
-// Specifically, host groups are arranged in a guest group as block-linear
-// column-major (for storage locality along both axes), and elements in a host
+// Within a guest group, the addressing of blocks is controlled by the host.
+// Specifically, host groups are arranged in a guest group as group-linear
+// column-major (for storage locality along both axes), and blocks in a host
// group are laid out as linear row-major (guest tiling therefore is applied
// only to whole guest groups, not within them, for simplicity).
//
// Addressing with resolution scaling is not intended to allow for
-// reinterpretation of resolution-scaled data between different numbers of bits
-// per element. Rather, it's designed for simple and efficient access on the
-// host, primarily when copying between tiled and linear storage, and to reduce
-// the differences in shader logic between unscaled and scaled data.
+// reinterpretation of resolution-scaled data between different numbers of bytes
+// per block. Rather, it's designed for simple and efficient access on the host,
+// primarily when copying between tiled and linear storage, and to reduce the
+// differences in shader logic between unscaled and scaled data.
//
// However, the groups are still small enough to preserve most of the tiling
// properties on a macro level, most importantly the possibility to resolve
@@ -121,32 +121,32 @@ int XenosTextureTiledAddressXInMacroXor(const int x,
// per pixel being the only needed metadata.
//
// A common pattern in Xenia is copying multiple 8-byte or (for >= 2bpe) 16-byte
-// sequences of consecutive elements along the X axis in a single shader
+// sequences of consecutive blocks along the X axis in a single shader
// invocation, by computing the tiled address once and merely flipping X bits in
// it.
//
// With the resolution scaling group size being no larger than 2^7 bytes, it may
// contain guest X bits [3:0] for <= 4bpe, [1:0] for 8bpe, and [0] for 16bpe
// (note that though X[3] always goes to address[6], for 8bpe, X[2] is
-// address[8], so a group can't be wider than 4 elements, and similarly for X[1]
+// address[8], so a group can't be wider than 4 blocks, and similarly for X[1]
// for 16bpe).
//
// Given these requirements, the group sizes are chosen as follows:
// - 1bpe - lower 7 bits of an unscaled address are X0, X1, X2, Y1, Y0, Y2, X3:
-// - Group width: 2^4 elements (maximum within 7 bits), or 2^4 bytes.
-// - Group height: 2^3 elements (Y[2:0] between X[3:0]).
+// - Group width: 2^4 blocks (maximum within 7 bits), or 2^4 bytes.
+// - Group height: 2^3 blocks (Y[2:0] between X[3:0]).
// - 2bpe - lower 7 bits of an unscaled address are 0, X0, X1, X2, Y0, Y1, X3:
-// - Group width: 2^4 elements (maximum within 7 bits), or 2^5 bytes.
-// - Group height: 2^2 elements (Y[1:0] between X[3:0]).
+// - Group width: 2^4 blocks (maximum within 7 bits), or 2^5 bytes.
+// - Group height: 2^2 blocks (Y[1:0] between X[3:0]).
// - 4bpe - lower 7 bits of an unscaled address are 0, 0, X0, X1, Y0, X2, X3:
-// - Group width: 2^4 elements (maximum within 7 bits), or 2^6 bytes.
-// - Group height: 2^1 elements (Y[0] between X[3:0]).
+// - Group width: 2^4 blocks (maximum within 7 bits), or 2^6 bytes.
+// - Group height: 2^1 blocks (Y[0] between X[3:0]).
// - 8bpe - lower 7 bits of an unscaled address are 0, 0, 0, X0, Y0, X1, X3:
-// - Group width: 2^2 elements (X[2] is beyond 7 bits), or 2^5 bytes.
-// - Group height: 2^1 elements (Y[0] between X[1:0]).
+// - Group width: 2^2 blocks (X[2] is beyond 7 bits), or 2^5 bytes.
+// - Group height: 2^1 blocks (Y[0] between X[1:0]).
// - 16bpe - lower 7 bits of an unscaled address are 0, 0, 0, 0, Y0, X0, X3:
-// - Group width: 2^1 elements (X[2:1] is beyond 7 bits), or 2^5 bytes.
-// - Group height: 2^1 elements (Y[0] below X[0]).
+// - Group width: 2^1 blocks (X[2:1] is beyond 7 bits), or 2^5 bytes.
+// - Group height: 2^1 blocks (Y[0] below X[0]).
//
// 2^6 bytes copied per invocation is likely to be optimal, as that consumes 16
// 32-bit VGPRs, out of a total of 24 (1024 / 40 rounded down to 4) available
@@ -154,19 +154,17 @@ int XenosTextureTiledAddressXInMacroXor(const int x,
// (although the occupancy of copy shaders is likely to be limited by memory
// accesses instead anyway).
//
-// Note that with the given group sizes, as well as with elements in a host
-// group stored as row-major, for 1bpe, 16x1 host elements are stored
-// consecutively with resolution scaling (even though in guest tiling, only 8x1
-// elements are), so they can be accessed via one 16-byte operation rather than
-// two 8-byte ones.
+// Note that with the given group sizes, as well as with blocks in a host group
+// stored as row-major, for 1bpe, 16x1 host blocks are stored consecutively with
+// resolution scaling (even though in guest tiling, only 8x1 blocks are), so
+// they can be accessed via one 16-byte operation rather than two 8-byte ones.
// Expected to be called for a compile-time constant.
-uint2_xe XeniaTextureResolutionScaledGroupElementsLog2(
- const uint bytes_per_element_log2) {
+uint2_xe XeniaTextureResolutionScaledGroupBlocksLog2(
+ const uint bytes_per_block_log2) {
// Based on the tiled address properties, see the comment above for details.
- return uint2_xe(
- bytes_per_element_log2 >= 3u ? 5u - bytes_per_element_log2 : 4u,
- 3u - min(bytes_per_element_log2, 2u));
+ return uint2_xe(bytes_per_block_log2 >= 3u ? 5u - bytes_per_block_log2 : 4u,
+ 3u - min(bytes_per_block_log2, 2u));
}
struct XeniaTextureResolutionScaledAddressing {
@@ -177,20 +175,20 @@ struct XeniaTextureResolutionScaledAddressing {
XeniaTextureResolutionScaledAddressing
XeniaTextureGetResolutionScaledAddressing(const uint2_xe position,
const uint2_xe resolution_scale,
- const uint bytes_per_element_log2) {
+ const uint bytes_per_block_log2) {
XeniaTextureResolutionScaledAddressing addressing;
- const uint2_xe group_elements_log2 =
- XeniaTextureResolutionScaledGroupElementsLog2(bytes_per_element_log2);
+ const uint2_xe group_blocks_log2 =
+ XeniaTextureResolutionScaledGroupBlocksLog2(bytes_per_block_log2);
- const uint2_xe host_group_id_in_texture = position >> group_elements_log2;
+ const uint2_xe host_group_id_in_texture = position >> group_blocks_log2;
const uint2_xe guest_group_id_in_texture =
host_group_id_in_texture / resolution_scale;
const uint2_xe host_group_id_in_guest_group =
host_group_id_in_texture - resolution_scale * guest_group_id_in_texture;
addressing.guest_group_origin =
- guest_group_id_in_texture << group_elements_log2;
+ guest_group_id_in_texture << group_blocks_log2;
// Host groups are stored as column-major in a guest group, but this can be
// changed freely.
@@ -198,18 +196,18 @@ XeniaTextureGetResolutionScaledAddressing(const uint2_xe position,
host_group_id_in_guest_group.x * resolution_scale.y +
host_group_id_in_guest_group.y;
// Shifts are expanded rather than chained because the number of bytes per
- // element, and thus also the group size, are expected to be compile-time
+ // block, and thus also the group size, are expected to be compile-time
// constants, so this is expected to be combined using GPU bitfield insert
// instructions.
const uint group_width_bytes_log2 =
- group_elements_log2.x + bytes_per_element_log2;
+ group_blocks_log2.x + bytes_per_block_log2;
const uint2_xe position_in_host_group =
- position & ((uint_x2_xe(1u) << group_elements_log2) - 1u);
+ position & ((uint_x2_xe(1u) << group_blocks_log2) - 1u);
addressing.host_byte_offset_in_guest_group =
(host_group_index_in_guest_group <<
- (group_width_bytes_log2 + group_elements_log2.y)) |
+ (group_width_bytes_log2 + group_blocks_log2.y)) |
(position_in_host_group.y << group_width_bytes_log2) |
- (position_in_host_group.x << bytes_per_element_log2);
+ (position_in_host_group.x << bytes_per_block_log2);
return addressing;
}
diff --git a/src/xenia/gpu/shaders/texture_load.xesli b/src/xenia/gpu/shaders/texture_load.xesli
index f2a28cb59..cc1b3664e 100644
--- a/src/xenia/gpu/shaders/texture_load.xesli
+++ b/src/xenia/gpu/shaders/texture_load.xesli
@@ -98,14 +98,14 @@ XeTextureLoadInfo XeTextureLoadGetInfo(param_push_consts_xe) {
uint XeTextureLoadSourceAddress(const XeTextureLoadInfo load_info,
const uint3_xe host_position,
- const uint bytes_per_element_log2) {
+ const uint bytes_per_block_log2) {
uint address;
uint3_xe guest_position = host_position;
#ifdef XE_TEXTURE_LOAD_RESOLUTION_SCALED
const XeniaTextureResolutionScaledAddressing resolution_scaled_addressing =
XeniaTextureGetResolutionScaledAddressing(host_position.xy,
load_info.resolution_scale,
- bytes_per_element_log2);
+ bytes_per_block_log2);
guest_position.xy = resolution_scaled_addressing.guest_group_origin;
#else
dont_flatten_xe if (!load_info.is_tiled) {
@@ -114,7 +114,7 @@ uint XeTextureLoadSourceAddress(const XeTextureLoadInfo load_info,
(guest_position.y +
load_info.guest_z_stride_block_rows_aligned *
guest_position.z)) <<
- bytes_per_element_log2;
+ bytes_per_block_log2;
} else
#endif
{
@@ -124,12 +124,12 @@ uint XeTextureLoadSourceAddress(const XeTextureLoadInfo load_info,
load_info.guest_pitch_aligned >> XENOS_TEXTURE_MACRO_TILE_WIDTH_LOG2,
load_info.guest_z_stride_block_rows_aligned >>
XENOS_TEXTURE_MACRO_TILE_HEIGHT_3D_LOG2,
- bytes_per_element_log2));
+ bytes_per_block_log2));
} else {
address = uint(XenosTextureTiledAddress2D(
int2_xe(guest_position.xy),
load_info.guest_pitch_aligned >> XENOS_TEXTURE_MACRO_TILE_WIDTH_LOG2,
- bytes_per_element_log2));
+ bytes_per_block_log2));
}
}
#ifdef XE_TEXTURE_LOAD_RESOLUTION_SCALED
@@ -143,24 +143,24 @@ uint XeTextureLoadSourceAddress(const XeTextureLoadInfo load_info,
// XOR to apply to the byte address to flip the bits corresponding to the given
// X coordinate bits within:
-// - Resolution-scaled tiled: XeniaTextureResolutionScaledGroupElements.x;
+// - Resolution-scaled tiled: XeniaTextureResolutionScaledGroupBlocks.x;
// - Unscaled tiled: macro tile width;
// - Linear: 256 bytes.
// Addition is recommended instead of XOR if the bits are known to be 0 in the
// original address, so the host GPU driver can optimize it into a constant load
// offset if available in the host hardware shader instruction set architecture.
uint XeTextureLoadLocalXAddressXor(const uint x,
- const uint bytes_per_element_log2,
+ const uint bytes_per_block_log2,
const bool is_tiled) {
uint x_address_xor;
#ifndef XE_TEXTURE_LOAD_RESOLUTION_SCALED
dont_flatten_xe if (is_tiled) {
x_address_xor = uint(
- XenosTextureTiledAddressXInMacroXor(int(x), bytes_per_element_log2));
+ XenosTextureTiledAddressXInMacroXor(int(x), bytes_per_block_log2));
} else
#endif
{
- x_address_xor = x << bytes_per_element_log2;
+ x_address_xor = x << bytes_per_block_log2;
}
return x_address_xor;
}
diff --git a/src/xenia/gpu/texture_address.h b/src/xenia/gpu/texture_address.h
index 5f1c49d37..8b36854be 100644
--- a/src/xenia/gpu/texture_address.h
+++ b/src/xenia/gpu/texture_address.h
@@ -37,19 +37,12 @@ namespace texture_address {
// must not access the data in the padding after aligning to 32x32
// (resulting in 1280x736) via the guest CPU memory mappings.
-// "Element" refers to a storage unit used in guest addressing calculations:
-// block for compressed or otherwise block-based formats, pixel for other
-// formats.
-// TODO(Triang3l): Research 32_32_32_FLOAT format ("Expand3x" in AddrLib terms)
-// texture storage. Should storage dimensions be rounded assuming that one
-// element is one component rather than the whole pixel?
-
// Level pitch (or width for non-base mip levels), height, and depth (for 3D
// textures - stacked 2D textures use the exact array layer count for the stride
// at every level, and cubemaps are normally stored with a stride of 6 faces)
// are rounded up by the hardware for the purposes of calculating strides of
// subresources and of macro tiles within a subresource to:
-// - 32x32 (2D) or 32x32x4 (3D) elements. This is applicable to both tiled and
+// - 32x32 (2D) or 32x32x4 (3D) blocks. This is applicable to both tiled and
// linear textures. Note that for 3D, this is larger than a macro tile
// (32x16x4).
// - Power of two, for non-base mip levels.
@@ -69,12 +62,12 @@ namespace texture_address {
// Another scenario where the product of the aligned dimensions may not be an
// accurate estimate (but in this case too small rather than too large) is when
// the width exceeds the pitch.
-constexpr unsigned int kStoragePitchHeightAlignmentElementsLog2 = 5;
-constexpr uint32_t kStoragePitchHeightAlignmentElements =
- uint32_t(1) << kStoragePitchHeightAlignmentElementsLog2;
-constexpr unsigned int kStorageDepthAlignmentElementsLog2 = 2;
-constexpr uint32_t kStorageDepthAlignmentElements =
- uint32_t(1) << kStorageDepthAlignmentElementsLog2;
+constexpr unsigned int kStoragePitchHeightAlignmentBlocksLog2 = 5;
+constexpr uint32_t kStoragePitchHeightAlignmentBlocks =
+ uint32_t(1) << kStoragePitchHeightAlignmentBlocksLog2;
+constexpr unsigned int kStorageDepthAlignmentBlocksLog2 = 2;
+constexpr uint32_t kStorageDepthAlignmentBlocks =
+ uint32_t(1) << kStorageDepthAlignmentBlocksLog2;
// 2D tiling from:
// https://github.com/BinomialLLC/crunch/blob/36479bc697be19168daafbf15f47f3c60ccec004/inc/crn_decomp.h#L4107
@@ -105,31 +98,31 @@ constexpr uint32_t kStorageDepthAlignmentElements =
// [4] = `y & 1` (Y least significant bit)
// [3:0] = `outer_inner_bytes[3:0]` (pipe interleave lower bits)
//
-// The "outer_inner" part is scaled by the number of bytes per element:
-// `outer_inner_bytes = outer_inner_elements << log2(bytes_per_element)`
-// where `outer_inner_elements` is a sum (or bitwise OR) of two terms:
-// - `outer_elements`: Origin of the 32x32 (2D) or 32x16x4 (3D) macro tile
-// within the subresource.
-// Macro tiles are treated as laid out block-linearly in the calculation of
-// this part, with Z being the most significant term, Y in between, and X
+// The "outer_inner" part is scaled by the number of bytes per block:
+// `outer_inner_bytes = outer_inner_blocks << log2(bytes_per_block)`
+// where `outer_inner_blocks` is a sum (or bitwise OR) of two terms:
+// - `outer_blocks`: Origin of the 32x32 (2D) or 32x16x4 (3D) macro tile within
+// the subresource.
+// Macro tiles are treated as laid out macro-tile-linearly in the calculation
+// of this part, with Z being the most significant term, Y in between, and X
// being the least significant.
// 2D:
// (x[:5] + ceil(pitch / 32) * y[:5]) << 6
// 3D:
// (x[:5] + ceil(pitch / 32) * (y[:4] + 2 * ceil(height / 32) * z[:2])) << 7
-// - `inner_elements`: Offset of 1x2x1 elements within a 8x16 (2D) or 8x8x4
-// micro tile.
+// - `inner_blocks`: Offset of 1x2x1 blocks within a 8x16 (2D) or 8x8x4 micro
+// tile.
// Though the LSB of Y always goes to the bit 4 of the memory address, within
// a micro tile, {X, Y[:1], Z} can be treated as linear in the calculation of
// this part, with Z being the most significant, Y in between, and X being the
// least significant.
// 2D:
-// - inner_elements[5:3] = y[3:1]
-// - inner_elements[2:0] = x[2:0]
+// - inner_blocks[5:3] = y[3:1]
+// - inner_blocks[2:0] = x[2:0]
// 3D:
-// - inner_elements[6:5] = z[1:0]
-// - inner_elements[4:3] = y[2:1]
-// - inner_elements[2:0] = x[2:0]
+// - inner_blocks[6:5] = z[1:0]
+// - inner_blocks[4:3] = y[2:1]
+// - inner_blocks[2:0] = x[2:0]
//
// However, the "outer/inner" part doesn't include the offset of the micro tile
// within the macro tile: X[4:3], and Y[4] (2D) or Y[3] (3D). These are encoded
@@ -191,54 +184,54 @@ Address TiledCombine(const Address outer_inner_bytes, const uint32_t bank,
}
// The absolute of the return value is below 2^31 (for 16384x8192 with 16 bytes
-// per element, though it's not even clear if the hardware allows pitches
-// greater than 8192, the maximum texture size, but the pitch field in a texture
-// fetch constant is 14 bits wide).
+// per block, though it's not even clear if the hardware allows pitches greater
+// than 8192, the maximum texture size, but the pitch field in a texture fetch
+// constant is 14 bits wide).
inline int32_t Tiled2D(const int32_t x, const int32_t y,
const uint32_t pitch_aligned,
- const unsigned int bytes_per_element_log2) {
+ const unsigned int bytes_per_block_log2) {
// Expecting that all the needed rounding (not only to 32x32, but also to a
// power of two for mips) is done before the call so this function works with
// the actual storage dimensions.
- assert_zero(pitch_aligned & (kStoragePitchHeightAlignmentElements - 1));
- const int32_t outer_elements =
+ assert_zero(pitch_aligned & (kStoragePitchHeightAlignmentBlocks - 1));
+ const int32_t outer_blocks =
((y >> kMacroTileHeight2DLog2) *
int32_t(pitch_aligned >> kMacroTileWidthLog2) +
(x >> kMacroTileWidthLog2))
<< 6;
- const int32_t inner_elements = (((y >> 1) & 0b111) << 3) | (x & 0b111);
- const int32_t outer_inner_bytes = (outer_elements | inner_elements)
- << bytes_per_element_log2;
+ const int32_t inner_blocks = (((y >> 1) & 0b111) << 3) | (x & 0b111);
+ const int32_t outer_inner_bytes = (outer_blocks | inner_blocks)
+ << bytes_per_block_log2;
const uint32_t bank = (y >> 4) & 0b1;
const uint32_t pipe = ((x >> 3) & 0b11) ^ (((y >> 3) & 0b1) << 1);
return TiledCombine(outer_inner_bytes, bank, pipe, y & 1);
}
// The absolute of the return value is below 2^39 (for 16384x2048x1024 with 16
-// bytes per element). This also means that 32 (more precisely, 27) bits is
-// always enough for the page index within a subresource.
+// bytes per block). This also means that 32 (more precisely, 27) bits is always
+// enough for the page index within a subresource.
inline int64_t Tiled3D(const int32_t x, const int32_t y, const int32_t z,
const uint32_t pitch_aligned,
const uint32_t height_aligned,
- const unsigned int bytes_per_element_log2) {
+ const unsigned int bytes_per_block_log2) {
// Expecting that all the needed rounding (not only to 32x32x4, but also to a
// power of two for mips) is done before the call so this function works with
// the actual storage dimensions.
- assert_zero(pitch_aligned & (kStoragePitchHeightAlignmentElements - 1));
- assert_zero(height_aligned & (kStoragePitchHeightAlignmentElements - 1));
- // The absolute of `outer_elements` is below (1024 / 4) * (2048 / 16) *
+ assert_zero(pitch_aligned & (kStoragePitchHeightAlignmentBlocks - 1));
+ assert_zero(height_aligned & (kStoragePitchHeightAlignmentBlocks - 1));
+ // The absolute of `outer_blocks` is below (1024 / 4) * (2048 / 16) *
// (16384 / 32) * 128 = 2^31.
- const int32_t outer_elements =
+ const int32_t outer_blocks =
((((z >> kMacroTileDepthLog2) *
(height_aligned >> kMacroTileHeight3DLog2) +
(y >> kMacroTileHeight3DLog2)) *
int32_t(pitch_aligned >> kMacroTileWidthLog2)) +
(x >> kMacroTileWidthLog2))
<< 7;
- const int32_t inner_elements =
+ const int32_t inner_blocks =
((z & 0b11) << 5) | (((y >> 1) & 0b11) << 3) | (x & 0b111);
- const int64_t outer_inner_bytes = int64_t(outer_elements | inner_elements)
- << bytes_per_element_log2;
+ const int64_t outer_inner_bytes = int64_t(outer_blocks | inner_blocks)
+ << bytes_per_block_log2;
const uint32_t bank = ((y >> 3) ^ (z >> 2)) & 0b1;
const uint32_t pipe = ((x >> 3) & 0b11) ^ (bank << 1);
return TiledCombine(outer_inner_bytes, bank, pipe, y & 1);