Files
psxrecomp/tools/embed_spirv.py
T
Matthew Stanley 0ac63b655c vulkan: 3rd renderer backend (WIP) — emitter, GPU-direct present, full-frame readback
Vulkan backend alongside software + OpenGL: geometry/textured-prim
pipelines, GPU-authoritative VRAM image, deferred-submit + drain-at-present
perf model, GPU-direct present (vk_renderer_present_vram), and a
full-VRAM-pack readback path (ensure_cpu rect_adds the whole VRAM rect
before pack_flush so screenshots/guest VRAM reads reflect live content,
not just the incremental pack-dirty rect — readback-only, no per-frame cost).

Runtime plumbing: --debug-port / --renderer / --window-title CLI overrides
(multi-instance fleet), latency_ring, SPIR-V shaders + embed_spirv.py,
config_loader renderer selection, debug_server screenshot wiring.

All on feat/vulkan-renderer; snapshot in backup/vulkan-wip-20260617.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 14:56:12 -07:00

70 lines
2.4 KiB
Python

#!/usr/bin/env python3
"""embed_spirv.py — compile GLSL shaders to SPIR-V (glslc) and emit one C header.
Each input shader (*.vert / *.frag) is compiled to SPIR-V and written into the
output header as a `static const uint32_t spv_<name>_<stage>[]` array plus its
byte length, so the Vulkan backend can create shader modules with zero runtime
file dependencies (keeps the self-contained exe). Stage is inferred from the
file extension.
Usage:
embed_spirv.py --glslc <glslc> --out <header.h> shader1.vert shader2.frag ...
"""
import argparse, os, subprocess, sys, struct
STAGE = {".vert": "vert", ".frag": "frag", ".comp": "comp"}
def ident(path):
base = os.path.basename(path)
name, ext = os.path.splitext(base)
return "%s_%s" % (name.replace("-", "_"), STAGE[ext]), STAGE[ext]
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--glslc", required=True)
ap.add_argument("--out", required=True)
ap.add_argument("shaders", nargs="+")
a = ap.parse_args()
os.makedirs(os.path.dirname(a.out), exist_ok=True)
out = ["/* Auto-generated by embed_spirv.py — do not edit. */",
"#ifndef PSX_VK_SHADERS_SPV_H",
"#define PSX_VK_SHADERS_SPV_H",
"#include <stdint.h>", ""]
for sh in a.shaders:
name, stage = ident(sh)
spv = sh + ".spv"
cmd = [a.glslc, "--target-env=vulkan1.1", "-O", sh, "-o", spv]
r = subprocess.run(cmd, capture_output=True, text=True)
if r.returncode != 0:
sys.stderr.write("glslc failed for %s:\n%s\n" % (sh, r.stderr))
return 1
with open(spv, "rb") as f:
data = f.read()
os.remove(spv)
if len(data) % 4 != 0:
sys.stderr.write("SPIR-V for %s not 4-byte aligned\n" % sh)
return 1
words = struct.unpack("<%dI" % (len(data) // 4), data)
out.append("static const uint32_t spv_%s[] = {" % name)
line = " "
for w in words:
tok = "0x%08x," % w
if len(line) + len(tok) > 96:
out.append(line); line = " "
line += tok
if line.strip():
out.append(line)
out.append("};")
out.append("static const uint32_t spv_%s_size = sizeof(spv_%s);" % (name, name))
out.append("")
out.append("#endif")
with open(a.out, "w") as f:
f.write("\n".join(out))
return 0
if __name__ == "__main__":
sys.exit(main())