webgpu support
This commit is contained in:
parent
5352ef69a2
commit
dedf6b0467
22 changed files with 1656 additions and 324 deletions
185
interfaces/Crafter.Graphics-DescriptorHeapWebGPU.cppm
Normal file
185
interfaces/Crafter.Graphics-DescriptorHeapWebGPU.cppm
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
Crafter®.Graphics
|
||||
Copyright (C) 2026 Catcrafts®
|
||||
catcrafts.net
|
||||
*/
|
||||
|
||||
// DOM-mode parallel to DescriptorHeapVulkan. WebGPU has no real bindless,
|
||||
// so the "heap" is purely a CPU-side slot allocator with a side-table
|
||||
// mapping slot → JS-side WebGPU handle. UIRenderer looks up the handle by
|
||||
// slot at dispatch time to build (or fetch from cache) the bind group.
|
||||
|
||||
export module Crafter.Graphics:DescriptorHeapWebGPU;
|
||||
#ifdef CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
import std;
|
||||
import :WebGPU;
|
||||
|
||||
export namespace Crafter {
|
||||
struct DescriptorHeapWebGPU;
|
||||
|
||||
struct DescriptorRange {
|
||||
std::uint16_t firstElement;
|
||||
std::uint16_t count;
|
||||
};
|
||||
|
||||
class BufferSlot {
|
||||
public:
|
||||
DescriptorHeapWebGPU* heap = nullptr;
|
||||
std::uint16_t firstElement = 0xFFFF;
|
||||
BufferSlot() = default;
|
||||
BufferSlot(DescriptorHeapWebGPU* h, std::uint16_t f) : heap(h), firstElement(f) {}
|
||||
BufferSlot(const BufferSlot&) = delete;
|
||||
BufferSlot& operator=(const BufferSlot&) = delete;
|
||||
BufferSlot(BufferSlot&& o) noexcept : heap(o.heap), firstElement(o.firstElement) { o.firstElement = 0xFFFF; }
|
||||
BufferSlot& operator=(BufferSlot&& o) noexcept;
|
||||
~BufferSlot();
|
||||
explicit operator bool() const noexcept { return firstElement != 0xFFFF; }
|
||||
operator std::uint16_t() const noexcept { return firstElement; }
|
||||
};
|
||||
|
||||
class ImageSlot {
|
||||
public:
|
||||
DescriptorHeapWebGPU* heap = nullptr;
|
||||
std::uint16_t firstElement = 0xFFFF;
|
||||
ImageSlot() = default;
|
||||
ImageSlot(DescriptorHeapWebGPU* h, std::uint16_t f) : heap(h), firstElement(f) {}
|
||||
ImageSlot(const ImageSlot&) = delete;
|
||||
ImageSlot& operator=(const ImageSlot&) = delete;
|
||||
ImageSlot(ImageSlot&& o) noexcept : heap(o.heap), firstElement(o.firstElement) { o.firstElement = 0xFFFF; }
|
||||
ImageSlot& operator=(ImageSlot&& o) noexcept;
|
||||
~ImageSlot();
|
||||
explicit operator bool() const noexcept { return firstElement != 0xFFFF; }
|
||||
operator std::uint16_t() const noexcept { return firstElement; }
|
||||
};
|
||||
|
||||
class SamplerSlot {
|
||||
public:
|
||||
DescriptorHeapWebGPU* heap = nullptr;
|
||||
std::uint16_t firstElement = 0xFFFF;
|
||||
SamplerSlot() = default;
|
||||
SamplerSlot(DescriptorHeapWebGPU* h, std::uint16_t f) : heap(h), firstElement(f) {}
|
||||
SamplerSlot(const SamplerSlot&) = delete;
|
||||
SamplerSlot& operator=(const SamplerSlot&) = delete;
|
||||
SamplerSlot(SamplerSlot&& o) noexcept : heap(o.heap), firstElement(o.firstElement) { o.firstElement = 0xFFFF; }
|
||||
SamplerSlot& operator=(SamplerSlot&& o) noexcept;
|
||||
~SamplerSlot();
|
||||
explicit operator bool() const noexcept { return firstElement != 0xFFFF; }
|
||||
operator std::uint16_t() const noexcept { return firstElement; }
|
||||
};
|
||||
|
||||
struct DescriptorHeapWebGPU {
|
||||
std::vector<WebGPUBufferRef> bufferTable;
|
||||
std::vector<WebGPUTextureRef> imageTable;
|
||||
std::vector<WebGPUSamplerRef> samplerTable;
|
||||
|
||||
std::vector<std::uint16_t> bufferFreelist;
|
||||
std::vector<std::uint16_t> imageFreelist;
|
||||
std::vector<std::uint16_t> samplerFreelist;
|
||||
|
||||
std::uint16_t nextBuffer = 0;
|
||||
std::uint16_t nextImage = 0;
|
||||
std::uint16_t nextSampler = 0;
|
||||
|
||||
void Initialize(std::uint16_t images, std::uint16_t buffers, std::uint16_t samplers) {
|
||||
imageTable.assign(images, 0);
|
||||
bufferTable.assign(buffers, 0);
|
||||
samplerTable.assign(samplers, 0);
|
||||
imageFreelist.reserve(images);
|
||||
bufferFreelist.reserve(buffers);
|
||||
samplerFreelist.reserve(samplers);
|
||||
}
|
||||
|
||||
DescriptorRange AllocateBufferSlots(std::uint16_t count) {
|
||||
if (count == 1 && !bufferFreelist.empty()) {
|
||||
auto f = bufferFreelist.back(); bufferFreelist.pop_back();
|
||||
return { f, 1 };
|
||||
}
|
||||
if (nextBuffer + count > bufferTable.size()) {
|
||||
std::println("DescriptorHeapWebGPU: buffer slots exhausted");
|
||||
std::abort();
|
||||
}
|
||||
DescriptorRange r{ nextBuffer, count };
|
||||
nextBuffer = static_cast<std::uint16_t>(nextBuffer + count);
|
||||
return r;
|
||||
}
|
||||
DescriptorRange AllocateImageSlots(std::uint16_t count) {
|
||||
if (count == 1 && !imageFreelist.empty()) {
|
||||
auto f = imageFreelist.back(); imageFreelist.pop_back();
|
||||
return { f, 1 };
|
||||
}
|
||||
if (nextImage + count > imageTable.size()) {
|
||||
std::println("DescriptorHeapWebGPU: image slots exhausted");
|
||||
std::abort();
|
||||
}
|
||||
DescriptorRange r{ nextImage, count };
|
||||
nextImage = static_cast<std::uint16_t>(nextImage + count);
|
||||
return r;
|
||||
}
|
||||
DescriptorRange AllocateSamplerSlots(std::uint16_t count) {
|
||||
if (count == 1 && !samplerFreelist.empty()) {
|
||||
auto f = samplerFreelist.back(); samplerFreelist.pop_back();
|
||||
return { f, 1 };
|
||||
}
|
||||
if (nextSampler + count > samplerTable.size()) {
|
||||
std::println("DescriptorHeapWebGPU: sampler slots exhausted");
|
||||
std::abort();
|
||||
}
|
||||
DescriptorRange r{ nextSampler, count };
|
||||
nextSampler = static_cast<std::uint16_t>(nextSampler + count);
|
||||
return r;
|
||||
}
|
||||
|
||||
void FreeBufferSlots(std::uint16_t first, std::uint16_t count) noexcept {
|
||||
for (std::uint16_t i = 0; i < count; ++i) {
|
||||
bufferTable[first + i] = 0;
|
||||
bufferFreelist.push_back(first + i);
|
||||
}
|
||||
}
|
||||
void FreeImageSlots(std::uint16_t first, std::uint16_t count) noexcept {
|
||||
for (std::uint16_t i = 0; i < count; ++i) {
|
||||
imageTable[first + i] = 0;
|
||||
imageFreelist.push_back(first + i);
|
||||
}
|
||||
}
|
||||
void FreeSamplerSlots(std::uint16_t first, std::uint16_t count) noexcept {
|
||||
for (std::uint16_t i = 0; i < count; ++i) {
|
||||
samplerTable[first + i] = 0;
|
||||
samplerFreelist.push_back(first + i);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ─── slot dtors (defined here since they reference DescriptorHeapWebGPU) ─
|
||||
|
||||
inline BufferSlot::~BufferSlot() {
|
||||
if (firstElement != 0xFFFF && heap) heap->FreeBufferSlots(firstElement, 1);
|
||||
}
|
||||
inline BufferSlot& BufferSlot::operator=(BufferSlot&& o) noexcept {
|
||||
if (this != &o) {
|
||||
if (firstElement != 0xFFFF && heap) heap->FreeBufferSlots(firstElement, 1);
|
||||
heap = o.heap; firstElement = o.firstElement; o.firstElement = 0xFFFF;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
inline ImageSlot::~ImageSlot() {
|
||||
if (firstElement != 0xFFFF && heap) heap->FreeImageSlots(firstElement, 1);
|
||||
}
|
||||
inline ImageSlot& ImageSlot::operator=(ImageSlot&& o) noexcept {
|
||||
if (this != &o) {
|
||||
if (firstElement != 0xFFFF && heap) heap->FreeImageSlots(firstElement, 1);
|
||||
heap = o.heap; firstElement = o.firstElement; o.firstElement = 0xFFFF;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
inline SamplerSlot::~SamplerSlot() {
|
||||
if (firstElement != 0xFFFF && heap) heap->FreeSamplerSlots(firstElement, 1);
|
||||
}
|
||||
inline SamplerSlot& SamplerSlot::operator=(SamplerSlot&& o) noexcept {
|
||||
if (this != &o) {
|
||||
if (firstElement != 0xFFFF && heap) heap->FreeSamplerSlots(firstElement, 1);
|
||||
heap = o.heap; firstElement = o.firstElement; o.firstElement = 0xFFFF;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
#endif // CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
Loading…
Add table
Add a link
Reference in a new issue