mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 10:56:58 +02:00
graphics: route compact color exports through CB_SHADER_MASK
This commit is contained in:
@@ -15610,6 +15610,7 @@ public:
|
||||
HW::UserConfig user_config{};
|
||||
HW::Shader shaders{};
|
||||
registers.SetRenderTargetMask(0xf);
|
||||
registers.SetShaderMask(0xf);
|
||||
scheduler.Begin(registers, user_config, shaders);
|
||||
auto &resources = context;
|
||||
auto &cache = context.GetTextureCache();
|
||||
@@ -16353,8 +16354,9 @@ public:
|
||||
registers.SetColorAttrib2(slot, {.height = side - 1, .width = side - 1});
|
||||
registers.SetColorAttrib3(slot,
|
||||
{.tile_mode = Prospero::TileMode::kLinear, .dimension = 1});
|
||||
registers.SetTargetOutputMode(slot, 4);
|
||||
}
|
||||
registers.SetTargetOutputMode(0, 4);
|
||||
registers.SetTargetOutputMode(1, 4);
|
||||
stencil_target.z_info.htile_acceleration = true;
|
||||
stencil_target.htile_data_base_addr = depth_address + 0x30000;
|
||||
registers.SetDepthRenderTarget(stencil_target);
|
||||
@@ -16416,7 +16418,7 @@ public:
|
||||
registers.SetDepthShaderControl({});
|
||||
registers.SetDepthControl({.z_enable = true, .z_write_enable = true,
|
||||
.zfunc = static_cast<uint8_t>(vk::CompareOp::eAlways)});
|
||||
for (const auto slot : {0u, 3u}) {
|
||||
for (const auto slot : {0u, 1u}) {
|
||||
registers.SetTargetOutputMode(slot, 0);
|
||||
}
|
||||
RenderExecutorTestAccess::DrawAuto(
|
||||
@@ -16427,37 +16429,48 @@ public:
|
||||
std::ranges::all_of(depth_only_pixels, [](u32 v) { return v == 0; }),
|
||||
"disabled color exports invoked the stale PS or clipped fixed-function depth");
|
||||
registers.SetPsInControl(0x8000);
|
||||
for (const auto slot : {0u, 3u}) {
|
||||
registers.SetTargetOutputMode(slot, 4);
|
||||
}
|
||||
registers.SetTargetOutputMode(0, 4);
|
||||
|
||||
// With MRT0 still bound, an MRT3-only export must retain location3 in
|
||||
// rendering attachments, pipeline formats, blend masks and dynamic write enables.
|
||||
static const auto sparse_pixel = [] {
|
||||
auto code = native_pixel;
|
||||
*std::ranges::find(code, EncodeExp0(0x00, 0xf)) = EncodeExp0(0x03, 0xf);
|
||||
return code;
|
||||
// Export ordinals follow CB_SHADER_MASK. A disabled CB_TARGET_MASK slot
|
||||
// still consumes an ordinal, and stale MRT0 must not clip physical MRT3.
|
||||
static const auto sparse_pixels_code = [] {
|
||||
std::array<std::vector<u32>, 2> result{native_pixel, native_pixel};
|
||||
auto &code = result[1];
|
||||
const auto exp = std::ranges::find(code, EncodeExp0(0, 0xf));
|
||||
*exp = EncodeExp0(0, 0xf, false);
|
||||
*(exp + 1) = EncodeExp1(0, 0, 0, 0);
|
||||
code.insert(exp + 2, {EncodeExp0(1, 0xf), EncodeExp1(1, 1, 1, 2)});
|
||||
return result;
|
||||
}();
|
||||
const auto sparse_address = reinterpret_cast<uint64_t>(sparse_pixel.data());
|
||||
ShaderMapUserData(sparse_address,
|
||||
{.type = Prospero::ShaderBinaryType::kPs,
|
||||
.code_size_bytes = static_cast<uint32_t>(sparse_pixel.size() * sizeof(u32))});
|
||||
shaders.SetPsShaderBase(sparse_address);
|
||||
registers.SetRenderTargetMask(0xf000);
|
||||
registers.SetDepthControl({});
|
||||
registers.SetDepthShaderControl({});
|
||||
RenderExecutorTestAccess::DrawAuto(
|
||||
executor, scheduler.Current(), {.vertex_count = 3, .instance_count = 1});
|
||||
RenderColorInfo sparse_color{};
|
||||
RenderExecutorTestAccess::ResolveRenderColorTarget(
|
||||
executor, scheduler.Current(), sparse_color, 3);
|
||||
const auto sparse_pixels = ReadCachedTexel(name, context, sparse_color.image_id,
|
||||
{}, {extent, extent, 1});
|
||||
for (size_t component = 0; component < sparse_pixels.size(); component++) {
|
||||
const auto expected = component % 4 == 3 ? 0x3f800000u : 0x3e800000u;
|
||||
Require(name, "sparse MRT3 output", sparse_pixels[component] == expected,
|
||||
"MRT3 was compacted to a different slot or clipped by unused MRT0");
|
||||
for (uint32_t index = 0; index < sparse_pixels_code.size(); index++) {
|
||||
const auto &code = sparse_pixels_code[index];
|
||||
const auto address = reinterpret_cast<uint64_t>(code.data());
|
||||
ShaderMapUserData(address,
|
||||
{.type = Prospero::ShaderBinaryType::kPs,
|
||||
.code_size_bytes = static_cast<uint32_t>(code.size() * sizeof(u32))});
|
||||
shaders.SetPsShaderBase(address);
|
||||
registers.SetShaderMask(index == 0 ? 0xf000 : 0xf00f);
|
||||
registers.SetTargetOutputMode(1, index == 0 ? 0 : 4);
|
||||
RenderExecutorTestAccess::ResolveRenderColorTarget(
|
||||
executor, scheduler.Current(), sparse_color, 3);
|
||||
TextureCacheTestAccess::ClearImage(cache, scheduler.Current(), sparse_color.image_id,
|
||||
{vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}, {});
|
||||
RenderExecutorTestAccess::DrawAuto(
|
||||
executor, scheduler.Current(), {.vertex_count = 3, .instance_count = 1});
|
||||
const auto pixels = ReadCachedTexel(name, context, sparse_color.image_id,
|
||||
{}, {extent, extent, 1});
|
||||
for (size_t component = 0; component < pixels.size(); component++) {
|
||||
const auto expected = component % 4 == 3 ? 0x3f800000u : 0x3e800000u;
|
||||
Require(name, "compact export to sparse MRT3", pixels[component] == expected,
|
||||
"shader output routing used the write mask or clipped MRT3 with stale MRT0");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// A fourth VS invocation reads beyond the descriptor instead of reconstructing the corner.
|
||||
const ShaderBufferResource rect_buffer{{
|
||||
static_cast<u32>(rect_address),
|
||||
@@ -16483,7 +16496,7 @@ public:
|
||||
}
|
||||
AppendVMovU32(&code, 22, 0);
|
||||
AppendVMovLiteral(&code, 23, 0x3f800000u);
|
||||
code.insert(code.end(), {EncodeExp0(0x03, 0xf), EncodeExp1(20, 21, 22, 23)});
|
||||
code.insert(code.end(), {EncodeExp0(0, 0xf), EncodeExp1(20, 21, 22, 23)});
|
||||
AppendEnd(&code);
|
||||
return code;
|
||||
}();
|
||||
|
||||
Reference in New Issue
Block a user