mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 05:46:56 +01:00
renderer: skip inactive pixel shaders
This commit is contained in:
@@ -575,12 +575,17 @@ RenderState RenderExecutor::AcquireRenderTargets(CommandBuffer& buffer, RenderCo
|
|||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool DrawHasActivePixelShader(const CommandBuffer& buffer) {
|
static uint32_t DrawColorOutputMask(const HW::Context& ctx) {
|
||||||
const auto& ctx = buffer.GetRegisters();
|
const auto& sh_regs = ctx.GetShaderRegisters();
|
||||||
const auto& sh_regs = ctx.GetShaderRegisters();
|
const auto write_mask = ctx.GetRenderTargetMask() & sh_regs.m_cbShaderMask;
|
||||||
const bool has_color_output = (ctx.GetRenderTargetMask() & sh_regs.m_cbShaderMask) != 0;
|
uint32_t output_mask = 0;
|
||||||
return buffer.GetShaders().GetPs().ps_regs.data_addr != 0 &&
|
for (uint32_t slot = 0; slot < RENDER_COLOR_ATTACHMENTS_MAX; slot++) {
|
||||||
(has_color_output || PixelShaderHasDepthOrCoverageSideEffects(sh_regs));
|
if (sh_regs.target_output_mode[slot] != 0 &&
|
||||||
|
render_target_mask_slot(write_mask, slot) != 0) {
|
||||||
|
output_mask |= 1u << slot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class CbColorMode : uint8_t {
|
enum class CbColorMode : uint8_t {
|
||||||
@@ -847,7 +852,7 @@ static bool ResolvePrimitiveRestart(const CommandBuffer& buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void RefreshShaders(CommandBuffer& buffer, const DrawCallInfo& draw,
|
static void RefreshShaders(CommandBuffer& buffer, const DrawCallInfo& draw,
|
||||||
DrawRenderState& state) {
|
uint32_t color_output_mask, DrawRenderState& state) {
|
||||||
auto& ctx = buffer.GetRegisters();
|
auto& ctx = buffer.GetRegisters();
|
||||||
auto& sh_ctx = buffer.GetShaders();
|
auto& sh_ctx = buffer.GetShaders();
|
||||||
|
|
||||||
@@ -861,7 +866,7 @@ static void RefreshShaders(CommandBuffer& buffer, const DrawCallInfo& draw,
|
|||||||
target_export_mapping {};
|
target_export_mapping {};
|
||||||
for (uint32_t slot = 0; slot < RENDER_COLOR_ATTACHMENTS_MAX; slot++) {
|
for (uint32_t slot = 0; slot < RENDER_COLOR_ATTACHMENTS_MAX; slot++) {
|
||||||
const auto& rt = ctx.GetRenderTarget(slot);
|
const auto& rt = ctx.GetRenderTarget(slot);
|
||||||
if (rt.base.addr != 0 && render_target_mask_slot(ctx.GetRenderTargetMask(), slot) != 0) {
|
if ((color_output_mask & (1u << slot)) != 0 && rt.base.addr != 0) {
|
||||||
target_export_mapping[slot] =
|
target_export_mapping[slot] =
|
||||||
TextureGetRenderTargetFormat(rt.info.format, rt.info.channel_type,
|
TextureGetRenderTargetFormat(rt.info.format, rt.info.channel_type,
|
||||||
rt.info.channel_order)
|
rt.info.channel_order)
|
||||||
@@ -880,8 +885,12 @@ static void RefreshShaders(CommandBuffer& buffer, const DrawCallInfo& draw,
|
|||||||
bool RenderExecutor::PrepareDrawRenderState(CommandBuffer& buffer, const DrawCallInfo& draw,
|
bool RenderExecutor::PrepareDrawRenderState(CommandBuffer& buffer, const DrawCallInfo& draw,
|
||||||
uint32_t render_target_slice_offset,
|
uint32_t render_target_slice_offset,
|
||||||
DrawRenderState& state) {
|
DrawRenderState& state) {
|
||||||
state.ps_active = DrawHasActivePixelShader(buffer);
|
const auto& shader_regs = buffer.GetRegisters().GetShaderRegisters();
|
||||||
RefreshShaders(buffer, draw, state);
|
const auto color_output_mask = DrawColorOutputMask(buffer.GetRegisters());
|
||||||
|
state.ps_active = buffer.GetShaders().GetPs().ps_regs.data_addr != 0 &&
|
||||||
|
(color_output_mask != 0 ||
|
||||||
|
PixelShaderHasDepthOrCoverageSideEffects(shader_regs));
|
||||||
|
RefreshShaders(buffer, draw, color_output_mask, state);
|
||||||
uint32_t mrt_mask = 0;
|
uint32_t mrt_mask = 0;
|
||||||
if (state.ps_active) {
|
if (state.ps_active) {
|
||||||
for (const auto& output: state.ps_input_info.stage.program->info.outputs) {
|
for (const auto& output: state.ps_input_info.stage.program->info.outputs) {
|
||||||
@@ -890,6 +899,7 @@ bool RenderExecutor::PrepareDrawRenderState(CommandBuffer& buffer, const DrawCal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mrt_mask &= color_output_mask;
|
||||||
if (draw.IsIndexed()) {
|
if (draw.IsIndexed()) {
|
||||||
LogDrawPhase(draw.Name(), "ResolveRenderColorTarget");
|
LogDrawPhase(draw.Name(), "ResolveRenderColorTarget");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14373,6 +14373,40 @@ public:
|
|||||||
"a stale color target clipped stencil coverage or the NULL-export shader was skipped");
|
"a stale color target clipped stencil coverage or the NULL-export shader was skipped");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A depth-only draw retains the previous PS address and write masks, but
|
||||||
|
// SPI_SHADER_COL_FORMAT disables its exports. Compiling this stale PS
|
||||||
|
// with the new zero-input metadata would fail before the depth draw.
|
||||||
|
static const auto stale_pixel = [] {
|
||||||
|
std::vector<u32> code{EncodeVintrp(0, 0, 0, 0, 0),
|
||||||
|
EncodeVintrp(1, 0, 0, 0, 1),
|
||||||
|
EncodeExp0(0, 0xf), EncodeExp1(0, 0, 0, 0)};
|
||||||
|
AppendEnd(&code);
|
||||||
|
return code;
|
||||||
|
}();
|
||||||
|
const auto stale_address = reinterpret_cast<uint64_t>(stale_pixel.data());
|
||||||
|
ShaderMapUserData(stale_address,
|
||||||
|
{.type = Prospero::ShaderBinaryType::kPs,
|
||||||
|
.code_size_bytes = static_cast<u32>(stale_pixel.size() * sizeof(u32))});
|
||||||
|
shaders.SetPsShaderBase(stale_address);
|
||||||
|
registers.SetPsInControl(0);
|
||||||
|
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}) {
|
||||||
|
registers.SetTargetOutputMode(slot, 0);
|
||||||
|
}
|
||||||
|
RenderExecutorTestAccess::DrawAuto(
|
||||||
|
executor, scheduler.Current(), {.vertex_count = 3, .instance_count = 1});
|
||||||
|
const auto depth_only_pixels = ReadCachedTexel(
|
||||||
|
name, context, depth.image_id, {}, {extent, extent, 1});
|
||||||
|
Require(name, "disabled stale PS preserves fixed-function depth",
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
// With MRT0 still bound, an MRT3-only export must retain location3 in
|
// With MRT0 still bound, an MRT3-only export must retain location3 in
|
||||||
// rendering attachments, pipeline formats, blend masks and dynamic write enables.
|
// rendering attachments, pipeline formats, blend masks and dynamic write enables.
|
||||||
static const auto sparse_pixel = [] {
|
static const auto sparse_pixel = [] {
|
||||||
|
|||||||
Reference in New Issue
Block a user