mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-06 13:30:00 +00:00
fix(libSceAgcDriver): degrade shallow GCN mip levels to thin tiles
This commit is contained in:
1 parent
cc596afba5
commit
9fde6efab2
5 files changed
+23
-7
No files matched your search
@@ -71,7 +71,7 @@ struct SurfaceGeometry {
|
||||
|
||||
bool levelMajor = false;
|
||||
std::uint64_t GuestOffset(std::uint32_t layer, const TileMipLayout& mip) const {
|
||||
return levelMajor ? mip.tiledOffset + static_cast<std::uint64_t>(thick ? layer / blockDepth : layer) * mip.tiledSize : GuestLayerOffset(layer) + mip.tiledOffset;
|
||||
return levelMajor ? mip.tiledOffset + static_cast<std::uint64_t>(thick && !mip.gcnMicroTiled ? layer / blockDepth : layer) * mip.tiledSize : GuestLayerOffset(layer) + mip.tiledOffset;
|
||||
}
|
||||
std::uint64_t GuestLayerOffset(std::uint32_t layer) const { return thick ? static_cast<std::uint64_t>(layer / blockDepth) * layerBytes : static_cast<std::uint64_t>(layer) * layerBytes; }
|
||||
std::uint64_t LinearLayerOffset(std::uint32_t layer) const { return static_cast<std::uint64_t>(layer) * sliceLinearBytes; }
|
||||
@@ -94,7 +94,7 @@ struct GcnTileGeometry {
|
||||
};
|
||||
GcnTileGeometry GcnTiling(TextureTileMode tileMode, std::uint32_t bytesPerElement);
|
||||
inline std::uint32_t GcnLayerBankXor(const GcnTileGeometry& geometry, std::uint32_t layer) { return ((geometry.layerBankStep * layer) & geometry.bankMask) << geometry.bankShift; }
|
||||
inline TextureTileMode MipTileMode(TextureTileMode tileMode, const TileMipLayout& mip) { return mip.gcnMicroTiled ? GcnMicroTileMode(tileMode) : tileMode; }
|
||||
inline TextureTileMode MipTileMode(TextureTileMode tileMode, const TileMipLayout& mip) { return mip.gcnMicroTiled ? (IsGcnThick(tileMode) ? TextureTileMode::kGcnThin1D : GcnMicroTileMode(tileMode)) : tileMode; }
|
||||
bool LevelsFitAllocation(const GuestTextureResource& surface, std::uint32_t levels);
|
||||
GuestTextureResource ViewedArrayWindow(const GuestTextureResource& viewed, bool keysReadAsStored);
|
||||
GuestTextureResource ArrayLayerWindow(const GuestTextureResource& viewed, std::uint32_t maxArrayLayers);
|
||||
|
||||
@@ -234,7 +234,7 @@ void TextureDetiler::Dispatch(VkCommandBuffer commands, TextureTileMode tileMode
|
||||
Require(source != VK_NULL_HANDLE && destination != VK_NULL_HANDLE, "texture detiling requires source and destination buffers");
|
||||
std::uint32_t columnEnd = 0, rowEnd = 0;
|
||||
checkWindow(layout, window, columnEnd, rowEnd);
|
||||
const auto target = pipeline(MipTileMode(tileMode, layout), elementBytes, retile, thick);
|
||||
const auto target = pipeline(MipTileMode(tileMode, layout), elementBytes, retile, thick && !(IsGcnThick(tileMode) && layout.gcnMicroTiled));
|
||||
const auto alignment = std::max<VkDeviceSize>(context.limits.minStorageBufferOffsetAlignment, 4);
|
||||
const auto sourceDescriptorOffset = sourceOffset - sourceOffset % alignment;
|
||||
const auto destinationDescriptorOffset = destinationOffset - destinationOffset % alignment;
|
||||
|
||||
@@ -593,16 +593,20 @@ SurfaceGeometry describeGcnVolume(const GuestTextureResource& descriptor) {
|
||||
levelHeight = std::bit_ceil(levelHeight);
|
||||
levelDepth = std::bit_ceil(levelDepth);
|
||||
}
|
||||
const auto rowElements = AlignUp(levelWidth, 8u);
|
||||
const bool thin = level != 0 && levelDepth < 4u;
|
||||
auto rowElements = AlignUp(levelWidth, 8u);
|
||||
const auto rows = AlignUp(levelHeight, 8u);
|
||||
const auto slabs = (levelDepth + 3u) / 4u;
|
||||
if (thin) while ((rowElements * rows * bytes) % 256u != 0) rowElements += 8u;
|
||||
const auto thickness = thin ? 1u : 4u;
|
||||
const auto slabs = (levelDepth + thickness - 1u) / thickness;
|
||||
if (level == 0) Require(rowElements == descriptor.gcnPitch, "PS4 volume pitch " + std::to_string(descriptor.gcnPitch) + " is not padded to the thick micro tile");
|
||||
auto& mip = geometry.mips[level];
|
||||
mip.width = TexelLevelDimension(descriptor.width, level, texelWidth);
|
||||
mip.height = TexelLevelDimension(descriptor.height, level, texelHeight);
|
||||
mip.blocksPerRow = rowElements / 8u;
|
||||
mip.pitchBytes = rowElements * bytes;
|
||||
mip.tiledSize = static_cast<std::uint64_t>(rowElements) * rows * 4u * bytes;
|
||||
mip.tiledSize = static_cast<std::uint64_t>(rowElements) * rows * thickness * bytes;
|
||||
mip.gcnMicroTiled = thin;
|
||||
mip.linearSize = static_cast<std::uint64_t>(mip.pitchBytes) * mip.height;
|
||||
mip.tiledOffset = offset;
|
||||
mip.linearOffset = linearOffset;
|
||||
|
||||
@@ -258,6 +258,18 @@ void gcnThickTilingTests() {
|
||||
for (std::size_t i = 1; i < slabs.size(); ++i) Require(slabs[i].first >= slabs[i - 1].second, "PS4 thick volume slabs overlap");
|
||||
Require(slabs.size() == 8u + 4u + 2u + 1u && slabs.back().second == deepGeometry.guestBytes, "PS4 thick volume slab count or size changed");
|
||||
Require(deepGeometry.GuestOffset(4u, deepGeometry.mips[1]) == deepGeometry.mips[1].tiledOffset + deepGeometry.mips[1].tiledSize, "PS4 thick volume level 1 slab stride is not its own slab size");
|
||||
deep.mipCount = 6u;
|
||||
deep.lastLevel = 5u;
|
||||
const auto full = DescribeSurface(deep);
|
||||
Require(full.guestBytes == 151296u && full.mips[4].tiledOffset == 150528u && full.mips[5].tiledOffset == 151040u, "PS4 full volume mip chain differs from addrlib");
|
||||
Require(full.mips[4].tiledSize == 256u && full.GuestOffset(1u, full.mips[4]) == 150784u, "PS4 two-slice mip must use separate thin slices");
|
||||
Require(MipTileMode(deep.tileMode, full.mips[4]) == TextureTileMode::kGcnThin1D && MipTileMode(deep.tileMode, full.mips[3]) == deep.tileMode, "PS4 mip tile mode must degrade only below four slices");
|
||||
for (const auto format : {1u, 12u}) {
|
||||
deep.format = format;
|
||||
const auto narrow = DescribeSurface(deep);
|
||||
Require(narrow.mips[5].tiledSize == 256u && narrow.mips[5].pitchBytes == 32u, "PS4 thin volume mip needs SI slice alignment at small element sizes");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void gcnTilingTests() {
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
- [Vertex input and color target overlap](../../../core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp) (AGC driver) - direct draws exclude the descriptor prefix skipped by `firstVertex` or `firstInstance` from the alias check; indexed draws conservatively use index zero as the lower bound before adding `firstVertex`. Indirect draws still check the full descriptor extent. Reads of the active target's bytes remain unsupported; same-draw console ordering is not established.
|
||||
- [PS4 (GCN) tiling](../../../core/libs/prx/libSceAgcDriver/Graphics/src/TextureTiling.cpp) (libSceAgcDriver, PS4) - not checked on a console. Surfaces with `GuestTextureResource::gcnPitch` set use the GB_TILE_MODE and GB_MACROTILE_MODE tables of [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/main/src/video_core/amdgpu/tiling.cpp) and addrlib's `ComputeSurfaceAddrFromCoordMicroTiled` and `MacroTiled`: 8x8 micro tiles in thin, depth or display element order, macro tiles with pipe config P8_32x32_16x16 (P8_32x32_8x16 for the two PRT thin modes), bank width 1 and a 256-byte pipe interleave, depth micro tiles split into slices a whole surface apart with the bank rotated by (banks / 2 + 1) per slice, PRT pipe, and for GB_TILE_MODE 11 and 16 bank, taken from the coordinates inside the macro tile, and LINEAR_GENERAL rows of exactly the pitch. [TextureTiling.cpp](../../../core/libs/prx/libSceAgcDriver/tests/TextureTiling.cpp) compares it with a separate implementation of them.
|
||||
- [PS4 (GCN) 2D PRT tiling](../../../core/libs/prx/libSceAgcDriver/Graphics/src/TextureTiling.cpp) (libSceAgcDriver, PS4) - not checked on a console. GB_TILE_MODE 6, 7, 12 and 17 take the bank from the coordinates inside the macro tile, as shadPS4 does; AMD's addrlib (Mesa 393bf0d1467c) and fpPS4 (04cefd43e6fd) use the whole coordinates for the bank of these 2D PRT modes and take it inside the macro tile only for modes 11 and 16, which fpPS4 documents as the ones that can alias virtual pages to one physical page.
|
||||
- [PS4 (GCN) thick and layered surfaces](../../../core/libs/prx/libSceAgcDriver/Graphics/src/TextureTiling.cpp) (libSceAgcDriver, PS4) - a 3D texture in tile mode 19 (`Thick_1dThick`) uses addrlib's 8x8x4 `ADDR_THICK` micro tiles, depth padded to 4, each level as slabs of four slices; a block-compressed volume, a thick mode on a non-3D T# and a storage image of a volume with mips throw. Modes 15 and 20 to 26 throw, and so does a storage image or depth plane of a layered surface with mips; a sampled one is stored level by level, unchecked on a console; [GcnDetile.cpp](../../../core/libs/prx/libSceAgcDriver/tests/execution/GcnDetile.cpp) covers the thin and depth modes; mode 19 has layout tests only. The bank of each layer of a tiled 2D array is rotated by (banks / 2 - 1) times the layer index outside the PRT modes, XORed in as AMD's address library and shadPS4 (`tiling.comp`, 0614ce324be0) do; fpPS4 (`ps4_tiling.pas`, 04cefd43e6fd) adds it to the bank instead. Not checked on a console.
|
||||
- [PS4 (GCN) thick and layered surfaces](../../../core/libs/prx/libSceAgcDriver/Graphics/src/TextureTiling.cpp) (libSceAgcDriver, PS4) - a 3D texture in tile mode 19 (`Thick_1dThick`) uses addrlib's 8x8x4 `ADDR_THICK` micro tiles, depth padded to 4, each level as slabs of four slices; nonzero levels below four slices degrade to 1D thin with one slice per stride and pitch raised until the slice is 256-byte aligned (addrlib `ComputeSurfaceInfoMicroTiled` and SI `HwlGetSizeAdjustmentMicroTiled`); a block-compressed volume, a thick mode on a non-3D T# and a storage image of a volume with mips throw. Modes 15 and 20 to 26 throw, and so does a storage image or depth plane of a layered surface with mips; a sampled one is stored level by level, unchecked on a console; [GcnDetile.cpp](../../../core/libs/prx/libSceAgcDriver/tests/execution/GcnDetile.cpp) covers the thin and depth modes; mode 19 has layout tests only. The bank of each layer of a tiled 2D array is rotated by (banks / 2 - 1) times the layer index outside the PRT modes, XORed in as AMD's address library and shadPS4 (`tiling.comp`, 0614ce324be0) do; fpPS4 (`ps4_tiling.pas`, 04cefd43e6fd) adds it to the bank instead. Not checked on a console.
|
||||
- [PS4 render targets and display buffers](../../../core/libs/prx/libSceAgcDriver/Execution/src/DisplayBuffer.cpp) (libSceAgcDriver, PS4) - a tiled PS4 display buffer is read as Display2DThin with rows padded to 128 elements, as shadPS4's `image_info.cpp` does. A PS4 render target spans its surface padded to whole macro tiles (1920x1080 at 32 bits is 1920x1088), the display buffer is its top-left corner, and a texture over that corner with the same pitch, tiling and texel size is a [GPU copy](../../../core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp) of it. A PS4 `DB_Z_INFO` names a GB_TILE_MODE index; the depth image stays on the GPU and HTILE is kept, as for the PS5. shadPS4 (`image_info.cpp`, 0614ce324be0) rounds the width of a tiled display buffer up to a multiple of 128 itself, whereas `DisplayBufferSize` requires the pitch to be one already. A PS4 depth target spans `DB_DEPTH_SIZE`; a smaller level-0 depth view reads a plane copy of its corner, a stencil one guest memory.
|
||||
- [PS4 pattern fill](../../../core/libs/prx/libSceAgcDriver/Execution/src/Driver/Memory/BufferFill.cpp) (libSceAgcDriver, PS4) - the PS4 build of the pattern-fill compute kernel seen in Limbo (CUSA01664), with user data s[4:7] a 32-bit UINT source, s[8:11] the 32-bit UINT destination and s[12:15] a control record of count and index mask, where thread i stores source[i & mask], runs as a GPU fill when the mask is 0, a single repeated dword; other masks run the kernel, since running Limbo's two-dword clears of a 64-bit target as fills made its gameplay advance more slowly per frame. The kernel is recognized by its code, not by an SDK symbol.
|
||||
|
||||
|
||||
Reference in new issue
Block a user