mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 02:47:02 +02:00
Graphics: share canonical padded layouts for single-sample color targets
This commit is contained in:
@@ -1238,38 +1238,6 @@ bool TileGetDccSize(uint32_t width, uint32_t height, uint32_t slices,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TileGetRenderTargetMipLayout(uint32_t width, uint32_t height, uint32_t pitch,
|
||||
uint32_t bytes_per_element, uint32_t levels,
|
||||
TileSizeAlign& total_size, TileSizeOffset* level_sizes,
|
||||
TilePaddedSize* padded_size) {
|
||||
total_size = {};
|
||||
if (width == 0 || height == 0 || levels == 0 || levels > 16 ||
|
||||
pitch != TileGetRenderTargetPitch(width, bytes_per_element)) {
|
||||
return false;
|
||||
}
|
||||
uint32_t max_levels = 1;
|
||||
uint32_t max_dimension = std::max(width, height);
|
||||
while (max_dimension > 1) {
|
||||
max_dimension >>= 1u;
|
||||
max_levels++;
|
||||
}
|
||||
if (levels > max_levels) {
|
||||
return false;
|
||||
}
|
||||
auto format = Prospero::BufferFormat::kInvalid;
|
||||
switch (bytes_per_element) {
|
||||
case 1: format = Prospero::BufferFormat::k8UNorm; break;
|
||||
case 2: format = Prospero::BufferFormat::k16UNorm; break;
|
||||
case 4: format = Prospero::BufferFormat::k32Float; break;
|
||||
case 8: format = Prospero::BufferFormat::k16_16_16_16Float; break;
|
||||
case 16: format = Prospero::BufferFormat::k32_32_32_32Float; break;
|
||||
default: return false;
|
||||
}
|
||||
TileGetTextureSize(format, width, height, levels, Prospero::TileMode::kRenderTarget,
|
||||
&total_size, level_sizes, padded_size);
|
||||
return total_size.size != 0 && total_size.align == 65536;
|
||||
}
|
||||
|
||||
void TileGetTextureSize(Prospero::BufferFormat format, uint32_t width, uint32_t height,
|
||||
uint32_t levels, Prospero::TileMode tile, TileSizeAlign* total_size,
|
||||
TileSizeOffset* level_sizes, TilePaddedSize* padded_size) {
|
||||
|
||||
@@ -126,10 +126,6 @@ bool TileGetRenderTargetSize(uint32_t width, uint32_t height, uint32_t pitch
|
||||
bool TileGetDccSize(uint32_t width, uint32_t height, uint32_t slices,
|
||||
uint32_t bytes_per_element, uint32_t levels, Prospero::TileMode tile,
|
||||
TileSizeAlign& total_size, uint32_t num_fragments_log2 = 0);
|
||||
bool TileGetRenderTargetMipLayout(uint32_t width, uint32_t height, uint32_t pitch,
|
||||
uint32_t bytes_per_element, uint32_t levels,
|
||||
TileSizeAlign& total_size, TileSizeOffset* level_sizes,
|
||||
TilePaddedSize* padded_size);
|
||||
void TileGetTextureSize(Prospero::BufferFormat format, uint32_t width, uint32_t height,
|
||||
uint32_t levels, Prospero::TileMode tile, TileSizeAlign* total_size,
|
||||
TileSizeOffset* level_sizes, TilePaddedSize* padded_size);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <bit>
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
@@ -200,8 +201,7 @@ void RenderExecutor::ResolveRenderColorTarget(CommandBuffer& buffer, RenderColor
|
||||
" layer=%u/%u\n",
|
||||
rt.attrib3.dimension, rt.attrib3.depth, view.base_layer, view.image_layers);
|
||||
}
|
||||
// PPSA28068: the linear EULA target and its sampled view must share the padded pitch.
|
||||
if (!tile || volume || texture_tile) {
|
||||
if (samples == 1) {
|
||||
pitch = TileGetTexturePitch(transfer_format, width, rt.attrib3.tile_mode);
|
||||
} else {
|
||||
pitch = TileGetRenderTargetPitch(width, bytes_per_element, rt.attrib.num_fragments);
|
||||
@@ -232,28 +232,23 @@ void RenderExecutor::ResolveRenderColorTarget(CommandBuffer& buffer, RenderColor
|
||||
} else {
|
||||
TileSizeAlign layout {};
|
||||
bool valid_layout = false;
|
||||
if (!tile || texture_tile) {
|
||||
if (samples == 1) {
|
||||
TileGetTextureSize(transfer_format, width, height, levels, rt.attrib3.tile_mode,
|
||||
&layout, mip_sizes, mip_padded);
|
||||
const auto alignment = tile ? texture_tile_layout.block.block_size : 256u;
|
||||
valid_layout = layout.size != 0 && layout.align == alignment;
|
||||
valid_layout = layout.size != 0 && layout.align != 0 &&
|
||||
(rt.attrib3.tile_mode != Prospero::TileMode::kRenderTarget ||
|
||||
levels <= std::bit_width(std::max(width, height)));
|
||||
} else {
|
||||
valid_layout =
|
||||
levels == 1 ? TileGetRenderTargetSize(width, height, pitch, bytes_per_element,
|
||||
layout, rt.attrib.num_fragments)
|
||||
: TileGetRenderTargetMipLayout(width, height, pitch, bytes_per_element,
|
||||
levels, layout, mip_sizes, mip_padded);
|
||||
valid_layout = TileGetRenderTargetSize(width, height, pitch, bytes_per_element,
|
||||
layout, rt.attrib.num_fragments);
|
||||
mip_sizes[0] = {layout.size, 0, 0, 0, 0, 0};
|
||||
mip_padded[0] = {pitch, height};
|
||||
}
|
||||
if (!valid_layout) {
|
||||
EXIT("unsupported render-target layout: %ux%u pitch=%u bytes=%u levels=%u\n", width,
|
||||
height, pitch, bytes_per_element, levels);
|
||||
}
|
||||
size = layout.size;
|
||||
EXIT_IF(size > UINT32_MAX);
|
||||
if (levels == 1) {
|
||||
mip_sizes[0] = {static_cast<uint32_t>(size), 0, 0, 0, 0, 0};
|
||||
mip_padded[0] = {pitch, height};
|
||||
}
|
||||
}
|
||||
if (size == 0 || (!volume && size > UINT64_MAX / view.image_layers)) {
|
||||
EXIT("render-target memory footprint is invalid\n");
|
||||
|
||||
@@ -8328,6 +8328,8 @@ public:
|
||||
TargetCase{1440, 720, 1, 1472, 0x40b000, Prospero::TileMode::kLinear},
|
||||
// PPSA01416: linear RGBA16F chains place the smallest mip first.
|
||||
TargetCase{128, 128, 1, 128, 0x2be00, Prospero::TileMode::kLinear, 7, true},
|
||||
// PPSA03541: the single texel still occupies a padded 128x64 block.
|
||||
TargetCase{1, 1, 1, 128, 0x10000, Prospero::TileMode::kRenderTarget, 1, true},
|
||||
};
|
||||
constexpr uint64_t allocation_size = 0x410000;
|
||||
|
||||
@@ -8409,6 +8411,12 @@ public:
|
||||
rendering.num_color_attachments == 1,
|
||||
"color attachment lost its dimensions or padded guest layout");
|
||||
|
||||
if (width == 1 && height == 1) {
|
||||
Require(name, "single-texel tiled layout",
|
||||
color.desc.info.mip_layout[0] == ImageMipInfo{0, 0x10000, 128, 64},
|
||||
"the render target lost the SDK's padded block height");
|
||||
}
|
||||
|
||||
if (target.levels == 7) {
|
||||
constexpr std::array offsets{0xbe00u, 0x3e00u, 0x1e00u, 0xe00u,
|
||||
0x600u, 0x200u, 0u};
|
||||
@@ -8422,7 +8430,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
if (target.tile == Prospero::TileMode::kLinear) {
|
||||
{
|
||||
vk::ClearValue clear{};
|
||||
clear.color.float32 = std::array{1.0f, 0.0f, 1.0f, 1.0f};
|
||||
TextureCacheTestAccess::ClearImage(
|
||||
@@ -8437,7 +8445,9 @@ public:
|
||||
(((width - 1u) & 3u) << 30u),
|
||||
((width - 1u) >> 2u) | ((height - 1u) << 14u),
|
||||
DstSel(4, 5, 6, 7) | ((target.levels - 1) << 16u) |
|
||||
(static_cast<uint32_t>(Prospero::ImageType::kColor2D) << 28u),
|
||||
(static_cast<uint32_t>(target.tile) << 20u) |
|
||||
(static_cast<uint32_t>(is_1d ? Prospero::ImageType::kColor1D
|
||||
: Prospero::ImageType::kColor2D) << 28u),
|
||||
0, 0x00700000u | ((target.levels - 1) << 4u), 0, 0}};
|
||||
ShaderRecompiler::IR::DescriptorValue value{};
|
||||
value.dword_count = 8;
|
||||
@@ -8445,27 +8455,28 @@ public:
|
||||
ShaderRecompiler::IR::ImageResource resource{};
|
||||
resource.resource_class = ShaderRecompiler::IR::ImageResourceClass::Sampled;
|
||||
resource.numeric_class = Prospero::TextureNumericClass::Float;
|
||||
resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
||||
resource.dimension = is_1d ? ShaderRecompiler::Decoder::ImageDimension::Dim1D
|
||||
: ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
||||
resource.read = true;
|
||||
const auto sampled =
|
||||
RenderExecutorTestAccess::ResolveTexture(executor, resource, value);
|
||||
Require(name, "linear target sampled alias",
|
||||
Require(name, "target sampled alias",
|
||||
sampled.image_id == color.image_id &&
|
||||
sampled.desc.info.pitch == target.pitch &&
|
||||
sampled.desc.info.data.size == target.size &&
|
||||
sampled.desc.info.mip_layout == color.desc.info.mip_layout &&
|
||||
texture_cache.FindTexture(sampled.image_id, sampled.desc) != nullptr,
|
||||
"sampling the linear target created a second image");
|
||||
"sampling the target changed its padded layout or created a second image");
|
||||
const auto expected = target.float16
|
||||
? std::vector<u32>{0x00003c00u, 0x3c003c00u}
|
||||
: std::vector<u32>{0xffff00ffu};
|
||||
for (uint32_t mip = 0; mip < target.levels; ++mip) {
|
||||
Require(name, "linear target sampled contents",
|
||||
Require(name, "target sampled contents",
|
||||
ReadCachedTexel(name, context, sampled.image_id,
|
||||
{static_cast<int32_t>((width >> mip) - 1),
|
||||
static_cast<int32_t>((height >> mip) - 1), 0},
|
||||
{1, 1, 1}, 0, mip) == expected,
|
||||
"the sampled linear target lost its GPU-written final texel");
|
||||
"the sampled target lost its GPU-written final texel");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user