backtrack
This commit is contained in:
@ -57,16 +57,6 @@ export class FakeShader {
|
|||||||
private offscreenCtx: OffscreenCanvasRenderingContext2D | null = null;
|
private offscreenCtx: OffscreenCanvasRenderingContext2D | null = null;
|
||||||
private useOffscreen: boolean = false;
|
private useOffscreen: boolean = false;
|
||||||
|
|
||||||
// Adaptive resolution scaling
|
|
||||||
private adaptiveCanvas: HTMLCanvasElement;
|
|
||||||
private adaptiveCtx: CanvasRenderingContext2D;
|
|
||||||
private currentScale: number = 1.0;
|
|
||||||
private targetRenderTime: number = 16; // Target 60 FPS
|
|
||||||
private performanceHistory: number[] = [];
|
|
||||||
private lastScaleAdjustment: number = 0;
|
|
||||||
private minScale: number = 0.25;
|
|
||||||
private maxScale: number = 1.0;
|
|
||||||
private renderStartTime: number = 0;
|
|
||||||
|
|
||||||
// Multi-worker state
|
// Multi-worker state
|
||||||
private tileResults: Map<number, ImageData> = new Map();
|
private tileResults: Map<number, ImageData> = new Map();
|
||||||
@ -108,8 +98,6 @@ export class FakeShader {
|
|||||||
this.ctx = canvas.getContext('2d')!;
|
this.ctx = canvas.getContext('2d')!;
|
||||||
this.code = code;
|
this.code = code;
|
||||||
|
|
||||||
// Initialize adaptive resolution canvas
|
|
||||||
this.initializeAdaptiveCanvas();
|
|
||||||
|
|
||||||
// Initialize offscreen canvas if supported
|
// Initialize offscreen canvas if supported
|
||||||
this.initializeOffscreenCanvas();
|
this.initializeOffscreenCanvas();
|
||||||
@ -130,21 +118,6 @@ export class FakeShader {
|
|||||||
this.compile();
|
this.compile();
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeAdaptiveCanvas(): void {
|
|
||||||
this.adaptiveCanvas = document.createElement('canvas');
|
|
||||||
this.adaptiveCtx = this.adaptiveCanvas.getContext('2d')!;
|
|
||||||
this.updateAdaptiveCanvasSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
private updateAdaptiveCanvasSize(): void {
|
|
||||||
const scaledWidth = Math.floor(this.canvas.width * this.currentScale);
|
|
||||||
const scaledHeight = Math.floor(this.canvas.height * this.currentScale);
|
|
||||||
|
|
||||||
if (this.adaptiveCanvas.width !== scaledWidth || this.adaptiveCanvas.height !== scaledHeight) {
|
|
||||||
this.adaptiveCanvas.width = scaledWidth;
|
|
||||||
this.adaptiveCanvas.height = scaledHeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private initializeOffscreenCanvas(): void {
|
private initializeOffscreenCanvas(): void {
|
||||||
if (typeof OffscreenCanvas !== 'undefined') {
|
if (typeof OffscreenCanvas !== 'undefined') {
|
||||||
@ -186,14 +159,8 @@ export class FakeShader {
|
|||||||
// Single worker mode
|
// Single worker mode
|
||||||
this.isRendering = false;
|
this.isRendering = false;
|
||||||
if (response.success && response.imageData) {
|
if (response.success && response.imageData) {
|
||||||
// Put ImageData on adaptive resolution canvas
|
// Put ImageData directly on main canvas
|
||||||
this.adaptiveCtx.putImageData(response.imageData, 0, 0);
|
this.ctx.putImageData(response.imageData, 0, 0);
|
||||||
|
|
||||||
// Upscale to main canvas with proper interpolation
|
|
||||||
this.upscaleToMainCanvas();
|
|
||||||
|
|
||||||
// Monitor performance and adjust scale
|
|
||||||
this.updatePerformanceMetrics();
|
|
||||||
} else {
|
} else {
|
||||||
console.error('Render failed:', response.error);
|
console.error('Render failed:', response.error);
|
||||||
this.fillBlack();
|
this.fillBlack();
|
||||||
@ -244,11 +211,6 @@ export class FakeShader {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update adaptive canvas size based on current scale
|
|
||||||
this.updateAdaptiveCanvasSize();
|
|
||||||
|
|
||||||
// Start performance timing
|
|
||||||
this.renderStartTime = performance.now();
|
|
||||||
|
|
||||||
this.isRendering = true;
|
this.isRendering = true;
|
||||||
this.currentRenderID = id;
|
this.currentRenderID = id;
|
||||||
@ -263,27 +225,24 @@ export class FakeShader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private renderWithSingleWorker(id: string, currentTime: number): void {
|
private renderWithSingleWorker(id: string, currentTime: number): void {
|
||||||
const scaledMouseX = this.mouseX * this.currentScale;
|
|
||||||
const scaledMouseY = this.mouseY * this.currentScale;
|
|
||||||
|
|
||||||
this.worker.postMessage({
|
this.worker.postMessage({
|
||||||
id,
|
id,
|
||||||
type: 'render',
|
type: 'render',
|
||||||
width: this.adaptiveCanvas.width,
|
width: this.canvas.width,
|
||||||
height: this.adaptiveCanvas.height,
|
height: this.canvas.height,
|
||||||
time: currentTime,
|
time: currentTime,
|
||||||
renderMode: this.renderMode,
|
renderMode: this.renderMode,
|
||||||
mouseX: scaledMouseX,
|
mouseX: this.mouseX,
|
||||||
mouseY: scaledMouseY,
|
mouseY: this.mouseY,
|
||||||
mousePressed: this.mousePressed,
|
mousePressed: this.mousePressed,
|
||||||
mouseVX: this.mouseVX * this.currentScale,
|
mouseVX: this.mouseVX,
|
||||||
mouseVY: this.mouseVY * this.currentScale,
|
mouseVY: this.mouseVY,
|
||||||
mouseClickTime: this.mouseClickTime,
|
mouseClickTime: this.mouseClickTime,
|
||||||
touchCount: this.touchCount,
|
touchCount: this.touchCount,
|
||||||
touch0X: this.touch0X * this.currentScale,
|
touch0X: this.touch0X,
|
||||||
touch0Y: this.touch0Y * this.currentScale,
|
touch0Y: this.touch0Y,
|
||||||
touch1X: this.touch1X * this.currentScale,
|
touch1X: this.touch1X,
|
||||||
touch1Y: this.touch1Y * this.currentScale,
|
touch1Y: this.touch1Y,
|
||||||
pinchScale: this.pinchScale,
|
pinchScale: this.pinchScale,
|
||||||
pinchRotation: this.pinchRotation,
|
pinchRotation: this.pinchRotation,
|
||||||
accelX: this.accelX,
|
accelX: this.accelX,
|
||||||
@ -305,8 +264,8 @@ export class FakeShader {
|
|||||||
this.tilesCompleted = 0;
|
this.tilesCompleted = 0;
|
||||||
this.totalTiles = this.workerCount;
|
this.totalTiles = this.workerCount;
|
||||||
|
|
||||||
const width = this.adaptiveCanvas.width;
|
const width = this.canvas.width;
|
||||||
const height = this.adaptiveCanvas.height;
|
const height = this.canvas.height;
|
||||||
const tileHeight = Math.ceil(height / this.workerCount);
|
const tileHeight = Math.ceil(height / this.workerCount);
|
||||||
|
|
||||||
// Distribute tiles to workers
|
// Distribute tiles to workers
|
||||||
@ -316,9 +275,6 @@ export class FakeShader {
|
|||||||
|
|
||||||
if (startY >= height) return; // Skip if tile is outside canvas
|
if (startY >= height) return; // Skip if tile is outside canvas
|
||||||
|
|
||||||
const scaledMouseX = this.mouseX * this.currentScale;
|
|
||||||
const scaledMouseY = this.mouseY * this.currentScale;
|
|
||||||
|
|
||||||
worker.postMessage({
|
worker.postMessage({
|
||||||
id: `${id}_tile_${index}`,
|
id: `${id}_tile_${index}`,
|
||||||
type: 'render',
|
type: 'render',
|
||||||
@ -328,17 +284,17 @@ export class FakeShader {
|
|||||||
startY: startY,
|
startY: startY,
|
||||||
time: currentTime,
|
time: currentTime,
|
||||||
renderMode: this.renderMode,
|
renderMode: this.renderMode,
|
||||||
mouseX: scaledMouseX,
|
mouseX: this.mouseX,
|
||||||
mouseY: scaledMouseY,
|
mouseY: this.mouseY,
|
||||||
mousePressed: this.mousePressed,
|
mousePressed: this.mousePressed,
|
||||||
mouseVX: this.mouseVX * this.currentScale,
|
mouseVX: this.mouseVX,
|
||||||
mouseVY: this.mouseVY * this.currentScale,
|
mouseVY: this.mouseVY,
|
||||||
mouseClickTime: this.mouseClickTime,
|
mouseClickTime: this.mouseClickTime,
|
||||||
touchCount: this.touchCount,
|
touchCount: this.touchCount,
|
||||||
touch0X: this.touch0X * this.currentScale,
|
touch0X: this.touch0X,
|
||||||
touch0Y: this.touch0Y * this.currentScale,
|
touch0Y: this.touch0Y,
|
||||||
touch1X: this.touch1X * this.currentScale,
|
touch1X: this.touch1X,
|
||||||
touch1Y: this.touch1Y * this.currentScale,
|
touch1Y: this.touch1Y,
|
||||||
pinchScale: this.pinchScale,
|
pinchScale: this.pinchScale,
|
||||||
pinchRotation: this.pinchRotation,
|
pinchRotation: this.pinchRotation,
|
||||||
accelX: this.accelX,
|
accelX: this.accelX,
|
||||||
@ -480,19 +436,19 @@ export class FakeShader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private compositeTiles(): void {
|
private compositeTiles(): void {
|
||||||
const width = this.adaptiveCanvas.width;
|
const width = this.canvas.width;
|
||||||
const height = this.adaptiveCanvas.height;
|
const height = this.canvas.height;
|
||||||
const tileHeight = Math.ceil(height / this.workerCount);
|
const tileHeight = Math.ceil(height / this.workerCount);
|
||||||
|
|
||||||
// Clear adaptive canvas
|
// Clear main canvas
|
||||||
this.adaptiveCtx.clearRect(0, 0, width, height);
|
this.ctx.clearRect(0, 0, width, height);
|
||||||
|
|
||||||
// Composite all tiles
|
// Composite all tiles directly on main canvas
|
||||||
for (let i = 0; i < this.workerCount; i++) {
|
for (let i = 0; i < this.workerCount; i++) {
|
||||||
const tileData = this.tileResults.get(i);
|
const tileData = this.tileResults.get(i);
|
||||||
if (tileData) {
|
if (tileData) {
|
||||||
const startY = i * tileHeight;
|
const startY = i * tileHeight;
|
||||||
this.adaptiveCtx.putImageData(tileData, 0, startY);
|
this.ctx.putImageData(tileData, 0, startY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -502,12 +458,6 @@ export class FakeShader {
|
|||||||
// Mark rendering as complete
|
// Mark rendering as complete
|
||||||
this.isRendering = false;
|
this.isRendering = false;
|
||||||
|
|
||||||
// Upscale to main canvas
|
|
||||||
this.upscaleToMainCanvas();
|
|
||||||
|
|
||||||
// Monitor performance
|
|
||||||
this.updatePerformanceMetrics();
|
|
||||||
|
|
||||||
// Process pending renders
|
// Process pending renders
|
||||||
if (this.pendingRenders.length > 0) {
|
if (this.pendingRenders.length > 0) {
|
||||||
this.pendingRenders.shift();
|
this.pendingRenders.shift();
|
||||||
@ -519,81 +469,6 @@ export class FakeShader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private upscaleToMainCanvas(): void {
|
|
||||||
// Clear main canvas
|
|
||||||
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
||||||
|
|
||||||
// Set interpolation based on scale
|
|
||||||
if (this.currentScale < 0.5) {
|
|
||||||
// Use smooth interpolation for heavily downscaled content
|
|
||||||
this.ctx.imageSmoothingEnabled = true;
|
|
||||||
this.ctx.imageSmoothingQuality = 'high';
|
|
||||||
} else {
|
|
||||||
// Use pixel-perfect scaling for minimal downscaling
|
|
||||||
this.ctx.imageSmoothingEnabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw scaled content to main canvas
|
|
||||||
this.ctx.drawImage(
|
|
||||||
this.adaptiveCanvas,
|
|
||||||
0, 0, this.adaptiveCanvas.width, this.adaptiveCanvas.height,
|
|
||||||
0, 0, this.canvas.width, this.canvas.height
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private updatePerformanceMetrics(): void {
|
|
||||||
const renderTime = performance.now() - this.renderStartTime;
|
|
||||||
|
|
||||||
// Add to performance history
|
|
||||||
this.performanceHistory.push(renderTime);
|
|
||||||
if (this.performanceHistory.length > 10) {
|
|
||||||
this.performanceHistory.shift(); // Keep only last 10 measurements
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adjust scale if we have enough data and enough time has passed
|
|
||||||
const now = performance.now();
|
|
||||||
if (this.performanceHistory.length >= 3 && now - this.lastScaleAdjustment > 500) {
|
|
||||||
this.adjustRenderScale();
|
|
||||||
this.lastScaleAdjustment = now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private adjustRenderScale(): void {
|
|
||||||
// Calculate average render time from recent history
|
|
||||||
const avgRenderTime = this.performanceHistory.reduce((a, b) => a + b, 0) / this.performanceHistory.length;
|
|
||||||
|
|
||||||
const tolerance = 2; // 2ms tolerance
|
|
||||||
|
|
||||||
if (avgRenderTime > this.targetRenderTime + tolerance) {
|
|
||||||
// Too slow - scale down
|
|
||||||
const newScale = Math.max(this.minScale, this.currentScale * 0.85);
|
|
||||||
if (newScale !== this.currentScale) {
|
|
||||||
this.currentScale = newScale;
|
|
||||||
console.log(`Scaling down to ${(this.currentScale * 100).toFixed(0)}% (${avgRenderTime.toFixed(1)}ms avg)`);
|
|
||||||
}
|
|
||||||
} else if (avgRenderTime < this.targetRenderTime - tolerance && this.currentScale < this.maxScale) {
|
|
||||||
// Fast enough - try scaling up
|
|
||||||
const newScale = Math.min(this.maxScale, this.currentScale * 1.1);
|
|
||||||
if (newScale !== this.currentScale) {
|
|
||||||
this.currentScale = newScale;
|
|
||||||
console.log(`Scaling up to ${(this.currentScale * 100).toFixed(0)}% (${avgRenderTime.toFixed(1)}ms avg)`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setAdaptiveQuality(enabled: boolean, targetFPS: number = 60): void {
|
|
||||||
if (enabled) {
|
|
||||||
this.targetRenderTime = 1000 / targetFPS;
|
|
||||||
this.currentScale = 1.0;
|
|
||||||
this.performanceHistory = [];
|
|
||||||
} else {
|
|
||||||
this.currentScale = 1.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getCurrentScale(): number {
|
|
||||||
return this.currentScale;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simplified method - kept for backward compatibility but always uses all cores
|
// Simplified method - kept for backward compatibility but always uses all cores
|
||||||
setMultiWorkerMode(enabled: boolean, workerCount?: number): void {
|
setMultiWorkerMode(enabled: boolean, workerCount?: number): void {
|
||||||
|
|||||||
Reference in New Issue
Block a user