Skip to content

Commit 77d4918

Browse files
committed
ci: correct why the Windows graphics run reaches no device
Three places recorded a missing `vulkan-1.dll` as the cause of `render unavailable` on the Windows runner. The log refutes it. That line is printed by `src/main.cpp` after the render function returns nothing, and the Vulkan leg imports `vkCreateInstance` from `vulkan-1.dll` through the import library -- a process that could not find that DLL would fail during image load and print nothing. It printed. mcpp-index's own `vulkan-tests` member calls `vkEnumerateInstanceVersion` on the windows shards and passes, which says the same thing from the other side. The conclusion came from generalising the descriptor's note about STATIC linkage into a claim about building at all. Measured against that: the Khronos loader in `compat:vulkan` cross-builds into a working `vulkan-1.dll` from the source the index already carries -- 265 exports matching upstream's `vulkan-1.def` name for name, DllMain present, importing only ADVAPI32, CFGMGR32, KERNEL32 and msvcrt. So a hermetic Windows loader is available whenever it is wanted, and it is not what this step is waiting on. What is open is why the lavapipe payload's ICD enumerates no device under a process mcpp launched. The notes are corrected in place rather than deleted, so a reader sees what was believed and what refuted it.
1 parent 8b931ec commit 77d4918

3 files changed

Lines changed: 85 additions & 40 deletions

File tree

.agents/docs/2026-09-07-module-first-heterogeneous-surface.md

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -695,7 +695,7 @@ test that was seen to fail without the change.
695695
| E2/E3 | mcpp | A `[rules]` manifest section, and activating rules from the files present | **withdrawn**, see 13.1.2 |
696696
| P6 | mcpp-plugins | Rules pass `--depfile`, `-MD -MF` and `-depfile` | staged, needs E1 released |
697697
| X1 | openxlings/xim-pkgindex | Raise the `xim:slang` pin toward upstream `v2026.17` | staged |
698-
| X2 | openxlings/xim-pkgindex | A Windows `vulkan-1.dll` package | staged, see 13.1.3 |
698+
| X2 | mcpplibs/mcpp-index | `compat:vulkan` builds its Windows loader from source instead of expecting a host DLL | measured feasible, see 13.1.3; not what the Windows run step is waiting on |
699699

700700
### 13.1.1 A cost the implementation paid, stated rather than hidden
701701

@@ -737,22 +737,53 @@ feature spelling and no module name -- and a new device language costs no engine
737737
change. `.slang` was removed from the built-in table to prove that, and
738738
`tests/slang-consumer` builds unchanged.
739739
740-
### 13.1.3 What the Windows measurement changed
740+
### 13.1.3 The Windows measurement, and the second reading that overturned it
741741
742742
Raising the graphics example from "builds" to "runs" on Windows was expected to
743743
be two CI steps. It is not. The manifest declaration worked --
744744
`Provisioning [xlings.workspace] entries (xim:mesa-lavapipe@26.2.0)` -- the ICD
745-
was found in the store, and the program still printed `render unavailable`.
746-
747-
`compat:vulkan` ships an import library on Windows and nothing else, and says
748-
why in its own descriptor: a statically linked loader cannot work there, because
749-
upstream's `loader_windows.c` creates its locks in `DllMain` and a static
750-
library never gets one. The runtime `vulkan-1.dll` is expected to come from an
751-
installed GPU driver, and a runner has none.
752-
753-
So the platform stays at "builds" and the example declares no device there --
754-
an entry would download 56 MB that nothing can load. The gap is a Windows loader
755-
package, which is X2.
745+
manifest was found in the store, and the program printed `render unavailable`.
746+
747+
The first reading of that attributed it to a missing loader: `compat:vulkan`
748+
ships an import library on Windows and nothing else, and says why in its own
749+
descriptor -- a statically linked loader cannot work there, because upstream's
750+
`loader_windows.c` creates its locks in `DllMain` and a static library never
751+
gets one. The runtime `vulkan-1.dll` was said to come from an installed GPU
752+
driver, which a runner has none of.
753+
754+
**That reading is wrong, and the log says so.** `render unavailable` is printed
755+
by `src/main.cpp` after the render function returns nothing. The Vulkan leg
756+
imports `vkCreateInstance` from `vulkan-1.dll` through the import library, so a
757+
process that could not find that DLL would fail during image load and print
758+
nothing at all. It printed. The loader was present, it ran, and it enumerated no
759+
device -- which is a statement about the ICD, not about the loader. A second
760+
fact stands with it: mcpp-index's own `vulkan-tests` member calls
761+
`vkEnumerateInstanceVersion` on the windows shards and passes.
762+
763+
Two things follow.
764+
765+
**X2 is not what the CI step is waiting on.** A Windows loader package would
766+
change nothing about `render unavailable`. What is unestablished is why the
767+
lavapipe payload's ICD produces no device under a process mcpp launched, and
768+
that is where the next measurement goes.
769+
770+
**X2 is nonetheless available, and it costs no redistribution decision.** The
771+
descriptor's note argues that a Windows loader must be a DLL, not that it cannot
772+
be built. Measured: the Khronos loader in `compat:vulkan` cross-builds into a
773+
working `vulkan-1.dll` from the source the index already carries -- 265 exports,
774+
matching upstream's `vulkan-1.def` name for name, all `vk*`-prefixed so
775+
`exports = ["vk*"]` reproduces the surface exactly; `DllMain` present; importing
776+
only ADVAPI32, CFGMGR32, KERNEL32 and msvcrt. The earlier conclusion that the
777+
only viable source was a third-party prebuilt binary came from generalising the
778+
descriptor's note about STATIC linkage into a claim about building at all. A
779+
package built this way makes the loader hermetic on Windows the way it already
780+
is on Linux and macOS, and needs no new artifact hosted anywhere.
781+
782+
The general form of the error is worth keeping: a recorded conclusion is
783+
re-read, its reasoning is not. Both notes that carried it -- in
784+
`.github/workflows/ci-windows.yml` and in the example's own manifest -- have
785+
been corrected in place rather than deleted, so the next reader sees what was
786+
believed and what refuted it.
756787

757788
### 13.2 Dependency structure across repositories
758789

.github/workflows/ci-windows.yml

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -456,28 +456,41 @@ jobs:
456456
done
457457
echo "ok: both shader stages compiled and the Vulkan half linked"
458458
459-
# WINDOWS STAYS AT "BUILDS", AND THE REASON IS A MISSING PACKAGE RATHER
460-
# THAN A MISSING CI STEP.
459+
# WINDOWS STAYS AT "BUILDS", AND WHAT REMAINS OPEN IS THE DRIVER.
461460
#
462-
# A run step was written, pushed, and measured. The manifest declaration
463-
# worked -- `Provisioning [xlings.workspace] entries
464-
# (xim:mesa-lavapipe@26.2.0)` -- and the ICD was found in the store, and
465-
# the program still printed `render unavailable`, which is its own report
466-
# that it enumerated no device.
461+
# A run step was written, pushed, and measured (run 34135108981). The
462+
# manifest declaration worked -- `Provisioning [xlings.workspace] entries
463+
# (xim:mesa-lavapipe@26.2.0)` -- the ICD manifest was found in the store,
464+
# and the program printed `render unavailable`, which is `src/main.cpp`
465+
# reporting that the render function returned nothing.
467466
#
468-
# The missing piece is the LOADER, not the driver. `compat:vulkan` ships
469-
# an import library on Windows and nothing else, and says why in its own
470-
# descriptor: a statically linked loader cannot work there, because
471-
# upstream's `loader_windows.c` creates its locks in `DllMain` and a
472-
# static library never gets one. The runtime `vulkan-1.dll` is expected
473-
# to come from an installed GPU driver, and a GitHub Windows runner has
474-
# none. `xim:mesa-lavapipe`'s Windows payload is an ICD; it imports system
475-
# DLLs and carries no loader either.
467+
# THAT OUTPUT PLACES THE FAILURE AFTER THE LOADER, NOT AT IT. The Vulkan
468+
# leg imports `vkCreateInstance` from `vulkan-1.dll` through the import
469+
# library, so a process missing that DLL fails during image load and
470+
# prints nothing at all. It printed. The loader was there, it ran, and it
471+
# enumerated no device -- which is a statement about the ICD.
476472
#
477-
# So raising this job to "runs" needs a Windows `vulkan-1.dll` package,
478-
# which is a packaging decision rather than a step in this file. macOS is
479-
# not in the same position: `compat:vulkan` builds the loader from source
480-
# everywhere except Windows, so that job does run.
473+
# An earlier revision of this comment named a missing `vulkan-1.dll` as
474+
# the cause. That was an inference from the descriptor's note about static
475+
# linkage rather than a reading of the failure, and the log refutes it.
476+
# Two facts stand against it: this program ran, and mcpp-index's own
477+
# `vulkan-tests` member calls `vkEnumerateInstanceVersion` on the windows
478+
# shards and passes.
479+
#
480+
# A separate measurement, recorded here because it removes a second thing
481+
# from the list of suspects: the Khronos loader in `compat:vulkan` builds
482+
# into a working `vulkan-1.dll` from the source the index already carries
483+
# (mingw, 265 exports matching upstream's `vulkan-1.def` exactly, DllMain
484+
# present, importing only ADVAPI32/CFGMGR32/KERNEL32/msvcrt). The
485+
# descriptor's note argues that a Windows loader must be a DLL, not that
486+
# it cannot be built -- so a hermetic Windows loader is available whenever
487+
# it is wanted. It is not what this step is waiting on.
488+
#
489+
# What this step is waiting on is `xim:mesa-lavapipe`'s Windows payload
490+
# producing a device under an mcpp-launched process. Until that is
491+
# measured, the job builds the Vulkan half and runs the CPU fallback.
492+
# macOS is not in the same position: MoltenVK enumerates once the instance
493+
# asks for portability, which `src/vulkan/render.cpp` now does.
481494

482495
- name: "Toolchain: LLVM — build mcpp (self-host)"
483496
shell: bash

examples/10-graphics/offscreen/mcpp.toml

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,16 @@ vulkan-runtime = "2026.09.07"
6565
# WINDOWS DECLARES NO DEVICE, AND THAT IS MEASURED RATHER THAN AN OVERSIGHT.
6666
#
6767
# `xim:mesa-lavapipe` publishes a Windows payload and it installs correctly, so
68-
# an entry here would work in the sense that the bytes arrive. The program still
69-
# reaches no device: `compat:vulkan` ships an import library on Windows and the
70-
# runtime `vulkan-1.dll` is expected to come from an installed GPU driver, which
71-
# a machine without one does not have. Declaring the driver would download 56 MB
72-
# that nothing can load.
68+
# an entry here would work in the sense that the bytes arrive. The program was
69+
# built and run with it declared, and printed `render unavailable` -- the report
70+
# `src/main.cpp` makes when the render function returns nothing.
7371
#
74-
# The gap is a Windows loader package. Until there is one, this platform builds
75-
# the Vulkan half and runs the CPU fallback, which is what the `cfg(not(...))`
76-
# section below carries.
72+
# The failure is after the loader rather than at it. This program imports
73+
# `vkCreateInstance` from `vulkan-1.dll`, so one that could not find that DLL
74+
# would fail during image load and print nothing; it printed. What has not been
75+
# established is why the payload's ICD enumerates no device under a process mcpp
76+
# launched. Until it is, this platform builds the Vulkan half and runs the CPU
77+
# fallback, which is what the `cfg(not(...))` section below carries.
7778

7879
[build]
7980
accel = "vulkan1.2"

0 commit comments

Comments
 (0)