mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-19 18:36:53 +02:00
graphics: preserve sparse spans in rebased mip-tail views
This commit is contained in:
@@ -21,7 +21,7 @@ bool IsDepthPlane(const ImageInfo& info) {
|
||||
info.tile_mode == Prospero::TileMode::kLinear);
|
||||
}
|
||||
|
||||
GuestRange ContiguousMipRange(const ImageInfo& info, uint32_t level) {
|
||||
GuestRange TiledMipRange(const ImageInfo& info, uint32_t level) {
|
||||
const auto& block = info.tiling.block;
|
||||
if (info.tile_mode != Prospero::TileMode::kStandard4KB ||
|
||||
block.family != TileBlockFamily::Standard4KB || info.IsVolume() || info.samples != 1 ||
|
||||
@@ -42,11 +42,10 @@ GuestRange ContiguousMipRange(const ImageInfo& info, uint32_t level) {
|
||||
!TileGetBlockOffset(block, mip.tail_x, mip.tail_y, 0, origin)) {
|
||||
return {};
|
||||
}
|
||||
// Standard4KB interleaves monotonically ordered X/Y bits. A dense rectangle
|
||||
// fills exactly this power-of-two interval, including when rebased into a tail.
|
||||
// Standard4KB interleaves monotonically ordered X/Y bits, so the last
|
||||
// corner bounds every active texel. Tiling preserves any holes in this span.
|
||||
const uint64_t size = uint64_t {last} + block.bytes_per_element;
|
||||
if (!std::has_single_bit(size) || size != uint64_t {width} * height * block.bytes_per_element ||
|
||||
(origin & (size - 1u)) != 0 || size > block.block_size - origin ||
|
||||
if ((origin & (std::bit_ceil(size) - 1u)) != 0 || size > block.block_size - origin ||
|
||||
mip.offset > UINT64_MAX - origin) {
|
||||
return {};
|
||||
}
|
||||
@@ -57,11 +56,11 @@ uint32_t CompactMipSize(const ImageInfo& info) {
|
||||
if (info.resources.levels != 1 || info.resources.layers != 1) {
|
||||
return 0;
|
||||
}
|
||||
const auto range = ContiguousMipRange(info, 0);
|
||||
if (range.size == 0 || range.address != 0) {
|
||||
const auto range = TiledMipRange(info, 0);
|
||||
if (range.size == 0 || range.size % 4 != 0 || range.address != 0) {
|
||||
return 0;
|
||||
}
|
||||
const auto alignment = std::max<uint64_t>(256, range.size);
|
||||
const auto alignment = std::max<uint64_t>(256, std::bit_ceil(range.size));
|
||||
const auto in_block = info.data.address & (info.tiling.block.block_size - 1u);
|
||||
return (info.data.address & (alignment - 1u)) == 0 &&
|
||||
range.size <= info.tiling.block.block_size - in_block
|
||||
@@ -226,7 +225,7 @@ uint32_t ImageInfo::DataAlignment() const {
|
||||
}
|
||||
const auto compact_size = CompactMipSize(*this);
|
||||
if (compact_size != 0 && data.size == compact_size && mip_layout[0].size == compact_size) {
|
||||
return std::max(256u, compact_size);
|
||||
return std::max(256u, std::bit_ceil(compact_size));
|
||||
}
|
||||
return tiling.block.block_size;
|
||||
}
|
||||
@@ -260,14 +259,14 @@ int32_t ImageInfo::SliceOf(const ImageInfo& container, int32_t mip) const noexce
|
||||
}
|
||||
|
||||
// PS5 block slices contain the entire reversed mip chain. A rebased tail
|
||||
// descriptor covers only its active bytes within the shared tail block.
|
||||
// descriptor covers its addressed span within the shared tail block.
|
||||
const auto slice_stride = container.data.size / container.resources.layers;
|
||||
const auto child_stride = data.size / resources.layers;
|
||||
auto mip_offset = layout.offset;
|
||||
auto mip_size = layout.size / container.resources.layers;
|
||||
const auto compact_size = CompactMipSize(*this);
|
||||
if (compact_size != 0 && child_stride == compact_size && mip_layout[0].size == compact_size) {
|
||||
const auto range = ContiguousMipRange(container, level);
|
||||
const auto range = TiledMipRange(container, level);
|
||||
if (range.size != compact_size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -18673,15 +18673,18 @@ public:
|
||||
check_round_trip("odd multi-mip", total.size, layout);
|
||||
}
|
||||
|
||||
{
|
||||
constexpr auto format = Prospero::BufferFormat::k16_16_16_16Float;
|
||||
for (const bool sparse : {false, true}) {
|
||||
const auto format = sparse ? Prospero::BufferFormat::k32_32_32_32UInt
|
||||
: Prospero::BufferFormat::k16_16_16_16Float;
|
||||
constexpr auto tile = Prospero::TileMode::kStandard4KB;
|
||||
auto view = MakeTilingImage(format, 16, 16, 1, 1, tile, 0, false);
|
||||
view.data.address = 0x5032b23800;
|
||||
const uint32_t extent = sparse ? 2 : 16;
|
||||
auto view = MakeTilingImage(format, extent, extent, 1, 1, tile, 0, false);
|
||||
view.data.address = sparse ? 0x50322e3500 : 0x5032b23800;
|
||||
view.UpdateSize();
|
||||
Require(name, "rebased mip footprint",
|
||||
view.data.size == 0x800 && view.DataAlignment() == 0x800 &&
|
||||
view.mip_layout[0].pitch == 32 &&
|
||||
view.data.size == (sparse ? 0x60 : 0x800) &&
|
||||
view.DataAlignment() == (sparse ? 0x100 : 0x800) &&
|
||||
view.mip_layout[0].pitch == (sparse ? 16 : 32) &&
|
||||
view.mip_layout[0].height == 16 &&
|
||||
view.tiled_slice_stride == 0x1000,
|
||||
"a compact view changed its allocation geometry");
|
||||
|
||||
@@ -1366,18 +1366,26 @@ void TestRebasedTextureMipViews() {
|
||||
Check(view.MipOf(chain) == -1,
|
||||
"full-block child ignored the parent mip's nonzero tail origin");
|
||||
|
||||
for (uint32_t variant = 0; variant < 7; ++variant) {
|
||||
for (uint32_t variant = 0; variant < 9; ++variant) {
|
||||
view = make_view(4, 0);
|
||||
view.data = {chain.data.address, 0};
|
||||
view.pitch = 0;
|
||||
switch (variant) {
|
||||
case 0: view.extent = {8, 16, 1}; break; // Holes in the Standard4KB span.
|
||||
case 0: view.extent = {7, 16, 1}; break; // Unproven non-power-of-two view.
|
||||
case 1: view.resources.levels = 2; break;
|
||||
case 2: view.resources.layers = 2; break;
|
||||
case 3: view.type = Prospero::ImageType::kColor3D; break;
|
||||
case 4: view.tile_mode = Prospero::TileMode::kStandard64KB; break;
|
||||
case 5: view.metadata.kind = ImageMetadataKind::Dcc; break;
|
||||
case 6: view.data = {0x5032b23800, 0x1000}; break;
|
||||
case 7:
|
||||
case 8:
|
||||
view.guest_format = variant == 7 ? Prospero::BufferFormat::k8UNorm
|
||||
: Prospero::BufferFormat::k16UNorm;
|
||||
view.pixel_format = variant == 7 ? vk::Format::eR8Unorm : vk::Format::eR16Unorm;
|
||||
view.bytes_per_block = 0;
|
||||
view.extent = {1, 1, 1};
|
||||
break;
|
||||
}
|
||||
view.UpdateSize();
|
||||
Check(view.data.size >= 0x1000 && view.DataAlignment() >= 0x1000,
|
||||
@@ -1388,6 +1396,40 @@ void TestRebasedTextureMipViews() {
|
||||
view.UpdateSize();
|
||||
Check(view.data.size == 0x1000 && view.DataAlignment() == 0x1000,
|
||||
"misaligned descriptor received compact tail alignment");
|
||||
|
||||
view = make_view(4, 0);
|
||||
view.data = {chain.data.address, 0};
|
||||
view.extent.width = 8;
|
||||
view.UpdateSize();
|
||||
Check(view.data.size == 0x600 && view.DataAlignment() == 0x800,
|
||||
"sparse rectangle confused addressed span with active byte count");
|
||||
|
||||
auto sparse_chain = chain;
|
||||
sparse_chain.data = {0x503225f000, 0};
|
||||
sparse_chain.pixel_format = vk::Format::eR32G32B32A32Uint;
|
||||
sparse_chain.guest_format = Prospero::BufferFormat::k32_32_32_32UInt;
|
||||
sparse_chain.extent = {64, 64, 1};
|
||||
sparse_chain.resources = {6, 7};
|
||||
sparse_chain.pitch = sparse_chain.bytes_per_block = 0;
|
||||
sparse_chain.UpdateSize();
|
||||
auto sparse = sparse_chain;
|
||||
sparse.data = {0x50322e3500, 0};
|
||||
sparse.extent = {2, 2, 1};
|
||||
sparse.resources = {1, 1};
|
||||
sparse.pitch = 0;
|
||||
sparse.UpdateSize();
|
||||
Check(sparse_chain.tiled_slice_stride == 0x16000 &&
|
||||
sparse.data.size == 0x60 && sparse.mip_layout[0].size == 0x60 &&
|
||||
sparse.DataAlignment() == 0x100 && sparse.LinearSize() == 0x200 &&
|
||||
sparse.MipOf(sparse_chain) == 5 && sparse.SliceOf(sparse_chain, 5) == 6,
|
||||
"captured sparse 2x2 view lost its byte span, tail origin, or array layer");
|
||||
sparse.UpdateSize();
|
||||
Check(sparse.data.size == 0x60 && sparse.mip_layout[0].size == 0x60 &&
|
||||
sparse.DataAlignment() == 0x100,
|
||||
"repeated sparse view sizing changed its span or alignment");
|
||||
sparse.data.address -= 0x100;
|
||||
Check(sparse.MipOf(sparse_chain) == -1,
|
||||
"sparse view accepted a different mip-tail origin");
|
||||
}
|
||||
|
||||
void TestShaderFeatureCollection() {
|
||||
|
||||
Reference in New Issue
Block a user