From 0f920e645441f42d006a3d2635115ff9bcfb37b8 Mon Sep 17 00:00:00 2001 From: Sylpheed RE agent Date: Mon, 31 Aug 2026 06:09:25 +0000 Subject: [PATCH] [RE] Log the blend state of every UI draw CaptureUiDrawForRE now records RB_BLENDCONTROL0, RB_COLORCONTROL and RB_COLOR_MASK per draw, raw alongside the decoded src/op/dst fields so a decode bug here cannot quietly become the answer. The question it answers: the Godot port composites every UI element with straight alpha-over and four elements come out too dark against the capture, with the shortfall correlating with the background. Nothing on the disc selects a per-element mode, so this reads what the GPU was actually told. Result: the title-side UI uses two states and one pixel shader -- 0x07010701 (src ONE, dst 1-SRC_ALPHA) for backgrounds, text and buttons, and 0x01010101 (src ONE, dst ONE, ADDITIVE) for the frame sprites and the rotated sweep strips. --- src/xenia/gpu/command_processor.cc | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/xenia/gpu/command_processor.cc b/src/xenia/gpu/command_processor.cc index e350f1132..d389e299c 100644 --- a/src/xenia/gpu/command_processor.cc +++ b/src/xenia/gpu/command_processor.cc @@ -296,6 +296,33 @@ void CommandProcessor::CaptureUiDrawForRE( if (ps) { ui_out << fmt::format(" ps=0x{:016X}", ps->ucode_data_hash()); } + // ── RE: the BLEND STATE of this draw ────────────────────────────────────── + // The question this answers: the port's renderer composites every UI element + // with straight alpha-over, and four elements (the menu's `ptframe1`/`2` and + // EXTRAS' `ptframe3`/`4`) come out too dark against the capture, with the + // shortfall correlating with the BACKGROUND rather than with the element's own + // contribution — the signature of a blend that scales what is already there. + // Nothing on the disc selects a per-element mode (checked in the declaration + // entry, every word and bit of the T8aD header, and the keyframe record), so + // the remaining candidate is the draw path. This logs what the GPU was + // actually told, per draw, rather than inferring it: + // blend= src/dst factors and combine op, colour+alpha + // cc= alpha test / blend enable + // mask= + // Raw values are printed alongside the decoded fields so a decode bug here + // cannot silently become the answer. + { + auto bc = register_file_->Get(); + auto cc = register_file_->Get(); + uint32_t mask = register_file_->values[XE_GPU_REG_RB_COLOR_MASK]; + ui_out << fmt::format( + " blend=0x{:08X}[c:src={} op={} dst={} a:src={} op={} dst={}]" + " cc=0x{:08X} mask=0x{:X}", + bc.value, uint32_t(bc.color_srcblend), uint32_t(bc.color_comb_fcn), + uint32_t(bc.color_destblend), uint32_t(bc.alpha_srcblend), + uint32_t(bc.alpha_comb_fcn), uint32_t(bc.alpha_destblend), cc.value, + mask); + } if (ps && ps->is_ucode_analyzed()) { for (const auto& tb : ps->texture_bindings()) { xenos::xe_gpu_texture_fetch_t tf =