105 lines
4.8 KiB
Markdown
105 lines
4.8 KiB
Markdown
# Crafter.Graphics
|
||
|
||
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.
|
||
|
||
## What's in here
|
||
|
||
- **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.
|
||
|
||
## UI system (three tiers)
|
||
|
||
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`):
|
||
|
||
```bash
|
||
crafter-build # build the library
|
||
crafter-build -r # build and run (in an example directory)
|
||
```
|
||
|
||
The build picks the window backend automatically: Wayland on Linux,
|
||
Win32 on Windows / mingw. Cross-compile via the standard `--target=...`
|
||
flag.
|
||
|
||
## Examples
|
||
|
||
See [examples/](examples/). Quick map:
|
||
|
||
- [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.
|
||
|
||
## License
|
||
|
||
LGPL 3.0. See per-file headers and `LICENSE`.
|