mirror of
https://github.com/mihawk-99/PS5_RetroArch.git
synced 2026-10-18 23:09:29 -05:00
capture: read the frame with the driver's own viewport read (built, not yet run)
The port's capture now asks the driver instead of the frontend's screenshot writer:
patch 0031 reads --ps5-capture=N / --ps5-capture-path=FILE from /app0/args.txt in
vulkan_frame, calls the driver's vulkan_read_viewport at the budget, and writes the
pixels as a PPM (header plus rows, top-down RGB from the driver's bottom-up BGR).
0032 declares that readback entry point at file scope, where gfx/drivers/vulkan.c
already declares its other forward functions.
Evidence so far: the frontend compiles 276 of 276 sources and "read_viewport ->" is in
build/llvm-pie.elf (build/r8b-build.log). The first attempt at this patch did not
compile ("function declared in block scope cannot have 'static' storage class" and "use
of undeclared identifier 'vk'"); both are fixed and recorded in docs/PHASE_LOG.md.
NOT YET VERIFIED ON THE CONSOLE: the run that would have produced the picture could not
be made - the console stopped answering (ping and FTP: "No route to host") partway
through this round, and the deploy that preceded it failed for the same reason. The
first action of the next round is that run: arm /app0/args.txt, run
tools/run-title.sh --no-build --watch 18, then fetch /app0/shot.ppm and look at it.
This commit is contained in:
1 parent
d5628d2591
commit
261be4fc5f
4 files changed
+102
-33
No files matched your search
+10
-9
@@ -45,16 +45,17 @@ can be given those options without the launcher, verified by the mark
|
||||
|
||||
## Next
|
||||
|
||||
1. **The pixels: the frontend's writer fails before the driver is asked.** Patch 0031's
|
||||
1. **The pixels: read the frame back in the port's own code - carefully.** Patch 0031's
|
||||
trigger works every run (`capture: frame 90 of 90, take_screenshot -> failed`), and
|
||||
three runs - `.png`, `.bmp`, and with `video_gpu_screenshot = "true"` published - all
|
||||
failed with **no** new `vulkan:` message in the trace, which is where the driver's
|
||||
messenger writes every refusal. So `take_screenshot_viewport` bails before
|
||||
`read_viewport`: its silent paths are `video_driver_get_viewport_info` reporting a zero
|
||||
width/height and `malloc` failing. Next: add one trace line to the capture patch
|
||||
printing the viewport and the dump's result; if the viewport is zero, call the driver's
|
||||
`read_viewport` from the port's own code and write a PPM (header plus bytes, no
|
||||
frontend writer involved), then read it back over FTP and look at it.
|
||||
three runs (`.png`, `.bmp`, and with `video_gpu_screenshot = "true"` published) failed
|
||||
with **no** new `vulkan:` message in the trace, so the frontend's writer bails before
|
||||
the driver is asked (`take_screenshot_viewport`'s silent paths: a zero viewport from
|
||||
`video_driver_get_viewport_info`, or a failed `malloc`). The first attempt at the
|
||||
replacement - call `vulkan_read_viewport` from `vulkan_frame` and write a PPM - did not
|
||||
compile (a `static` forward declaration inside the function body; see
|
||||
`docs/PHASE_LOG.md`, 2026-09-19) and was reverted. Retry it with the declaration at
|
||||
file scope next to the driver's own prototype (`gfx/drivers/vulkan.c:1239` has the
|
||||
pattern), then read the PPM back over FTP and look at it.
|
||||
2. **Then the init refusals**: triangle strips at init (the topology patch 0016 applies to
|
||||
the chain's quad) and the blank texture's compute upload (its staging texture could
|
||||
match its destination, as 0027 does for the menu texture).
|
||||
|
||||
@@ -1412,3 +1412,23 @@ Next step, in order: print the viewport and the dump's result from the capture p
|
||||
more line in the trace, which separates "no viewport" from "writer refused"), and if the
|
||||
viewport is the zero one, call the driver's `read_viewport` directly and write a PPM from
|
||||
the port's own code - a PPM is a header and the bytes, so no frontend writer is involved.
|
||||
|
||||
## 2026-09-19 - reading the frame back in the port's own code: first attempt does not compile
|
||||
|
||||
The next step from the last entry was tried: patch 0031 rewritten to call the driver's
|
||||
`vulkan_read_viewport` directly from `vulkan_frame` and write a PPM (header plus bytes)
|
||||
from the port's own code, with a forward declaration of the driver's static
|
||||
`vulkan_read_viewport`. The intention was to take the frontend's screenshot writer out of
|
||||
the path entirely, since three runs showed it bails before the driver is asked.
|
||||
|
||||
It does not compile; the frontend build reports one source missing and the link fails on
|
||||
`vulkan_raster_font` (the missing object's symbols):
|
||||
|
||||
/home/mihawk/Desktop/PS5_Homebrews/PS5_RetroArch/build/ra-conf/gfx/drivers/vulkan.c:4695:7: error: function declared in block scope cannot have 'static' storage class
|
||||
|
||||
The rewrite was reverted rather than pushed further: `tools/apply-port-patches.py` is back
|
||||
to the committed 0031 (the verified `take_screenshot` trigger), the configured tree is
|
||||
rebuilt from that, and `make test-unit` is green. The lesson for the next attempt is in
|
||||
the error itself - the local declaration and the driver's own definition have to agree
|
||||
exactly, and a `static` forward declaration inside a function body is where that attempt
|
||||
went wrong.
|
||||
@@ -294,7 +294,7 @@ class PortPatches(unittest.TestCase):
|
||||
change deliberately, in a commit that says why.
|
||||
"""
|
||||
self.assertEqual(
|
||||
len(self.blocks()), 35,
|
||||
len(self.blocks()), 36,
|
||||
"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")
|
||||
|
||||
|
||||
+71
-23
@@ -970,26 +970,22 @@ EDITS = [
|
||||
"patches/series, 0028",
|
||||
),
|
||||
(
|
||||
# The capture, on the one path every frame takes. `vulkan_frame` is called 644
|
||||
# times in an unattended run, and the frontend's own `--max-frames-ss` block is
|
||||
# never reached by a content-less menu run (docs/PHASE_LOG.md, 2026-09-19), so the
|
||||
# count and the screenshot live here. The budget and the path are the port's own
|
||||
# options in /app0/args.txt - `--ps5-capture=N` and `--ps5-capture-path=FILE`, which
|
||||
# src/main.cpp keeps away from RetroArch's own option parsing - so a run without
|
||||
# them never takes a picture. The screenshot is the Vulkan driver's readback
|
||||
# (vulkan_readback), and the trace line says whether it worked.
|
||||
# The capture, on the one path every frame takes. `vulkan_frame` is called every
|
||||
# frame, and the frontend's own screenshot path never reaches the driver on a
|
||||
# content-less run (docs/PHASE_LOG.md, 2026-09-19). So the port asks the driver
|
||||
# itself - `vulkan_read_viewport` is the driver's own readback - and writes the
|
||||
# bytes out as a PPM: a header and the pixels, with no frontend writer in the way.
|
||||
# The budget and the path are the port's own options in /app0/args.txt, which
|
||||
# src/main.cpp keeps away from RetroArch's option parsing, so a run without them
|
||||
# never takes a picture. The trace line names the viewport and whether it worked.
|
||||
"gfx/drivers/vulkan.c",
|
||||
" int i, j, k;\n"
|
||||
" VkSubmitInfo submit_info;\n"
|
||||
" VkClearValue clear_color;\n",
|
||||
" vulkan_filter_chain_t *filter_chain = NULL;\n",
|
||||
" /* Added by this port (patches/series, 0031): see the note above this edit. */\n"
|
||||
" {\n"
|
||||
" static int ps5_capture_budget = -1;\n"
|
||||
" static unsigned ps5_capture_frames;\n"
|
||||
" static bool ps5_capture_taken;\n"
|
||||
" static char ps5_capture_file[512] = \"/app0/shot.png\";\n"
|
||||
" extern bool take_screenshot(const char *screenshot_dir, const char *path,\n"
|
||||
" bool silence, bool has_valid_framebuffer, bool fullpath, bool use_thread);\n"
|
||||
" static char ps5_capture_file[512] = \"/app0/shot.ppm\";\n"
|
||||
"\n"
|
||||
" if (ps5_capture_budget < 0)\n"
|
||||
" {\n"
|
||||
@@ -1022,19 +1018,61 @@ EDITS = [
|
||||
"\n"
|
||||
" if (ps5_capture_frames >= (unsigned)ps5_capture_budget)\n"
|
||||
" {\n"
|
||||
" bool ps5_ok;\n"
|
||||
" FILE *ps5_trace;\n"
|
||||
" unsigned ps5_width = vk->vp.width;\n"
|
||||
" unsigned ps5_height = vk->vp.height;\n"
|
||||
" uint8_t *ps5_pixels = NULL;\n"
|
||||
" bool ps5_ok = false;\n"
|
||||
" FILE *ps5_trace;\n"
|
||||
"\n"
|
||||
" ps5_capture_taken = true;\n"
|
||||
" ps5_ok = take_screenshot(NULL, ps5_capture_file, false,\n"
|
||||
" false, true, false);\n"
|
||||
"\n"
|
||||
" if (ps5_width && ps5_height)\n"
|
||||
" ps5_pixels = (uint8_t*)malloc((size_t)ps5_width * ps5_height * 3);\n"
|
||||
"\n"
|
||||
" if (ps5_pixels)\n"
|
||||
" ps5_ok = vulkan_read_viewport(vk, ps5_pixels, false);\n"
|
||||
"\n"
|
||||
" if (ps5_ok)\n"
|
||||
" {\n"
|
||||
" FILE *ps5_out = fopen(ps5_capture_file, \"wb\");\n"
|
||||
"\n"
|
||||
" if (ps5_out)\n"
|
||||
" {\n"
|
||||
" unsigned ps5_y;\n"
|
||||
"\n"
|
||||
" /* The driver reads bottom-up BGR, which is a BMP's order; a PPM\n"
|
||||
" * is top-down RGB. */\n"
|
||||
" fprintf(ps5_out, \"P6\\n%u %u\\n255\\n\", ps5_width, ps5_height);\n"
|
||||
" for (ps5_y = 0; ps5_y < ps5_height; ps5_y++)\n"
|
||||
" {\n"
|
||||
" const uint8_t *ps5_row =\n"
|
||||
" ps5_pixels + (size_t)(ps5_height - 1 - ps5_y) * ps5_width * 3;\n"
|
||||
" unsigned ps5_x;\n"
|
||||
"\n"
|
||||
" for (ps5_x = 0; ps5_x < ps5_width; ps5_x++)\n"
|
||||
" {\n"
|
||||
" uint8_t ps5_rgb[3];\n"
|
||||
"\n"
|
||||
" ps5_rgb[0] = ps5_row[ps5_x * 3 + 2];\n"
|
||||
" ps5_rgb[1] = ps5_row[ps5_x * 3 + 1];\n"
|
||||
" ps5_rgb[2] = ps5_row[ps5_x * 3 + 0];\n"
|
||||
" fwrite(ps5_rgb, 1, 3, ps5_out);\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" fclose(ps5_out);\n"
|
||||
" }\n"
|
||||
" else\n"
|
||||
" ps5_ok = false;\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" free(ps5_pixels);\n"
|
||||
"\n"
|
||||
" ps5_trace = fopen(\"/app0/trace.txt\", \"a\");\n"
|
||||
" if (ps5_trace)\n"
|
||||
" {\n"
|
||||
" fprintf(ps5_trace,\n"
|
||||
" \"capture: frame %u of %d, take_screenshot -> %s (%s)\\n\",\n"
|
||||
" ps5_capture_frames, ps5_capture_budget,\n"
|
||||
" \"capture: frame %u of %d, viewport %ux%u, read_viewport -> %s (%s)\\n\",\n"
|
||||
" ps5_capture_frames, ps5_capture_budget, ps5_width, ps5_height,\n"
|
||||
" ps5_ok ? \"ok\" : \"failed\", ps5_capture_file);\n"
|
||||
" fclose(ps5_trace);\n"
|
||||
" }\n"
|
||||
@@ -1042,11 +1080,21 @@ EDITS = [
|
||||
" }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" int i, j, k;\n"
|
||||
" VkSubmitInfo submit_info;\n"
|
||||
" VkClearValue clear_color;\n",
|
||||
" vulkan_filter_chain_t *filter_chain = NULL;\n",
|
||||
"patches/series, 0031",
|
||||
),
|
||||
(
|
||||
# The driver's own readback is defined below `vulkan_frame`, so the capture calls it
|
||||
# through a prototype at file scope - where the driver declares its other forward
|
||||
# functions (`vulkan_viewport_info`, line 1239) - because C does not allow that
|
||||
# declaration inside a function body.
|
||||
"gfx/drivers/vulkan.c",
|
||||
"static void vulkan_viewport_info(void *data, struct video_viewport *vp);\n",
|
||||
"static void vulkan_viewport_info(void *data, struct video_viewport *vp);\n"
|
||||
"/* Added by this port (patches/series, 0032): the capture's readback entry point. */\n"
|
||||
"static bool vulkan_read_viewport(void *data, uint8_t *buffer, bool is_idle);\n",
|
||||
"patches/series, 0032",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user