Files
PS5_RetroArch/tests/test_snes9x_video.py
T
Mihawk 3aad94459d Withdraw the red/blue compensations and relink against the migrated driver
Build the frontend against ../PS5_Vulkan 8b311e3 and remove the changes that
existed only because that driver could not sample the frontend's own byte order.

Driver review (8b311e3, "Migrate the driver to ps5-opengl 0.3.0's compiler fork,
and close the console SIGFPE at its owner"): driver/ps5vk_image.c is not touched,
VK_FORMAT_B8G8R8A8_UNORM still carries SAMPLED_IMAGE_BIT with the 8_8_8_8_UNORM
word and the ZYXW selectors, and the format audit's counts are unchanged (179
required, 58 reported, 0 missing, 55 conditional, split 0/0/0/0/0), so the fetch
order this port depends on survived the migration. What did change there is the
compiler tree (ps5-opengl 0.3.0's opengnm-psbc, metadata v14), the compute
dispatch words, a null shader module in ps5vk_compile_stage that faulted every
meta clear/blit/resolve, and a driver-owned 32 MiB compile stack. The console
SIGFPE of round 15 was the probe's own unfilled std::array row, not ACO:
symbolization had missed the PIE load base.

Withdrawn: 0014's format substitution (its usage mask stays), 0075's core-frame
RGBA upload and 0077's menu colour and cached-frame ownership.
tools/apply-port-patches.py grew an 0083 group and a WITHDRAWN tuple that
exchanges each named insertion for the upstream text it replaced, so a tree that
already carries the insertion and a fresh one converge - checked by patching a
copy of vendor/retroarch's gfx/drivers/vulkan.c and the withdrawn build/ra-conf
and comparing (identical). src/core_frame_ps5.cpp no longer converts channels,
four tests assert the core's own bytes instead of the conversion's output, two new
tests pin the mechanism, and the patch-count pin moved 179 -> 185. Kept: 0027/0055
(the 16-bit RGUI frame, still converted by hand into R8G8B8A8 because a B4G4R4A4
view with a B/R swizzle is refused), 0015 (upstream's own VK_REMAP_TO_TEXFMT) and
0081 (upstream's TODO: supports_rgba follows the order a caller asked for).

Command and result:
  PS5_VULKAN_DIR=$PWD/build/frozen-driver \
  PS5_VULKAN_ICD=$PWD/build/frozen-driver/build/driver/ps5/libvulkan.so.1 \
  bash tools/verify.sh
  -> format PASS (1s), unit PASS (12s, 75 tests), build PASS (247s),
     integration PASS (10s), evidence PASS (0s),
     verify: PASS (format unit build integration evidence)

Artifact: dist/PPSA99169/eboot.bin, 34,703,515 bytes, sha256 82534b86..., title
identity f9e4ea6c..., two consecutive runs byte-identical. The four driver
archives were frozen into build/frozen-driver/ before the build and re-hashed
unchanged after it, and the identity was recomputed from tools/build-title.sh's
own input list against those hashes and matched, so the eboot names the driver it
carries. Record: evidence/driver-1.0-native-byte-order/.

Four runs preceded the green one: unit (three new markers did not appear in their
own replacements and the count pin was stale), build (the frozen tree's .deps/work
symlink was one level short), a run interrupted when 8b311e3 landed, and evidence
(the new step directory had no capture/expectation yet). Logs:
build/verify-native-byte-order-first-run.log, -second-run.log,
-third-run-killed.log, -gates-4-of-5.log.

Not verified on the console: the colours of this build are the owner's check, and
the withdrawn path is the one that was accepted before. The command is recorded in
docs/ACTIVE.md.
2026-09-20 20:39:18 -04:00

64 lines
3.6 KiB
Python

"""Check every RGB565 colour through the exact core conversion and its upload bytes."""
import ctypes
from pathlib import Path
import subprocess
import tempfile
import unittest
ROOT = Path(__file__).resolve().parent.parent
class Snes9xVideo(unittest.TestCase):
def test_colours_pitch_bounds_and_cached_source(self):
with tempfile.TemporaryDirectory() as td:
source = Path(td) / 'video.cpp'
source.write_text('#include "' + str(ROOT / 'tooling/snes9x/ps5-video.h') + '"\n'
'extern "C" bool convert(uint32_t *d, size_t n, '
'const uint16_t *s, size_t p, unsigned w, unsigned h) '
'{ return ps5_snes9x_frame(d, n, s, p, w, h); }\n')
lib = Path(td) / 'video.so'
subprocess.run(['c++', '-shared', '-fPIC', '-Wall', '-Wextra', '-Werror',
str(source), '-o', str(lib)], check=True)
api = ctypes.CDLL(str(lib))
convert = api.convert
convert.argtypes = [ctypes.c_void_p, ctypes.c_size_t, ctypes.c_void_p,
ctypes.c_size_t, ctypes.c_uint, ctypes.c_uint]
convert.restype = ctypes.c_bool
# All 65536 inputs, not only primaries, catch bit-order/green-width errors.
src = (ctypes.c_uint16 * 65536)(*range(65536))
core = (ctypes.c_uint32 * 65536)()
self.assertTrue(convert(core, 65536, src, 512, 256, 256))
self.assertEqual(list(src), list(range(65536)))
# These are the bytes an upload copies into a B8G8R8A8 image, which is
# libretro's little-endian XRGB8888 layout: blue, green, red, unused.
pixels = (ctypes.c_uint8 * (65536 * 4)).from_buffer(core)
for pixel in range(65536):
r, g, b = pixel >> 11, (pixel >> 5) & 63, pixel & 31
self.assertEqual(list(pixels[pixel * 4:pixel * 4 + 4]),
[b * 8 + b // 4, g * 4 + g // 16, r * 8 + r // 4, 0])
# Actual common, hires, NTSC and 4x widths; non-tight input row pitch.
for width, height in [(256, 224), (512, 478), (602, 239), (1024, 478)]:
pitch = (width + 8) * 2
data = (ctypes.c_uint16 * ((width + 8) * height))()
out = (ctypes.c_uint32 * (width * height + 1))()
out[-1] = 0xdeadbeef
for y in range(height):
data[y * (width + 8)] = 0xf800
data[y * (width + 8) + width - 1] = 0x001f
data[y * (width + 8) + width] = 0xffff
original = bytes(data)
for _ in range(2):
self.assertTrue(convert(out, width * height, data, pitch, width, height))
self.assertEqual(bytes(data), original)
for y in range(height):
self.assertEqual(out[y * width], 0xff0000)
self.assertEqual(out[y * width + width - 1], 0x0000ff)
self.assertEqual(out[-1], 0xdeadbeef)
before = bytes(out)
for capacity, stride, w, h in [(width * height - 1, pitch, width, height),
(width * height, width * 2 - 2, width, height),
(width * height, pitch + 1, width, height),
(width * height, pitch, 0, height)]:
self.assertFalse(convert(out, capacity, data, stride, w, h))
self.assertEqual(bytes(out), before)