mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-22 01:57:44 +00:00
Update GameRenderer and TerritoryLayer for improved performance profiling; adjust minimum FPS and enhance layer profiling with new profileName method. Refactor rendering logic in Canvas and WebGL territory renderers .
This commit is contained in:
@@ -372,7 +372,7 @@ export class GameRenderer {
|
||||
|
||||
if (this.backlogTurns > 0) {
|
||||
const BASE_FPS = 60;
|
||||
const MIN_FPS = 10;
|
||||
const MIN_FPS = 30;
|
||||
const BACKLOG_MAX_TURNS = 50;
|
||||
|
||||
const scale = Math.min(1, this.backlogTurns / BACKLOG_MAX_TURNS);
|
||||
@@ -426,8 +426,11 @@ export class GameRenderer {
|
||||
|
||||
const layerStart = FrameProfiler.start();
|
||||
layer.renderLayer?.(this.context);
|
||||
const name = layer.constructor?.name ?? "UnknownLayer";
|
||||
FrameProfiler.end(name, layerStart);
|
||||
const profileName =
|
||||
(layer as any).profileName?.() ??
|
||||
layer.constructor?.name ??
|
||||
"UnknownLayer";
|
||||
FrameProfiler.end(profileName, layerStart);
|
||||
}
|
||||
handleTransformState(false, isTransformActive); // Ensure context is clean after rendering
|
||||
this.transformHandler.resetChanged();
|
||||
|
||||
@@ -4,4 +4,5 @@ export interface Layer {
|
||||
renderLayer?: (context: CanvasRenderingContext2D) => void;
|
||||
shouldTransform?: () => boolean;
|
||||
redraw?: () => void;
|
||||
profileName?: () => string;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,10 @@ import {
|
||||
import { TerritoryWebGLRenderer } from "./TerritoryWebGLRenderer";
|
||||
|
||||
export class TerritoryLayer implements Layer {
|
||||
profileName(): string {
|
||||
return "TerritoryLayer:renderLayer";
|
||||
}
|
||||
|
||||
private userSettings: UserSettings;
|
||||
private borderAnimTime = 0;
|
||||
|
||||
@@ -92,6 +96,7 @@ export class TerritoryLayer implements Layer {
|
||||
}
|
||||
|
||||
tick() {
|
||||
const tickProfile = FrameProfiler.start();
|
||||
if (this.game.inSpawnPhase()) {
|
||||
this.spawnHighlight();
|
||||
}
|
||||
@@ -188,6 +193,7 @@ export class TerritoryLayer implements Layer {
|
||||
if (currentMyPlayer !== this.lastMyPlayerSmallId) {
|
||||
this.redraw();
|
||||
}
|
||||
FrameProfiler.end("TerritoryLayer:tick", tickProfile);
|
||||
}
|
||||
|
||||
private spawnHighlight() {
|
||||
@@ -537,10 +543,17 @@ export class TerritoryLayer implements Layer {
|
||||
return;
|
||||
}
|
||||
let numToRender = Math.floor(this.tileToRenderQueue.size() / 10);
|
||||
if (numToRender === 0 || this.game.inSpawnPhase()) {
|
||||
if (
|
||||
numToRender === 0 ||
|
||||
this.game.inSpawnPhase() ||
|
||||
this.territoryRenderer.isWebGL()
|
||||
) {
|
||||
numToRender = this.tileToRenderQueue.size();
|
||||
}
|
||||
|
||||
const useNeighborPaint = !(this.territoryRenderer?.isWebGL() ?? false);
|
||||
const neighborsToPaint: TileRef[] = [];
|
||||
const mainSpan = FrameProfiler.start();
|
||||
while (numToRender > 0) {
|
||||
numToRender--;
|
||||
|
||||
@@ -551,9 +564,24 @@ export class TerritoryLayer implements Layer {
|
||||
|
||||
const tile = entry.tile;
|
||||
this.paintTerritory(tile);
|
||||
for (const neighbor of this.game.neighbors(tile)) {
|
||||
|
||||
if (useNeighborPaint) {
|
||||
for (const neighbor of this.game.neighbors(tile)) {
|
||||
neighborsToPaint.push(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
FrameProfiler.end("TerritoryLayer:renderTerritory.mainPaint", mainSpan);
|
||||
|
||||
if (useNeighborPaint && neighborsToPaint.length > 0) {
|
||||
const neighborSpan = FrameProfiler.start();
|
||||
for (const neighbor of neighborsToPaint) {
|
||||
this.paintTerritory(neighbor, true); //this is a misuse of the _Border parameter, making it a maybe stale border
|
||||
}
|
||||
FrameProfiler.end(
|
||||
"TerritoryLayer:renderTerritory.neighborPaint",
|
||||
neighborSpan,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ export class CanvasTerritoryRenderer implements TerritoryRendererStrategy {
|
||||
} else {
|
||||
this.clearTile(tile);
|
||||
}
|
||||
FrameProfiler.end("TerritoryLayer:paintTerritory.cpu", cpuStart);
|
||||
FrameProfiler.end("CanvasTerritoryRenderer:paintTile", cpuStart);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ export class CanvasTerritoryRenderer implements TerritoryRendererStrategy {
|
||||
150,
|
||||
);
|
||||
}
|
||||
FrameProfiler.end("TerritoryLayer:paintTerritory.cpu", cpuStart);
|
||||
FrameProfiler.end("CanvasTerritoryRenderer:paintTile", cpuStart);
|
||||
}
|
||||
|
||||
render(
|
||||
@@ -165,7 +165,7 @@ export class CanvasTerritoryRenderer implements TerritoryRendererStrategy {
|
||||
width,
|
||||
height,
|
||||
);
|
||||
FrameProfiler.end("TerritoryLayer:putImageData", putImageStart);
|
||||
FrameProfiler.end("CanvasTerritoryRenderer:putImageData", putImageStart);
|
||||
}
|
||||
|
||||
const drawCanvasStart = FrameProfiler.start();
|
||||
@@ -176,7 +176,7 @@ export class CanvasTerritoryRenderer implements TerritoryRendererStrategy {
|
||||
this.game.width(),
|
||||
this.game.height(),
|
||||
);
|
||||
FrameProfiler.end("TerritoryLayer:drawCanvas", drawCanvasStart);
|
||||
FrameProfiler.end("CanvasTerritoryRenderer:drawCanvas", drawCanvasStart);
|
||||
}
|
||||
|
||||
setAlternativeView(enabled: boolean): void {
|
||||
@@ -304,7 +304,7 @@ export class WebglTerritoryRenderer implements TerritoryRendererStrategy {
|
||||
): void {
|
||||
const webglRenderStart = FrameProfiler.start();
|
||||
this.renderer.render();
|
||||
FrameProfiler.end("TerritoryLayer:territoryWebGL.render", webglRenderStart);
|
||||
FrameProfiler.end("WebglTerritoryRenderer:render", webglRenderStart);
|
||||
|
||||
const drawCanvasStart = FrameProfiler.start();
|
||||
context.drawImage(
|
||||
@@ -314,10 +314,7 @@ export class WebglTerritoryRenderer implements TerritoryRendererStrategy {
|
||||
this.game.width(),
|
||||
this.game.height(),
|
||||
);
|
||||
FrameProfiler.end(
|
||||
"TerritoryLayer:territoryWebGL.drawImage",
|
||||
drawCanvasStart,
|
||||
);
|
||||
FrameProfiler.end("WebglTerritoryRenderer:drawImage", drawCanvasStart);
|
||||
}
|
||||
|
||||
setAlternativeView(enabled: boolean): void {
|
||||
|
||||
@@ -481,10 +481,13 @@ export class TerritoryWebGLRenderer {
|
||||
}
|
||||
const gl = this.gl;
|
||||
|
||||
const uploadSpan = FrameProfiler.start();
|
||||
const uploadStateSpan = FrameProfiler.start();
|
||||
this.uploadStateTexture();
|
||||
FrameProfiler.end("TerritoryWebGLRenderer:uploadState", uploadStateSpan);
|
||||
|
||||
const uploadBorderSpan = FrameProfiler.start();
|
||||
this.uploadBorderTexture();
|
||||
FrameProfiler.end("TerritoryWebGLRenderer:uploadState", uploadSpan);
|
||||
FrameProfiler.end("TerritoryWebGLRenderer:uploadBorder", uploadBorderSpan);
|
||||
|
||||
const renderSpan = FrameProfiler.start();
|
||||
gl.viewport(0, 0, this.canvas.width, this.canvas.height);
|
||||
@@ -524,12 +527,16 @@ export class TerritoryWebGLRenderer {
|
||||
FrameProfiler.end("TerritoryWebGLRenderer:draw", renderSpan);
|
||||
}
|
||||
|
||||
private uploadStateTexture() {
|
||||
if (!this.gl || !this.stateTexture) return;
|
||||
private uploadStateTexture(): { rows: number; bytes: number } {
|
||||
if (!this.gl || !this.stateTexture) return { rows: 0, bytes: 0 };
|
||||
const gl = this.gl;
|
||||
gl.activeTexture(gl.TEXTURE0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.stateTexture);
|
||||
|
||||
const bytesPerPixel = Uint16Array.BYTES_PER_ELEMENT;
|
||||
let rowsUploaded = 0;
|
||||
let bytesUploaded = 0;
|
||||
|
||||
if (this.needsFullUpload) {
|
||||
gl.texImage2D(
|
||||
gl.TEXTURE_2D,
|
||||
@@ -544,11 +551,13 @@ export class TerritoryWebGLRenderer {
|
||||
);
|
||||
this.needsFullUpload = false;
|
||||
this.dirtyRows.clear();
|
||||
return;
|
||||
rowsUploaded = this.canvas.height;
|
||||
bytesUploaded = this.canvas.width * this.canvas.height * bytesPerPixel;
|
||||
return { rows: rowsUploaded, bytes: bytesUploaded };
|
||||
}
|
||||
|
||||
if (this.dirtyRows.size === 0) {
|
||||
return;
|
||||
return { rows: 0, bytes: 0 };
|
||||
}
|
||||
|
||||
for (const [y, span] of this.dirtyRows) {
|
||||
@@ -566,16 +575,23 @@ export class TerritoryWebGLRenderer {
|
||||
gl.UNSIGNED_SHORT,
|
||||
rowSlice,
|
||||
);
|
||||
rowsUploaded++;
|
||||
bytesUploaded += width * bytesPerPixel;
|
||||
}
|
||||
this.dirtyRows.clear();
|
||||
return { rows: rowsUploaded, bytes: bytesUploaded };
|
||||
}
|
||||
|
||||
private uploadBorderTexture() {
|
||||
if (!this.gl || !this.borderColorTexture) return;
|
||||
private uploadBorderTexture(): { rows: number; bytes: number } {
|
||||
if (!this.gl || !this.borderColorTexture) return { rows: 0, bytes: 0 };
|
||||
const gl = this.gl;
|
||||
gl.activeTexture(gl.TEXTURE3);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.borderColorTexture);
|
||||
|
||||
const bytesPerPixel = Uint8Array.BYTES_PER_ELEMENT * 4; // RGBA8
|
||||
let rowsUploaded = 0;
|
||||
let bytesUploaded = 0;
|
||||
|
||||
if (this.borderNeedsFullUpload) {
|
||||
gl.texImage2D(
|
||||
gl.TEXTURE_2D,
|
||||
@@ -590,11 +606,13 @@ export class TerritoryWebGLRenderer {
|
||||
);
|
||||
this.borderNeedsFullUpload = false;
|
||||
this.borderDirtyRows.clear();
|
||||
return;
|
||||
rowsUploaded = this.canvas.height;
|
||||
bytesUploaded = this.canvas.width * this.canvas.height * bytesPerPixel;
|
||||
return { rows: rowsUploaded, bytes: bytesUploaded };
|
||||
}
|
||||
|
||||
if (this.borderDirtyRows.size === 0) {
|
||||
return;
|
||||
return { rows: 0, bytes: 0 };
|
||||
}
|
||||
|
||||
for (const [y, span] of this.borderDirtyRows) {
|
||||
@@ -615,8 +633,27 @@ export class TerritoryWebGLRenderer {
|
||||
gl.UNSIGNED_BYTE,
|
||||
rowSlice,
|
||||
);
|
||||
rowsUploaded++;
|
||||
bytesUploaded += width * bytesPerPixel;
|
||||
}
|
||||
this.borderDirtyRows.clear();
|
||||
return { rows: rowsUploaded, bytes: bytesUploaded };
|
||||
}
|
||||
|
||||
private labelUpload(
|
||||
base: string,
|
||||
metrics: { rows: number; bytes: number },
|
||||
): string {
|
||||
if (metrics.rows === 0 || metrics.bytes === 0) {
|
||||
return `${base} (skip)`;
|
||||
}
|
||||
const rowBucket =
|
||||
metrics.rows >= this.canvas.height
|
||||
? "full"
|
||||
: `${Math.ceil(metrics.rows / 50) * 50}`;
|
||||
const kb = Math.max(1, Math.round(metrics.bytes / 1024));
|
||||
const kbBucket = kb > 1024 ? `${Math.round(kb / 1024)}MB` : `${kb}KB`;
|
||||
return `${base} rows:${rowBucket} bytes:${kbBucket}`;
|
||||
}
|
||||
|
||||
private uploadPalette() {
|
||||
|
||||
Reference in New Issue
Block a user