5 Commits
Author SHA1 Message Date
libretroadmin b48265ebd6 TA parse: C89 lists and strip indices; Vulkan draws from where it parses
The frame's lists are ta_list.c's (C89): List<T> is a typed facade over
it. A strip's indices are ta_index.c's C89 kernel: one branch-free check
of the whole strip, then a straight run of indices; the per-vertex loop
only where a vertex is bad or the room runs out. The parse is about 20%
faster (2.74 to 2.17 ns a vertex on the heavy disc), its output the same
byte for byte.

With Vulkan on a machine whose video memory the CPU reads back fast (one
memory, as lavapipe's and integrated GPUs'), the vertices and indices
are parsed straight into a slice of memory the card reads, one slice a
frame in flight (rend/parse_arena.h, vulkan/parse_arena_vk.h), and the
translucent sort writes after them: no copy into the main buffer. Other
machines copy as ever.

Tests: tools/pvr/ta_index_test.sh (against the old loop, 1M strips),
tools/rend/parse_arena_test.sh, tools/vulkan/vk_parse_arena.sh (every
render in place, pictures those of the copy, each renderer, threaded,
upscaler, a change of size), tools/pvr/ta_parse_bench.sh; vk_hdr gains
VKH_UNCACHED, VKH_OPTS_AT and VKH_BUFFERS.
2026-11-02 13:11:59 +01:00
LibretroAdmin ca3fee8eaa rend: the chip's write-out on the raster renderers, with the 16-bit dither; the old PowerVR2 filter goes
The core option is now "PowerVR2 scaler, flicker filter and dither"
(reicast_pvr2_scaler, still off by default). It does what the
PowerVR2 does to the picture as it writes the tiles to video memory,
in the chip's order: the X scaler, the Y filter, then the packing to a
framebuffer of 16 bits a pixel and its dither (FB_W_CTRL). The picture
shown is that framebuffer as the video output reads it back, with
FB_R_CTRL's fb_concat in the low bits.

- rend/tile/pvr_scaler.h: pvr_fb_word() and pvr_fb_write(), the
  packing to 0555/1555 or 565 with rend/rtt_watch.cpp's 4x4 pattern
  (the same arithmetic as the renders to a texture). At internal
  resolution N the pattern goes by the chip's pixel (N picture pixels
  to one). 4444 and the 24/32-bit formats are left as they are.
  Checked against an independent copy of rtt_watch.cpp's packing plus
  TexCache.cpp's read-back: no difference in 195072 cases.
- The compute renderer's in-place pass (PVRC_K_YFILTER) does the
  packing and dither after the Y filter, and runs on any frame with
  either (ComputeFrame::WriteOut()). tile_ref and refsw do the same.
  refsw did not dither the picture before: it does now.
- The raster renderers run the same pass in place over their picture
  after the frame (before the VMUs and crosshairs on Direct3D and
  OpenGL; on Vulkan they are in the frame's render pass, so the pass
  runs over them too):
  - Vulkan, both renderers: the compute renderer's own SPIR-V
    (vulkan/writeout.cpp).
  - Direct3D 12, both renderers: the compute renderer's own DXIL
    (dx12/dx12_writeout.cpp). Needs typed UAV loads of R8G8B8A8_UNORM.
  - Direct3D 11, both renderers: the same pass in HLSL, compiled when
    the renderer starts (dx11/dx11_writeout.cpp). Needs typed UAV
    loads of R8G8B8A8_UNORM (TypedUAVLoadAdditionalFormats).
  - OpenGL 4.3 and later, both renderers: the same pass in GLSL,
    compiled (and cached) when the renderer starts
    (gles/gl_writeout.cpp). The frontend's framebuffer is not a
    texture of the core's, so the picture is blitted to the pass's
    texture and back.
  Not on OpenGL ES, OpenGL 3 or Direct3D 9.
  The pictures are made writable by a compute shader only when the
  option is on. Turning the option on or off counts as a change of size:
  the renderer makes its pictures again between frames, never during
  one. Off, the renderers do what they did before, at no cost.
- The rasterizers' X scaler is not done here: they still squash the
  game's double-width drawing in the transform, as before. No dumped
  game sets SCALER_CTL's horizontal scaling.

The old "PowerVR2 Post-processing Filter" (reicast_pvr2_filtering,
OpenGL only) is removed: PostProcessor, gles/postprocess.cpp/.h, the
PowerVR2Filter setting, the option in every language, and its
Makefile entry. It guessed at a 3-tap vertical blur, which the exact Y
filter now replaces. It also dithered by its own rules and added a made-up
"VGA signal loss" smear, which the hardware does not do. It compiled its
shaders mid-game and drew through an extra framebuffer.
RetroArch ignores old values of the option left in users' configs.

Gates (lavapipe/llvmpipe and vkd3d, not a real GPU):
- tile_test VF3tb 1x on Vulkan, at 1 and 4 samples, and on Direct3D 12,
  at 1 and 4 samples: off, filter + 565 dither (VF3tb's own
  registers), 555 dither alone, and taps 3 lines apart with fb_concat 5.
  16/16 runs are the same as tile_ref on each.
- RetroArch (Vulkan, then glcore) with VF3tb booted, frame 900, for each
  of Vulkan per-triangle, Vulkan per-pixel, OpenGL per-triangle and
  OpenGL 4 per-pixel. With the option off, the picture is the same as
  master's, byte for byte. With it on, the picture is exactly the
  option-off picture through an independent model of the filter and
  dither (Y_COEFF 0x8040, 565, dither on). No validation errors.
- Direct3D 11 and 12 rasterizers: syntax-checked with mingw, and the
  Direct3D 11 pass compiled with d3dcompiler_47 (cs_5_0). Not run.
2026-10-24 22:13:36 +02:00
LibretroAdmin 6959fc6f43 libretro: the PVR2 scaler / flicker filter option is off by default
With the flicker filter on, the compute renderer at 8x shades extra
lines around every tile for the filter's taps, which is too slow for
now. Off until the filter is done without them; a core that has not
been given the option yet also starts with it off.
2026-10-24 15:55:20 +02:00
LibretroAdmin 3efb00129f rend/tile: the chip's X and Y scalers in the compute renderer, a core option
The PowerVR2 passes every tile through its X and Y scalers on the way
from the accumulation buffer to video memory (SCALER_CTL, Y_COEFF; the
Dreamcast System Architecture manual, 3.4.11). refsw does since the last
change; now the compute renderer does too, with the same arithmetic
(rend/tile/pvr_scaler.h), behind a new core option "PVR2 scaler /
flicker filter" (reicast_pvr2_scaler, enabled by default; the compute
renderer only - the raster renderers ignore it).

- X scaler (SCALER_CTL bit 16): the game draws twice as wide; the frame
  is drawn so, and each pair of pixels is resolved as one box of 2S x S
  samples (S the SSAA samples), with no pass or image of its own.
- Y filter (vertical scale factor above 0x400; most Sega games set 0x401
  and Y_COEFF 0x8040): each line blended with the lines above and below
  by Y_COEFF (centre bits 15:8, neighbours 7:0, in 256ths), its taps N
  lines apart at internal resolution N (the picture's height over 480),
  the picture's first and last lines in the place of the missing one.
  The walk's fine tile shades a halo of N lines above and below the
  lines it writes, the taps in its own lanes (shared memory), so there
  is no new pass, image or readback; a coarse tile's lists are binned N
  lines taller at each side to cover the halo, and its rows of fine
  tiles each write their lines less the halo (pvrc_walk_down(), so the
  variants' dispatches across, pvrc_walk_x(), take the frame's flags).
  Where the halo would be large the fine tile is made narrower and
  taller (pvrc_fine_yfilter()); Direct3D 12's table of dispatches across
  has a row for each count of lines, made at Init(). The filter is in
  spare bits of a frame word (PVRC_F_FLAGS): turning the
  option on or off mid-game compiles and allocates nothing.

Disabled, the frame words and the kernels' work are what they were, and
the picture is the same byte for byte. Nothing is added to the save
state: the registers are already the render context's.

tile_ref.c does the same, and tile_test draws each frame with the filter
off and on (TILE_YFILTER, default "off 1:8040"); tile_bench takes
BENCH_YFILTER to time it.
2026-10-24 15:47:27 +02:00
LibretroAdmin f87567f454 rend/tile: the compute renderer's frame packed by code the renderers share
ComputeFrame::Pack(), which makes the kernels' frame words from the
render context, was the Vulkan drawer's, built on its BaseDrawer for the
transform, the base scissor, the tile clip and the fragment constants.
It is now rend/tile/compute_frame.cpp, built in every configuration,
with a renderer giving only what is its own: its matrices made for the
frame (Begin()), its base scissor and its flat shading's colours. The
tile clip is ::GetTileClip() against that scissor and the fragment
constants are the formulas both raster renderers have, as they were.
VulkanComputeFrame is the Vulkan renderers' (and tile_dump's).

The words are the same: the new and the old Pack() compared word for word
on ten frames of five Jet Grind Radio states (tile_dump with both).
2026-10-21 06:16:50 +02:00