"""tools/validate_shader_cache.py on a fake shader cache: the entries the game would refuse (a cut or zero-filled module, another magic number, a reflection that is not one JSON object naming its stage, a missing half of a pair) are named, packed and loose entries are both read with the loose one standing for its packed copy, --every samples, and, where spirv-val is installed, a whole module that is not valid SPIR-V is refused by it. No game files. Run: python tests/validate_shader_cache_test.py """ import hashlib import struct import sys import tempfile import unittest from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT / 'tools')) import pack_shader_cache as psc # noqa: E402 import validate_shader_cache as vsc # noqa: E402 RES = b'{"stage":"cs","textures":[]}' def name(seed): return hashlib.sha256(seed.encode()).hexdigest() def insn(op, *operands): return struct.pack('<%dI' % (1 + len(operands)), (1 + len(operands)) << 16 | op, *operands) def text(s): b = s.encode() + b'\0' b += b'\0' * (-len(b) % 4) return struct.unpack('<%dI' % (len(b) // 4), b) def module(memory_model=True): """A compute shader that does nothing, SPIR-V 1.3: ids 1 main, 2 void, 3 the function type, 4 the label.""" body = insn(17, 1) # OpCapability Shader if memory_model: body += insn(14, 0, 1) # OpMemoryModel Logical GLSL450 body += insn(15, 5, 1, *text('main')) # OpEntryPoint GLCompute %1 "main" body += insn(16, 1, 17, 1, 1, 1) # OpExecutionMode %1 LocalSize 1 1 1 body += insn(19, 2) + insn(33, 3, 2) # OpTypeVoid, OpTypeFunction body += insn(54, 2, 1, 0, 3) + insn(248, 4) + insn(253) + insn(56) # OpFunction, OpLabel, OpReturn, OpFunctionEnd return struct.pack('<5I', vsc.SPIRV_MAGIC, 0x00010300, 0, 5, 0) + body def cut_module(): """A module whose last instruction says three words and has one: what a write cut short leaves.""" return module() + struct.pack('