webgpu support
This commit is contained in:
parent
5352ef69a2
commit
dedf6b0467
22 changed files with 1656 additions and 324 deletions
|
|
@ -2,47 +2,53 @@
|
|||
Crafter®.Graphics
|
||||
Copyright (C) 2026 Catcrafts®
|
||||
catcrafts.net
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License version 3.0 as published by the Free Software Foundation;
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
module;
|
||||
#ifndef CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
#include "vulkan/vulkan.h"
|
||||
#endif
|
||||
#include "../lib/stb_truetype.h"
|
||||
module Crafter.Graphics:FontAtlas_impl;
|
||||
import :FontAtlas;
|
||||
import :Font;
|
||||
import :GraphicsTypes;
|
||||
#ifndef CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
import :ImageVulkan;
|
||||
import :Device;
|
||||
#else
|
||||
import :WebGPU;
|
||||
#endif
|
||||
import std;
|
||||
|
||||
using namespace Crafter;
|
||||
|
||||
void FontAtlas::Initialize(VkCommandBuffer cmd) {
|
||||
std::uint8_t* FontAtlas::PixelPtr() noexcept {
|
||||
#ifndef CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
return image.buffer.value;
|
||||
#else
|
||||
return staging.data();
|
||||
#endif
|
||||
}
|
||||
|
||||
void FontAtlas::Initialize(GraphicsCommandBuffer cmd) {
|
||||
#ifndef CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
image.Create(
|
||||
kAtlasSize, kAtlasSize, /*mipLevels*/ 1, cmd,
|
||||
VK_FORMAT_R8_UNORM,
|
||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
||||
);
|
||||
// Staging buffer is mapped; clear it so empty atlas regions sample as
|
||||
// distance < onedge (i.e. fully outside any glyph).
|
||||
std::memset(image.buffer.value, 0, kAtlasSize * kAtlasSize);
|
||||
dirty = true;
|
||||
#else
|
||||
(void)cmd;
|
||||
staging.assign(kAtlasSize * kAtlasSize, 0);
|
||||
textureHandle = WebGPU::wgpuCreateAtlasTexture(kAtlasSize, kAtlasSize);
|
||||
dirty = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FontAtlas::ShelfPlace(int w, int h, int& outX, int& outY) {
|
||||
// Try existing shelves first — same height heuristic keeps fragmentation low.
|
||||
for (Shelf& s : shelves_) {
|
||||
if (h <= s.height && s.cursorX + w <= kAtlasSize) {
|
||||
outX = s.cursorX;
|
||||
|
|
@ -51,7 +57,6 @@ bool FontAtlas::ShelfPlace(int w, int h, int& outX, int& outY) {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
// New shelf below current ones.
|
||||
if (nextShelfY_ + h > kAtlasSize) return false;
|
||||
Shelf s{};
|
||||
s.y = nextShelfY_;
|
||||
|
|
@ -70,7 +75,6 @@ bool FontAtlas::Ensure(Font& font, std::uint32_t codepoint) {
|
|||
|
||||
float fontScale = stbtt_ScaleForPixelHeight(&font.font, kBaseSize);
|
||||
|
||||
// Advance is always present, even for empty glyphs (e.g. space).
|
||||
int advanceUnits = 0, lsb = 0;
|
||||
stbtt_GetCodepointHMetrics(&font.font, static_cast<int>(codepoint), &advanceUnits, &lsb);
|
||||
|
||||
|
|
@ -90,12 +94,12 @@ bool FontAtlas::Ensure(Font& font, std::uint32_t codepoint) {
|
|||
int px = 0, py = 0;
|
||||
if (!ShelfPlace(sw, sh, px, py)) {
|
||||
stbtt_FreeSDF(sdf, nullptr);
|
||||
return false; // V1: silently drop overflow; V2: grow atlas
|
||||
return false;
|
||||
}
|
||||
// Blit row-by-row into the mapped staging buffer.
|
||||
std::uint8_t* dst = PixelPtr();
|
||||
for (int row = 0; row < sh; ++row) {
|
||||
std::memcpy(
|
||||
image.buffer.value + (py + row) * kAtlasSize + px,
|
||||
dst + (py + row) * kAtlasSize + px,
|
||||
sdf + row * sw,
|
||||
static_cast<std::size_t>(sw)
|
||||
);
|
||||
|
|
@ -110,8 +114,6 @@ bool FontAtlas::Ensure(Font& font, std::uint32_t codepoint) {
|
|||
g.v1 = static_cast<float>(py + sh) / kAtlasSize;
|
||||
dirty = true;
|
||||
}
|
||||
// For empty glyphs (whitespace) we still cache the entry — the size-0
|
||||
// fields tell the emitter to skip the quad but advance the cursor.
|
||||
|
||||
cache_.emplace(key, g);
|
||||
return true;
|
||||
|
|
@ -122,8 +124,18 @@ const Glyph* FontAtlas::Lookup(Font& font, std::uint32_t codepoint) const {
|
|||
return it == cache_.end() ? nullptr : &it->second;
|
||||
}
|
||||
|
||||
void FontAtlas::Update(VkCommandBuffer cmd) {
|
||||
void FontAtlas::Update(GraphicsCommandBuffer cmd) {
|
||||
if (!dirty) return;
|
||||
#ifndef CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
image.Update(cmd, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
#else
|
||||
(void)cmd;
|
||||
// Full-atlas upload. Future: track dirty region.
|
||||
WebGPU::wgpuWriteAtlasRegion(
|
||||
textureHandle, staging.data(),
|
||||
kAtlasSize, kAtlasSize, kAtlasSize,
|
||||
0, 0, kAtlasSize, kAtlasSize
|
||||
);
|
||||
#endif
|
||||
dirty = false;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue