restructuing dev command
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
import os
|
||||
import shutil
|
||||
import struct
|
||||
import subprocess
|
||||
|
||||
|
||||
# Mixed into DevCommand (bin/dev), which provides _project_root.
|
||||
class ShadersCommand:
|
||||
SHADER_EXTENSIONS = (".vert", ".frag", ".comp", ".geom", ".tesc", ".tese")
|
||||
|
||||
def shaders(self, *args, **kwargs):
|
||||
shaders_dir = os.path.join(self._project_root(), "engine", "src", "shaders")
|
||||
if not os.path.isdir(shaders_dir):
|
||||
raise ValueError(f"Shaders directory not found: {shaders_dir}")
|
||||
|
||||
glslc = self._find_glslc()
|
||||
|
||||
shader_paths = sorted(
|
||||
os.path.join(root, filename)
|
||||
for root, _dirs, files in os.walk(shaders_dir)
|
||||
for filename in files
|
||||
if filename.endswith(self.SHADER_EXTENSIONS)
|
||||
)
|
||||
|
||||
if not shader_paths:
|
||||
print(f"No shaders found in {shaders_dir}")
|
||||
return
|
||||
|
||||
for shader_path in shader_paths:
|
||||
self._generate_shader_header(glslc, shader_path)
|
||||
|
||||
def _find_glslc(self):
|
||||
glslc = shutil.which("glslc")
|
||||
if glslc is None:
|
||||
raise RuntimeError(
|
||||
"glslc not found on PATH (install the Vulkan SDK)"
|
||||
)
|
||||
return glslc
|
||||
|
||||
def _generate_shader_header(self, glslc, shader_path):
|
||||
relative_path = os.path.relpath(shader_path, self._project_root())
|
||||
print(f"Compiling shader: {relative_path}")
|
||||
|
||||
result = subprocess.run(
|
||||
[glslc, shader_path, "-o", "-"],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError(
|
||||
f"failed to compile {shader_path}: {result.stderr.decode()}"
|
||||
)
|
||||
|
||||
spirv = result.stdout
|
||||
if len(spirv) % 4 != 0:
|
||||
raise RuntimeError(
|
||||
f"invalid SPIR-V output for {shader_path} (size not a multiple of 4)"
|
||||
)
|
||||
|
||||
word_count = len(spirv) // 4
|
||||
words = struct.unpack(f"<{word_count}I", spirv)
|
||||
|
||||
filename = os.path.basename(shader_path)
|
||||
variable_name = f"{filename.replace('.', '_')}_spv"
|
||||
header_path = shader_path + ".spv.h"
|
||||
|
||||
body_lines = [
|
||||
" " + ", ".join(f"0x{word:08x}" for word in words[i:i + 4]) + ","
|
||||
for i in range(0, len(words), 4)
|
||||
]
|
||||
|
||||
header = "\n".join([
|
||||
"#pragma once",
|
||||
"",
|
||||
"#include <array>",
|
||||
"#include <cstdint>",
|
||||
"",
|
||||
"namespace sophia::shaders {",
|
||||
"",
|
||||
f"inline constexpr std::array<uint32_t, {word_count}> {variable_name} = {{",
|
||||
*body_lines,
|
||||
"};",
|
||||
"",
|
||||
"} // namespace sophia::shaders",
|
||||
"",
|
||||
])
|
||||
|
||||
with open(header_path, "w") as f:
|
||||
f.write(header)
|
||||
|
||||
print(f"Wrote {os.path.relpath(header_path, self._project_root())} "
|
||||
f"({word_count * 4} bytes)")
|
||||
Reference in New Issue
Block a user