Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 74 additions & 9 deletions pkgs/c/compat.vulkan.lua
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,15 @@
-- this through `APPLE_STATIC_LOADER` + pthread_once; Linux through
-- `__attribute__((constructor))`. Windows has neither.
--
-- The supported Windows arrangement is the ordinary one every Vulkan
-- application uses: link `vulkan-1.lib` and let the system `vulkan-1.dll`,
-- installed by any GPU driver, do the ICD loading. The windows xpm entry is
-- therefore a small artifact carrying that import library — symbol stubs, no
-- code — generated from Khronos' own `loader/vulkan-1.def` (shipped in this
-- very loader tarball) with a single reproducible command:
-- The supported Windows arrangement is the ordinary one: link `vulkan-1.lib`
-- and load `vulkan-1.dll` at process start. Through 1.4.357.2 that DLL was
-- assumed to come from the machine's GPU driver, which a driverless machine
-- does not have (0xC0000135 before `main`, measured on `windows-2022`). From
-- 1.4.357.3 the artifact also carries the DLL, built from the same tag, and
-- `runtime.library_dirs` has mcpp place it beside every consuming executable;
-- see the windows xpm entry. The import library in that artifact — symbol
-- stubs, no code — is generated from Khronos' own `loader/vulkan-1.def`
-- (shipped in this very loader tarball) with a single reproducible command:
--
-- llvm-dlltool -d vulkan-1.def -l lib/vulkan-1.lib -m i386:x86-64
--
Expand Down Expand Up @@ -89,6 +92,16 @@ package = {
-- version -- and where a consumer also names the farm directly, the
-- two disagree and the build stops. Measured on a CI runner with a
-- warm ~/.mcpp; see the note on compat.vulkan 1.4.357.1.
-- 1.4.357.3: the same loader source. A new version on every platform
-- because the WINDOWS artifact changed -- it now carries the loader DLL
-- (see the windows entry) -- and a version is one key across platforms.
["1.4.357.3"] = {
url = {
GLOBAL = "https://github.com/KhronosGroup/Vulkan-Loader/archive/refs/tags/vulkan-sdk-1.4.357.0.tar.gz",
CN = "https://gitcode.com/mcpp-res/vulkan/releases/download/1.4.357.0/vulkan-1.4.357.0.tar.gz",
},
sha256 = "54f2537df22313768da0317dda2abdaaab7711b4081c48c869a79db343d0ae70",
},
["1.4.357.2"] = {
url = {
GLOBAL = "https://github.com/KhronosGroup/Vulkan-Loader/archive/refs/tags/vulkan-sdk-1.4.357.0.tar.gz",
Expand Down Expand Up @@ -136,6 +149,16 @@ package = {
-- version -- and where a consumer also names the farm directly, the
-- two disagree and the build stops. Measured on a CI runner with a
-- warm ~/.mcpp; see the note on compat.vulkan 1.4.357.1.
-- 1.4.357.3: the same loader source. A new version on every platform
-- because the WINDOWS artifact changed -- it now carries the loader DLL
-- (see the windows entry) -- and a version is one key across platforms.
["1.4.357.3"] = {
url = {
GLOBAL = "https://github.com/KhronosGroup/Vulkan-Loader/archive/refs/tags/vulkan-sdk-1.4.357.0.tar.gz",
CN = "https://gitcode.com/mcpp-res/vulkan/releases/download/1.4.357.0/vulkan-1.4.357.0.tar.gz",
},
sha256 = "54f2537df22313768da0317dda2abdaaab7711b4081c48c869a79db343d0ae70",
},
["1.4.357.2"] = {
url = {
GLOBAL = "https://github.com/KhronosGroup/Vulkan-Loader/archive/refs/tags/vulkan-sdk-1.4.357.0.tar.gz",
Expand Down Expand Up @@ -183,6 +206,37 @@ package = {
-- version -- and where a consumer also names the farm directly, the
-- two disagree and the build stops. Measured on a CI runner with a
-- warm ~/.mcpp; see the note on compat.vulkan 1.4.357.1.
-- 1.4.357.3: THE LOADER DLL SHIPS WITH THE IMPORT LIBRARY.
--
-- `vulkan-1.dll` is not a Windows component: it arrives with a GPU
-- driver, with LunarG's Vulkan Runtime redistributable, or beside an
-- application. So a machine without a driver has no loader, and a
-- program linking `vulkan-1.lib` dies before `main` with 0xC0000135
-- (STATUS_DLL_NOT_FOUND). Measured on GitHub's `windows-2022` image
-- (mcpp-index #387 probe; `vulkan`, `eui-neo-vulkan` and
-- `vulkan-hpp-module` all failed that way).
--
-- The artifact adds `bin/vulkan-1.dll`, built from
-- `vulkan-sdk-1.4.357.0` -- the same tag as the headers and the .def --
-- by xlings-res/vulkan-loader's windows workflow, which loads the DLL
-- and resolves its entry points before publishing. `lib/vulkan-1.lib`
-- is byte-identical to 1.4.357.1's, and the DLL exports exactly the
-- 265 names in `vulkan-1.def`: every import that library can produce
-- resolves, so no consumer can hit "entry point not found".
--
-- ON A MACHINE THAT ALREADY HAS A DRIVER nothing is lost. The copy
-- beside the executable is found first (the application directory
-- precedes System32), and the loader still reads
-- HKLM\SOFTWARE\Khronos\Vulkan\Drivers, so the GPU driver the
-- machine has is the ICD it uses. This is the ordinary arrangement for
-- an application that redistributes the loader.
["1.4.357.3"] = {
url = {
GLOBAL = "https://github.com/xlings-res/vulkan-import/releases/download/1.4.357.3/vulkan-import-1.4.357.3.tar.gz",
CN = "https://gitcode.com/mcpp-res/vulkan-import/releases/download/1.4.357.3/vulkan-import-1.4.357.3.tar.gz",
},
sha256 = "8118f1bd897e553baffabf484a14db980ce1f0a6cfdb5a6222c0a236ecdf12f5",
},
["1.4.357.2"] = {
url = {
GLOBAL = "https://github.com/xlings-res/vulkan-import/releases/download/1.4.357.1/vulkan-import-1.4.357.1.tar.gz",
Expand Down Expand Up @@ -359,15 +413,26 @@ package = {
-- .def it came from. The anchor keeps a buildable target, the same
-- shape `compat.opengl` uses for a headers-only package.
--
-- The artifact is packed FLAT — lib/ at the archive root, no wrap
-- directory — because `-L` is not glob-expanded the way
-- The artifact is packed FLAT — lib/ and bin/ at the archive root, no
-- wrap directory — because `-L` is not glob-expanded the way
-- include_dirs and sources are. With a wrap layer the relative
-- `-Llib` below misses and the link fails with
-- "LNK1181: cannot open input file 'vulkan-1.lib'".
sources = { "mcpp_generated/vulkan_import_anchor.c" },
ldflags = { "-Llib", "-lvulkan-1" },
runtime = {
-- vulkan-1.dll ships with the GPU driver, not with us.
-- THE LOADER TRAVELS WITH THE PROGRAM (1.4.357.3+). mcpp copies
-- every *.dll under a dependency's runtime library_dirs beside the
-- executable it builds -- for transitive dependencies too -- and
-- `mcpp pack` always searches the executable's own directory, so
-- the same file reaches a packed distribution. Versions before
-- 1.4.357.3 have no bin/ in their artifact; mcpp skips a declared
-- directory that does not exist, so for them this is inert.
--
-- The ICD is deliberately NOT supplied: on a machine with a GPU
-- driver the driver's ICD is the right one, and a software
-- fallback would hide a missing driver behind a slow device.
library_dirs = { "bin" },
dlopen_libs = { "vulkan-1.dll" },
capabilities = { "vulkan.icd.driver" },
},
Expand Down
32 changes: 31 additions & 1 deletion pkgs/e/compat.eui-neo.lua
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,13 @@ package = {
url = "https://github.com/sudoevolve/EUI-NEO/archive/refs/tags/v0.5.9.tar.gz",
sha256 = "370d1da706d94bbbb144fa1634e1d9796a8a1ffd58b696fbb801296aef15703d",
},
-- 0.5.9.1: upstream 0.5.9 unchanged. Exists because the `vulkan`
-- feature now pins compat.vulkan 1.4.357.3, whose Windows artifact
-- carries the loader DLL; an installed 0.5.9 records the old pin.
["0.5.9.1"] = {
url = "https://github.com/sudoevolve/EUI-NEO/archive/refs/tags/v0.5.9.tar.gz",
sha256 = "370d1da706d94bbbb144fa1634e1d9796a8a1ffd58b696fbb801296aef15703d",
},
},
macosx = {
["0.5.3"] = {
Expand Down Expand Up @@ -183,6 +190,13 @@ package = {
url = "https://github.com/sudoevolve/EUI-NEO/archive/refs/tags/v0.5.9.tar.gz",
sha256 = "370d1da706d94bbbb144fa1634e1d9796a8a1ffd58b696fbb801296aef15703d",
},
-- 0.5.9.1: upstream 0.5.9 unchanged. Exists because the `vulkan`
-- feature now pins compat.vulkan 1.4.357.3, whose Windows artifact
-- carries the loader DLL; an installed 0.5.9 records the old pin.
["0.5.9.1"] = {
url = "https://github.com/sudoevolve/EUI-NEO/archive/refs/tags/v0.5.9.tar.gz",
sha256 = "370d1da706d94bbbb144fa1634e1d9796a8a1ffd58b696fbb801296aef15703d",
},
},
windows = {
["0.5.3"] = {
Expand Down Expand Up @@ -218,6 +232,13 @@ package = {
url = "https://github.com/sudoevolve/EUI-NEO/archive/refs/tags/v0.5.9.tar.gz",
sha256 = "370d1da706d94bbbb144fa1634e1d9796a8a1ffd58b696fbb801296aef15703d",
},
-- 0.5.9.1: upstream 0.5.9 unchanged. Exists because the `vulkan`
-- feature now pins compat.vulkan 1.4.357.3, whose Windows artifact
-- carries the loader DLL; an installed 0.5.9 records the old pin.
["0.5.9.1"] = {
url = "https://github.com/sudoevolve/EUI-NEO/archive/refs/tags/v0.5.9.tar.gz",
sha256 = "370d1da706d94bbbb144fa1634e1d9796a8a1ffd58b696fbb801296aef15703d",
},
},
},

Expand Down Expand Up @@ -420,7 +441,7 @@ package = {
"*/core/render/vulkan/vulkan_shadertoy.cpp",
"*/core/render/vulkan/vulkan_text.cpp",
},
deps = { ["compat.vulkan"] = "1.4.357.0" },
deps = { ["compat.vulkan"] = "1.4.357.3" },
},
-- ── Window backend ────────────────────────────────────────────
-- Exclusive in the same way and for the same reason as the render
Expand Down Expand Up @@ -676,7 +697,16 @@ local function normalise_layout(layer)
-- hook runs on every platform; the host guard is further down and it only
-- covers the glib staging. With no directory listing available, the
-- archive's shape is ASKED ABOUT by name rather than discovered.
--
-- The name carries UPSTREAM's version, which is not always this package's.
-- A fourth component is this index re-releasing the same tag -- 0.5.9.1 is
-- upstream 0.5.9 with one dependency re-pinned -- and the archive still
-- unpacks to `EUI-NEO-0.5.9/`. Taking the version verbatim looked for
-- `EUI-NEO-0.5.9.1/`, found nothing, and failed with the error below;
-- measured on the first 0.5.9.1 install. Three-component versions are
-- unchanged by this.
local v = pkginfo.version()
v = v:match("^(%d+%.%d+%.%d+)%.%d+$") or v
for _, name in ipairs({ "EUI-NEO-" .. v, "eui-neo-" .. v,
"EUI-NEO-v" .. v, "eui-neo-v" .. v }) do
if os.isfile(path.join(name, "CMakeLists.txt")) then
Expand Down
2 changes: 1 addition & 1 deletion tests/examples/eui-neo-vulkan/mcpp.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ version = "0.1.0"
# package resolves the exclusive choice in its own preprocessor from the
# MCPP_FEATURE_* flags. The window backend stays GLFW, unnamed.
[dependencies.compat]
eui-neo = { version = "0.5.9", features = ["vulkan"] }
eui-neo = { version = "0.5.9.1", features = ["vulkan"] }

[build]
cxxflags = ["-DHAVE_EUI_VULKAN=1"]
2 changes: 1 addition & 1 deletion tests/examples/vulkan/mcpp.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "vulkan-tests"
version = "0.1.0"

[dependencies.compat]
vulkan = "1.4.357.0"
vulkan = "1.4.357.3"

# All three platforms now carry compat.vulkan — linux/macOS build the loader
# from source, windows links the import library. HAVE_VULKAN_LOADER stays as the
Expand Down
52 changes: 49 additions & 3 deletions tests/examples/vulkan/tests/loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,22 @@
// legitimately ABSENT on a driverless machine and asserting on it would just be
// testing the runner's hardware.
//
// HAVE_VULKAN_LOADER is set by THIS project's own [target.'cfg(...)'.build]
// cxxflags, because compat.vulkan has no windows entry. A consumer that keys
// its source off a dependency's presence has to declare that itself.
// HAVE_VULKAN_LOADER is set by THIS project's own [build] cxxflags. A consumer
// that keys its source off a dependency's presence has to declare that itself.
#if defined(HAVE_VULKAN_LOADER)
#include <vulkan/vulkan.h>
#endif
import std;

#if defined(HAVE_VULKAN_LOADER) && defined(_WIN32)
// Declared rather than taken from <windows.h>: two functions are needed, and
// the header's macros and min/max collide with `import std`. Both live in
// kernel32, which every Windows program already links.
extern "C" __declspec(dllimport) void* GetModuleHandleW(const wchar_t* name);
extern "C" __declspec(dllimport) unsigned long GetModuleFileNameW(void* module, wchar_t* path,
unsigned long size);
#endif

#if !defined(HAVE_VULKAN_LOADER)
int main() {
std::println("compat.vulkan: skipped (no windows build — static loader unsupported upstream)");
Expand All @@ -36,6 +44,44 @@ int main() {
return 2;
}

#if defined(_WIN32)
// WHERE THE LOADER CAME FROM is the point of compat.vulkan 1.4.357.3 on
// Windows: the package now ships vulkan-1.dll and mcpp places it beside the
// executable, so a machine with no GPU driver can still start this program.
// The loader has just answered, so the DLL is mapped; its directory must be
// this executable's. That holds on a machine WITH a driver too (the
// application directory precedes System32), which is what makes this a real
// check: with an older compat.vulkan the loader came from System32 there,
// and on a driverless machine the process never reached main.
{
std::vector<wchar_t> dll(32768), exe(32768);
void* module = GetModuleHandleW(L"vulkan-1.dll");
if (module == nullptr) {
std::println("vulkan-1.dll answered but is not mapped in this process");
return 7;
}
const auto dllLen = GetModuleFileNameW(module, dll.data(), 32768);
const auto exeLen = GetModuleFileNameW(nullptr, exe.data(), 32768);
auto dirOf = [](std::wstring_view p) {
std::wstring d(p.substr(0, p.find_last_of(L"\\/")));
for (auto& c : d) c = static_cast<wchar_t>(std::towlower(c));
return d;
};
auto narrow = [](std::wstring_view p) {
std::string out;
for (wchar_t c : p) out.push_back(c < 128 ? static_cast<char>(c) : '?');
return out;
};
const std::wstring_view dllPath(dll.data(), dllLen), exePath(exe.data(), exeLen);
if (dirOf(dllPath) != dirOf(exePath)) {
std::println("vulkan-1.dll was loaded from {}, not beside {}",
narrow(dllPath), narrow(exePath));
return 8;
}
std::println("compat.vulkan: loader deployed beside the executable ({})", narrow(dllPath));
}
#endif

std::uint32_t extensionCount = 0;
if (vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr) != VK_SUCCESS) {
std::println("vkEnumerateInstanceExtensionProperties failed");
Expand Down
Loading