2026-05-02 00:03:24 +02:00
|
|
|
|
# Crafter.Graphics
|
|
|
|
|
|
|
2026-05-02 21:08:20 +02:00
|
|
|
|
Vulkan-based graphics library built around C++20 modules and the bindless
|
|
|
|
|
|
`VK_EXT_descriptor_heap` extension. Provides window management, ray
|
|
|
|
|
|
tracing, and a compute-shader-driven UI on a single, opinionated stack.
|
2026-05-02 00:03:24 +02:00
|
|
|
|
|
2026-05-02 21:08:20 +02:00
|
|
|
|
## What's in here
|
2026-05-02 00:03:24 +02:00
|
|
|
|
|
2026-05-02 21:08:20 +02:00
|
|
|
|
- **Window** — Wayland and Win32 backends, swapchain ring, frame pacing,
|
|
|
|
|
|
input events. Pick a backend at build time via the target triple.
|
|
|
|
|
|
- **Device** — single-Vulkan-instance bring-up. The library targets
|
|
|
|
|
|
`VK_EXT_descriptor_heap` exclusively; pipelines are created with
|
|
|
|
|
|
`VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT` so there are no
|
|
|
|
|
|
descriptor-set layouts and push constants travel via
|
|
|
|
|
|
`vkCmdPushDataEXT`.
|
|
|
|
|
|
- **DescriptorHeapVulkan** — bindless slot allocator. `AllocateImageSlots`
|
|
|
|
|
|
/ `AllocateBufferSlots` / `AllocateSamplerSlots`, with byte-offset
|
|
|
|
|
|
helpers for direct descriptor writes.
|
|
|
|
|
|
- **VulkanBuffer\<T, Mapped\>** — typed buffer with optional host mapping
|
|
|
|
|
|
and a `FlushDevice` that issues the right host-write barrier.
|
|
|
|
|
|
- **ImageVulkan\<Pixel\>** — image + staging buffer, mip-chain support,
|
|
|
|
|
|
one-shot uploads via a command buffer.
|
|
|
|
|
|
- **PipelineRTVulkan / ShaderBindingTableVulkan / RTPass** — ray-tracing
|
|
|
|
|
|
pipeline, SBT, and a `RenderPass` that dispatches it.
|
|
|
|
|
|
- **ComputeShader** — the Tier 1 wrapper used by the UI system. Loads a
|
|
|
|
|
|
`.spv`, builds a heap-bound compute pipeline, dispatches with
|
|
|
|
|
|
`vkCmdPushDataEXT`. Use it directly for any custom compute.
|
|
|
|
|
|
- **UI** — three-tier UI system; see below.
|
|
|
|
|
|
- **FontAtlas** — single-channel SDF atlas (1024×1024, 32pt base,
|
|
|
|
|
|
shelf-packed, lazy `Ensure` per codepoint, dirty-flush via `Update`).
|
|
|
|
|
|
- **Mesh / RenderingElement3D / Animation** — BLAS/TLAS construction
|
|
|
|
|
|
and 3D scene plumbing for the ray-tracing path.
|
2026-05-02 00:03:24 +02:00
|
|
|
|
|
2026-05-02 21:08:20 +02:00
|
|
|
|
## UI system (three tiers)
|
2026-05-02 00:03:24 +02:00
|
|
|
|
|
2026-05-02 21:08:20 +02:00
|
|
|
|
The UI is *deliberately* layered to balance no-boilerplate against
|
|
|
|
|
|
no-lock-in:
|
|
|
|
|
|
|
|
|
|
|
|
- **Tier 1 — `ComputeShader`.** Load any `.spv`, dispatch with push
|
|
|
|
|
|
constants, library inserts inter-dispatch barriers. The escape hatch:
|
|
|
|
|
|
if the standard shaders don't fit, write your own compute and
|
|
|
|
|
|
dispatch it next to them.
|
|
|
|
|
|
- **Tier 2 — `UIRenderer` + standard shaders.** Four shipped compute
|
|
|
|
|
|
shaders (`drawQuads`, `drawCircles`, `drawImages`, `drawText`), POD
|
|
|
|
|
|
item structs (`QuadItem`, `CircleItem`, `ImageItem`, `GlyphItem`), a
|
|
|
|
|
|
shared GLSL contract in [shaders/ui-shared.glsl](shaders/ui-shared.glsl),
|
|
|
|
|
|
and helpers (`RegisterBuffer`, `RegisterImage`, `RegisterSampler`,
|
|
|
|
|
|
`FillHeader`, `Dispatch*`, `ShapeText`). You build your own per-shader
|
|
|
|
|
|
SSBOs (manual batching) and call one `Dispatch*` per shader type per
|
|
|
|
|
|
frame. Item array order = draw order.
|
|
|
|
|
|
- **Tier 3 — stateless presentation functions.** `DrawButton`,
|
|
|
|
|
|
`DrawCheckbox`, `DrawSlider`, `DrawProgressBar`. Each is a small
|
|
|
|
|
|
function that *appends* items to your buffers — they don't dispatch.
|
|
|
|
|
|
Colors come in as small inline `*Colors` aggregates, no library
|
|
|
|
|
|
`Theme` type. **The source is the customization API**: if a
|
|
|
|
|
|
component doesn't fit, copy its body and edit it. No virtual hooks,
|
|
|
|
|
|
no extension points.
|
|
|
|
|
|
|
|
|
|
|
|
What's *not* in the UI: widget tree, layout engine (just a `Rect::SubRect`
|
|
|
|
|
|
carving helper), theming, hit-testing, focus management. State for
|
|
|
|
|
|
interactive components (hover, drag, focus) lives in user-owned POD
|
|
|
|
|
|
structs, not the library.
|
|
|
|
|
|
|
|
|
|
|
|
### UI dispatch model
|
|
|
|
|
|
|
|
|
|
|
|
Standard shaders dispatch one workgroup per 8×8 *screen tile* — each
|
|
|
|
|
|
thread iterates every item in the SSBO in array order, accumulating
|
|
|
|
|
|
into a local `dst`, and stores once. Total cost is `O(W·H·N)`; works
|
|
|
|
|
|
well up to a few hundred items at 1080p. Splitting one buffer into
|
|
|
|
|
|
multiple dispatches doesn't help — the same total work plus barrier
|
|
|
|
|
|
overhead. If you need to render thousands of UI items, you want a
|
|
|
|
|
|
different shader (tile binning, per-item-list resolve), not more
|
|
|
|
|
|
dispatches.
|
|
|
|
|
|
|
|
|
|
|
|
## Build
|
|
|
|
|
|
|
|
|
|
|
|
The repository is built with `crafter-build` (a project-config based
|
|
|
|
|
|
build system; the project description lives in `project.cpp`):
|
2026-05-02 00:03:24 +02:00
|
|
|
|
|
|
|
|
|
|
```bash
|
2026-05-02 21:08:20 +02:00
|
|
|
|
crafter-build # build the library
|
|
|
|
|
|
crafter-build -r # build and run (in an example directory)
|
2026-05-02 00:03:24 +02:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-05-02 21:08:20 +02:00
|
|
|
|
The build picks the window backend automatically: Wayland on Linux,
|
|
|
|
|
|
Win32 on Windows / mingw. Cross-compile via the standard `--target=...`
|
|
|
|
|
|
flag.
|
2026-05-02 00:03:24 +02:00
|
|
|
|
|
|
|
|
|
|
## Examples
|
|
|
|
|
|
|
2026-05-02 21:08:20 +02:00
|
|
|
|
See [examples/](examples/). Quick map:
|
2026-05-02 00:03:24 +02:00
|
|
|
|
|
2026-05-02 21:08:20 +02:00
|
|
|
|
- [HelloWindow](examples/HelloWindow/) — minimal window, no rendering.
|
|
|
|
|
|
- [VulkanTriangle](examples/VulkanTriangle/) — ray-traced triangle, the
|
|
|
|
|
|
smallest test of the bindless + ray-tracing path.
|
|
|
|
|
|
- [HelloUI](examples/HelloUI/) — UI smoke test using all three tiers
|
|
|
|
|
|
(background quad, slider, progress bar, button with text label,
|
|
|
|
|
|
cursor-tracking circle).
|
|
|
|
|
|
- [CustomShader](examples/CustomShader/) — Tier 1 demo: a user-authored
|
|
|
|
|
|
compute shader inverting RGB under a list of item-circles, dispatched
|
|
|
|
|
|
alongside the standard `drawQuads`. The "could attempt #2 do this?" test.
|
2026-05-02 00:03:24 +02:00
|
|
|
|
|
|
|
|
|
|
## License
|
|
|
|
|
|
|
2026-05-02 21:08:20 +02:00
|
|
|
|
LGPL 3.0. See per-file headers and `LICENSE`.
|