mirror of
https://github.com/mihawk-99/PS5_RetroArch.git
synced 2026-10-18 23:09:29 -05:00
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.
111 lines
5.7 KiB
Python
111 lines
5.7 KiB
Python
"""Exercise the core's RGB565 packing, cropped frames and upload byte order."""
|
|
import ctypes
|
|
import hashlib
|
|
from pathlib import Path
|
|
import subprocess
|
|
import tarfile
|
|
import tempfile
|
|
import unittest
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
ARCHIVE = ROOT / '.deps/downloads/genesis-plus-gx-c2838c7dc4236fc2fe94e5dbd08b41486067918e.tar.gz'
|
|
|
|
|
|
class GenesisVideo(unittest.TestCase):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
cls.tmp = tempfile.TemporaryDirectory()
|
|
directory = Path(cls.tmp.name)
|
|
source = directory / 'adapter.c'
|
|
source.write_text('#include "' + str(ROOT / 'tooling/genesis-plus-gx/ps5-video.h') + '"\n'
|
|
'bool convert(uint32_t *d, size_t n, const uint16_t *s, '
|
|
'size_t pixels, size_t p, size_t offset, unsigned w, unsigned h) '
|
|
'{ return ps5_genesis_frame(d, n, s, pixels, p, offset, w, h); }\n')
|
|
obj = directory / 'adapter.o'
|
|
subprocess.run(['cc', '-std=c99', '-fPIC', '-Wall', '-Wextra', '-Werror',
|
|
'-c', str(source), '-o', str(obj)], check=True)
|
|
lib = directory / 'video.so'
|
|
subprocess.run(['c++', '-shared', '-fPIC', '-Wall', '-Wextra', '-Werror',
|
|
str(obj), '-o', str(lib)], check=True)
|
|
cls.api = ctypes.CDLL(str(lib))
|
|
cls.convert = cls.api.convert
|
|
cls.convert.argtypes = [ctypes.c_void_p, ctypes.c_size_t, ctypes.c_void_p,
|
|
ctypes.c_size_t, ctypes.c_size_t, ctypes.c_size_t,
|
|
ctypes.c_uint, ctypes.c_uint]
|
|
cls.convert.restype = ctypes.c_bool
|
|
|
|
@classmethod
|
|
def tearDownClass(cls):
|
|
cls.tmp.cleanup()
|
|
|
|
def test_all_colours_from_upstream_packing_to_gpu(self):
|
|
if not ARCHIVE.exists():
|
|
self.skipTest('build Genesis Plus GX first to fetch the pinned source')
|
|
self.assertEqual(hashlib.sha256(ARCHIVE.read_bytes()).hexdigest(),
|
|
'7ba2eab9d6dae71bb42e8208573300ad3475a4263e860178c4d19c36d85fc92b')
|
|
with tarfile.open(ARCHIVE) as tar:
|
|
member = next(m for m in tar.getmembers() if m.name.endswith('/core/vdp_render.h'))
|
|
renderer = tar.extractfile(member).read().decode().replace('\r\n', '\n')
|
|
packing = renderer.split('#elif defined(USE_16BPP_RENDERING)\n')[1].split('\n')[0]
|
|
directory = Path(self.tmp.name)
|
|
source = directory / 'packing.c'
|
|
source.write_text('#include <stdint.h>\n' + packing + '\n'
|
|
'void pack(uint16_t *p) { for (unsigned r=0; r<32; ++r) '
|
|
'for (unsigned g=0; g<64; ++g) for (unsigned b=0; b<32; ++b) '
|
|
'*p++ = PIXEL(r,g,b); }\n')
|
|
lib = directory / 'packing.so'
|
|
subprocess.run(['cc', '-shared', '-fPIC', '-Wall', '-Werror', str(source),
|
|
'-o', str(lib)], check=True)
|
|
api = ctypes.CDLL(str(lib))
|
|
api.pack.argtypes = [ctypes.c_void_p]
|
|
src = (ctypes.c_uint16 * 65536)()
|
|
api.pack(src)
|
|
original = bytes(src)
|
|
core = (ctypes.c_uint32 * 65536)()
|
|
self.assertTrue(self.convert(core, 65536, src, 65536, 512, 0, 256, 256))
|
|
# 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])
|
|
self.assertEqual(bytes(src), original)
|
|
|
|
def test_cropping_pitch_cached_frames_and_geometry_transitions(self):
|
|
pixels = 720 * 576
|
|
data = (ctypes.c_uint16 * pixels)()
|
|
out = (ctypes.c_uint32 * (pixels + 1))()
|
|
# Reuse buffers over resolution changes, including cropped SMS/NTSC views.
|
|
for width, height, offset in [(320, 224, 0), (160, 144, 0), (248, 192, 16),
|
|
(256, 240, 0), (320, 480, 0), (600, 448, 40),
|
|
(720, 576, 0), (256, 224, 0)]:
|
|
ctypes.memset(data, 0, ctypes.sizeof(data))
|
|
start = offset // 2
|
|
for y in range(height):
|
|
data[start + y * 720] = 0xf800
|
|
data[start + y * 720 + width - 1] = 0x001f
|
|
original = bytes(data)
|
|
out[width * height] = 0xdeadbeef
|
|
for _ in range(2):
|
|
self.assertTrue(self.convert(out, width * height, data, pixels,
|
|
1440, offset, 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[width * height], 0xdeadbeef)
|
|
|
|
def test_invalid_viewports_do_not_write(self):
|
|
src = (ctypes.c_uint16 * 1440)()
|
|
out = (ctypes.c_uint32 * 1440)(*[0xdeadbeef] * 1440)
|
|
before = bytes(out)
|
|
for capacity, pixels, pitch, offset, width, height in [
|
|
(1, 1440, 1440, 0, 2, 1), (1440, 1440, 1441, 0, 1, 1),
|
|
(1440, 1440, 1440, 1, 1, 1), (1440, 1440, 1440, 2880, 1, 1),
|
|
(1440, 1440, 1440, 16, 720, 1), (1440, 1440, 1440, 0, 1, 3),
|
|
(1440, 1440, 0, 0, 1, 1), (1440, 1440, 1440, 0, 0, 1),
|
|
(1440, 1440, 1440, 0, 1, 0), (1440, 0, 1440, 0, 1, 1)]:
|
|
self.assertFalse(self.convert(out, capacity, src, pixels, pitch, offset, width, height))
|
|
self.assertEqual(bytes(out), before)
|