Commit graph Crafter.Graphics/examples
Author SHA1 Message Date
079b6b0e1f
feat: windows on their own clock, deferred deletion for every handle owner, staged re-uploads, and RTPass push data
Window
- updateInterval runs Update on the window's own clock while the
  compositor sends no frame callbacks (hidden, minimized): the Wayland loop
  is a poll() loop, and the Win32 loop sleeps until the next update. Both
  read the interval each pass.
- SetPresentMode (FIFO, Mailbox, Immediate). A mode the surface lacks, or
  whose swapchain has other than numFrames images (Mesa's Mailbox has four),
  falls back to FIFO until the mode is set again.
- AddPollFd / RemovePollFd wake the Wayland loop on the app's descriptors.
- The swapchain has TRANSFER_DST where the surface allows it.
- CaptureNextFrame replaces SaveFrame: it records the copy in the frame,
  before the present, where SaveFrame read an image already presented. A
  frame unwound past before the write still frees the readback buffer.
- Inter-pass barriers on the swapchain image carry the access masks of the
  stages the passes use.

Deferred deletion (issue #101)
- VulkanBuffer, Mesh, VulkanShader, ComputeShader and PipelineRTVulkan hand
  their handles to the deletion queue from their destructors and moves, as
  a frame in flight may still use them; a static owner goes after the
  driver has torn down. VulkanShader and PipelineRTVulkan move and can't be
  copied; re-Load and re-Init queue the old pipeline.
- The queue and its mutex are never destroyed, and the queue takes handles
  from any thread; Device::frameCounter is atomic. Both the queue and the
  staging rings count frames as one window renders them (documented).
- DrainDeletions also lets every buffer's staging ring start over: without
  a Window nothing else reclaims either, so an app without one calls it
  after waiting for its work.

Meshes and buffers
- A Mesh rebuild queues the old acceleration structure and builds into the
  same storage after a barrier, so the BLAS address stays put when it fits.
  The refit and rebuild barriers cover compute ray queries too.
- RTBuildOptions::noDuplicateAnyHit. Mesh::geometryFlags replaces opaque,
  and the refit and rebuild fallbacks keep the flags.
- A re-upload into a buffer a frame in flight may read (UploadDeviceLocal
  of the same size, UploadDeviceLocalRange) copies on the GPU, after those
  reads, through a per-frame staging ring; on ReBAR it used to write the
  buffer in place. Empty uploads record nothing.
- A compressed Mesh::Build that keeps its buffers decompresses into them
  after the reads of frames in flight, and the hit shaders and ray queries
  wait for the decompress as well as the BLAS build. Its vertex buffer
  takes a ranged refit's copies.
- Mesh move-assigns (queueing the BLAS it replaces), so it can be replaced
  in place or erased from a vector.
- VulkanBuffer::Create asks for a device address only for buffers with
  SHADER_DEVICE_ADDRESS usage, as vkGetBufferDeviceAddress requires; the
  others have address 0. UIRenderer::RegisterBuffer refuses those.
- Build inputs are synchronized as shader reads.

Other
- RTPass pushes the app's own push data and traces at an explicit size.
- DescriptorHeapVulkan hands freed slot ranges out again (they leaked), and
  keeps its free lists sorted.
- ImageVulkan's mip chain clamps each level to 1 texel: a non-square
  image's shorter side went to 0.
- VulkanShader throws on a missing file instead of failing in bad_alloc.
- CRAFTER_GRAPHICS_DEVICE picks the GPU by its number among the distinct
  GPUs Vulkan lists; anything but such a number is an error.
- The debug messenger prints info messages only with
  CRAFTER_GRAPHICS_VALIDATION set.
- Windows: the WinRT gamepad code moved to a C file (mingw-w64's WinRT
  headers don't compile as C++), -lcombase dropped, a reference leak fixed.
- project.cpp honours --local for Crafter.Event, Math and Asset, as Asset
  does for Math, and builds every test through one helper, projectArgs
  included.
- Tests: DebugMessengerSeverity, DeletionQueueThreads, DeviceSelection,
  HeapSlotReuse, MeshLifetime, MipChainNonSquare, PipelineLifetime,
  RTPassPushData, SwapchainTransferDst, UploadInFlight, VulkanBufferAddress,
  VulkanShaderLifetime, WindowUpdateClock; others extended.

Breaking: SaveFrame is CaptureNextFrame; Mesh::opaque is geometryFlags; a
buffer without SHADER_DEVICE_ADDRESS usage has no address; frameCounter is
std::atomic.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 20:20:29 +02:00
449d5da553
docs: where the NVIDIA descriptor-heap faults stand on 615.78.08
The heap acceleration-structure read still needs the rewrite on
615.78.08; the READMEs say so and point at HeapASRead --no-workaround
for checking a newer driver. Dynamic descriptor indexing in hit shaders
is fixed there, which the README and the Sponza and SponzaBench notes
now say, and the VulkanTriangle investigation no longer contradicts
itself about llvmpipe, which advertises VK_EXT_descriptor_heap now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 03:03:17 +02:00
48aa9be5ce feat(vulkan): run the compute/UI path without VK_EXT_descriptor_heap
Device::Initialize required twelve device extensions with no capability
check. Mesa Turnip (Adreno) lacks six of them: VK_EXT_descriptor_heap,
VK_KHR_shader_untyped_pointers, VK_EXT_device_fault and the three ray
tracing extensions. vkCreateDevice failed there, so not even a UI-only
program could start, although the UI path is compute-only and needs
nothing else that Turnip is missing.

The descriptor heap, ray tracing and device fault are now optional
groups, detected at start-up from the extension list and the feature
bits (Device::descriptorHeapSupported, rayTracingSupported,
deviceFaultSupported). Ray tracing needs the heap; on a device without
it the ray tracing entry points throw a message naming the cause.

Without the heap the same bindless slots live in one update-after-bind
descriptor set per frame, owned by DescriptorHeapVulkan: binding 0
storage images, 1 sampled images, 2 samplers, 3 storage buffers. Slot
allocation, the slot handles, UIDispatchHeader and the UIRenderer API
are unchanged; buffer slots simply stop being offset. Window::Render
binds that frame's set where it binds the heap, every compute pipeline
shares the heap object's pipeline layout, and push data travels as push
constants.

Each UI kernel is built twice from one source. ui-shared.glsl declares
its resources through UI_HEAP_* macros that expand to descriptor_heap
or, with CRAFTER_GRAPHICS_DESCRIPTOR_SETS defined, to set/binding.
<name>.comp.spv and <name>.comp.sets.spv ship side by side and
ComputeShader::Load picks one. The heap build of every shader is
byte-identical to before.

Breaking:
- ComputeShader::Load takes the heap as a second argument.
- DescriptorHeapVulkan is no longer copyable or movable.
- Custom UI shaders declare heap resources with the UI_HEAP_* macros
  and are registered twice in project.cpp (see the README).
- project.cpp uses Shader::defines and Shader::variant, so it needs a
  crafter-build that has them (Crafter.Build master, fe38cc1 or later).

Also:
- maintenance5 is enabled as a feature, not only as an extension:
  every VulkanBuffer already relied on VkBufferUsageFlags2CreateInfo.
- Barrier stage masks drop RAY_TRACING_SHADER on devices without ray
  tracing, and ImageVulkan::Create resolves its default consumer stage
  to COMPUTE_SHADER there.
- Window refuses a swapchain whose image count is not numFrames
  instead of writing past images[]. The limitation itself is #160.
- CRAFTER_GRAPHICS_NO_DESCRIPTOR_HEAP forces the fallback on a driver
  that has the heap, so it can be exercised on a desktop GPU.

Verified on an RTX 4090 in both modes under the validation layer, and
on a Fairphone 6 (Turnip, Adreno 810, postmarketOS), where the fallback
is the only path.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 17:28:46 +02:00
42a479572d SPDX license update 2026-07-22 18:09:06 +02:00
catbot
619e39369d test(bench): SponzaBench harness + #40→HEAD perf measurement (#155)
Headless benchmark around the native Sponza RT scene: times setup and a
measured Render() loop over the full multi-mesh atrium, prints BENCH
metrics, and exits. Includes run-bench.sh and a README documenting the
methodology and the measured net gain from #40 to current master.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 19:35:54 +00:00
catbot
931500ddc3 perf(webgpu): byteCount-bounded readback for over-provisioned buffers (#133)
WebGPUBuffer::EnqueueReadback / PollReadback always copied the full
buffer `size` GPU→staging→wasm. Over-provisioned event-queue buffers
(e.g. Forts3D's GPU physics event drain) paid the full-capacity copy
every drain even when only a small live prefix held data.

Add an optional `byteCount` parameter (default 0 = whole buffer, so the
existing full-buffer callers are unchanged) bounding the readback to the
live prefix. Pass the same byteCount to the paired PollReadback so the
matching number of bytes lands in `.value`.

JS bridge: the staging buffer is now sized to the full device-buffer
capacity (not the first call's byteSize) so a varying prefix length never
overflows it, while the copyBufferToBuffer + mapAsync/getMappedRange are
bounded to the requested prefix — that's where the copy saving lands.

Verified end-to-end in the browser via RayQueryPick: the full readback
still resolves correctly, and a follow-up 8-byte prefix read copies only
hit+customIndex while primitiveIndex keeps its poison sentinel, proving
the copy was bounded. Native `crafter-build test` suite: 24 passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 14:00:36 +00:00
catbot
574242dd30 perf(ui): add additive DispatchFused to collapse consecutive UI passes (#47)
Add a fifth UI compute path — DispatchFused — alongside the four
per-element Dispatch* calls. It composites quads → circles → images →
text (canonical back-to-front order) in ONE dispatch that loads the
destination image once and stores once, eliminating the per-pass
load+store and the inter-pass VkMemoryBarriers a run of consecutive
Dispatch* calls would pay. The win materialises at >= 2 non-empty
categories; an absent category is a zero-trip, push-constant-uniform
loop (~free).

The new uber-kernel (shaders/ui-fused.comp.glsl) reuses each category's
exact cooperative shared-memory tile-cull + per-pixel accumulate, so a
fused category is pixel-identical to its standalone pass. Categories run
sequentially per thread and share one set of shared-memory scratch, so
the VGPR/shared high-water mark stays at the per-category level, not the
sum.

Additive and non-breaking: the per-element Dispatch* calls and the
frozen 48-byte UIDispatchHeader are untouched. DispatchFused gets its own
128-byte push-constant layout (UIFusedHeader: four uvec4 headers + four
per-category clip vec4s). To interleave a custom ui.Dispatch() between
standard passes, bracket it with two DispatchFused calls — the dispatch
boundary is the explicit, app-declared flush point.

WebGPU (Vulkan-second): DispatchFused falls back to the per-element
Dispatch* calls in canonical order — one texture/sampler per dispatch
there can't feed the bindless image phase — so the result matches; only
the load/store fusion is Vulkan-only.

HelloUI now composites its background quads, mouse circle, and label
text in a single DispatchFused. Verified rendering identical on a live
Vulkan/Wayland session.

Resolves #47

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 17:03:24 +00:00
catbot
0d1312ac09 example(RTVolume): GPU-written device-buffer procedural AABBs (#37)
A compute shader (aabbs.comp.{glsl,wgsl}) writes the procedural box into a
device buffer that BuildProcedural consumes by device address/handle with no
host copy; the WebGPU path also refits from it each frame so the box breathes.
Verified rendering on both Vulkan (native) and WebGPU (browser).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 14:12:12 +00:00
catbot
40c4184d41 test(vulkan-rt): port RTVolume example to native Vulkan (#33)
Regression test for the procedural BLAS path: the same 3x3x3 grid of
unit-box AABBs runs through a PROCEDURAL_HIT_GROUP_KHR group whose GLSL
intersection shader (reportIntersectionEXT) turns each box into a
radius-1 sphere, the any-hit shader punches the spherical-checkerboard
cut-out (visible proof non-opaque geometry runs any-hit), and the
closest-hit shades per-instance tints — the WebGPU example behavior
reproduced natively. Fixed camera in raygen.glsl; the WebGPU/DOM path is
unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 00:17:37 +00:00
catbot
f7fc441253 test(webgpu-rt): RTMultiShadow example exercising N shadow rays/pixel/bounce (#30)
Five pillars, four colored point lights; closest-hit emits one shadow ray
per light from the same invocation (raysPerPixel = 4, maxDepth = 2), so up
to four rays per pixel rtAccumulate in a single SHADE pass — the contention
case #30 exists for. Each pillar casts four separable colored shadows; an
accumulator race or capacity drop shows as flickering dark noise or a
missing shadow color. Two frames a second apart diff at 2 px / 1.85 M
(last-ulp CAS ordering), confirming no lost updates.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 22:45:33 +00:00
catbot
bbe1b21c22 test(webgpu): HDRBloom example exercising the HDR post-process primitives (#27)
RT→rgba16float→threshold→blur→composite, end-to-end proof of the three
primitives. threshold/blur run from onBeforeUpdate (one submit each) so the
storage-write→sampled-read dependency gets WebGPU's per-submit barrier
(there is none between dispatches within a compute pass); the composite is a
UI custom shader so it owns the canvas ping-pong. Documents the Vulkan
symmetry (gap 4): the native present path records passes generically and
barriers between them, so the same chain is wireable today.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 12:55:14 +00:00
catbot
097cc37347 feat(webgpu): HDR post-process primitives — float textures, storage-texture bindings, RESOLVE→HDR target (#27)
Adds the minimal WebGPU-backend surface an HDR bloom/post chain needs:

1. wgpuCreateStorageImage2D + StorageImage2D<>: runtime rgba16float (or
   other format) textures with STORAGE_BINDING|TEXTURE_BINDING usage, no
   CompressedTextureAsset upload — GPU-produced HDR targets.
2. UICustomBindingKind::StorageTexture (kind 5): write-only storage-texture
   binding carrying a texel format (the freed UICustomBinding::format byte),
   wired through all three binding paths (UI custom / RT / plain compute).
   Float textures already sample via SampledTexture (sampleType float).
3. PipelineRTWebGPU::Init(..., hdrOutputFormat): RESOLVE writes the linear
   accumulator into a user rgba16float texture (RTPass::outTexHandle)
   instead of the rgba8unorm canvas, leaving the composite→swapchain pass to
   the app. Default RGBA8Unorm keeps the canvas path byte-identical.

Existing RT examples updated for the _pad→format field rename; the default
paths are unchanged (verified RTStress builds + renders).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 12:55:14 +00:00
catbot
b645746c8c test(webgpu-rt): RayQueryPick example exercising the rayQuery TLAS shim (#25)
Adds an 8^3 = 512-instance TLAS pick test that shoots one analytically
determined ray through a rayQuery=true PlainComputeShader and checks the
read-back committed hit (customIndex 484, t 40.75). 512 instances sit in
the < 8193 regime that the hardcoded 16384-leaf start used to miss, so the
example fails fast if the shim regresses. Verified in Firefox/WebGPU:
"[RayQueryPick] PASS".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 13:33:04 +00:00
catbot
d08c7cea11 docs(vulkan-rt): document dynamic descriptor_heap-index hit-shader fault (#23)
Indexing a `layout(descriptor_heap)` array with a runtime (non-constant)
index inside a ray-tracing hit shader device-losts on NVIDIA 610.43.02,
for both SSBO and sampled-image descriptors. A constant/spec-constant
index is fine, and the same dynamic pattern works in fragment shaders, so
it's an RT-stage-specific driver fault — the same family as #7/#15
(descriptor-heap AS reads) and #21/#22 (RT recursion + compute TLAS push).

Unlike the AS-read fault, this cannot be worked around transparently: a
sampled image has no device-address escape hatch the way an acceleration
structure does (OpConvertUToAccelerationStructureKHR), and a buffer-only
buffer_reference rewrite would need a whole address-table architecture
while still leaving the texture half broken. So the resolution is the
documented-limitation path (the precedent set by #7).

Records the fault and its isolation in README's Native RT status and in
the Sponza example README (the textured-closest-hit example, which already
reads its albedo through a spec-constant slot for exactly this reason).
Documents the recommended consumer pattern: bind one resource and index
*within* it dynamically (single geometry SSBO / buffer_reference at a
spec-constant slot; one texture2DArray indexed by layer) rather than
selecting a descriptor dynamically — what the WebGPU path already does.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 20:05:12 +00:00
catbot
45ecc91424 fix(vulkan-rt): merge TLAS push constant into existing block (#18)
The NVIDIA descriptor-heap AS-read workaround (#15) rewrote heap
acceleration-structure reads into a load of the TLAS device address from
a push-constant block. It always *synthesized a new* push-constant block,
so any ray-tracing shader that already declared one ended up with two —
which SPIR-V forbids ("at most one push constant block statically used per
entry point"), and vkCreateShaderModule's spirv-val check rejected:

    Entry point id '4' uses more than one PushConstant interface.

WorkaroundNvidiaAS::Patch now detects an existing PushConstant variable and,
when present, appends a single ulong member (the TLAS address) to that
block instead of adding a second one, reading the address through the
shader's own push-constant variable. The append offset is the end of the
user's block, computed from the members' explicit Offset/ArrayStride/
MatrixStride decorations (correct under both scalar and std140 layout) and
rounded up to 8. Shaders with no push constant of their own keep getting a
freshly synthesized single-member block at offset 0, exactly as before.

That offset is published via Device::workaroundTlasPushOffset and RTPass
feeds it to vkCmdPushDataEXT so the address lands where the rewritten load
reads it (0 for the synthesized case, preserving prior behaviour).

Verified on the affected driver (NVIDIA 610.43.02, RTX 4090): VulkanTriangle
ray-traces correctly and validation-clean both with and without a
user-declared raygen push constant.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 02:28:02 +00:00
catbot
950059c86e fix(vulkan-rt): work around NVIDIA descriptor-heap AS-read device-loss (#15)
Reading an acceleration structure through VK_EXT_descriptor_heap aborts
with VK_ERROR_DEVICE_LOST on NVIDIA 610.43.02 — a brand-new-extension
driver fault isolated in #7 (engine setup is correct and validation-clean;
images/buffers through the same heap work, and both traceRayEXT and inline
rayQuery fault identically on the AS read).

An acceleration structure can equally be reached by its device address via
OpConvertUToAccelerationStructureKHR, which reads no descriptor and so never
touches the faulting heap path. glslang has no GLSL spelling for that
conversion, so VulkanShader rewrites the compiled SPIR-V at module-load
time: every `OpLoad %accelStruct <heap-ptr>` becomes a load of the TLAS
device address from a synthesized push-constant block followed by the
convert. RTPass pushes the active frame's TLAS address into that push
constant. User GLSL and example code are unchanged; acceleration structures
still bind into the heap normally.

The workaround is gated on Device::workaroundDescriptorHeapAS (true only on
the NVIDIA proprietary driver) and confined to one fenced block in
Crafter.Graphics-ShaderVulkan.cppm plus the RTPass push and the shaderInt64
feature toggle — delete those once a fixed NVIDIA driver ships and the heap
AS read becomes the direct path again.

Verified: VulkanTriangle ray-traces correctly on native NVIDIA (RTX 4090),
validation-layer-clean, no device loss. The SPIR-V rewrite was independently
validated with spirv-val on both the VulkanTriangle and Sponza raygen
modules.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 01:59:54 +00:00
catbot
5dd1086f08 docs(webgpu-rt): add RTVolume example (procedural spheres + any-hit cut-out)
A 3x3x3 grid of AABB-geometry spheres rendered through an analytic
ray-sphere intersection shader, with an any-hit spherical-checkerboard
cut-out so the background shows through. Exercises both features end to
end on the WebGPU wavefront tracer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 22:09:30 +00:00
catbot
464cb66063 docs(vulkan-rt): record native descriptor-heap AS read as a driver fault
Investigated the VK_ERROR_DEVICE_LOST on the native VulkanTriangle (#7).
Verified the engine side is correct and validation-clean: the BLAS/TLAS
build finishes before render (FinishInit waits), the built instance is
well-formed (identity transform, mask=0xFF, correct BLAS ref), and
vkWriteResourceDescriptorsEXT stores the TLAS device address at the
expected heap offset (confirmed by dumping the heap bytes). Khronos
validation 1.4.350 reports zero errors.

The fault is isolated to reading the acceleration structure through
VK_EXT_descriptor_heap:
- images/buffers via the same heap render fine (trace disabled -> the
  raygen imageStore path renders a full gradient);
- both traceRayEXT and inline rayQueryEXT (no SBT) fault identically on
  the AS read;
- reproduces with the AS descriptor at heap byte 0 / shader index 0 (no
  offset/stride ambiguity) and regardless of pAddressRange size.

NVIDIA 610.43.02 is the only descriptor_heap implementation available
(llvmpipe lacks the extension), so there is no second implementation to
cross-check. Conclusion: driver-side fault in NVIDIA's brand-new
VK_EXT_descriptor_heap acceleration-structure path; should be reported to
NVIDIA. The traceRayEXT call is left active so the example stays a
faithful reproducer. Documented in both READMEs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 22:21:57 +00:00
catbot
376e66aeed WebGPU RT: port Sponza to wavefront (shadow ray in SHADE)
Restructure Sponza for the wavefront model: raygen emits the primary ray;
closesthit (in SHADE) gathers albedo/normal, accumulates ambient, and
emits a shadow ray carrying the pending direct term; miss adds the sky
(primary) or the direct term (shadow miss). resolve.wgsl applies the same
Reinhard+gamma the megakernel raygen did inline. User bindings moved to
group 3 (groups 0..2 reserved). RTPass maxDepth=2.

Renders the atrium correctly through the wavefront pipeline (textures,
two-sided shading, sun+ambient, shadows, tonemap).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 20:16:04 +00:00
catbot
f4d6493d91 wip: uncommitted changes from claude run on issue #3 2026-05-31 16:28:38 +00:00
catbot
4e42d663a6 WebGPU RT: wavefront tracer core (GENERATE/PREP/TRACE/SHADE/RESOLVE)
Replace the megakernel @compute entry with five wavefront kernels sharing
one module, connected by GPU ray/hit/payload buffers and a GPU-driven
indirect bounce loop:

  GENERATE -> (PREP -> TRACE -> SHADE) x maxDepth -> RESOLVE

- TRACE contains zero user code (pure _rtwTraverseTlas/Blas, opaque-only).
- PREP publishes dispatchWorkgroupsIndirect args from the live ray count;
  the indirect-args buffer lives in its own bind group so it is never
  bound read-write in the same dispatch that consumes it as INDIRECT.
- New emit/accumulate API: rtEmitPrimaryRay / rtEmitRay / rtAccumulate,
  plus an optional user Resolve stage (tonemap hook; identity by default).
- Per-pass WfParams via a dynamic-offset uniform ring (curIsA/bounce vary
  between passes within one submit).
- Payload-typed wfPayload binding emitted in the codegen region after the
  user's struct Payload; payload travels with each ray (2*W*H slots).
- Request maxBufferSize / maxStorageBufferBindingSize / maxComputeWorkgroups
  PerDimension so the W*H-sized work buffers fit past the 128MB baseline.

VulkanTriangle ported to the new API and renders bit-identical to the
megakernel baseline at maxDepth=1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 16:24:41 +00:00
b5d0f52da0 webgpu sponza 2026-05-19 00:27:09 +02:00
5553ded476 webgpu triangle 2026-05-18 18:43:30 +02:00
64116cd980 custom shader webgpu 2026-05-18 05:39:17 +02:00
dedf6b0467 webgpu support 2026-05-18 04:58:52 +02:00
5352ef69a2 browser DOM support 2026-05-18 02:07:48 +02:00
3859c43ce3 compression example 2026-05-12 00:27:55 +02:00
ac2eb7fb0a new input system 2026-05-12 00:24:48 +02:00
c054f1e0b3 update 2026-05-03 02:45:38 +02:00
1f5697326c UI rewrite 3rd attempt 2026-05-02 21:08:20 +02:00
c9fd1b1585 animated example 2026-05-02 00:03:24 +02:00
216972e73a new UI system 2026-05-01 23:35:37 +02:00
d840a81448 bugfixes 2026-04-30 23:15:43 +02:00
bc669b5e05 crafter-build V2 2026-04-30 01:30:08 +02:00
8a2fd33efc crafter-build V2 2026-04-30 01:29:17 +02:00
ea18f32300 vulkan2d fixes 2026-04-11 23:18:41 +02:00
1c1a142f52 rendertargetvulkan 2026-04-11 18:48:00 +02:00
3f4ad87746 writing ui descriptors 2026-04-10 22:25:55 +02:00
5427867fff descriptor heap static offset method 2026-04-10 20:30:58 +02:00
177f873639 vulkan UI 2026-04-09 00:15:09 +02:00
f8e142fb06 descriptor heap rewrite 2026-04-05 22:53:59 +02:00
d661c88ee2 cleaned up renderer 2026-03-09 20:10:19 +01:00
72bf6c83e1 windows build fix 2026-03-02 23:53:13 +01:00
b5e69c90fa Win32 vulkan window 2026-02-24 02:32:37 +01:00
415e523a45 runtime pipeline 2026-02-22 00:46:38 +01:00
d1b8e45fb6 new descriptor layout 2 2026-02-03 21:03:11 +01:00
74832c6824 templated pipeline 2026-01-31 21:08:42 +01:00
db1616ff0e vulkan animation 2026-01-30 00:09:37 +01:00
1d0b7a615b descriptor fixed 2026-01-29 23:43:54 +01:00
5e3a7738ed fixed descriptors 2026-01-29 23:31:56 +01:00