Some checks failed
Orchestrator / Commit Message Validation (push) Has been skipped
Orchestrator / Lint (push) Failing after 2m0s
Orchestrator / Windows (x86-64) (push) Has been skipped
Orchestrator / Linux (x86-64) (push) Has been skipped
Orchestrator / Create Release (push) Has been skipped
Working-tree snapshot taken 2026-07-28 so this work is not lost. To be clear about provenance: NONE of this was written in the session that committed it — it is pre-existing uncommitted work on phase-a-tracing, last committed 2026-07-09, from the xenia-rs decoder/deadlock investigation. It is recorded verbatim, not reviewed and not tested. Contents: 24 tracked modifications (ppc_emit_memory, xex_module, object_table, shim_utils, xboxkrnl threading/rtl, xevent/xobject/xthread, memory) plus the untracked probe sources audit_68_host_mem_watch, audit_69_event_signal_watch, audit_70_semaphore_release_watch, phase_b_snapshot, and cmake/toolchains. Deliberately excluded: build-cross/ (51 GB of build output) and vkd3d-proton.cache. Note third_party/snappy is a submodule pointer change whose target may not be pushed anywhere, so this branch is a preservation record rather than a guaranteed-buildable tree. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
136 lines
4.0 KiB
Python
136 lines
4.0 KiB
Python
#!/usr/bin/env python3
|
|
|
|
"""Compiles a single shader to DXBC and generates a C header via FXC.
|
|
|
|
Usage: compile_shader_dxbc.py <input_path> <output_path>
|
|
|
|
FXC directly produces the .h file — no post-processing needed.
|
|
"""
|
|
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from glob import glob
|
|
|
|
|
|
DXBC_STAGES = ["vs", "hs", "ds", "gs", "ps", "cs"]
|
|
|
|
|
|
def find_fxc():
|
|
"""Find FXC via FXC_PATH env or Windows SDK search."""
|
|
fxc = os.environ.get("FXC_PATH")
|
|
if fxc:
|
|
return fxc
|
|
|
|
# Search Windows Kits.
|
|
program_files_x86 = os.environ.get("ProgramFiles(x86)", "")
|
|
candidates = glob(os.path.join(
|
|
program_files_x86, "Windows Kits", "10", "bin", "*", "x64", "fxc.exe"))
|
|
if candidates:
|
|
return candidates[-1] # Highest version is last
|
|
|
|
return None
|
|
|
|
|
|
def parse_stage(filename):
|
|
"""Extract the 2-char shader stage from filename like 'foo.cs.xesl'."""
|
|
basename = os.path.splitext(filename)[0] # 'foo.cs'
|
|
identifier = basename.replace(".", "_") # 'foo_cs'
|
|
stage_key = identifier[-2:]
|
|
if stage_key not in DXBC_STAGES:
|
|
return None
|
|
return stage_key
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) != 3:
|
|
print(f"Usage: {sys.argv[0]} <input_path> <output_path>", file=sys.stderr)
|
|
return 1
|
|
|
|
input_path = sys.argv[1]
|
|
output_path = sys.argv[2]
|
|
|
|
src_name = os.path.basename(input_path)
|
|
src_dir = os.path.dirname(input_path)
|
|
|
|
stage = parse_stage(src_name)
|
|
if stage is None:
|
|
print(f"ERROR: cannot determine shader stage from: {src_name}", file=sys.stderr)
|
|
return 1
|
|
|
|
identifier = os.path.splitext(src_name)[0].replace(".", "_")
|
|
|
|
fxc = find_fxc()
|
|
if not fxc:
|
|
print("ERROR: could not find fxc! Set FXC_PATH environment variable "
|
|
"or install Windows SDK.", file=sys.stderr)
|
|
return 1
|
|
|
|
# Create output directory if needed.
|
|
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
|
|
|
is_dxc = "dxc" in os.path.basename(fxc).lower()
|
|
|
|
# Start with base command — use wine on non-Windows platforms.
|
|
# fxc.exe sees '/foo' as a switch, so unix-rooted paths must be
|
|
# translated to Windows form (Z:\...) before being passed.
|
|
if sys.platform != "win32":
|
|
def _wineify(p):
|
|
try:
|
|
out = subprocess.check_output(["winepath", "-w", p],
|
|
stderr=subprocess.DEVNULL)
|
|
return out.decode("utf-8", "replace").strip()
|
|
except (OSError, subprocess.CalledProcessError):
|
|
return p
|
|
input_path = _wineify(input_path)
|
|
output_path = _wineify(output_path)
|
|
src_dir = _wineify(src_dir)
|
|
compiler_args = ["wine", fxc]
|
|
else:
|
|
compiler_args = [fxc]
|
|
|
|
if is_dxc:
|
|
# DXC supports both SM 5.x (-> DXBC) and SM 6.x (-> DXIL). xenia's D3D12
|
|
# backend reads DXBC (output dir is bytecode/d3d12_5_1/), so target
|
|
# SM 5_1 to keep DXBC parity with FXC output.
|
|
compiler_args.extend([
|
|
"-T", f"{stage}_5_1",
|
|
"-HV", "2017",
|
|
"-D", "SHADING_LANGUAGE_HLSL_XE=1",
|
|
"-I", src_dir,
|
|
"-Fh", output_path,
|
|
"-Vn", identifier,
|
|
"-nologo",
|
|
input_path,
|
|
])
|
|
else:
|
|
# FXC uses traditional syntax.
|
|
compiler_args.extend([
|
|
"/D", "SHADING_LANGUAGE_HLSL_XE=1",
|
|
"/I", src_dir,
|
|
"/Fh", output_path,
|
|
"/T", f"{stage}_5_1",
|
|
"/Vn", identifier,
|
|
"/O3",
|
|
"/Qstrip_reflect",
|
|
"/Qstrip_debug",
|
|
"/Qstrip_priv",
|
|
"/Gfp",
|
|
"/nologo",
|
|
input_path,
|
|
])
|
|
|
|
result = subprocess.run(compiler_args, stdout=subprocess.DEVNULL,
|
|
stderr=subprocess.PIPE)
|
|
if result.returncode != 0:
|
|
print(f"ERROR: failed to compile DXBC shader: {src_name}", file=sys.stderr)
|
|
if result.stderr:
|
|
sys.stderr.buffer.write(result.stderr)
|
|
return 1
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|