From 2a348f21044cb32aa99b75763234dba5abf243b6 Mon Sep 17 00:00:00 2001 From: Matt Harding Date: Tue, 19 Nov 2024 21:38:46 +0000 Subject: [PATCH 1/4] Don't try to open a websocket when doing platform dev When we're developing the wasm4 web runtime itself, there's no w4 CLI websocket to connect to. But trying to connect anyway fights for the Vite websocket, which causes hangs on reload occasionally. --- runtimes/web/src/devkit.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/runtimes/web/src/devkit.ts b/runtimes/web/src/devkit.ts index ec135955..fed09ed9 100644 --- a/runtimes/web/src/devkit.ts +++ b/runtimes/web/src/devkit.ts @@ -1,4 +1,9 @@ import * as constants from "./constants"; -export const websocket = constants.GAMEDEV_MODE +// True if we're developers of the WASM4 runtime itself, and are running the runtime +// using `npm start` or `vite` etc. In this case, there's no wasm4 CLI web socket to +// connect to, but we might be fighting for the Vite websocket. +const PLATFORM_DEVELOPER_MODE = import.meta.env.MODE === "development"; + +export const websocket = constants.GAMEDEV_MODE && !PLATFORM_DEVELOPER_MODE ? new WebSocket((location.protocol == "https:" ? "wss" : "ws") + "://" + location.host) : null; From b18afb02e2ba99831fd028c609bc46fc2dd285ba Mon Sep 17 00:00:00 2001 From: Matt Harding Date: Fri, 20 Dec 2024 12:05:37 +0000 Subject: [PATCH 2/4] Improve devtools FPS counter Frame timings are now averaged in a mathematically sound way, and with more samples. --- devtools/web/src/devtools-manager.ts | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/devtools/web/src/devtools-manager.ts b/devtools/web/src/devtools-manager.ts index ebb22ba8..2e91ee46 100644 --- a/devtools/web/src/devtools-manager.ts +++ b/devtools/web/src/devtools-manager.ts @@ -47,6 +47,7 @@ interface RuntimeInfo { wasmBufferByteLen: number; } +const INTER_FRAME_TIME_BUFFER_SIZE = 30; export class DevtoolsManager { /** * @private @@ -58,17 +59,19 @@ export class DevtoolsManager { */ private _bufferedData = new BufferedRuntimeData(); - private _fpsBuffer : number[] = [0,0,0,0,0,0,0,0,0,0]; + private _interFrameTimeBuffer : number[] = new Array(INTER_FRAME_TIME_BUFFER_SIZE).fill(1000/60); private _fpsBufferIdx = 0; - //calculate an average FPS for the last 10 frames private _calcAvgFPS = () => { - let sum = this._fpsBuffer[0]; - for (let i = 1; i < 10; i++) - sum += this._fpsBuffer[i]; - return Math.floor(sum / 10); + let totalFramesTimeMs = this._interFrameTimeBuffer[0]; + for (let i = 1; i < INTER_FRAME_TIME_BUFFER_SIZE; i++) + totalFramesTimeMs += this._interFrameTimeBuffer[i]; + return Math.round(INTER_FRAME_TIME_BUFFER_SIZE * 1000 / totalFramesTimeMs); } private _nextFPSBufferIdx = () => { - (this._fpsBufferIdx == 9) ? this._fpsBufferIdx = 0 : this._fpsBufferIdx++; + this._fpsBufferIdx++; + if (this._fpsBufferIdx == INTER_FRAME_TIME_BUFFER_SIZE) { + this._fpsBufferIdx = 0; + } return this._fpsBufferIdx; } @@ -77,10 +80,10 @@ export class DevtoolsManager { */ updateCompleted = ( runtimeInfo: Info, - deltaFrame: number + interFrameTime: number ) => { if (this._enabled) { - this._fpsBuffer[this._nextFPSBufferIdx()] = 1_000 / deltaFrame; + this._interFrameTimeBuffer[this._nextFPSBufferIdx()] = interFrameTime; this._bufferedData.update(runtimeInfo.data); this._notifyUpdateCompleted( runtimeInfo.data, From 1e807898dd3bc8109107f4e58a4638092e8b6eef Mon Sep 17 00:00:00 2001 From: Matt Harding Date: Mon, 11 Nov 2024 12:56:46 +0000 Subject: [PATCH 3/4] Fix web devtools palette issue with most significant byte On Wasm-4, palette colours are in the order `0xAARRGGBB`, where `A` represents unused/alpha. On the web/css however, the order is `#RRGGBBAA`. This meant that previously, if the most significant byte wasn't 0, the colours in the devtool's palette viewer were garbled. --- devtools/web/src/components/palette/palette.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devtools/web/src/components/palette/palette.ts b/devtools/web/src/components/palette/palette.ts index b81b3fb1..3f7d5712 100644 --- a/devtools/web/src/components/palette/palette.ts +++ b/devtools/web/src/components/palette/palette.ts @@ -34,7 +34,7 @@ export class Wasm4Palette extends LitElement { ${this.heading && html`

${this.heading}

`}
${this.palette.slice(0, 4).map((color) => { - const colorHex = formatColor(color); + const colorHex = formatColor(color & 0xffffff); const shouldInvertColor = ((color & 0xff) + ((color >> 8) & 0xff) + (color >> 16)) / 3 > 128; From 77d21108f12e3439c45578e9750cd43f6f7181b5 Mon Sep 17 00:00:00 2001 From: Matt Harding Date: Fri, 20 Dec 2024 23:17:50 +0000 Subject: [PATCH 4/4] Reorganise and rename config constants etc --- runtimes/web/src/config-constants.ts | 7 +++++++ runtimes/web/src/constants.ts | 1 - runtimes/web/src/devkit.ts | 11 +++++------ runtimes/web/src/runtime.ts | 7 ++++--- runtimes/web/src/ui/app.ts | 10 +++++----- 5 files changed, 21 insertions(+), 15 deletions(-) create mode 100644 runtimes/web/src/config-constants.ts diff --git a/runtimes/web/src/config-constants.ts b/runtimes/web/src/config-constants.ts new file mode 100644 index 00000000..d8c15bc3 --- /dev/null +++ b/runtimes/web/src/config-constants.ts @@ -0,0 +1,7 @@ +/** True if the runtime is in Game Developer mode, with access to the devtools window. */ +// WASM4_GAMEDEV_MODE is defined in vite.config.ts +export const GAMEDEV_MODE = WASM4_GAMEDEV_MODE; + +/** True if we're developers of the WASM4 runtime itself, and are running the runtime + using `npm start` or `vite` etc. */ +export const PLATFORM_DEVELOPER_MODE = import.meta.env.MODE === "development"; \ No newline at end of file diff --git a/runtimes/web/src/constants.ts b/runtimes/web/src/constants.ts index c4c2b93f..5ae58046 100644 --- a/runtimes/web/src/constants.ts +++ b/runtimes/web/src/constants.ts @@ -1,4 +1,3 @@ -export const GAMEDEV_MODE = WASM4_GAMEDEV_MODE; export const WIDTH = 160; export const HEIGHT = 160; diff --git a/runtimes/web/src/devkit.ts b/runtimes/web/src/devkit.ts index fed09ed9..bc39d3de 100644 --- a/runtimes/web/src/devkit.ts +++ b/runtimes/web/src/devkit.ts @@ -1,9 +1,8 @@ -import * as constants from "./constants"; -// True if we're developers of the WASM4 runtime itself, and are running the runtime -// using `npm start` or `vite` etc. In this case, there's no wasm4 CLI web socket to -// connect to, but we might be fighting for the Vite websocket. -const PLATFORM_DEVELOPER_MODE = import.meta.env.MODE === "development"; +import { GAMEDEV_MODE, PLATFORM_DEVELOPER_MODE } from "./config-constants"; -export const websocket = constants.GAMEDEV_MODE && !PLATFORM_DEVELOPER_MODE +// The w4 CLI web socket only exists for gamedev mode. +// But if we're running `npm start` or `vite` there is no w4 CLI to connect to, +// but there is a vite websocket we may be fighting for, causing issues with vite. +export const cli_websocket = GAMEDEV_MODE && !PLATFORM_DEVELOPER_MODE ? new WebSocket((location.protocol == "https:" ? "wss" : "ws") + "://" + location.host) : null; diff --git a/runtimes/web/src/runtime.ts b/runtimes/web/src/runtime.ts index 515cc151..dd3ceec6 100644 --- a/runtimes/web/src/runtime.ts +++ b/runtimes/web/src/runtime.ts @@ -5,6 +5,7 @@ import { Framebuffer } from "./framebuffer"; import { WebGLCompositor } from "./compositor"; import * as devkit from "./devkit"; import { wasmPatchExportGlobals } from "./wasm-patch"; +import * as configConstants from "./config-constants"; export class Runtime { canvas: HTMLCanvasElement; @@ -120,7 +121,7 @@ export class Runtime { this.wasm = null; if (wasmBuffer.byteLength > limit) { - if (constants.GAMEDEV_MODE) { + if (configConstants.GAMEDEV_MODE) { if (!this.warnedFileSize) { this.warnedFileSize = true; this.print(`Warning: Cart is larger than ${limit} bytes. Ensure the release build of your cart is small enough to be bundled.`); @@ -262,8 +263,8 @@ export class Runtime { } printToServer (str: string) { - if (devkit.websocket != null && devkit.websocket.readyState == 1) { - devkit.websocket.send(str); + if (devkit.cli_websocket != null && devkit.cli_websocket.readyState == 1) { + devkit.cli_websocket.send(str); } } diff --git a/runtimes/web/src/ui/app.ts b/runtimes/web/src/ui/app.ts index 0b3d1274..132771bd 100644 --- a/runtimes/web/src/ui/app.ts +++ b/runtimes/web/src/ui/app.ts @@ -2,6 +2,7 @@ import { LitElement, html, css } from "lit"; import { customElement, state, query } from 'lit/decorators.js'; import * as constants from "../constants"; +import * as configConstants from "../config-constants"; import * as devkit from "../devkit"; import * as utils from "./utils"; import * as z85 from "../z85"; @@ -141,7 +142,7 @@ export class App extends LitElement { // Nothing }, }; - if (constants.GAMEDEV_MODE) { + if (configConstants.GAMEDEV_MODE) { devtoolsManager = await import('@wasm4/web-devtools').then(({ DevtoolsManager}) => new DevtoolsManager()); } @@ -153,8 +154,8 @@ export class App extends LitElement { this.copyNetplayLink(); } - if (constants.GAMEDEV_MODE) { - devkit.websocket?.addEventListener("message", async event => { + if (configConstants.GAMEDEV_MODE) { + devkit.cli_websocket?.addEventListener("message", async event => { switch (event.data) { case "reload": this.resetCart(await loadCartWasm()); @@ -481,8 +482,7 @@ export class App extends LitElement { runtime.composite(); - if (constants.GAMEDEV_MODE) { - // FIXED(2023-12-13): Pass the correct FPS for display + if (configConstants.GAMEDEV_MODE) { devtoolsManager.updateCompleted(runtime, timeFrameStart - lastTimeFrameStart); lastTimeFrameStart = timeFrameStart; }