mirror of
https://github.com/mihawk-99/PS5_RetroArch.git
synced 2026-10-18 23:09:29 -05:00
Build pinned libretro Snes9x 1.63 with this project's SDK and official metadata.
Convert final RGB565 frames to independent XRGB8888 storage for the existing
Vulkan upload path. Integrate staging, native imports and loader diagnostics.
Keep C++ destructor registration inside the unloadable core. Validate bounded
fini arrays before constructors and execute cleanup at last-reference close.
Test all 65536 colours through GPU upload, pitches/bounds/cached frames and
C++ destruction/reload/malformed finalizers. Existing core bytes are unchanged.
Verification: bash tools/verify.sh passed format/unit/build/integration/evidence
with 60 tests. bash tools/run-title.sh --no-build --core-test=snes9x --watch 180
passed loader/recovery and remained running until runner close. Owner: Works
flawlessly, answering colours/audio/input and menu/content-transition checks.
Zero Vulkan refusals, GPU API failures or kernel fatal-signal reports.
Evidence: evidence/snes9x-native/{capture,expectation,iterations,abi,build}.json,
loader/recovery reports and exact linked-driver hashes. Replay with
bash tools/verify.sh evidence. Frontend identity:
64bef2e7826e5a63a6644a933e24ef5403d28c754230c0038eb8a76b4baa1c53.
PS5_Vulkan was not modified; special-mode/save-state/performance coverage is
not implied by this ordinary-game acceptance.
67 lines
3.7 KiB
Python
67 lines
3.7 KiB
Python
"""Check every RGB565 colour through the exact core and frontend upload helpers."""
|
|
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'
|
|
'#include "' + str(ROOT / 'src/core_frame_ps5.cpp') + '"\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
|
|
upload = api.ps5_core_frame_rgba
|
|
upload.argtypes = [ctypes.c_void_p, ctypes.c_size_t, ctypes.c_void_p,
|
|
ctypes.c_size_t, ctypes.c_uint, ctypes.c_uint]
|
|
# All 65536 inputs, not only primaries, catch bit-order/green-width errors.
|
|
src = (ctypes.c_uint16 * 65536)(*range(65536))
|
|
core = (ctypes.c_uint32 * 65536)()
|
|
gpu = (ctypes.c_uint8 * (65536 * 4))()
|
|
self.assertTrue(convert(core, 65536, src, 512, 256, 256))
|
|
upload(gpu, 1024, core, 1024, 256, 256)
|
|
for pixel in range(65536):
|
|
r, g, b = pixel >> 11, (pixel >> 5) & 63, pixel & 31
|
|
self.assertEqual(list(gpu[pixel * 4:pixel * 4 + 4]),
|
|
[r * 8 + r // 4, g * 4 + g // 16, b * 8 + b // 4, 255])
|
|
self.assertEqual(list(src), list(range(65536)))
|
|
# 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)
|