mirror of
https://github.com/libretro/parallel-ps2.git
synced 2026-11-09 03:19:41 -10:00
The Vulkan renderer wrote GLSL at run time and compiled it with glslang:
for each TFX selector it assembled a source string of ~60 #defines in
front of tfx.glsl, hashed it, looked it up in an on-disk SPIR-V cache and
compiled what was missing; the utility shaders likewise. glslang was
about 1.6 MB of the core's code, and the warm-up thread could not build a
TFX pipeline whose SPIR-V a session before had not cached.
Now the GLSL lives in pcsx2/GS/Renderers/Vulkan/shaders/ and is compiled
ahead of time by tools/vk_spirv.py into VKShaders.inc, which is
committed (as parallel-dc, swanstation and parallel-n64 do theirs). The
core makes its modules straight from those words.
- Every draw selector field is a specialization constant of tfx.glsl. A
pipeline passes the selector to the driver in VkSpecializationInfo:
no source text, macros, string hashing or compiler. The generator
writes the constant IDs out as an enum (VKSC_*), and a static_assert
catches a constant with no value in the C++.
- What changes a shader's interface is settled in the SPIR-V. There are
two vertex modules (with and without VS_EXPAND) and three fragment
modules (the target not read, read as an input attachment, read as a
sampled image). Each fragment module carries the dual-source output,
gl_PrimitiveID and gl_FragDepth. For a draw that does without one,
VKSpirvPatch.c turns it into a private variable in the words: a draw
that does not clamp depth gets no DepthReplacing (so early depth
testing stays), one without the alpha test passes needs no geometry
capability, and so on. It also drops the colour varying's Flat
decoration for an interpolating draw. That keeps the TFX SPIR-V at
five modules (224 KB) instead of one per combination; all 24 would
be 1.7 MB.
- The utility shaders are one module per entry point.
- Modules are made once per thread as each is first asked for. The
warm-up thread has its own set and builds every listed pipeline; it no
longer leaves TFX ones it has no SPIR-V for to the render thread.
- VKShaderCache is gone. The driver's pipeline cache stays and is
handed the file as read; the stale vulkan_shaders.idx/.bin are
deleted. The pipeline list is tied to the shaders (VKSPV_VERSION),
not SHADER_CACHE_VERSION.
- 3rdparty/glslang is removed from the tree and from both builds.
On lavapipe, all 74 tests/swdraw cases at 1x and 2x present the same
picture as before, with both the CMake and Makefile cores. The text
segment is 1.9 MB smaller, and a cold start (no caches) is about 150 ms
faster.
One behaviour is kept on purpose. VS_PROVOKING_VERTEX_LAST was always
defined (as 0 or 1), so its #ifdef always took the provoking-vertex-last
line end, and the shader still does.
Tests:
- tests/vkspirv (new, in CI):
- tools/vk_spirv.py check fails if a shader changed without the .inc
being regenerated.
- The harness makes every module the renderer can make (three
fragment modules x 16 interfaces, both vertex modules) and reads
each back as SPIR-V. Dropped variables must be private, of the
right pointer type, undecorated and out of the interface; kept
ones unchanged. The geometry capability and depth replacing must
go exactly with their variables. Malformed modules are refused.
- A patcher that leaves the capability, the execution mode, the
decoration or the interface entry, or writes the pointer type
wrong, fails it.
- tests/vknegotiate: the corrupt-index lane is now a pipeline cache with
junk after its header plus an old SPIR-V cache beside it. The run
must go on, and the old cache must be gone; on master it is
rewritten.
- tests/vkpipewarm: the driver change now also stamps the pipeline
cache with another device's UUID, and the cache must be refused.