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.
This commit is contained in:
Mihawk committed 2026-09-19 10:19:08 -04:00
1 parent 574974ee2e
commit 5fb5d1a8c1
9 files changed
+171 -20

No files matched your search

+20 -19
View File
@@ -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.
+11
View File
@@ -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.
+12
View File
@@ -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.
+30
View File
@@ -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"
]
}
@@ -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": []
}
+3
View File
@@ -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
+1 -1
View File
@@ -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")
+64
View File
@@ -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 <stdint.h>
#include <stdio.h>
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)
+19
View File
@@ -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",
),
]