custom shader webgpu
This commit is contained in:
parent
dedf6b0467
commit
64116cd980
12 changed files with 445 additions and 36 deletions
|
|
@ -2,8 +2,17 @@
|
|||
// standard ones. The custom shader inverts RGB in the area covered by a
|
||||
// list of circles. The mouse-tracking circle moves; two static ones sit
|
||||
// on a striped background drawn with the standard DrawQuads shader.
|
||||
//
|
||||
// Works on both Vulkan (native) and WebGPU (DOM). The shader source is
|
||||
// in two files — inverse-circle.comp.glsl (native, SPIR-V) and
|
||||
// inverse-circle.comp.wgsl (DOM). The C++ surface differs only at the
|
||||
// shader-load / buffer-flag sites; the per-frame UI building logic is
|
||||
// identical.
|
||||
|
||||
#ifndef CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
#include "vulkan/vulkan.h"
|
||||
#endif
|
||||
#include <cstddef> // offsetof — a macro, so not visible via `import std;`
|
||||
|
||||
import Crafter.Graphics;
|
||||
import Crafter.Event;
|
||||
|
|
@ -11,18 +20,22 @@ import std;
|
|||
using namespace Crafter;
|
||||
|
||||
// Application-side item POD. Matches `struct InverseCircleItem { vec4
|
||||
// centerRadius; }` in inverse-circle.comp.glsl byte-for-byte.
|
||||
// centerRadius; }` in inverse-circle.comp.{glsl,wgsl} byte-for-byte.
|
||||
struct InverseCircleItem {
|
||||
float cx, cy, radius, _pad;
|
||||
};
|
||||
|
||||
int main() {
|
||||
Device::Initialize();
|
||||
#ifdef CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
static Window window(1280, 720, "Custom Shader");
|
||||
#else
|
||||
Window window(1280, 720, "Custom Shader");
|
||||
#endif
|
||||
|
||||
VkCommandBuffer init = window.StartInit();
|
||||
auto init = window.StartInit();
|
||||
|
||||
DescriptorHeapVulkan heap;
|
||||
GraphicsDescriptorHeap heap;
|
||||
heap.Initialize(/*images*/ 8, /*buffers*/ 8, /*samplers*/ 4);
|
||||
window.descriptorHeap = &heap;
|
||||
|
||||
|
|
@ -30,26 +43,46 @@ int main() {
|
|||
ui.Initialize(window, heap, init);
|
||||
window.passes.push_back(&ui);
|
||||
|
||||
// Load the user-authored shader. Same wrapper as the four shipped with
|
||||
// the library — there is no privileged path.
|
||||
ComputeShader inverseCircle;
|
||||
// Load the user-authored shader. On native it's an offline-compiled
|
||||
// SPIR-V from .comp.glsl; on DOM it's WGSL source compiled at
|
||||
// startup by the device. The DOM Load takes an extra `bindings` arg
|
||||
// declaring resources the renderer should bind at dispatch time —
|
||||
// here just one entry: the items SSBO at group 2, with its heap slot
|
||||
// read from `hdr.itemBuffer` in the push data.
|
||||
GraphicsComputeShader inverseCircle;
|
||||
#ifndef CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
inverseCircle.Load("inverse-circle.comp.spv");
|
||||
#else
|
||||
UICustomBinding invBindings[] = {
|
||||
{ .group = 2,
|
||||
.binding = 0,
|
||||
.kind = UICustomBindingKind::Buffer,
|
||||
._pad = 0,
|
||||
.pushOffset = static_cast<std::uint32_t>(offsetof(Crafter::UIDispatchHeader, itemBuffer)) },
|
||||
};
|
||||
inverseCircle.Load(std::filesystem::path("inverse-circle.comp.wgsl"), invBindings);
|
||||
#endif
|
||||
|
||||
// User-owned buffers.
|
||||
VulkanBuffer<QuadItem, true> quadsBuf;
|
||||
VulkanBuffer<InverseCircleItem, true> invBuf;
|
||||
GraphicsBuffer<QuadItem, true> quadsBuf;
|
||||
GraphicsBuffer<InverseCircleItem, true> invBuf;
|
||||
#ifndef CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
quadsBuf.Create(
|
||||
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 64);
|
||||
invBuf.Create(
|
||||
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 16);
|
||||
#else
|
||||
quadsBuf.Create(64);
|
||||
invBuf.Create(16);
|
||||
#endif
|
||||
|
||||
auto quadsSlot = ui.RegisterBuffer(quadsBuf);
|
||||
auto invSlot = ui.RegisterBuffer(invBuf);
|
||||
|
||||
EventListener<UIBuildArgs> buildSub(&ui.onBuild, [&](UIBuildArgs a) {
|
||||
VkCommandBuffer cmd = a.cmd;
|
||||
auto cmd = a.cmd;
|
||||
|
||||
Rect canvas = Rect::FromWindow(window);
|
||||
|
||||
|
|
@ -82,15 +115,24 @@ int main() {
|
|||
|
||||
// Standard dispatch first — paints the stripes.
|
||||
if (qc > 0) {
|
||||
#ifndef CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
quadsBuf.FlushDevice(cmd, VK_ACCESS_SHADER_READ_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
#else
|
||||
quadsBuf.FlushDevice();
|
||||
#endif
|
||||
ui.DispatchQuads(cmd, quadsSlot, qc);
|
||||
}
|
||||
|
||||
// Custom dispatch second — reads the stripes, inverts under
|
||||
// circles, writes back. The library inserts the inter-dispatch
|
||||
// SHADER_WRITE → SHADER_READ|WRITE barrier automatically.
|
||||
// SHADER_WRITE → SHADER_READ|WRITE barrier automatically on
|
||||
// Vulkan; WebGPU's compute-pass tracking does it for free.
|
||||
if (ic > 0) {
|
||||
#ifndef CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
invBuf.FlushDevice(cmd, VK_ACCESS_SHADER_READ_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
#else
|
||||
invBuf.FlushDevice();
|
||||
#endif
|
||||
struct PC { UIDispatchHeader hdr; } pc { ui.FillHeader(invSlot, ic) };
|
||||
std::uint32_t gx = (window.width + 7) / 8;
|
||||
std::uint32_t gy = (window.height + 7) / 8;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue