mirror of
https://github.com/mihawk-99/PS5_RetroArch.git
synced 2026-10-18 23:09:29 -05:00
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.
This commit is contained in:
1 parent
2b1d12949c
commit
3aad94459d
15 files changed
+599
-204
No files matched your search
+84
-118
@@ -1,139 +1,105 @@
|
||||
# Active work
|
||||
|
||||
_Updated: 2026-09-19_
|
||||
_Updated: 2026-09-20_
|
||||
|
||||
## PPSSPP Track A: the core builds
|
||||
## Now: the title is relinked against the migrated driver, on its own byte order
|
||||
|
||||
**Driver (`../PS5_Vulkan` `8b311e3`) is at rung 1.0 with its SDK fork migrated.** The
|
||||
format audit has no gaps (179 required, 58 reported, 0 missing, 55 conditional, split
|
||||
0/0/0/0/0) and `driver/ps5vk_image.c` was not touched by the migration, so
|
||||
`VK_FORMAT_B8G8R8A8_UNORM` still samples through the `8_8_8_8_UNORM` word with the
|
||||
`ZYXW` selectors — the byte order libretro's little-endian XRGB8888 already is. What the
|
||||
migration changed is the shader compiler (ps5-opengl 0.3.0's `opengnm-psbc` tree,
|
||||
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
|
||||
"ACO SIGFPE" is closed and was never ACO: rebased, it was the probe's own unfilled
|
||||
`std::array` row dividing by a zero texel size. Archived in
|
||||
`evidence/driver-1.0-native-byte-order/driver-archives.json`.
|
||||
|
||||
**Withdrawn here: the red/blue compensation.** 0014's format substitution, 0075's
|
||||
core-frame RGBA upload and 0077's menu colour and cached-frame ownership existed only
|
||||
because the driver could not sample the frontend's own byte order. They are now in
|
||||
`tools/apply-port-patches.py`'s `WITHDRAWN` tuple, which exchanges each insertion for the
|
||||
upstream text it replaced, so an existing build tree and a fresh one converge.
|
||||
`src/core_frame_ps5.cpp` no longer converts channels. Kept, each for a reason that does
|
||||
not depend on the sample order: **0027/0055** (the 16-bit RGUI frame is converted by hand
|
||||
into R8G8B8A8, because a B4G4R4A4 view with a B/R swizzle is still refused), **0015**
|
||||
(upstream's own `VK_REMAP_TO_TEXFMT` needs the bpp case) and **0081** (upstream's TODO:
|
||||
`supports_rgba` follows the order a caller asked for).
|
||||
|
||||
**Verified here.** `tools/verify.sh` with the driver frozen into `build/frozen-driver/`
|
||||
passes all five gates (format, unit 75 tests, build, integration, evidence); title
|
||||
identity `f9e4ea6c…`, eboot 34,703,515 bytes sha256 `82534b86…`, two consecutive runs
|
||||
byte-identical. The frozen archives were re-hashed unchanged after the build and the
|
||||
printed identity was recomputed from its own input list and matched, so the eboot names
|
||||
the driver it carries. Record: `evidence/driver-1.0-native-byte-order/`.
|
||||
|
||||
**Pending, and the only thing that decides the colours: a console run.** The withdrawn
|
||||
path is the one the owner accepted earlier; the native byte order has host evidence and
|
||||
the driver's own console `v0-formats` battery. Deploy, then have the owner launch:
|
||||
`JOBS=14 bash tools/run-title.sh --no-build --deploy --watch 120`, and check menu
|
||||
colours, core colours, and the Quick Menu over a paused game. Until that is recorded,
|
||||
this step is host-verified only.
|
||||
|
||||
## PPSSPP Track A: parked at the owner's request
|
||||
|
||||
Plan: [PPSSPP_Implementation_Plan.md](../PPSSPP_Implementation_Plan.md); platform
|
||||
analysis: [PPSSPP_Core_Plan.md](../PPSSPP_Core_Plan.md). Track A is PPSSPP on its
|
||||
software GPU core, with no PS5_Vulkan dependency.
|
||||
analysis: [PPSSPP_Core_Plan.md](../PPSSPP_Core_Plan.md). A1–A4 are done: the core is
|
||||
built from pinned `f293b10` (29 submodules, zero `PT_TLS`, the three allowed `NEEDED`
|
||||
modules), ABI-checked, linked into the title, and loaded on the console with the runtime
|
||||
assets staged (`cycles=8, exports=25, api=1`; `evidence/ppsspp-native/`).
|
||||
|
||||
**Done — A1-A3: build, ABI and title link.** `tools/build-ppsspp.sh` fetches pinned
|
||||
`f293b10` (29 submodules) and ABI-checks a core with **zero `PT_TLS`** and `NEEDED`
|
||||
exactly the three allowed modules; `ppsspp` is in `core_names`, so the title links it.
|
||||
`thread_local` needed no patch (the SDK uses `-femulated-tls`); two flag shims
|
||||
(`static_assert`, `ZSTD_TRACE`) and a libc shim carry the vendored code.
|
||||
Reproducibility: `SOURCE_DATE_EPOCH` from the pinned commit, two builds byte-identical.
|
||||
|
||||
**Done — A4: the core loads on the console.** The loader diagnostic passes:
|
||||
`cycles=8, exports=25, api=1`, identity `73d2aad8…`, `ran 110 initializers`,
|
||||
`symbols=19430 relocations=24812 mapped_bytes=18923520`. Three blockers fell, each
|
||||
found on the console: unresolvable imports (four `libScePosixForWebKit` symbols now
|
||||
shimmed, 83 OpenGL ones excluded by `patches/ppsspp/0003-no-opengl.patch`; table 497 →
|
||||
410 bindings), the thread pool (256/512 → **16/32**), and the runtime assets
|
||||
(`assets/` from the pinned source, 193 files, staged to `dist/…/system/PPSSPP` and
|
||||
published to `/app0/system/PPSSPP`). Evidence: `evidence/ppsspp-native/`.
|
||||
|
||||
**Blocker — the first frame.** The title takes a SIGSEGV on a worker thread during
|
||||
`ThreadManager::Init` (fault address 0x70, frames inside `libkernel.sprx`), so no PSP
|
||||
frame has been presented. Renderer-independent, and next. The console's libkernel can
|
||||
now be symbolized (NID = `SHA1(name || salt)`, byte-reversed, base-64), which names the
|
||||
faulting frame `pthread_get_specificarray_np+0x3b` reached from
|
||||
`pthread_create_name_np`, resolving a caller address inside the core's anonymous
|
||||
mapping and dereferencing the miss.
|
||||
|
||||
**Deployed and armed:** the console holds `eac82195…` — the loader probe, the import and
|
||||
asset fixes, PPSSPP's thread-pool diagnostic (`ThreadManager::Init: creating N`) and
|
||||
`system/PPSSPP` — with the loader test **PASS** (`cycles=8, exports=25, api=1`, both
|
||||
negative cases rejected). No `thread-test.txt` is armed, so the next launch goes
|
||||
straight to the core: `JOBS=14 bash tools/run-title.sh --no-build --no-deploy
|
||||
--core-test=ppsspp --watch 90`, and the log names the last pool step before the crash.
|
||||
|
||||
**Driver: rung 1.0 closed, title relinked.** `PS5_Vulkan` `d4e73ff`, embedded
|
||||
`libps5vk.ps5.a` `d41f934b…`, title identity `735f7eb1…`, all five gates pass. Still
|
||||
missing for PPSSPP's Vulkan renderer: a **combined depth/stencil format** (only D16 and
|
||||
D32F exist; PPSSPP asserts without one of D24S8/D32S8/D16S8 — the device-creation
|
||||
blocker), **attachments smaller than 3840x2160**, **cull mode**, **colour write
|
||||
masks**, **stencil test with dynamic stencil state** and **dynamic blend constants**.
|
||||
|
||||
## Now
|
||||
|
||||
**Owner accepted the thumbnail and configuration-reset fixes: “Perfect. Commit”.**
|
||||
Landing on `main`; evidence: `evidence/thumbnail-input-defaults/`.
|
||||
Details and regression checks: `docs/THUMBNAIL_INPUT_DEFAULTS.md`.
|
||||
|
||||
- Async image loading discarded the requested RGBA flag; patch 0081 preserves it.
|
||||
Gameplay pixels and saved PNG encoding are unchanged.
|
||||
- Compiled input was ps5 but joypad default was null; patch 0082 selects ps5.
|
||||
Reset also clears auto-binds without recreating the driver, so the next pad poll
|
||||
now reannounces the connected controller once to restore the built-in profile.
|
||||
- Three regression tests failed before the fixes; all four focused tests pass
|
||||
afterward, including native-pad recovery without new samples or a device reopen.
|
||||
- All five gates pass: 74 tests, 278 frontend sources; normal diagnostics mode.
|
||||
Identity: `e11018a79a62ce91fa723deaad6939c1e48a47bace21b3527ae84f4452148451`.
|
||||
Exact artifacts/gate logs: `klog/thumbnail-input-build/`; sanitized host report
|
||||
in evidence/thumbnail-input-defaults/. Driver archives and Mesa utility objects
|
||||
match the accepted normal XMB build. Logging and PS5_Vulkan unchanged.
|
||||
- Uploaded eboot only after idle checks, runtime identity read back, live config
|
||||
unchanged. Capture: `klog/thumbnail-input-upload-20260919-205531/`. Saved joypad
|
||||
selection was empty (automatic), not null; no configuration repair was needed.
|
||||
No launch/kill sent. Owner accepted the fixes after deployment. No fresh console
|
||||
logs or individual checklist results were captured; acceptance is owner observation.
|
||||
**Blocker — the first frame.** A SIGSEGV on a worker thread during `ThreadManager::Init`
|
||||
(fault address 0x70, frames inside `libkernel.sprx`, `pthread_get_specificarray_np+0x3b`
|
||||
reached from `pthread_create_name_np`). Every isolation probe passes. The console's
|
||||
libkernel can now be symbolized (NID = `SHA1(name || salt)`, byte-reversed, base-64),
|
||||
which is what named the frame. Next attempt: remove PPSSPP's `thread_local` uses, since
|
||||
core TLS compiles to `__emutls_get_address` → `pthread_getspecific`, exactly the family
|
||||
in the backtrace.
|
||||
|
||||
## Accepted baselines
|
||||
|
||||
- XMB: `601e575` fixed large-list allocation failures, `6b857a9` merged the README;
|
||||
the owner confirmed crash-free navigation and the normal build removed the
|
||||
five-second hitches. Detail: `docs/XMB_LIST_SAFETY.md`,
|
||||
crash-free navigation and no five-second hitches. Detail: `docs/XMB_LIST_SAFETY.md`,
|
||||
`evidence/xmb-safe-list-run/`.
|
||||
- Gameplay: Genesis Plus GX frontend `ecfcddd5…` with all five gates green and owner
|
||||
acceptance of colours, sound, controls and menu/next-game transitions;
|
||||
FCEUmm, mGBA, Snes9x and FBNeo evidence stays in `native-core-loading/`,
|
||||
`mgba-native/`, `snes9x-native/` and `fbneo-native/`. Core pins, hashes and
|
||||
acceptance limits are in `docs/PHASE_LOG.md`.
|
||||
|
||||
## Failure being addressed
|
||||
|
||||
Resolved and superseded. The XMB large-list crash (`601e575`), the hitches after it
|
||||
and the thumbnail/input defaults (`e11018a`) are all accepted; the investigation
|
||||
record is `docs/XMB_ALLOCATION_INVESTIGATION.md`, the fix notes
|
||||
`docs/XMB_LIST_SAFETY.md` and `docs/THUMBNAIL_INPUT_DEFAULTS.md`, and the raw
|
||||
captures are `klog/xmb-*` with evidence under `evidence/xmb-*` and
|
||||
`evidence/thumbnail-input-defaults/`. The unsafe driver error logger under
|
||||
arbitrary OOM remains outside the frontend fix.
|
||||
|
||||
## Previous console-verified baseline
|
||||
|
||||
Superseded by the baselines above and recorded in full in `docs/PHASE_LOG.md`: the
|
||||
Genesis Plus GX run `ecfcddd5…` (66 tests, owner-confirmed gameplay) and the FCEUmm,
|
||||
mGBA, Snes9x and FBNeo runs whose evidence stays in `native-core-loading/`,
|
||||
`mgba-native/`, `snes9x-native/` and `fbneo-native/`.
|
||||
- Gameplay: Genesis Plus GX frontend `ecfcddd5…`, all five gates green, owner acceptance
|
||||
of colours, sound, controls and menu/next-game transitions. FCEUmm, mGBA, Snes9x and
|
||||
FBNeo evidence stays in `native-core-loading/`, `mgba-native/`, `snes9x-native/` and
|
||||
`fbneo-native/`. Core pins, hashes and acceptance limits are in `docs/PHASE_LOG.md`.
|
||||
- Thumbnail and configuration-reset fixes accepted (patches 0081/0082):
|
||||
`evidence/thumbnail-input-defaults/`, `docs/THUMBNAIL_INPUT_DEFAULTS.md`.
|
||||
|
||||
## Named errors and remaining limits
|
||||
|
||||
- First frontend snapshot has five intentional missing-core recovery errors and
|
||||
two archive-extraction failures. The owner identified the failing content as
|
||||
ARCADE - Sega System 16 & 32: these boards belong to FBNeo, not Genesis Plus GX.
|
||||
Archive structure was not inspected; no general archive fix is inferred.
|
||||
- Second-launch frontend snapshot has zero ERROR lines. Neither run records an
|
||||
invalid bitmap viewport or rejected XRGB8888 format.
|
||||
- Console verification does not cover every supported Sega system, BIOS/disc/CHD,
|
||||
NTSC/interlace options, SRAM/state round trips, long-run A/V or performance.
|
||||
Silence/discard counters include menu/start/stop; zero backend errors is not
|
||||
proof of uninterrupted audio across all workloads.
|
||||
- Existing upstream compiler warnings include old zlib prototypes, Tremor's
|
||||
long-to-int abs conversion and unused blip_discard_samples_dirty missing return.
|
||||
That blip helper has no callers in this source. Disc codecs remain unverified
|
||||
on console; warnings are not suppressed or treated as runtime acceptance.
|
||||
- Loader still rejects TLS, legacy init/fini, nonempty preinit and unsupported
|
||||
relocations/dependencies. General unwind registration is absent. Cores share
|
||||
the frontend process; safe load rejection cannot isolate arbitrary core faults.
|
||||
- First frontend snapshot has five intentional missing-core recovery errors and two
|
||||
archive-extraction failures; the owner identified the content as Sega System 16 & 32,
|
||||
which belongs to FBNeo. No general archive fix is inferred.
|
||||
- Console verification does not cover every supported system, BIOS/disc/CHD, NTSC and
|
||||
interlace options, SRAM/state round trips, long-run A/V or performance. Zero backend
|
||||
errors is not proof of uninterrupted audio across all workloads.
|
||||
- Upstream compiler warnings (old zlib prototypes, Tremor's long-to-int abs conversion,
|
||||
an unused blip helper's missing return) are neither suppressed nor treated as
|
||||
acceptance.
|
||||
- The loader still rejects TLS, legacy init/fini, nonempty preinit and unsupported
|
||||
relocations/dependencies; cores share the frontend process, so a rejected load is safe
|
||||
but an arbitrary core fault is not isolated.
|
||||
- The withdrawn path has the console history; the native byte order does not yet. A
|
||||
colour regression would show as red and blue exchanged in the menu, in core frames or
|
||||
in thumbnails, and is the first thing to check on the next run.
|
||||
|
||||
## Preserved platform and file locations
|
||||
|
||||
XMB stays default and RGUI selectable. Vulkan remains the presentation route;
|
||||
video_ps5 stays selectable as CPU fallback. Native audio/input/binding, config
|
||||
saving, FTP permissions and directory browsing remain. Useful logs are retained.
|
||||
Deployments preserve live settings/games.
|
||||
XMB stays default and RGUI selectable. Vulkan remains the presentation route; video_ps5
|
||||
stays selectable as CPU fallback. Native audio/input/binding, config saving, FTP
|
||||
permissions and directory browsing remain. Deployments preserve live settings/games.
|
||||
|
||||
FTP base `/data/homebrew/PPSA99169/` corresponds to in-title `/app0`.
|
||||
Use content/, system/, cores/, config/retroarch.cfg, savefiles/, savestates/.
|
||||
Genesis Plus GX Sega CD BIOS files use system/ root; FBNeo uses system/fbneo/.
|
||||
See `docs/DEPLOYMENT.md` for procedures and metadata-listed BIOS filenames.
|
||||
FTP base `/data/homebrew/PPSA99169/` corresponds to in-title `/app0`. Use content/,
|
||||
system/, cores/, config/retroarch.cfg, savefiles/, savestates/. Genesis Plus GX Sega CD
|
||||
BIOS files use system/ root; FBNeo uses system/fbneo/. See `docs/DEPLOYMENT.md`.
|
||||
|
||||
## Operating notes
|
||||
|
||||
Uploads are authorized; check console idle before deployment. A new launch needs
|
||||
owner intervention. Start klog first, preserve old logs and capture allocation,
|
||||
frontend and trace logs. Never interrupt another title. Preserve crash/freeze logs
|
||||
before relaunch. No new core or unrelated driver work is assigned by this file.
|
||||
Uploads are authorized; check console idle before deployment. A new launch needs owner
|
||||
intervention. Start klog first, preserve old logs, and capture allocation, frontend and
|
||||
trace logs. Never interrupt another title. No new core or unrelated driver work is
|
||||
assigned by this file.
|
||||
@@ -2857,3 +2857,59 @@ No historical regression verdict or exact heap-capacity claim is established.
|
||||
See `evidence/xmb-playlist-allocation-crash/` for sanitized first-failure owners,
|
||||
context history, source comparison and playlist counts. Raw user data remains
|
||||
in ignored capture storage.
|
||||
|
||||
## 2026-09-20 — the driver samples the byte order the frontend uploads
|
||||
|
||||
`../PS5_Vulkan`'s `VK_FORMAT_B8G8R8A8_UNORM` entry is a sampled one
|
||||
(`driver/ps5vk_image.c`: `SAMPLED_IMAGE_BIT`, the linear filter, the transfer and
|
||||
blit pairs, and the `8_8_8_8_UNORM` word with the `ZYXW` selectors, which read the
|
||||
memory's B, G, R, A as R, G, B, A). That project's `v0-formats` battery proves the
|
||||
fetch on the console and `docs/M5_PHASE_C.md`'s round 6 records the words:
|
||||
`B8G8R8A8_UNORM` takes `ZYXW`, "VideoOut's byte order", while
|
||||
`A8B8G8R8_UNORM_PACK32` takes `WZYX` because the console's fetch of *that* format
|
||||
reverses. The frontend uploads libretro's little-endian XRGB8888, whose four bytes
|
||||
are the same B, G, R, A, so the two now agree byte for byte and no conversion
|
||||
between them is owed.
|
||||
|
||||
Four of this port's changes existed because that entry did not:
|
||||
|
||||
- **0014** substituted `R8G8B8A8_UNORM` for any format whose entry did not
|
||||
advertise `SAMPLED_IMAGE_BIT`. An application's B, G, R, A bytes then landed in
|
||||
an image the driver reads as R, G, B, A: the red and blue reversal. The usage
|
||||
mask in the same block is what actually mattered, and it stays.
|
||||
- **0075** made `vk->tex_fmt` R8G8B8A8 for a 32-bit core frame and converted every
|
||||
frame's channels on the CPU into it, because a B8G8R8A8 staging buffer beside a
|
||||
substituted R8G8B8A8 image selected `vulkan_copy_staging_to_dynamic`'s
|
||||
RGB565-only compute branch and aborted there.
|
||||
- **0077** decoded menu images as RGBA and uploaded them as R8G8B8A8, and refused
|
||||
the writable software framebuffer so that the XRGB-to-RGBA conversion could not
|
||||
mutate cached source pixels while the Quick Menu paused emulation.
|
||||
- **0081** is kept. It makes `supports_rgba` follow the order a caller asked for,
|
||||
where upstream leaves `false` behind its own TODO. It is inert without an RGBA
|
||||
request and correct with one, so it is not part of the reversal.
|
||||
|
||||
The withdrawal is `tools/apply-port-patches.py`'s `WITHDRAWN` tuple: each marker
|
||||
names an EDITS block whose insertion is exchanged for the upstream text it
|
||||
replaced. A tree that already carries the insertion and a fresh tree end in the
|
||||
same file, which is checked by applying the patcher to a copy of
|
||||
`vendor/retroarch`'s `gfx/drivers/vulkan.c` and to the withdrawn `build/ra-conf`
|
||||
and comparing the two (identical). Two blocks that look like the same decision
|
||||
stay, for reasons that do not depend on the sample order: **0027** and **0055**
|
||||
convert the menu's 16-bit RGBA4444 frame by hand into R8G8B8A8, because this
|
||||
driver still refuses a view whose component mapping is not the identity and so
|
||||
cannot sample the B4G4R4A4 texture with the B/R swizzle upstream asks for; and
|
||||
**0015** stays for upstream's own `VK_REMAP_TO_TEXFMT`, which turns an RGB565
|
||||
request into R8G8B8A8.
|
||||
|
||||
What this does not establish: the withdrawn path is the one the console accepted
|
||||
earlier (owner-confirmed colours in `native-core-loading/`, `mgba-native/` and
|
||||
`xmb-safe-list-run/`), and the native byte order has host evidence and the
|
||||
driver's own console battery so far. The first console run after this change is
|
||||
what decides the title's colours.
|
||||
|
||||
A second finding, from the same round: `tools/core-imports.py` rewrites
|
||||
`build/core_imports.inc`, and that file is insertion-ordered by the core list, so
|
||||
running the tool by hand to read a count changes a build input and with it the
|
||||
build identity. The identity does not lie about what it hashed — recomputing it
|
||||
from its own inputs reproduced the printed identity — but a tree whose include was
|
||||
rewritten by hand no longer describes the eboot that was built from it.
|
||||
@@ -2916,3 +2916,79 @@ now motivated by the emutls path: core TLS becomes `__emutls_get_address` →
|
||||
`pthread_getspecific`, which is exactly the family in the backtrace). If that is not
|
||||
enough, the fix has to make libkernel's lookup succeed for core addresses, or keep
|
||||
libkernel's thread-specific-data path off every stack that contains core frames.
|
||||
|
||||
## 2026-09-20 — relinked against the migrated driver with the red/blue compensation withdrawn
|
||||
|
||||
**Task.** Two asks: build the frontend against `../PS5_Vulkan` now that its migration
|
||||
landed (`8b311e3`), and remove this port's red/blue compensation, which 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".** The compile-side surface moved: the
|
||||
driver links ps5-opengl 0.3.0's `opengnm-psbc` tree (upstream `a92a1228` + the
|
||||
release's patch, tree `a27cbecc`, metadata v14) with this repository's compiler patches
|
||||
on top, `patch-compute-metadata.py` is dropped, `patch-vertex-formats.py`'s anchor moved
|
||||
and a new `patch-aco-min-waves.py` restores `program->workgroup_size`'s
|
||||
"unknown is UINT_MAX" invariant before `calc_min_waves`. The console SIGFPE that round
|
||||
15 had laid at ACO's door was the *probe's* own: earlier symbolization had missed the
|
||||
PIE load base (`xotext: 0000000000400000`), and rebased, `rip 0x430b34` is `div %r13d`
|
||||
in `run_sampled_format_frames`, dividing by an unfilled `std::array<SampledFormat, 10>`
|
||||
row's zero texel size; both tables now declare their rows and a `static_assert` makes a
|
||||
declared-but-unfilled row a build error (console: pid 299, seven of seven cases, 1581
|
||||
PASS records, no `signal:`). Three fixes in the same commit matter here: `ps5vk_compile_stage`
|
||||
dereferenced a null shader module for the NIR stages Mesa's meta operations hand it —
|
||||
every meta clear, blit and resolve faulted — `ps5vk_queue_flip` recorded the wrong
|
||||
submission's words, and shader compilation now runs on a driver-allocated 32 MiB stack
|
||||
via `pthread_attr_setstack`, so an application thread's small stack cannot overflow the
|
||||
compiler's recursion. **What the port depends on is unchanged**: `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 the same
|
||||
(179 required, 58 reported, 0 missing, 55 conditional, split 0/0/0/0/0).
|
||||
|
||||
**Withdrawn: 0014's format substitution, 0075, 0077.** `tools/apply-port-patches.py`
|
||||
grew an 0083 group (the substitution goes, the usage mask stays, and 0027's and 0015's
|
||||
comments are restated for the reasons they still have) and a `WITHDRAWN` tuple that
|
||||
exchanges each named insertion for the upstream text it replaced, so an existing tree
|
||||
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: the upload is a row copy of
|
||||
libretro's little-endian XRGB8888 into a B8G8R8A8 image, which is the same four bytes.
|
||||
Four tests now assert the core's own bytes instead of the conversion's output, and two
|
||||
new `tests/test_frontend.py` cases pin the mechanism (a withdrawal must name exactly one
|
||||
EDITS block, and the withdrawn set is named). The patch-count pin moved 179 → 185.
|
||||
|
||||
**Build and gates.** `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)`. Title identity `f9e4ea6c…`, eboot 34,703,515 bytes sha256
|
||||
`82534b86…`, and two consecutive gate runs built it byte for byte the same. The four
|
||||
driver archives were frozen into `build/frozen-driver/` before the build and re-hashed
|
||||
unchanged after it, and the printed identity was recomputed from `tools/build-title.sh`'s
|
||||
own input list against those hashes and matched, so the eboot's embedded identity names
|
||||
the driver it carries. Record: `evidence/driver-1.0-native-byte-order/`.
|
||||
|
||||
**Four runs before the green one, at the same detail.** 1) The first `tools/verify.sh`
|
||||
failed at `unit`: three new 0083 markers did not appear in their own replacements — the
|
||||
port pins that so a rebuild cannot append an edit twice — and the patch-count pin was
|
||||
stale; both fixed (`build/verify-native-byte-order-first-run.log`). 2) The second failed
|
||||
at `build` after 324 s because the frozen tree's `.deps/work` symlink was one level short
|
||||
and the Mesa utility sources read as missing (`…-second-run.log`). 3) A third was
|
||||
interrupted mid-build when the driver's `8b311e3` landed and the freeze was rebuilt
|
||||
(`…-third-run-killed.log`). 4) The fourth passed format, unit, build and integration and
|
||||
failed only at `evidence`, because the new step directory held no `capture.json` /
|
||||
`expectation.json` yet (`…-gates-4-of-5.log`).
|
||||
|
||||
**Also found.** `tools/core-imports.py` rewrites `build/core_imports.inc`, and that file
|
||||
is insertion-ordered by the core list: running the tool by hand to read a count changes a
|
||||
build input and with it the build identity. The identity does not lie about what it
|
||||
hashed — recomputing it from its own inputs reproduced both printed identities — but a
|
||||
tree whose include was rewritten by hand no longer describes the eboot built from it.
|
||||
|
||||
**Pending, and the only thing that decides the colours: a console run.** The withdrawn
|
||||
path is the one the owner accepted earlier (`native-core-loading/`, `mgba-native/`,
|
||||
`xmb-safe-list-run/`), and the native byte order has host evidence plus the driver's own
|
||||
console `v0-formats` battery. The command is
|
||||
`JOBS=14 bash tools/run-title.sh --no-build --deploy --watch 120` with the owner
|
||||
launching; the check is menu colours, core colours, and the Quick Menu over a paused
|
||||
game.
|
||||
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"step": "driver-1.0-native-byte-order",
|
||||
"recorded": "2026-09-20",
|
||||
"revision": "ca02af3 (title source) / 8b311e3 (the driver the link carries)",
|
||||
"command": "PS5_VULKAN_DIR=$PWD/build/frozen-driver PS5_VULKAN_ICD=$PWD/build/frozen-driver/build/driver/ps5/libvulkan.so.1 bash tools/verify.sh",
|
||||
"raw_capture": "build/verify-native-byte-order.log",
|
||||
"raw_lines": 7718,
|
||||
"raw_bytes": 3172524,
|
||||
"lines": [
|
||||
"==> [ra] compiled 278 of 278 sources",
|
||||
"==> [ra] archived 278 objects into build/ra/libretroarch.a",
|
||||
" gfx/drivers/vulkan.c: withdrawn (patches/series, 0075: matching)",
|
||||
" gfx/drivers/vulkan.c: withdrawn (patches/series, 0075: libretro XRGB)",
|
||||
" gfx/drivers/vulkan.c: withdrawn (patches/series, 0077: decode menu images for sampled RGBA)",
|
||||
" gfx/drivers/vulkan.c: withdrawn (patches/series, 0077: preserve original core pixels across cached frames)",
|
||||
" gfx/drivers/vulkan.c: withdrawn (patches/series, 0077: upload decoded menu images as RGBA)",
|
||||
"core ABI PASS: fceumm_libretro.so; 25 exports; kernel_web",
|
||||
"core ABI PASS: mgba_libretro.so; 25 exports; kernel_web",
|
||||
"core ABI PASS: snes9x_libretro.so; 25 exports; kernel_web",
|
||||
"core ABI PASS: fbneo_libretro.so; 25 exports; kernel_web",
|
||||
"core ABI PASS: genesis_plus_gx_libretro.so; 25 exports; kernel_web",
|
||||
"core ABI PASS: ppsspp_libretro.so; 25 exports; kernel_web",
|
||||
"core imports: 409 explicit native bindings for 6 cores",
|
||||
"==> [title] build identity: f9e4ea6c9d6261cda7854fed71c854e0f138aa8733f54869733d3727919f54fe",
|
||||
"==> [title] staged the Vulkan driver: libvulkan.so.1 (16862080 bytes)",
|
||||
"==> [title] built /home/mihawk/Desktop/PS5_Homebrews/PS5_RetroArch/dist/PPSA99169 (354 files, eboot.bin 34703515 bytes)",
|
||||
"eboot.bin is a fake self application image (4f153d1d)",
|
||||
"verify: PASS (format unit build integration evidence)"
|
||||
],
|
||||
"gates": {
|
||||
"format": "PASS (1s)",
|
||||
"unit": "PASS (12s)",
|
||||
"build": "PASS (247s)",
|
||||
"integration": "PASS (10s)",
|
||||
"evidence": "PASS (0s)"
|
||||
},
|
||||
"title": {
|
||||
"build_identity": "f9e4ea6c9d6261cda7854fed71c854e0f138aa8733f54869733d3727919f54fe",
|
||||
"eboot_bytes": 34703515,
|
||||
"eboot_sha256": "82534b86717cf423dcc12b6014dcb1d68cfe9de2d3c8c88817cc13a93d24d629",
|
||||
"reproducible": "two consecutive gate runs built the same eboot byte for byte"
|
||||
},
|
||||
"driver": {
|
||||
"ps5_vulkan_revision": "8b311e3027a3f8988615847e7da38ed0b245883d",
|
||||
"archives_frozen_at": "build/frozen-driver",
|
||||
"archive_hashes": "evidence/driver-1.0-native-byte-order/driver-archives.json",
|
||||
"identity_recomputed_from_the_frozen_inputs": true
|
||||
},
|
||||
"withdrawn": [
|
||||
"0014's format substitution: an image is the format it was asked for",
|
||||
"0075: vk->tex_fmt R8G8B8A8 and the per-frame ps5_core_frame_rgba conversion",
|
||||
"0077: RGBA menu decode/upload and the refused writable software framebuffer"
|
||||
],
|
||||
"kept": [
|
||||
"0027 and 0055: the 16-bit RGUI frame, converted by hand into R8G8B8A8",
|
||||
"0015: the bpp case upstream's VK_REMAP_TO_TEXFMT and 0027 both need",
|
||||
"0081: supports_rgba follows the requested order (upstream's own TODO)"
|
||||
],
|
||||
"console_verification": "pending: no console run of this build yet; the owner's colour check is what decides it"
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"note": "The driver the title links, frozen out of ../PS5_Vulkan into build/frozen-driver/ before this build and verified unchanged after it: the archives are copied to a stable tree and PS5_VULKAN_DIR/PS5_VULKAN_ICD point at it, because that project is developed concurrently and a rebuilt archive under the title's link is a different driver. Keys are the paths under the driver's root, as in evidence/mgba-native/driver-archives.json.",
|
||||
"ps5_vulkan_revision": "8b311e3027a3f8988615847e7da38ed0b245883d",
|
||||
"ps5_vulkan_subject": "Migrate the driver to ps5-opengl 0.3.0's compiler fork, and close the console SIGFPE at its owner",
|
||||
"ps5_vulkan_state": "The format audit is unchanged by the migration (179 formats required, 58 reported, 0 missing a required feature, 55 conditional, split 0/0/0/0/0), and driver/ps5vk_image.c is not touched by this commit: VK_FORMAT_B8G8R8A8_UNORM still carries SAMPLED_IMAGE_BIT with the 8_8_8_8_UNORM descriptor word and the ZYXW selectors, which is the fetch order the frontend's own XRGB8888 bytes rely on. What the commit does change is the shader compiler (ps5-opengl 0.3.0's opengnm-psbc tree, 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.",
|
||||
"archives_are_current_for_the_tree": "no driver/*.c, driver/*.h, tooling/*.py or tools/*.sh file is newer than the archives, and the driver's working tree is clean at this revision",
|
||||
"frozen_at": "build/frozen-driver (git-ignored; the two commands that build it are in docs/PHASE_LOG.md)",
|
||||
"archives": {
|
||||
"build/driver/ps5/libps5vk.ps5.a": "8ff68c27c52a47deaf13e7f008352a43b8e00503e81aa6ed89388823c114391e",
|
||||
"build/driver/ps5/libpsbc_driver.ps5.a": "7a71bfa72936092df1eab966ca7f908b0139ce506978cd6e63771ef7b0982f60",
|
||||
".deps/native/psbc/lib/libpsbc_support.ps5.a": "3a58df8a9078f8eee6e6670c4b72a71cabd60d4a1df7753152f91f2ce3ad5655",
|
||||
".deps/native/vulkan-runtime/lib/libvk_runtime.ps5.a": "4106a2c56b269bc52a3976b6bc0134c00b5006ff5358a4b45355afce4a907aa7"
|
||||
},
|
||||
"runtime_icd": {
|
||||
"build/driver/ps5/libvulkan.so.1": "d4a90c9dcf2ea7d74e989c637cad7a5d31bee8ca2a7d1767a2a46d79034e54a4"
|
||||
},
|
||||
"driver_archives_unchanged_during_the_build": true,
|
||||
"title": {
|
||||
"build_identity": "f9e4ea6c9d6261cda7854fed71c854e0f138aa8733f54869733d3727919f54fe",
|
||||
"eboot_bytes": 34703515,
|
||||
"eboot_sha256": "82534b86717cf423dcc12b6014dcb1d68cfe9de2d3c8c88817cc13a93d24d629"
|
||||
},
|
||||
"identity_covers_these_archives": "tools/build-title.sh's printed identity f9e4ea6c9d6261cda7854fed71c854e0f138aa8733f54869733d3727919f54fe was recomputed from that script's own input list - src/, the frontend archive, config.h, the six core objects, the four driver archives and the three Mesa utility objects - against these exact frozen archive hashes, and matched. The identity string is compiled into the title, so the shipped eboot names the driver it carries."
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"step": "driver-1.0-native-byte-order",
|
||||
"note": "The frontend builds and links against ../PS5_Vulkan 8b311e3 with the red/blue compensations withdrawn, and every gate replays. The withdrawal is visible in the build's own patch report: 0014's format substitution, 0075's core-frame RGBA upload and 0077's menu colour and cached-frame ownership are exchanged for the upstream text they replaced, so the frontend uploads libretro's little-endian XRGB8888 into a VK_FORMAT_B8G8R8A8_UNORM image the driver samples in that same byte order. The driver archives were frozen before the build and re-hashed unchanged after it, and the build identity - which covers those archives and is compiled into the title - was recomputed from tools/build-title.sh's own input list and matched.",
|
||||
"must_contain": [
|
||||
"==> [ra] compiled 278 of 278 sources",
|
||||
"gfx/drivers/vulkan.c: withdrawn (patches/series, 0075: matching)",
|
||||
"gfx/drivers/vulkan.c: withdrawn (patches/series, 0075: libretro XRGB)",
|
||||
"gfx/drivers/vulkan.c: withdrawn (patches/series, 0077: decode menu images for sampled RGBA)",
|
||||
"gfx/drivers/vulkan.c: withdrawn (patches/series, 0077: preserve original core pixels across cached frames)",
|
||||
"gfx/drivers/vulkan.c: withdrawn (patches/series, 0077: upload decoded menu images as RGBA)",
|
||||
"core ABI PASS: fceumm_libretro.so; 25 exports; kernel_web",
|
||||
"core ABI PASS: ppsspp_libretro.so; 25 exports; kernel_web",
|
||||
"core imports: 409 explicit native bindings for 6 cores",
|
||||
"==> [title] build identity: f9e4ea6c9d6261cda7854fed71c854e0f138aa8733f54869733d3727919f54fe",
|
||||
"eboot.bin 34703515 bytes",
|
||||
"verify: PASS (format unit build integration evidence)"
|
||||
],
|
||||
"must_not_contain": [
|
||||
"verify: FAIL",
|
||||
"ANCHOR NOT FOUND",
|
||||
"error: the driver's Mesa utility objects did not build"
|
||||
],
|
||||
"human_check": "Not yet seen on the console. The withdrawn path is the one the owner accepted earlier (colours confirmed for FCEUmm, mGBA, Snes9x, FBNeo and the XMB), and the native byte order has host evidence plus the driver's own console v0-formats battery; the first launch of this build is what decides the title's colours, the Quick Menu over a paused game and core frames. Until that run is recorded this step is host-verified only."
|
||||
}
|
||||
+13
-3
@@ -87,12 +87,17 @@
|
||||
# Opt-in native loader diagnostic verifies rejected loads preserve the live menu.
|
||||
0074-native-core-recovery-diagnostic
|
||||
|
||||
0075-native-core-rgba-upload
|
||||
# 0075 and 0077 are withdrawn. Both existed because this driver's B8G8R8A8_UNORM
|
||||
# entry was not a sampled one: the frontend's software core frames and its
|
||||
# menu images ask for that format, 0014's substitution turned them into
|
||||
# R8G8B8A8 images, and their bytes were then read in the wrong order - the
|
||||
# red and blue reversal. The entry is sampled now, so the frontend keeps
|
||||
# libretro's own byte order again. Their markers are in the WITHDRAWN tuple
|
||||
# of tools/apply-port-patches.py, which exchanges each insertion for the
|
||||
# upstream text it replaced.
|
||||
|
||||
0076-archive-read-error-diagnostics
|
||||
|
||||
0077-vulkan-menu-colour-and-cached-frame-ownership
|
||||
|
||||
0078-crop-padded-core-source
|
||||
|
||||
# Opt-in, bounded first-failure XMB context; no allocator or menu policy change.
|
||||
@@ -106,3 +111,8 @@
|
||||
|
||||
# Native joypad defaults and live auto-binding recovery after reset.
|
||||
0082-reset-native-input-defaults
|
||||
|
||||
# 0083 an image is the format it was asked for: 0014's substitution to
|
||||
# R8G8B8A8_UNORM is withdrawn, its usage mask kept, and 0027's and 0015's
|
||||
# comments re-stated for the reason each still has
|
||||
0083-image-is-the-requested-format
|
||||
+11
-19
@@ -1,22 +1,14 @@
|
||||
/* Convert libretro's little-endian XRGB8888 to the sampled RGBA8 upload format. */
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
extern "C" void ps5_core_frame_rgba(void *output, size_t stride, const void *input, size_t pitch,
|
||||
unsigned width, unsigned height)
|
||||
{
|
||||
auto *dst = static_cast<uint8_t *>(output);
|
||||
auto *src = static_cast<const uint8_t *>(input);
|
||||
for (unsigned y = 0; y < height; ++y, dst += stride, src += pitch)
|
||||
for (unsigned x = 0; x < width; ++x)
|
||||
{
|
||||
const uint8_t blue = src[4 * x], green = src[4 * x + 1], red = src[4 * x + 2];
|
||||
dst[4 * x] = red;
|
||||
dst[4 * x + 1] = green;
|
||||
dst[4 * x + 2] = blue;
|
||||
dst[4 * x + 3] = 255;
|
||||
}
|
||||
}
|
||||
/* The padded source quad a software core's frame is sampled through.
|
||||
*
|
||||
* Nothing here touches channels, and that is a measured property of the pair on
|
||||
* either side rather than an omission. A software core hands libretro
|
||||
* little-endian XRGB8888, and ../PS5_Vulkan samples VK_FORMAT_B8G8R8A8_UNORM in
|
||||
* that format's own B, G, R, A byte order - its 8_8_8_8_UNORM descriptor word
|
||||
* with the ZYXW selectors (driver/ps5vk_image.c), which its own v0-formats
|
||||
* battery proves on the console. The two layouts are the same four bytes, so the
|
||||
* frontend's upload is a row copy and this file holds only the geometry a
|
||||
* 256-byte-row image needs when its sampled width is wider than the core's.
|
||||
*/
|
||||
|
||||
/* Two triangle-list quads, with UVs restricted to the logical source image.
|
||||
* The caller uses a buffer belonging to the current, fence-retired sync slot. */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Verify core upload channel order, alpha, row pitch and in-place writes."""
|
||||
"""Verify the padded source quad's UVs across width and transition changes."""
|
||||
import ctypes
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
@@ -9,34 +9,6 @@ ROOT = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
class CoreFrame(unittest.TestCase):
|
||||
def test_xrgb_upload_with_padding_and_in_place(self):
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
lib = Path(td) / 'frame.so'
|
||||
subprocess.run(['c++', '-shared', '-fPIC', '-Wall', '-Wextra', '-Werror',
|
||||
str(ROOT / 'src/core_frame_ps5.cpp'), '-o', str(lib)], check=True)
|
||||
convert = ctypes.CDLL(str(lib)).ps5_core_frame_rgba
|
||||
convert.argtypes = [ctypes.c_void_p, ctypes.c_size_t, ctypes.c_void_p,
|
||||
ctypes.c_size_t, ctypes.c_uint, ctypes.c_uint]
|
||||
source = bytes([0, 0, 255, 0, 0, 255, 0, 128, 9, 9, 9, 9,
|
||||
255, 0, 0, 0, 0x56, 0x34, 0x12, 1, 9, 9, 9, 9])
|
||||
expected = bytes([255, 0, 0, 255, 0, 255, 0, 255,
|
||||
0, 0, 255, 255, 0x12, 0x34, 0x56, 255])
|
||||
src = ctypes.create_string_buffer(source)
|
||||
dst = ctypes.create_string_buffer(bytes([0xAA]) * 32)
|
||||
convert(dst, 16, src, 12, 2, 2)
|
||||
self.assertEqual(dst.raw[:8] + dst.raw[16:24], expected)
|
||||
self.assertEqual(dst.raw[8:16] + dst.raw[24:32], bytes([0xAA]) * 16)
|
||||
# Quick Menu repeats the cached core frame into alternating images.
|
||||
# The source remains XRGB, so repeated uploads must be identical.
|
||||
self.assertEqual(src.raw[:len(source)], source)
|
||||
for _ in range(4):
|
||||
convert(dst, 16, src, 12, 2, 2)
|
||||
self.assertEqual(dst.raw[:8] + dst.raw[16:24], expected)
|
||||
self.assertEqual(src.raw[:len(source)], source)
|
||||
convert(src, 12, src, 12, 2, 2)
|
||||
self.assertEqual(src.raw[:8] + src.raw[12:20], expected)
|
||||
self.assertEqual(src.raw[8:12] + src.raw[20:24], bytes([9]) * 8)
|
||||
|
||||
def test_padded_source_sampling_across_core_transitions(self):
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
wrapper = Path(td) / 'quad.cpp'
|
||||
|
||||
@@ -58,17 +58,18 @@ int main() {
|
||||
r'static UINT32 __cdecl ' + name + r'\([^}]+\}', video).group()
|
||||
for name in ['HighCol16', 'HighCol32'])
|
||||
(work / 'video.cpp').write_text(
|
||||
'#include <cassert>\n#include <cstdint>\nusing UINT32 = uint32_t;\nusing INT32 = int32_t;\n#define __cdecl\n' + functions + '\n'
|
||||
f'#include "{ROOT}/src/core_frame_ps5.cpp"\n'
|
||||
'#include <cassert>\n#include <cstdint>\n#include <cstring>\nusing UINT32 = uint32_t;\nusing INT32 = int32_t;\n#define __cdecl\n' + functions + '\n'
|
||||
f'#include "{ROOT}/tooling/fbneo/ps5-video.h"\n' + r'''
|
||||
int main() {
|
||||
for (unsigned r = 0; r < 256; ++r)
|
||||
for (unsigned g = 0; g < 256; ++g)
|
||||
for (unsigned b = 0; b < 256; ++b) {
|
||||
uint32_t native = HighCol32(r, g, b, 0);
|
||||
uint8_t gpu[4] = {};
|
||||
ps5_core_frame_rgba(gpu, 4, &native, 4, 1, 1);
|
||||
assert(gpu[0] == r && gpu[1] == g && gpu[2] == b && gpu[3] == 255);
|
||||
/* The upload copies these bytes into a B8G8R8A8 image, so
|
||||
libretro's little-endian XRGB8888 word is blue, green, red. */
|
||||
uint8_t bytes[4];
|
||||
memcpy(bytes, &native, 4);
|
||||
assert(bytes[0] == b && bytes[1] == g && bytes[2] == r && bytes[3] == 0);
|
||||
uint16_t packed = HighCol16(r, g, b, 0);
|
||||
assert(packed == ((r >> 3) << 11 | (g >> 2) << 5 | b >> 3));
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Check every RGB565 colour through the exact core and frontend upload helpers."""
|
||||
"""Check every RGB565 colour through the exact core conversion and its upload bytes."""
|
||||
import ctypes
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
@@ -13,7 +13,6 @@ class FBNeoVideo(unittest.TestCase):
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
source = Path(td) / 'video.cpp'
|
||||
source.write_text('#include "' + str(ROOT / 'tooling/fbneo/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_fbneo_frame(d, n, s, p, w, h); }\n')
|
||||
@@ -25,20 +24,18 @@ class FBNeoVideo(unittest.TestCase):
|
||||
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)
|
||||
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(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)))
|
||||
self.assertEqual(list(pixels[pixel * 4:pixel * 4 + 4]),
|
||||
[b * 8 + b // 4, g * 4 + g // 16, r * 8 + r // 4, 0])
|
||||
# Horizontal, vertical and non-aligned arcade widths; non-tight input row pitch.
|
||||
for width, height in [(320, 224), (224, 384), (384, 224), (402, 256)]:
|
||||
pitch = (width + 8) * 2
|
||||
|
||||
+43
-1
@@ -293,6 +293,48 @@ class PortPatches(unittest.TestCase):
|
||||
with self.subTest(file=name, marker=marker):
|
||||
self.assertIn(marker, replacement)
|
||||
|
||||
def withdrawn(self) -> list:
|
||||
import ast
|
||||
source = self.script.read_text(encoding="utf-8")
|
||||
for node in ast.parse(source).body:
|
||||
if isinstance(node, ast.Assign) and getattr(node.targets[0], "id", "") == "WITHDRAWN":
|
||||
return ast.literal_eval(node.value)
|
||||
raise AssertionError(f"{self.script} no longer defines WITHDRAWN")
|
||||
|
||||
def test_every_withdrawal_names_one_patch(self) -> None:
|
||||
"""A withdrawal that names no block, or names one twice, restores nothing.
|
||||
|
||||
The withdrawal is that block's own substitution in reverse, so its marker
|
||||
has to be a marker some EDITS block defines and no two withdrawals may
|
||||
share one: the second would look for an insertion the first has removed.
|
||||
"""
|
||||
markers = [edit[3] for edit in self.blocks()]
|
||||
withdrawn = self.withdrawn()
|
||||
self.assertEqual(len(set(withdrawn)), len(withdrawn),
|
||||
f"a marker is withdrawn twice: {sorted(withdrawn)}")
|
||||
for marker in withdrawn:
|
||||
self.assertIn(marker, markers,
|
||||
f"WITHDRAWN names {marker!r}, which no EDITS block defines")
|
||||
|
||||
def test_no_withdrawal_removes_an_edit_the_port_still_needs(self) -> None:
|
||||
"""The withdrawn blocks are the ones that existed for the old driver.
|
||||
|
||||
They are named here rather than counted, because a withdrawal is a
|
||||
behaviour change on the console: 0014's format substitution, 0075's core
|
||||
frame upload and 0077's menu colour and cached-frame ownership were all
|
||||
answers to a B8G8R8A8 entry that was not sampled. Withdrawing another
|
||||
block means re-checking that claim.
|
||||
"""
|
||||
self.assertEqual(
|
||||
sorted(self.withdrawn()),
|
||||
sorted([
|
||||
'patches/series, 0075: matching',
|
||||
'patches/series, 0075: libretro XRGB',
|
||||
'patches/series, 0077: decode menu images for sampled RGBA',
|
||||
'patches/series, 0077: upload decoded menu images as RGBA',
|
||||
'patches/series, 0077: preserve original core pixels across cached frames',
|
||||
]))
|
||||
|
||||
def test_the_patch_set_is_the_size_it_should_be(self) -> None:
|
||||
"""Pinned so an accidental addition or deletion is a visible diff.
|
||||
|
||||
@@ -300,7 +342,7 @@ class PortPatches(unittest.TestCase):
|
||||
change deliberately, in a commit that says why.
|
||||
"""
|
||||
self.assertEqual(
|
||||
len(self.blocks()), 179,
|
||||
len(self.blocks()), 185,
|
||||
"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")
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Exercise the core's RGB565 packing, cropped frames and actual Vulkan upload."""
|
||||
"""Exercise the core's RGB565 packing, cropped frames and upload byte order."""
|
||||
import ctypes
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
@@ -26,16 +26,13 @@ class GenesisVideo(unittest.TestCase):
|
||||
'-c', str(source), '-o', str(obj)], check=True)
|
||||
lib = directory / 'video.so'
|
||||
subprocess.run(['c++', '-shared', '-fPIC', '-Wall', '-Wextra', '-Werror',
|
||||
str(obj), str(ROOT / 'src/core_frame_ps5.cpp'), '-o', str(lib)], check=True)
|
||||
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
|
||||
cls.upload = cls.api.ps5_core_frame_rgba
|
||||
cls.upload.argtypes = [ctypes.c_void_p, ctypes.c_size_t, ctypes.c_void_p,
|
||||
ctypes.c_size_t, ctypes.c_uint, ctypes.c_uint]
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
@@ -65,13 +62,14 @@ class GenesisVideo(unittest.TestCase):
|
||||
api.pack(src)
|
||||
original = bytes(src)
|
||||
core = (ctypes.c_uint32 * 65536)()
|
||||
gpu = (ctypes.c_uint8 * (65536 * 4))()
|
||||
self.assertTrue(self.convert(core, 65536, src, 65536, 512, 0, 256, 256))
|
||||
self.upload(gpu, 1024, core, 1024, 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(gpu[pixel * 4:pixel * 4 + 4]),
|
||||
[r * 8 + r // 4, g * 4 + g // 16, b * 8 + b // 4, 255])
|
||||
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):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Check every RGB565 colour through the exact core and frontend upload helpers."""
|
||||
"""Check every RGB565 colour through the exact core conversion and its upload bytes."""
|
||||
import ctypes
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
@@ -13,7 +13,6 @@ class Snes9xVideo(unittest.TestCase):
|
||||
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')
|
||||
@@ -25,20 +24,18 @@ class Snes9xVideo(unittest.TestCase):
|
||||
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)
|
||||
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(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)))
|
||||
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
|
||||
|
||||
@@ -20,6 +20,10 @@ Every edit prints `applied` or `present`, so the script reports what it did rath
|
||||
than leaving the tree in an unknown state. Nothing is ever written to
|
||||
vendor/retroarch: the tree passed in is the configured copy under build/.
|
||||
|
||||
A change the driver has outgrown is withdrawn rather than deleted: its marker
|
||||
goes in WITHDRAWN below, and the script exchanges that insertion for the upstream
|
||||
text it replaced, so a tree that already carried it and a fresh one agree.
|
||||
|
||||
Exit status is 0 when every edit is present at the end, 1 otherwise.
|
||||
"""
|
||||
|
||||
@@ -2428,8 +2432,164 @@ EDITS = [
|
||||
('tasks/task_image.c', " /* TODO/FIXME - shouldn't we set this ? */\n image->ti.supports_rgba = false;", ' /* patches/series, 0081: async images honor the renderer channel order. */\n image->ti.supports_rgba = supports_rgba;', 'patches/series, 0081: async images'),
|
||||
('configuration.c', ' case JOYPAD_NULL:\n break;', ' case JOYPAD_NULL:\n /* patches/series, 0082: native joypad survives configuration reset. */\n return "ps5";', 'patches/series, 0082: native joypad'),
|
||||
('retroarch.c', ' case CMD_EVENT_MENU_RESET_TO_DEFAULT_CONFIG:\n config_set_defaults(global_get_ptr());\n break;', ' case CMD_EVENT_MENU_RESET_TO_DEFAULT_CONFIG:\n {\n /* patches/series, 0082: resetting defaults also clears auto-binds. */\n extern void ps5_input_reset_autoconfig(void);\n config_set_defaults(global_get_ptr());\n ps5_input_reset_autoconfig();\n break;\n }', 'patches/series, 0082: resetting defaults'),
|
||||
# 0083: the requested format is the image's format.
|
||||
#
|
||||
# ../PS5_Vulkan samples B8G8R8A8_UNORM in the byte order an application
|
||||
# uploads: the 8_8_8_8_UNORM word with the ZYXW selectors, which is Mesa's
|
||||
# radv_compose_swizzle for that format's description and which that project's
|
||||
# v0-formats battery proves on the console (docs/BLOCKERS.md defect 13,
|
||||
# docs/M5_PHASE_C.md round 6). An image is therefore the format it was asked
|
||||
# for, and 0014's substitution is withdrawn: reading an application's B, G, R,
|
||||
# A bytes as R, G, B, A is the red and blue reversal that made the port ask
|
||||
# for R8G8B8A8 everywhere (0075, 0077). What 0014 was really protecting stays
|
||||
# - the usage mask, which is derived from the requested format's own
|
||||
# features, so it cannot change what an image holds. Every format the
|
||||
# frontend asks for now advertises SAMPLED, so the substitution no longer
|
||||
# fired in any case; a format that does lose SAMPLED is better refused at
|
||||
# draw time than silently reinterpreted.
|
||||
(
|
||||
"gfx/drivers/vulkan.c",
|
||||
" /* Added by this port (patches/series, 0014): a create-info may only ask\n"
|
||||
" * for usage bits the format advertises, and a texture that cannot be\n"
|
||||
" * sampled is not a texture. Masking handles the first; the second is\n"
|
||||
" * handled by asking for R8G8B8A8_UNORM, which this driver reports as\n"
|
||||
" * sampled and which is the same image for a uniform colour. Only image\n"
|
||||
" * types are touched: STAGING and READBACK are buffers here. */\n",
|
||||
" /* Added by this port (patches/series, 0014): a create-info may only ask for\n"
|
||||
" * usage bits the format advertises. ../PS5_Vulkan refuses an image whose\n"
|
||||
" * usage its format's features do not allow, and upstream asks for\n"
|
||||
" * SAMPLED | TRANSFER_DST | TRANSFER_SRC on the 4x4 blank and the 1x1\n"
|
||||
" * default texture. The mask is built from the requested format's own\n"
|
||||
" * features, so it cannot change what an image holds. Only image types are\n"
|
||||
" * touched: STAGING and READBACK are buffers here.\n"
|
||||
" * patches/series, 0083: the mask is the whole edit. */\n",
|
||||
"patches/series, 0083: the mask is the whole edit",
|
||||
),
|
||||
(
|
||||
"gfx/drivers/vulkan.c",
|
||||
" VkFormat request = info.format;\n"
|
||||
"\n"
|
||||
" memset(&format_properties, 0, sizeof(format_properties));\n"
|
||||
" vkGetPhysicalDeviceFormatProperties(vk->context->gpu,\n"
|
||||
" request, &format_properties);\n"
|
||||
" if ( !(format_properties.optimalTilingFeatures\n"
|
||||
" & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)\n"
|
||||
" && request != VK_FORMAT_R8G8B8A8_UNORM)\n"
|
||||
" {\n"
|
||||
" request = VK_FORMAT_R8G8B8A8_UNORM;\n"
|
||||
" memset(&format_properties, 0, sizeof(format_properties));\n"
|
||||
" vkGetPhysicalDeviceFormatProperties(vk->context->gpu,\n"
|
||||
" request, &format_properties);\n"
|
||||
" }\n",
|
||||
" /* patches/series, 0083: the requested format is the image's format. */\n"
|
||||
" VkFormat request = info.format;\n"
|
||||
"\n"
|
||||
" memset(&format_properties, 0, sizeof(format_properties));\n"
|
||||
" vkGetPhysicalDeviceFormatProperties(vk->context->gpu,\n"
|
||||
" request, &format_properties);\n",
|
||||
"patches/series, 0083: the requested format",
|
||||
),
|
||||
(
|
||||
"gfx/drivers/vulkan.c",
|
||||
" info.format = request;\n"
|
||||
" info.usage &= allowed;\n",
|
||||
" /* patches/series, 0083: nothing to write back to the image's format. */\n"
|
||||
" info.usage &= allowed;\n",
|
||||
"patches/series, 0083: nothing to write back",
|
||||
),
|
||||
(
|
||||
"gfx/drivers/vulkan.c",
|
||||
" if (request != format)\n"
|
||||
" {\n"
|
||||
" /* The view, the staging buffer's pitch and tex.format are all\n"
|
||||
" * built from this local, so a substituted format has to reach\n"
|
||||
" * all four or the view is created for a format the image is not. */\n"
|
||||
" format = request;\n"
|
||||
" buffer_width = (width * vulkan_format_to_bpp(format) + 3u) & ~3u;\n"
|
||||
" buffer_info.size = buffer_width * height;\n"
|
||||
" }\n",
|
||||
" /* patches/series, 0083: no substituted format reaches the view, the\n"
|
||||
" * staging pitch or tex.format, so nothing is written back from it. */\n",
|
||||
"patches/series, 0083: no substituted format",
|
||||
),
|
||||
(
|
||||
# 0027's decision stays; only its reason moves. The format it names has to
|
||||
# be a 32-bit one the conversion below can write and this driver can
|
||||
# sample, and both textures keep whatever it names, so the substitution
|
||||
# 0027 cited is no longer part of the argument.
|
||||
"gfx/drivers/vulkan.c",
|
||||
" /* Added by this port (patches/series, 0027): ../PS5_Vulkan samples only\n"
|
||||
" * views whose component mapping is the identity (ps5vk_draw.c,\n"
|
||||
" * V0-formats), so the B4G4R4A4 texture and its B/R view swizzle cannot be\n"
|
||||
" * sampled: the draw is refused. The 32-bit texture and the CPU conversion\n"
|
||||
" * below carry the same pixels with no swizzle, which is the branch a device\n"
|
||||
" * without B4G4R4A4 tiling already takes. The format is named rather than\n"
|
||||
" * left at B8G8R8A8 because the staging texture keeps the format it is\n"
|
||||
" * created with: ../PS5_Vulkan's B8G8R8A8 entry is not a sampled one, so the\n"
|
||||
" * image is substituted to R8G8B8A8 and a staging texture in B8G8R8A8 would\n"
|
||||
" * make the two formats differ - which takes the compute path, whose\n"
|
||||
" * storage-image descriptor the driver has no entry for. */\n",
|
||||
" /* Added by this port (patches/series, 0027): ../PS5_Vulkan samples only\n"
|
||||
" * views whose component mapping is the identity (ps5vk_draw.c,\n"
|
||||
" * V0-formats), so the B4G4R4A4 texture and its B/R view swizzle cannot be\n"
|
||||
" * sampled: the draw is refused. The 32-bit texture and the CPU conversion\n"
|
||||
" * below carry the same pixels with no swizzle, which is the branch a device\n"
|
||||
" * without B4G4R4A4 tiling already takes.\n"
|
||||
" * patches/series, 0083: the format the conversion writes is named here\n"
|
||||
" * because it writes 32 bits per texel, and R8G8B8A8_UNORM is the 32-bit\n"
|
||||
" * format this driver samples through the identity selectors - the order\n"
|
||||
" * the store below is written in. Both the staging texture and the optimal\n"
|
||||
" * image are created with this one local, so naming it here is what keeps\n"
|
||||
" * the two from differing, which would take the compute path whose\n"
|
||||
" * storage-image descriptor the driver has no entry for. */\n",
|
||||
"patches/series, 0083: the format the conversion writes",
|
||||
),
|
||||
(
|
||||
# 0015's case is still required: upstream's own VK_REMAP_TO_TEXFMT turns an
|
||||
# RGB565 request into R8G8B8A8_UNORM, and 0027 names that format for the
|
||||
# 16-bit menu frame. Only its reason is rewritten.
|
||||
"gfx/drivers/vulkan.c",
|
||||
" /* Added by this port (patches/series, 0015): the format 0014 is\n"
|
||||
" * substituted with when a format cannot be sampled. Without this\n"
|
||||
" * case the staging buffer sized from it came out zero bytes long,\n"
|
||||
" * and the driver aborted inside vk_buffer_init. */\n",
|
||||
" /* Added by this port (patches/series, 0015): 32 bits per pixel for\n"
|
||||
" * R8G8B8A8_UNORM. Upstream's own VK_REMAP_TO_TEXFMT turns an RGB565\n"
|
||||
" * request into this format, and the 16-bit menu frame is converted into\n"
|
||||
" * it by hand (patches/series, 0027), so the staging buffer sized from it\n"
|
||||
" * must not come out zero bytes long: ../PS5_Vulkan's vk_buffer_init\n"
|
||||
" * aborts on a zero size.\n"
|
||||
" * patches/series, 0083: 32 bits per pixel for the format 0027 names and\n"
|
||||
" * upstream's own remap produces. */\n",
|
||||
"patches/series, 0083: 32 bits per pixel for",
|
||||
),
|
||||
]
|
||||
|
||||
# Changes that are withdrawn rather than deleted, by marker.
|
||||
#
|
||||
# An entry here names an insertion this driver no longer needs, and the
|
||||
# withdrawal is that entry's own substitution in reverse: the text it inserted
|
||||
# is exchanged for the upstream text it replaced. Nothing leaves EDITS, because
|
||||
# build/ra-conf already holds the insertion - a patch that is merely deleted
|
||||
# from this file stays applied in every tree that already has it, which is the
|
||||
# silent state the whole script exists to avoid.
|
||||
#
|
||||
# 0075 and 0077 were written while this driver's B8G8R8A8_UNORM entry advertised
|
||||
# the colour-attachment bit alone. The frontend asks for that format for its
|
||||
# software core frames and for its menu images, the substitution above turned
|
||||
# every one of them into an R8G8B8A8 image, and the bytes were then read in the
|
||||
# wrong order: the red and blue reversal. The entry is sampled now, so the
|
||||
# frontend uploads the core's own pixels again, decodes and uploads menu images
|
||||
# in the order they are decoded, and hands out its writable software framebuffer
|
||||
# instead of refusing it.
|
||||
WITHDRAWN = (
|
||||
'patches/series, 0075: matching',
|
||||
'patches/series, 0075: libretro XRGB',
|
||||
'patches/series, 0077: decode menu images for sampled RGBA',
|
||||
'patches/series, 0077: upload decoded menu images as RGBA',
|
||||
'patches/series, 0077: preserve original core pixels across cached frames',
|
||||
)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if len(sys.argv) != 2:
|
||||
@@ -2460,6 +2620,26 @@ def main() -> int:
|
||||
continue
|
||||
path.write_text(text.replace(anchor, replacement, 1), encoding="utf-8")
|
||||
print(f" {name}: applied")
|
||||
|
||||
# Withdrawals are processed after every insertion, so a fresh tree and a tree
|
||||
# that already carried the withdrawn text end in the same state.
|
||||
for name, anchor, replacement, marker in EDITS:
|
||||
if marker not in WITHDRAWN:
|
||||
continue
|
||||
path = tree / name
|
||||
if not path.is_file():
|
||||
print(f" {name}: MISSING (withdrawal, {marker})")
|
||||
ok = False
|
||||
continue
|
||||
text = path.read_text(encoding="utf-8")
|
||||
if replacement not in text:
|
||||
# Either this tree never carried the insertion or the withdrawal has
|
||||
# already run. Both end in the upstream text the withdrawal restores.
|
||||
print(f" {name}: upstream ({marker})")
|
||||
continue
|
||||
path.write_text(text.replace(replacement, anchor, 1), encoding="utf-8")
|
||||
print(f" {name}: withdrawn ({marker})")
|
||||
|
||||
return 0 if ok else 1
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user