Crafter.Graphics/project.cpp

243 lines
12 KiB
C++
Raw Normal View History

2026-04-30 01:29:17 +02:00
import std;
import Crafter.Build;
namespace fs = std::filesystem;
using namespace Crafter;
extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> args) {
std::vector<std::string> depArgs(args.begin(), args.end());
2026-05-12 00:24:48 +02:00
2026-05-27 04:38:30 +02:00
Configuration* event = GitProject({
.source = { .url = "https://forgejo.catcrafts.net/Catcrafts/Crafter.Event.git" },
.args = depArgs,
});
Configuration* math = GitProject({
.source = { "https://forgejo.catcrafts.net/Catcrafts/Crafter.Math.git" },
.args = depArgs,
});
Configuration* asset = GitProject({
.source = { "https://forgejo.catcrafts.net/Catcrafts/Crafter.Asset.git" },
.args = depArgs,
});
2026-04-30 01:29:17 +02:00
Configuration cfg;
cfg.path = "./";
cfg.name = "Crafter.Graphics";
cfg.outputName = "Crafter.Graphics";
cfg.type = ConfigurationType::LibraryStatic;
auto opts = ApplyStandardArgs(cfg, args);
2026-05-19 00:27:09 +02:00
cfg.dependencies = { event, math, asset };
2026-04-30 01:29:17 +02:00
// Window backend follows the target triple. V1 had separate lib-wayland /
// lib-win32 configurations; V2 picks the right one automatically based on
// where the build is going. Cross-compile (`--target=...`) flips the
2026-05-18 02:07:48 +02:00
// backend along with everything else. The DOM backend is reached by any
// wasm32-* target and produces a Vulkan-free build whose Window is wired
// to a custom JS env (see additional/dom-env.js).
bool dom = cfg.target.find("wasm") != std::string::npos;
bool windows = !dom
&& (cfg.target.find("windows") != std::string::npos
|| cfg.target.find("mingw") != std::string::npos);
if (dom) {
cfg.defines.push_back({"CRAFTER_GRAPHICS_WINDOW_DOM", ""});
// No native window libs, no Vulkan loader, no Wayland/X11. The JS
// bridge satisfies every dynamic symbol via wasm imports. Crafter.Build
// strips -march/-mtune from the clang command line for any wasm32-*
// triple, so cfg.march/mtune can stay at their defaults — keeping them
// matches the VariantId of dependency PCMs.
2026-05-19 00:27:09 +02:00
//
// WasmAlloc / WasmFree live in Crafter.Graphics-Dom.cpp and back
// dom-env.js's __writeUtf8 path (every keyboard / text-input event
// routes through them). The TU defines no symbols main.cpp would
// reference, so wasm-ld dead-strips it from libCrafter.Graphics.a
// for examples that don't touch the `Dom::HtmlElement*` API (like
// Sponza). `--export=` both forces the export AND pulls the
// defining .o in — solving both halves of the dead-strip problem.
cfg.linkFlags.push_back("-Wl,--export=WasmAlloc");
cfg.linkFlags.push_back("-Wl,--export=WasmFree");
2026-05-18 02:07:48 +02:00
} else if (windows) {
2026-04-30 01:29:17 +02:00
cfg.defines.push_back({"CRAFTER_GRAPHICS_WINDOW_WIN32", ""});
cfg.linkFlags.push_back("-lkernel32");
cfg.linkFlags.push_back("-luser32");
cfg.linkFlags.push_back("-lgdi32");
2026-05-12 00:24:48 +02:00
// Windows.Gaming.Input (WGI) needs the WinRT activation runtime
// and combase for HSTRING / RoGetActivationFactory.
cfg.linkFlags.push_back("-lruntimeobject");
cfg.linkFlags.push_back("-lcombase");
2026-04-30 01:29:17 +02:00
} else {
cfg.defines.push_back({"CRAFTER_GRAPHICS_WINDOW_WAYLAND", ""});
cfg.linkFlags.push_back("-lwayland-client");
cfg.linkFlags.push_back("-lxkbcommon");
2026-05-12 00:24:48 +02:00
// Gamepad: libudev for hot-plug + device enumeration; libevdev
// for event parsing + axis calibration. libevdev ships its headers
// under a versioned dir (libevdev-1.0/) so the -I is mandatory.
cfg.linkFlags.push_back("-ludev");
cfg.linkFlags.push_back("-levdev");
cfg.compileFlags.push_back("-I/usr/include/libevdev-1.0");
2026-04-30 01:29:17 +02:00
cfg.cFiles.push_back("lib/xdg-shell-protocol");
cfg.cFiles.push_back("lib/wayland-xdg-decoration-unstable-v1-client-protocol");
cfg.cFiles.push_back("lib/fractional-scale-v1");
cfg.cFiles.push_back("lib/viewporter");
}
2026-05-18 02:07:48 +02:00
// Vulkan is the only renderer on native targets. Software fallback is
// provided externally via the Vulkan loader (e.g. llvmpipe / lavapipe) —
// no separate code path. The DOM backend doesn't render in V1 (the
// UIRenderer and every Vulkan-typed module are excluded below); the
// WebGPU follow-up will gain its own headers/loader rather than reuse
// the Vulkan ones.
if (!dom) {
ExternalDependency& vkHeaders = cfg.externalDependencies.emplace_back();
vkHeaders.name = "Vulkan-Headers";
vkHeaders.source.url = "https://github.com/KhronosGroup/Vulkan-Headers.git";
vkHeaders.builder = ExternalBuilder::None;
vkHeaders.includeDirs = { "include" };
ExternalDependency& vkUtility = cfg.externalDependencies.emplace_back();
vkUtility.name = "Vulkan-Utility-Libraries";
vkUtility.source.url = "https://github.com/KhronosGroup/Vulkan-Utility-Libraries.git";
vkUtility.builder = ExternalBuilder::None;
vkUtility.includeDirs = { "include" };
cfg.linkFlags.push_back(windows ? "-lvulkan-1" : "-lvulkan");
}
2026-04-30 01:29:17 +02:00
if (opts.Has("--timing")) cfg.defines.push_back({"CRAFTER_TIMING", ""});
2026-05-18 02:07:48 +02:00
// One master interface list. Every partition exists on every target
// — Crafter.Build's dependency scanner doesn't respect `#ifdef` on
// `import :X` statements, so the partition file must be present even
// when its body is gated out. Vulkan-typed partitions stub to empty
// modules under CRAFTER_GRAPHICS_WINDOW_DOM; the Dom/DomEvents/Router
// partitions stub to empty modules in the opposite direction.
2026-05-24 13:32:08 +02:00
std::array<fs::path, 42> ifaces = {
2026-04-30 01:29:17 +02:00
"interfaces/Crafter.Graphics",
"interfaces/Crafter.Graphics-Animation",
2026-05-12 00:24:48 +02:00
"interfaces/Crafter.Graphics-Clipboard",
2026-05-02 21:08:20 +02:00
"interfaces/Crafter.Graphics-ComputeShader",
2026-05-12 00:24:48 +02:00
"interfaces/Crafter.Graphics-Decompress",
2026-04-30 01:29:17 +02:00
"interfaces/Crafter.Graphics-DescriptorHeapVulkan",
2026-05-18 04:58:52 +02:00
"interfaces/Crafter.Graphics-DescriptorHeapWebGPU",
2026-04-30 01:29:17 +02:00
"interfaces/Crafter.Graphics-Device",
2026-05-18 02:07:48 +02:00
"interfaces/Crafter.Graphics-Dom",
"interfaces/Crafter.Graphics-DomEvents",
2026-04-30 01:29:17 +02:00
"interfaces/Crafter.Graphics-Font",
2026-05-02 21:08:20 +02:00
"interfaces/Crafter.Graphics-FontAtlas",
2026-04-30 01:29:17 +02:00
"interfaces/Crafter.Graphics-ForwardDeclarations",
2026-05-12 00:24:48 +02:00
"interfaces/Crafter.Graphics-Gamepad",
2026-05-18 04:58:52 +02:00
"interfaces/Crafter.Graphics-GraphicsTypes",
2026-05-19 00:27:09 +02:00
"interfaces/Crafter.Graphics-Image2D",
2026-04-30 01:29:17 +02:00
"interfaces/Crafter.Graphics-ImageVulkan",
2026-05-12 00:24:48 +02:00
"interfaces/Crafter.Graphics-Input",
2026-05-03 02:45:38 +02:00
"interfaces/Crafter.Graphics-InputField",
2026-05-12 00:24:48 +02:00
"interfaces/Crafter.Graphics-Keys",
2026-04-30 01:29:17 +02:00
"interfaces/Crafter.Graphics-Mesh",
"interfaces/Crafter.Graphics-PipelineRTVulkan",
2026-05-18 18:43:30 +02:00
"interfaces/Crafter.Graphics-PipelineRTWebGPU",
2026-05-24 13:32:08 +02:00
"interfaces/Crafter.Graphics-PlainComputeShader",
2026-04-30 01:29:17 +02:00
"interfaces/Crafter.Graphics-RenderingElement3D",
2026-05-01 23:35:37 +02:00
"interfaces/Crafter.Graphics-RenderPass",
2026-05-18 02:07:48 +02:00
"interfaces/Crafter.Graphics-Router",
2026-05-18 18:43:30 +02:00
"interfaces/Crafter.Graphics-RT",
2026-05-01 23:35:37 +02:00
"interfaces/Crafter.Graphics-RTPass",
2026-04-30 01:29:17 +02:00
"interfaces/Crafter.Graphics-SamplerVulkan",
"interfaces/Crafter.Graphics-ShaderBindingTableVulkan",
2026-05-18 18:43:30 +02:00
"interfaces/Crafter.Graphics-ShaderBindingTableWebGPU",
2026-04-30 01:29:17 +02:00
"interfaces/Crafter.Graphics-ShaderVulkan",
"interfaces/Crafter.Graphics-Types",
2026-05-01 23:35:37 +02:00
"interfaces/Crafter.Graphics-UI",
2026-05-02 21:08:20 +02:00
"interfaces/Crafter.Graphics-UIComponents",
2026-04-30 01:29:17 +02:00
"interfaces/Crafter.Graphics-VulkanBuffer",
"interfaces/Crafter.Graphics-VulkanTransition",
2026-05-18 04:58:52 +02:00
"interfaces/Crafter.Graphics-WebGPU",
"interfaces/Crafter.Graphics-WebGPUBuffer",
"interfaces/Crafter.Graphics-WebGPUComputeShader",
2026-04-30 01:29:17 +02:00
"interfaces/Crafter.Graphics-Window",
};
2026-05-18 02:07:48 +02:00
if (dom) {
2026-05-18 04:58:52 +02:00
// DOM impl set. UI-Shared.cpp is backend-agnostic; UI-WebGPU.cpp
// is the DOM-only implementation of UIRenderer's GPU-touching
2026-05-24 13:32:08 +02:00
// methods. Font / FontAtlas / UIComponents / InputField are now
// portable.
std::array<fs::path, 17> domImpls = {
2026-05-18 02:07:48 +02:00
"implementations/Crafter.Graphics-Clipboard",
"implementations/Crafter.Graphics-Dom",
2026-05-18 04:58:52 +02:00
"implementations/Crafter.Graphics-Font",
"implementations/Crafter.Graphics-FontAtlas",
2026-05-18 02:07:48 +02:00
"implementations/Crafter.Graphics-Gamepad",
"implementations/Crafter.Graphics-Input",
2026-05-24 13:32:08 +02:00
"implementations/Crafter.Graphics-InputField",
2026-05-18 18:43:30 +02:00
"implementations/Crafter.Graphics-Mesh-WebGPU",
"implementations/Crafter.Graphics-PipelineRTWebGPU",
"implementations/Crafter.Graphics-RenderingElement3D-WebGPU",
2026-05-18 02:07:48 +02:00
"implementations/Crafter.Graphics-Router",
2026-05-18 18:43:30 +02:00
"implementations/Crafter.Graphics-ShaderBindingTableWebGPU",
2026-05-18 04:58:52 +02:00
"implementations/Crafter.Graphics-UI-Shared",
"implementations/Crafter.Graphics-UI-WebGPU",
"implementations/Crafter.Graphics-UIComponents",
2026-05-18 05:39:17 +02:00
"implementations/Crafter.Graphics-WebGPUComputeShader",
2026-05-18 02:07:48 +02:00
"implementations/Crafter.Graphics-Window",
};
cfg.GetInterfacesAndImplementations(ifaces, domImpls);
// JS glue shipped alongside the .wasm so the loader has the
// env-import surface the Window/Dom bindings expect.
cfg.files.emplace_back(fs::path("additional/dom-env.js"));
2026-05-18 04:58:52 +02:00
cfg.files.emplace_back(fs::path("additional/dom-webgpu.js"));
2026-05-18 02:07:48 +02:00
} else {
2026-05-18 04:58:52 +02:00
std::array<fs::path, 14> impls = {
2026-05-18 02:07:48 +02:00
"implementations/Crafter.Graphics-Clipboard",
"implementations/Crafter.Graphics-ComputeShader",
"implementations/Crafter.Graphics-Device",
"implementations/Crafter.Graphics-Font",
"implementations/Crafter.Graphics-FontAtlas",
"implementations/Crafter.Graphics-Gamepad",
"implementations/Crafter.Graphics-Input",
"implementations/Crafter.Graphics-InputField",
"implementations/Crafter.Graphics-Mesh",
"implementations/Crafter.Graphics-RenderingElement3D",
"implementations/Crafter.Graphics-UI",
2026-05-18 04:58:52 +02:00
"implementations/Crafter.Graphics-UI-Shared",
2026-05-18 02:07:48 +02:00
"implementations/Crafter.Graphics-UIComponents",
"implementations/Crafter.Graphics-Window",
};
cfg.GetInterfacesAndImplementations(ifaces, impls);
cfg.shaders.emplace_back(fs::path("shaders/ui-quads.comp.glsl"), std::string("main"), ShaderType::Compute);
cfg.shaders.emplace_back(fs::path("shaders/ui-circles.comp.glsl"), std::string("main"), ShaderType::Compute);
cfg.shaders.emplace_back(fs::path("shaders/ui-images.comp.glsl"), std::string("main"), ShaderType::Compute);
cfg.shaders.emplace_back(fs::path("shaders/ui-text.comp.glsl"), std::string("main"), ShaderType::Compute);
cfg.buildFiles.emplace_back(fs::path("shaders/ui-shared.glsl"));
// Regression test for issue #18: drive the NVIDIA descriptor-heap
// AS-read workaround's SPIR-V rewrite over real compiled shaders and
// check the result with spirv-val (one push-constant block, correct
// TLAS offset). The test executable recompiles the whole module plus
// tests/PushConstantRewrite/main.cpp; Configuration isn't copyable
// (it owns the parsed module list), so the shared build settings are
// mirrored field by field. glslang and spirv-val are invoked at
// runtime, so the test declares them as required tools. Remove with
// the rest of the workaround.
Test pcTest;
Configuration& tc = pcTest.config;
tc.path = cfg.path;
tc.name = "PushConstantRewrite";
tc.outputName = "PushConstantRewrite";
tc.type = ConfigurationType::Executable;
tc.target = cfg.target;
tc.march = cfg.march;
tc.mtune = cfg.mtune;
tc.debug = cfg.debug;
tc.sysroot = cfg.sysroot;
tc.dependencies = cfg.dependencies;
tc.externalDependencies = cfg.externalDependencies;
tc.compileFlags = cfg.compileFlags;
tc.linkFlags = cfg.linkFlags;
tc.defines = cfg.defines;
tc.cFiles = cfg.cFiles;
std::vector<fs::path> testImpls(impls.begin(), impls.end());
testImpls.emplace_back("tests/PushConstantRewrite/main");
tc.GetInterfacesAndImplementations(ifaces, testImpls);
pcTest.requires_ = { "tool:glslang", "tool:spirv-val" };
cfg.tests.push_back(std::move(pcTest));
2026-05-18 02:07:48 +02:00
}
2026-05-01 23:35:37 +02:00
2026-04-30 01:29:17 +02:00
return cfg;
}