mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 13:56:59 +01:00
renderer: clear compressed stencil with pending depth metadata
This commit is contained in:
@@ -321,9 +321,6 @@ void RenderExecutor::ResolveRenderDepthTarget(CommandBuffer& buffer, RenderDepth
|
|||||||
|
|
||||||
r.stencil_clear_enable =
|
r.stencil_clear_enable =
|
||||||
has_stencil && rc.stencil_clear_enable && !z.depth_view.stencil_write_disable;
|
has_stencil && rc.stencil_clear_enable && !z.depth_view.stencil_write_disable;
|
||||||
r.load_clear_aspects = {};
|
|
||||||
if (r.depth_clear_enable) r.load_clear_aspects |= vk::ImageAspectFlagBits::eDepth;
|
|
||||||
if (r.stencil_clear_enable) r.load_clear_aspects |= vk::ImageAspectFlagBits::eStencil;
|
|
||||||
r.stencil_clear_value = hw.GetStencilClearValue();
|
r.stencil_clear_value = hw.GetStencilClearValue();
|
||||||
r.stencil_test_enable = has_stencil && dc.stencil_enable;
|
r.stencil_test_enable = has_stencil && dc.stencil_enable;
|
||||||
if (r.stencil_test_enable) {
|
if (r.stencil_test_enable) {
|
||||||
|
|||||||
@@ -507,17 +507,14 @@ RenderState RenderExecutor::AcquireRenderTargets(CommandBuffer& buffer, RenderCo
|
|||||||
}
|
}
|
||||||
const auto image_view = cache.FindDepthTarget(depth.image_id, depth.desc);
|
const auto image_view = cache.FindDepthTarget(depth.image_id, depth.desc);
|
||||||
const auto& metadata = depth.desc.info.metadata;
|
const auto& metadata = depth.desc.info.metadata;
|
||||||
if (metadata.kind == ImageMetadataKind::Htile && depth.depth_clear_enable &&
|
|
||||||
!cache.ClearMeta(metadata.range.address)) {
|
|
||||||
EXIT("failed to acquire HTile metadata for a depth clear\n");
|
|
||||||
}
|
|
||||||
const bool meta_clear =
|
const bool meta_clear =
|
||||||
metadata.kind == ImageMetadataKind::Htile &&
|
metadata.kind == ImageMetadataKind::Htile &&
|
||||||
cache.IsMetaCleared(metadata.range.address, depth.desc.view_info.base_layer);
|
cache.IsMetaCleared(metadata.range.address, depth.desc.view_info.base_layer);
|
||||||
depth.load_clear_aspects = {};
|
depth.load_clear_aspects = {};
|
||||||
if (depth.depth_clear_enable || meta_clear)
|
if (depth.depth_clear_enable || meta_clear)
|
||||||
depth.load_clear_aspects |= vk::ImageAspectFlagBits::eDepth;
|
depth.load_clear_aspects |= vk::ImageAspectFlagBits::eDepth;
|
||||||
if (depth.stencil_clear_enable)
|
// Apply pending clears to compressed stencil as well as depth.
|
||||||
|
if (depth.stencil_clear_enable || (meta_clear && metadata.stencil_compressed))
|
||||||
depth.load_clear_aspects |= vk::ImageAspectFlagBits::eStencil;
|
depth.load_clear_aspects |= vk::ImageAspectFlagBits::eStencil;
|
||||||
if (meta_clear &&
|
if (meta_clear &&
|
||||||
!cache.TouchMeta(metadata.range.address, depth.desc.view_info.base_layer, false)) {
|
!cache.TouchMeta(metadata.range.address, depth.desc.view_info.base_layer, false)) {
|
||||||
|
|||||||
@@ -14709,6 +14709,8 @@ public:
|
|||||||
RenderDepthInfo depth_only{};
|
RenderDepthInfo depth_only{};
|
||||||
RenderExecutorTestAccess::ResolveRenderDepthTarget(
|
RenderExecutorTestAccess::ResolveRenderDepthTarget(
|
||||||
executor, scheduler.Current(), depth_only);
|
executor, scheduler.Current(), depth_only);
|
||||||
|
(void)RenderExecutorTestAccess::AcquireRenderTargets(
|
||||||
|
executor, scheduler.Current(), &no_color, 0, depth_only);
|
||||||
Require(
|
Require(
|
||||||
name, "depth-only target with stale stencil state",
|
name, "depth-only target with stale stencil state",
|
||||||
depth_only.image_id && depth_only.desc.view_info.format == vk::Format::eD32Sfloat &&
|
depth_only.image_id && depth_only.desc.view_info.format == vk::Format::eD32Sfloat &&
|
||||||
@@ -17912,7 +17914,7 @@ public:
|
|||||||
registers.SetTargetOutputMode(1, 4);
|
registers.SetTargetOutputMode(1, 4);
|
||||||
stencil_target.z_info.htile_acceleration = true;
|
stencil_target.z_info.htile_acceleration = true;
|
||||||
stencil_target.htile_data_base_addr = depth_address + 0x30000;
|
stencil_target.htile_data_base_addr = depth_address + 0x30000;
|
||||||
registers.SetDepthRenderTarget(stencil_target);
|
registers.SetStencilClearValue(5);
|
||||||
registers.SetDepthClearValue(1);
|
registers.SetDepthClearValue(1);
|
||||||
stencil_control = {};
|
stencil_control = {};
|
||||||
stencil_control.stencil_enable = true;
|
stencil_control.stencil_enable = true;
|
||||||
@@ -17922,35 +17924,60 @@ public:
|
|||||||
registers.SetStencilMask({0x80, 0, 0x80, 1, 0x80, 0, 0x80, 1});
|
registers.SetStencilMask({0x80, 0, 0x80, 1, 0x80, 0, 0x80, 1});
|
||||||
user_config.SetPrimitiveType(Prospero::PrimitiveType::kTriList);
|
user_config.SetPrimitiveType(Prospero::PrimitiveType::kTriList);
|
||||||
shaders.SetEsShaderBase(vertex_address);
|
shaders.SetEsShaderBase(vertex_address);
|
||||||
for (uint32_t discard = 0; discard < null_pixels.size(); discard++) {
|
// Compressed metadata clears stencil; an uncompressed plane and an explicit
|
||||||
const auto &code = null_pixels[discard];
|
// depth-only clear preserve its previous contents. Match Suikoden's stale mask 2.
|
||||||
const auto address = reinterpret_cast<uint64_t>(code.data());
|
for (uint32_t clear_mode = 0; clear_mode < 3; clear_mode++) {
|
||||||
ShaderMapUserData(address,
|
stencil_target.stencil_info.htile_stencil_disabled = clear_mode == 0;
|
||||||
{.type = Prospero::ShaderBinaryType::kPs,
|
registers.SetDepthRenderTarget(stencil_target);
|
||||||
.code_size_bytes = static_cast<uint32_t>(code.size() * sizeof(u32))});
|
registers.SetRenderControl({.depth_clear_enable = clear_mode == 2});
|
||||||
shaders.SetPsShaderBase(address);
|
for (uint32_t discard = 0; discard < null_pixels.size(); discard++) {
|
||||||
RenderExecutorTestAccess::ResolveRenderDepthTarget(executor, scheduler.Current(), depth);
|
const auto &code = null_pixels[discard];
|
||||||
(void)cache.FindDepthTarget(depth.image_id, depth.desc);
|
const auto address = reinterpret_cast<uint64_t>(code.data());
|
||||||
vk::ClearValue zero{};
|
ShaderMapUserData(address,
|
||||||
TextureCacheTestAccess::ClearImage(cache, scheduler.Current(), depth.image_id,
|
{.type = Prospero::ShaderBinaryType::kPs,
|
||||||
{vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil,
|
.code_size_bytes = static_cast<uint32_t>(code.size() * sizeof(u32))});
|
||||||
0, 1, 0, 1}, zero);
|
shaders.SetPsShaderBase(address);
|
||||||
Require(name, "pending stencil-pass HTile clear",
|
RenderExecutorTestAccess::ResolveRenderDepthTarget(executor, scheduler.Current(), depth);
|
||||||
cache.ClearMeta(stencil_target.htile_data_base_addr),
|
(void)cache.FindDepthTarget(depth.image_id, depth.desc);
|
||||||
"the stencil pass did not retain its HTile metadata");
|
vk::ClearValue zero{};
|
||||||
RenderExecutorTestAccess::DrawAuto(
|
zero.depthStencil.stencil = 2;
|
||||||
executor, scheduler.Current(), {.vertex_count = 3, .instance_count = 1});
|
TextureCacheTestAccess::ClearImage(cache, scheduler.Current(), depth.image_id,
|
||||||
const auto depth_pixels = ReadCachedTexel(name, context, depth.image_id,
|
{vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil,
|
||||||
{}, {extent, extent, 1});
|
0, 1, 0, 1}, zero);
|
||||||
Require(name, "NULL-export full depth clear",
|
Require(name, "pending stencil-pass HTile clear",
|
||||||
std::ranges::all_of(depth_pixels, [](u32 v) { return v == 0x3f800000u; }),
|
clear_mode == 2
|
||||||
"an unexported color target clipped the pending depth clear");
|
? cache.TouchMeta(stencil_target.htile_data_base_addr, 0, false)
|
||||||
const auto stencil = read_stencil();
|
: cache.ClearMeta(stencil_target.htile_data_base_addr),
|
||||||
const auto expected = discard == 0 ? 0x80808080u : 0u;
|
"the stencil pass did not retain its HTile metadata");
|
||||||
Require(name, "NULL-export stencil coverage and discard",
|
RenderExecutorTestAccess::DrawAuto(
|
||||||
std::ranges::all_of(stencil, [=](u32 v) { return v == expected; }),
|
executor, scheduler.Current(), {.vertex_count = 3, .instance_count = 1});
|
||||||
"a stale color target clipped stencil coverage or the NULL-export shader was skipped");
|
const auto depth_pixels = ReadCachedTexel(name, context, depth.image_id,
|
||||||
|
{}, {extent, extent, 1});
|
||||||
|
Require(name, "NULL-export full depth clear",
|
||||||
|
std::ranges::all_of(depth_pixels, [](u32 v) { return v == 0x3f800000u; }),
|
||||||
|
"an unexported color target clipped the pending depth clear");
|
||||||
|
const auto stencil = read_stencil();
|
||||||
|
const auto cleared = clear_mode == 1 ? 0x05050505u : 0x02020202u;
|
||||||
|
const auto expected = cleared | (discard == 0 ? 0x80808080u : 0u);
|
||||||
|
Require(name, "NULL-export stencil coverage and discard",
|
||||||
|
std::ranges::all_of(stencil, [=](u32 v) { return v == expected; }),
|
||||||
|
"a stale color target clipped stencil coverage or the NULL-export shader was skipped");
|
||||||
|
Require(name, "HTile clear consumed once",
|
||||||
|
!cache.IsMetaCleared(stencil_target.htile_data_base_addr, 0),
|
||||||
|
"the draw retained a pending metadata clear");
|
||||||
|
if (clear_mode == 1 && discard == 1) {
|
||||||
|
zero.depthStencil.stencil = 9;
|
||||||
|
TextureCacheTestAccess::ClearImage(cache, scheduler.Current(), depth.image_id,
|
||||||
|
{vk::ImageAspectFlagBits::eStencil, 0, 1, 0, 1}, zero);
|
||||||
|
RenderExecutorTestAccess::DrawAuto(
|
||||||
|
executor, scheduler.Current(), {.vertex_count = 3, .instance_count = 1});
|
||||||
|
Require(name, "consumed HTile clear preserves later stencil",
|
||||||
|
std::ranges::all_of(read_stencil(), [](u32 v) { return v == 0x09090909u; }),
|
||||||
|
"a consumed metadata clear ran again on the next draw");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
registers.SetRenderControl({});
|
||||||
|
|
||||||
// A depth-only draw retains the previous PS address and write masks, but
|
// A depth-only draw retains the previous PS address and write masks, but
|
||||||
// SPI_SHADER_COL_FORMAT disables its exports. Compiling this stale PS
|
// SPI_SHADER_COL_FORMAT disables its exports. Compiling this stale PS
|
||||||
|
|||||||
Reference in New Issue
Block a user