mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-11 05:58:29 +00:00
Use dirty flags to coalesce tile updates in SAB ring
- Extend SharedTileRing to include a shared dirtyFlags buffer alongside header and data - Pass shared dirty buffer through WorkerClient/WorkerMessages and initialize views in Worker.worker - In SAB mode, mark tiles dirty via Atomics.compareExchange before enqueuing to ensure each tile is queued at most once until processed - On the main thread, clear dirty flags when draining the ring and build packedTileUpdates from distinct tile refs - Keep non-SAB behaviour unchanged while reducing ring pressure and making overflows reflect true backlog, not duplicate updates
This commit is contained in:
@@ -192,6 +192,8 @@ async function createClientGame(
|
||||
|
||||
let sharedTileRingBuffers: SharedTileRingBuffers | undefined;
|
||||
let sharedTileRingViews: SharedTileRingViews | null = null;
|
||||
let sharedDirtyBuffer: SharedArrayBuffer | undefined;
|
||||
let sharedDirtyFlags: Uint8Array | null = null;
|
||||
const isIsolated =
|
||||
typeof (globalThis as any).crossOriginIsolated === "boolean"
|
||||
? (globalThis as any).crossOriginIsolated === true
|
||||
@@ -210,8 +212,14 @@ async function createClientGame(
|
||||
// Capacity is number of tile updates that can be queued.
|
||||
// This is a compromise between memory usage and backlog tolerance.
|
||||
const TILE_RING_CAPACITY = 262144;
|
||||
sharedTileRingBuffers = createSharedTileRingBuffers(TILE_RING_CAPACITY);
|
||||
const numTiles = gameMap.gameMap.width() * gameMap.gameMap.height();
|
||||
sharedTileRingBuffers = createSharedTileRingBuffers(
|
||||
TILE_RING_CAPACITY,
|
||||
numTiles,
|
||||
);
|
||||
sharedTileRingViews = createSharedTileRingViews(sharedTileRingBuffers);
|
||||
sharedDirtyBuffer = sharedTileRingBuffers.dirty;
|
||||
sharedDirtyFlags = sharedTileRingViews.dirtyFlags;
|
||||
}
|
||||
|
||||
const worker = new WorkerClient(
|
||||
@@ -219,6 +227,7 @@ async function createClientGame(
|
||||
lobbyConfig.clientID,
|
||||
sharedTileRingBuffers,
|
||||
sharedStateBuffer,
|
||||
sharedDirtyBuffer,
|
||||
);
|
||||
await worker.initialize();
|
||||
const gameView = new GameView(
|
||||
@@ -247,6 +256,7 @@ async function createClientGame(
|
||||
worker,
|
||||
gameView,
|
||||
sharedTileRingViews,
|
||||
sharedDirtyFlags,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -278,6 +288,7 @@ export class ClientGameRunner {
|
||||
private pendingStart = 0;
|
||||
private isProcessingUpdates = false;
|
||||
private tileRingViews: SharedTileRingViews | null;
|
||||
private dirtyFlags: Uint8Array | null;
|
||||
|
||||
constructor(
|
||||
private lobby: LobbyConfig,
|
||||
@@ -288,9 +299,11 @@ export class ClientGameRunner {
|
||||
private worker: WorkerClient,
|
||||
private gameView: GameView,
|
||||
tileRingViews: SharedTileRingViews | null,
|
||||
dirtyFlags: Uint8Array | null,
|
||||
) {
|
||||
this.lastMessageTime = Date.now();
|
||||
this.tileRingViews = tileRingViews;
|
||||
this.dirtyFlags = dirtyFlags;
|
||||
}
|
||||
|
||||
private saveGame(update: WinUpdate) {
|
||||
@@ -698,22 +711,31 @@ export class ClientGameRunner {
|
||||
);
|
||||
const drainTime = performance.now() - drainStart;
|
||||
|
||||
// Deduplicate tile refs for this render slice
|
||||
const uniqueTiles = new Set<TileRef>();
|
||||
for (const ref of tileRefs) {
|
||||
uniqueTiles.add(ref);
|
||||
}
|
||||
|
||||
// Calculate ring buffer utilization and overflow
|
||||
const TILE_RING_CAPACITY = 262144;
|
||||
const utilization = (tileRefs.length / TILE_RING_CAPACITY) * 100;
|
||||
const utilization = (uniqueTiles.size / TILE_RING_CAPACITY) * 100;
|
||||
const overflow = Atomics.load(
|
||||
this.tileRingViews.header,
|
||||
TILE_RING_HEADER_OVERFLOW,
|
||||
);
|
||||
|
||||
tileMetrics = {
|
||||
count: tileRefs.length,
|
||||
count: uniqueTiles.size,
|
||||
utilization,
|
||||
overflow,
|
||||
drainTime,
|
||||
};
|
||||
|
||||
for (const ref of tileRefs) {
|
||||
for (const ref of uniqueTiles) {
|
||||
if (this.dirtyFlags) {
|
||||
Atomics.store(this.dirtyFlags, ref, 0);
|
||||
}
|
||||
combinedPackedTileUpdates.push(BigInt(ref));
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user