webgpu support
This commit is contained in:
parent
5352ef69a2
commit
dedf6b0467
22 changed files with 1656 additions and 324 deletions
|
|
@ -69,6 +69,10 @@ import :Gamepad;
|
|||
import :VulkanTransition;
|
||||
import :DescriptorHeapVulkan;
|
||||
import :RenderPass;
|
||||
#ifdef CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
import :WebGPU;
|
||||
import :DescriptorHeapWebGPU;
|
||||
#endif
|
||||
import std;
|
||||
|
||||
using namespace Crafter;
|
||||
|
|
@ -1323,23 +1327,22 @@ Window::Window(std::uint32_t w, std::uint32_t h, const std::string_view title)
|
|||
|
||||
Window::Window(std::uint32_t w, std::uint32_t h) : width(w), height(h) {
|
||||
if (g_domWindow != nullptr) {
|
||||
// Only one Window per page in V1. Subsequent constructions are
|
||||
// a programming error — log loudly and clobber the previous
|
||||
// pointer so the new Window's events at least fire.
|
||||
// (stderr isn't reachable via `import std;` on wasi-sdk yet; just log
|
||||
// to cout. The browser console pipes both to the same place.)
|
||||
std::println("Crafter::Window: only one DOM Window per page; "
|
||||
"overwriting the previous instance.");
|
||||
}
|
||||
g_domWindow = this;
|
||||
|
||||
// Use the browser-reported viewport size as the initial dimensions
|
||||
// unless the caller asked for something specific. Browser owns the
|
||||
// real size; w/h passed in are advisory.
|
||||
if (w == 0 || h == 0) {
|
||||
width = static_cast<std::uint32_t>(Crafter::DomEnv::domGetInnerWidth());
|
||||
height = static_cast<std::uint32_t>(Crafter::DomEnv::domGetInnerHeight());
|
||||
}
|
||||
// Browser owns the real surface size. The width/height passed in are
|
||||
// advisory only — useful as a native-side hint, ignored on DOM. We
|
||||
// always sync to innerWidth/innerHeight so:
|
||||
// - window.width/.height match the canvas's CSS pixel size,
|
||||
// - MouseEvent.clientX/.clientY (CSS pixels) compare correctly
|
||||
// against any layout done with window.width/.height,
|
||||
// - the dispatch group count from window.width/8 covers the
|
||||
// canvas exactly.
|
||||
(void)w; (void)h;
|
||||
width = static_cast<std::uint32_t>(Crafter::DomEnv::domGetInnerWidth());
|
||||
height = static_cast<std::uint32_t>(Crafter::DomEnv::domGetInnerHeight());
|
||||
|
||||
// The handle passed to attach is just a non-zero token the JS side
|
||||
// includes back in every dispatcher call. We don't use it on the
|
||||
|
|
@ -1394,10 +1397,18 @@ void Window::SetDefaultCursor() {
|
|||
}
|
||||
|
||||
void Window::StartSync() {
|
||||
// Hand the loop to rAF. Returns immediately; the wasm `_start`
|
||||
// (main) finishes, and the runtime keeps the module alive while
|
||||
// the JS-side rAF chain ticks `__crafterDom_frame`.
|
||||
// Hand the loop to rAF, then exit the wasm via _Exit so wasi-libc
|
||||
// skips __wasm_call_dtors. If we let main return normally, _start
|
||||
// calls __wasm_call_dtors → static destructors fire (including
|
||||
// Window's own), then __wasi_proc_exit → wasm trap. Subsequent rAF
|
||||
// calls into the wasm would then trap too, killing rendering.
|
||||
// _Exit jumps straight to __wasi_proc_exit, which our runtime.js
|
||||
// catches via a thrown sentinel so the instance stays alive while
|
||||
// every static-allocated object (Window, UIRenderer, GPU buffers,
|
||||
// event listeners) remains untouched. Callers' code after
|
||||
// StartSync() never runs — match that contract on native too.
|
||||
Crafter::DomEnv::domStartFrameLoop();
|
||||
std::_Exit(0);
|
||||
}
|
||||
|
||||
void Window::StartUpdate() {
|
||||
|
|
@ -1421,10 +1432,25 @@ void Window::Update() {
|
|||
}
|
||||
|
||||
void Window::Render() {
|
||||
// V1: no rendering in DOM mode. Kept as a callable no-op so
|
||||
// existing cross-platform code paths (e.g. main loops calling
|
||||
// window.Render() before window.StartSync()) compile. V2 will
|
||||
// hang the WebGPU command-submit here.
|
||||
if (!open) return;
|
||||
Crafter::WebGPU::wgpuFrameBegin();
|
||||
for (RenderPass* p : passes) {
|
||||
if (p) p->Record(/*cmd*/ 0u, currentBuffer, *this);
|
||||
}
|
||||
Crafter::WebGPU::wgpuFrameEnd();
|
||||
}
|
||||
|
||||
WebGPUCommandEncoderRef Window::StartInit() {
|
||||
// DOM init: no command buffer needed — texture / buffer creation goes
|
||||
// through synchronous wgpu* imports. Return 0 as a placeholder; the
|
||||
// value is opaque to user code (auto-typed in HelloUI).
|
||||
Crafter::WebGPU::wgpuInit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Window::FinishInit() {
|
||||
// Nothing to submit in DOM mode; all init writes are queued at call
|
||||
// time via queue.writeBuffer / writeTexture.
|
||||
}
|
||||
|
||||
// ─── C exports the JS bridge calls back into ──────────────────────────
|
||||
|
|
@ -1437,6 +1463,7 @@ extern "C" {
|
|||
g_domWindow->onBeforeUpdate.Invoke();
|
||||
if (g_domWindow->updating) {
|
||||
g_domWindow->Update();
|
||||
g_domWindow->Render();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue