From 5fb5d1a8c1929566376faea16c889c7db8911d70 Mon Sep 17 00:00:00 2001 From: Mihawk <163614687+mihawk-99@users.noreply.github.com> Date: Sat, 19 Sep 2026 10:19:08 -0400 Subject: [PATCH] Correct RGUI RGBA4444 upload channel order and range Verification: bash tools/verify.sh (all five gates, 25 tests); bash tools/run-title.sh --no-build --watch 30. Evidence: evidence/vulkan-menu-rgba/. Exhaustive 65536-value host check and zero-refusal console run; owner sees green RGUI but flicker remains unresolved. --- docs/ACTIVE.md | 39 ++++++------- docs/FINDINGS.md | 11 ++++ docs/PHASE_LOG.md | 12 ++++ evidence/vulkan-menu-rgba/capture.json | 30 ++++++++++ evidence/vulkan-menu-rgba/expectation.json | 11 ++++ patches/series | 3 + tests/test_frontend.py | 2 +- tests/test_vulkan_menu_color.py | 64 ++++++++++++++++++++++ tools/apply-port-patches.py | 19 +++++++ 9 files changed, 171 insertions(+), 20 deletions(-) create mode 100644 evidence/vulkan-menu-rgba/capture.json create mode 100644 evidence/vulkan-menu-rgba/expectation.json create mode 100644 tests/test_vulkan_menu_color.py diff --git a/docs/ACTIVE.md b/docs/ACTIVE.md index 34cb0d3..d46b8de 100644 --- a/docs/ACTIVE.md +++ b/docs/ACTIVE.md @@ -35,30 +35,31 @@ frontend. Previously only the CPU video driver's open method called it. ## Current diagnosis -The RGBA conversion is corrected and exhaustively tested over all 65,536 inputs, -but the owner still reports wrong colours. The 30-second colour run completed -and the script closed it, with zero refusals/errors in the retrieved trace. -A subsequent identity build proves the console runs the intended input set: +The owner now clarifies that the menu is green, with blue flickers everywhere and +black triangles appearing/disappearing in fixed positions. The RGBA4444 conversion +correction is exhaustive over all 65,536 inputs. The 30-second colour run completed +and the script closed it, with zero refusals or recorded API errors. Evidence: +`evidence/vulkan-menu-rgba/`. Flicker remains unresolved. + +The identity build proves the console runs the intended input set: `df3a593a85388d58bc9fcc847dbd1deac6d9f1de8e4170493e84a84f87e362e3`. `evidence/vulkan-build-identity/` records local/remote/trace agreement. All five -gates and 25 tests pass. Generic startup markers alone cannot prove a build. +gates and 25 tests passed. Generic startup markers alone cannot prove a build. -The next diagnostic is to read the uploaded texture and rendered image through -the released driver's test-only image-storage API, without hardware writes or -sibling changes, to separate upload pixels from rendered pixels. +Read-only driver inspection found a relevant historical blue-channel corruption: +`../PS5_Vulkan/docs/HARDWARE_FINDINGS.md` records source-alpha blending needing +FP16_ABGR pixel exports. The current driver chooses that for blend-enabled +pipelines, while opaque pipelines use 32_ABGR and omit explicit blend registers. +This is a hypothesis for mixed opaque/blended draws, not a proven root cause. ## Next smallest step -Correct the colour conversion using the RGUI producer's actual RGBA4444 nibble -order (R in bits 12-15) and expand each nibble to 8 bits. The current 0028 code -reverses red/blue and scales 15 to 240 instead of 255. Preserve A2's matching -32-bit RGBA textures and plain-copy path. Diagnose flicker separately from colour. - -A host regression test also caught the existing 0023 patch marker missing from -its own replacement. The marker-only fix is verified separately: all five gates and 22 host tests -pass. Evidence is in `evidence/frontend-patch-idempotence/`. A fresh upstream replay is byte-identical on its second application. -The configured shader source was regenerated from upstream plus the named edits -to remove the accumulated duplicates. No colour or rendering code was changed. +Test a frontend-only, equivalent ONE/ZERO blend state for the opaque stock shader +pass, to force explicit blend programming and FP16 exports. Compare the same menu +on the same unchanged driver; keep source-alpha menu blending unchanged. If that +does not resolve the defect, retire the diagnostic and report the remaining +uncertainty rather than claiming a driver fix. Public debug image readback is +another possible way to separate correct upload pixels from corrupt rendering. ## Working notes @@ -74,7 +75,7 @@ to remove the accumulated duplicates. No colour or rendering code was changed. - A2 remains the matching 32-bit RGBA upload and plain copy path; do not reopen the settled choice. The traced menu dynamic/staging formats are both 37. - CPU fallback sources and registration have not been changed. -- Patch count is 68 with the pending RGBA conversion correction. `vendor/` is untouched. +- Patch count is 68 including the RGBA conversion correction. `vendor/` is untouched. - Fresh replay of all port patches succeeds. The configured shader file contains only the intended 0023 sampler fallback block after regeneration. Its marker now appears in its replacement, so repeated builds cannot accumulate it. diff --git a/docs/FINDINGS.md b/docs/FINDINGS.md index f4e368c..b570d18 100644 --- a/docs/FINDINGS.md +++ b/docs/FINDINGS.md @@ -2481,3 +2481,14 @@ Patch 0028 instead writes the blue nibble into the R8G8B8A8 texture's red byte a red into blue, and shifts four-bit channels into only the high nibble of each byte (15 becomes 240). This is a frontend conversion defect, independently of the still-unexplained flicker; fixing it preserves matching 32-bit upload formats. + +## 2026-09-19 — RGUI upload and remaining visual corruption + +The RGUI producer packs R in bits 12-15, G in 8-11, B in 4-7 and A in 0-3. +Patch 0028 reversed R/B and expanded to 240 rather than 255; 0055 corrects both. +The exhaustive producer-to-upload test covers all 65,536 words. Evidence is in +`evidence/vulkan-menu-rgba/`; the owner sees green RGUI but blue flicker and fixed +black triangles remain. Successful Vulkan calls alone do not prove correct pixels. +Read-only driver findings record an earlier similar blue blending defect fixed by +FP16 exports; current code skips blend-register writes on opaque draws. This +suggests a mixed-pipeline diagnostic, not a confirmed cause of this title's issue. diff --git a/docs/PHASE_LOG.md b/docs/PHASE_LOG.md index f463dda..95b3a85 100644 --- a/docs/PHASE_LOG.md +++ b/docs/PHASE_LOG.md @@ -1601,3 +1601,15 @@ reported exactly the staged identity in its trace; see but does not prove correct pixels. The identity run closed before its final query. No driver project files were modified and no new dependency or compiler flag was introduced. The generated header is not committed. + +## 2026-09-19 — Correct the RGUI upload channel order and range + +Patch 0055 expands the producer's RGBA4444 nibbles to RGBA8888 bytes, preserving +A2's matching 32-bit textures and plain-copy route. Its regression test failed +before the fix and checks all 65,536 inputs after it. The five gates passed with +25 tests. The full 30-second colour run ended with a live title which the script +closed; its fresh trace has zero refusals and successful initial API results. +`evidence/vulkan-menu-rgba/` records the capture and expectations. The subsequent +identity run was verified as the intended input set. The owner's clarified report +is a green menu with blue flicker and black triangles; upload correction does not +resolve GPU corruption, and the overall goal remains open. diff --git a/evidence/vulkan-menu-rgba/capture.json b/evidence/vulkan-menu-rgba/capture.json new file mode 100644 index 0000000..cf0af3d --- /dev/null +++ b/evidence/vulkan-menu-rgba/capture.json @@ -0,0 +1,30 @@ +{ + "step": "vulkan-menu-rgba", + "command": "bash tools/verify.sh; bash tools/run-title.sh --no-build --watch 30", + "revision": "44c6fb7 plus RGBA correction (also tested before identity instrumentation)", + "raw_capture": "klog/gpu-colour-latest-trace.txt", + "raw_lines": 385, + "lines": [ + "gpu result: vkEndCommandBuffer calls=1 failures=0 result=0", + "gpu result: vkQueueSubmit calls=1 failures=0 result=0", + "gpu result: vkEndCommandBuffer calls=2 failures=0 result=0", + "gpu result: vkQueueSubmit calls=2 failures=0 result=0", + "gpu result: vkEndCommandBuffer calls=3 failures=0 result=0", + "gpu result: vkQueueSubmit calls=3 failures=0 result=0", + "gpu result: vkEndCommandBuffer calls=4 failures=0 result=0", + "gpu result: vkQueueSubmit calls=4 failures=0 result=0", + "gpu result: vkQueuePresentKHR calls=1 failures=0 result=0", + "gpu result: swapchain image calls=1 failures=0 result=0", + "vulkan copy_staging_to_dynamic: dynamic 320x240 fmt=37 type=2, staging fmt=37 type=1, compute=0", + "gpu result: vkQueuePresentKHR calls=2 failures=0 result=0", + "gpu result: swapchain image calls=2 failures=0 result=0", + "gpu result: vkQueuePresentKHR calls=3 failures=0 result=0", + "gpu result: swapchain image calls=3 failures=0 result=0", + "gpu result: vkQueuePresentKHR calls=4 failures=0 result=0", + "gpu result: swapchain image calls=4 failures=0 result=0", + "audit: refusals=0; recorded API failures=0", + "runner: completed 30-second watch, final process count=1, script closed title", + "host: all 65536 RGBA4444 inputs match producer and RGBA8888 bytes", + "owner: green RGUI visible, blue flickers and fixed-position black triangles remain" + ] +} diff --git a/evidence/vulkan-menu-rgba/expectation.json b/evidence/vulkan-menu-rgba/expectation.json new file mode 100644 index 0000000..2066a36 --- /dev/null +++ b/evidence/vulkan-menu-rgba/expectation.json @@ -0,0 +1,11 @@ +{ + "step": "vulkan-menu-rgba", + "note": "Corrects upload channel order/range only; GPU flicker remains unresolved.", + "must_contain": [ + "host: all 65536", + "refusals=0", + "vkEndCommandBuffer calls=4 failures=0 result=0", + "green RGUI visible" + ], + "must_not_contain": [] +} diff --git a/patches/series b/patches/series index cafeef5..42fba5a 100644 --- a/patches/series +++ b/patches/series @@ -31,3 +31,6 @@ # 0054 observe command completion, queue submission, presentation and menu draw inputs 0054-observe-vulkan-api-results + +# 0055 convert the RGUI producer RGBA4444 channels to full-range RGBA8888 +0055-correct-rgui-rgba8888-upload diff --git a/tests/test_frontend.py b/tests/test_frontend.py index 6b683c8..399aac2 100644 --- a/tests/test_frontend.py +++ b/tests/test_frontend.py @@ -300,7 +300,7 @@ class PortPatches(unittest.TestCase): change deliberately, in a commit that says why. """ self.assertEqual( - len(self.blocks()), 67, + len(self.blocks()), 68, "the patch count changed: if a block was added or removed on purpose, " "update this number in the same commit and say why in its message") diff --git a/tests/test_vulkan_menu_color.py b/tests/test_vulkan_menu_color.py new file mode 100644 index 0000000..62b7540 --- /dev/null +++ b/tests/test_vulkan_menu_color.py @@ -0,0 +1,64 @@ +"""RGUI's producer and the port's upload must agree on RGBA channel order.""" + +import ast +import re +import shutil +import subprocess +import tempfile +import unittest +from pathlib import Path + +ROOT = Path(__file__).resolve().parent.parent + + +class VulkanMenuColor(unittest.TestCase): + def test_all_rgba4444_values_reach_the_matching_rgba8888_bytes(self): + script = ast.parse((ROOT / "tools/apply-port-patches.py").read_text()) + edits = next(ast.literal_eval(node.value) for node in script.body + if isinstance(node, ast.Assign) + and getattr(node.targets[0], "id", "") == "EDITS") + source = (ROOT / "vendor/retroarch/gfx/drivers/vulkan.c").read_text() + for name, anchor, replacement, marker in edits: + if name == "gfx/drivers/vulkan.c" and marker not in source: + self.assertIn(anchor, source) + source = source.replace(anchor, replacement, 1) + upload = source.split("static void vulkan_set_texture_frame(", 1)[1] + expression = re.search(r"\n\s+\*dstpix\s*=\s*(.*?);", upload, re.S).group(1) + rgui = (ROOT / "vendor/retroarch/menu/drivers/rgui.c").read_text() + producer = re.search(r"static uint16_t argb32_to_rgba4444\(uint32_t col\)\s*" + r"\{(.*?)\n\}", rgui, re.S).group(1) + program = r''' +#include +#include +static uint16_t produce(uint32_t col) { PRODUCER } +static uint32_t convert(uint32_t pix) { return EXPRESSION; } +int main(void) +{ + for (unsigned rgba = 0; rgba < 65536; ++rgba) + { + unsigned r = ((rgba >> 12) & 15) * 17; + unsigned g = ((rgba >> 8) & 15) * 17; + unsigned b = ((rgba >> 4) & 15) * 17; + unsigned a = (rgba & 15) * 17; + uint16_t packed = produce((a << 24) | (r << 16) | (g << 8) | b); + uint32_t got = convert(packed); + uint32_t want = r | (g << 8) | (b << 16) | (a << 24); + if (got != want) + { + fprintf(stderr, "RGBA4444=%04x got=%08x want=%08x\n", packed, got, want); + return 1; + } + } + puts("65536 RGBA4444 colours match RGBA8888 byte order and full-range expansion"); +} +'''.replace("PRODUCER", producer).replace("EXPRESSION", expression) + compiler = shutil.which("clang") or shutil.which("gcc") + self.assertIsNotNone(compiler) + with tempfile.TemporaryDirectory() as directory: + source_file = Path(directory) / "colour.c" + binary = Path(directory) / "colour" + source_file.write_text(program) + subprocess.run([compiler, "-std=c11", str(source_file), "-o", str(binary)], + check=True, capture_output=True, text=True) + run = subprocess.run([str(binary)], capture_output=True, text=True) + self.assertEqual(run.returncode, 0, run.stderr) diff --git a/tools/apply-port-patches.py b/tools/apply-port-patches.py index 6dda266..0e789a8 100755 --- a/tools/apply-port-patches.py +++ b/tools/apply-port-patches.py @@ -1939,6 +1939,25 @@ EDITS = [ " vkCmdDraw(vk->cmd, 6, 1, 0, 0);\n", "gpu quad: alpha=", ), + ( + "gfx/drivers/vulkan.c", + " /* Added by this port (patches/series, 0028): R8G8B8A8's byte order,\n" + " * from the B4G4R4A4 source the caller hands over. */\n" + " *dstpix = (\n" + " (pix & 0x00f0) )\n" + " | ((pix & 0x0f00) << 4)\n" + " | ((pix & 0xf000) << 8)\n" + " | ((pix & 0x000f) << 28);\n", + " /* Supersedes patches/series, 0028. */\n" + " /* Added by this port (patches/series, 0055): RGUI produces RGBA4444,\n" + " * red in the high nibble. Expand all channels to 0..255 and store\n" + " * R,G,B,A bytes for the matching R8G8B8A8 staging/dynamic textures. */\n" + " *dstpix = (((pix >> 12) & 15u)\n" + " | (((pix >> 8) & 15u) << 8)\n" + " | (((pix >> 4) & 15u) << 16)\n" + " | ((pix & 15u) << 24)) * 17u;\n", + "patches/series, 0055", + ), ]