Skip to content

Commit

Permalink
Pick up Mini vMac blitting optimizations
Browse files Browse the repository at this point in the history
Picks up mihaip/minivmac@9742b0e
and takes into account the dirty rect when deciding what to copy into
the canvas.

Updates #71
  • Loading branch information
mihaip committed Jan 14, 2023
1 parent ec0fbda commit fcb93e0
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 20 deletions.
2 changes: 1 addition & 1 deletion minivmac
Submodule minivmac updated 1 files
+45 −18 src/OSGLUESC.c
8 changes: 8 additions & 0 deletions src/emulator/emulator-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,21 @@ export type EmulatorWorkerVideoBlit =
| EmulatorWorkerSharedMemoryVideoBlit
| EmulatorWorkerFallbackVideoBlit;

export type EmulatorWorkerVideoBlitRect = {
top: number;
left: number;
bottom: number;
right: number;
};
export type EmulatorWorkerSharedMemoryVideoBlit = {
type: "shared-memory";
rect?: EmulatorWorkerVideoBlitRect;
};

export type EmulatorWorkerFallbackVideoBlit = {
type: "fallback";
data: Uint8Array;
rect?: EmulatorWorkerVideoBlitRect;
};

export type EmulatorWorkerInputConfig =
Expand Down
47 changes: 46 additions & 1 deletion src/emulator/emulator-ui-video.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type {
EmulatorWorkerFallbackVideoConfig,
EmulatorWorkerSharedMemoryVideoConfig,
EmulatorWorkerVideoBlit,
EmulatorWorkerVideoBlitRect,
EmulatorWorkerVideoConfig,
} from "./emulator-common";
import type {EmulatorConfig} from "./emulator-ui";
Expand All @@ -13,6 +14,7 @@ export interface EmulatorVideo {
workerConfig(): EmulatorWorkerVideoConfig;
blit(blitData: EmulatorWorkerVideoBlit): void;
imageData(): Uint8Array | undefined;
consumeBlitRect(): EmulatorWorkerVideoBlitRect | undefined;
}

export class SharedMemoryEmulatorVideo implements EmulatorVideo {
Expand All @@ -21,6 +23,7 @@ export class SharedMemoryEmulatorVideo implements EmulatorVideo {
#screenBufferView: Uint8Array;
#videoModeBuffer = new SharedArrayBuffer(VIDEO_MODE_BUFFER_SIZE * 4);
#videoModeBufferView = new Int32Array(this.#videoModeBuffer);
#lastBlitRect?: EmulatorWorkerVideoBlitRect;

constructor(config: EmulatorConfig) {
this.#config = config;
Expand All @@ -42,18 +45,35 @@ export class SharedMemoryEmulatorVideo implements EmulatorVideo {
}

blit(blitData: EmulatorWorkerVideoBlit) {
// No-op, we get updates via the SharedArrayBuffer
// Don't need to do anything with the data, it's automatically read in
// via the SharedArrayBuffer.
const {rect} = blitData;
if (!rect) {
return;
}
if (!this.#lastBlitRect) {
this.#lastBlitRect = rect;
} else {
unionBlitRect(this.#lastBlitRect, rect);
}
}

imageData(): Uint8Array {
const bufferSize = this.#videoModeBufferView[0];
return this.#screenBufferView.subarray(0, bufferSize);
}

consumeBlitRect(): EmulatorWorkerVideoBlitRect | undefined {
const rect = this.#lastBlitRect;
this.#lastBlitRect = undefined;
return rect;
}
}

export class FallbackEmulatorVideo implements EmulatorVideo {
#config: EmulatorConfig;
#lastBlitData?: EmulatorWorkerFallbackVideoBlit;
#lastBlitRect?: EmulatorWorkerVideoBlitRect;

constructor(config: EmulatorConfig) {
this.#config = config;
Expand All @@ -69,9 +89,34 @@ export class FallbackEmulatorVideo implements EmulatorVideo {
}

this.#lastBlitData = blitData;
const {rect} = blitData;
if (!rect) {
return;
}
if (!this.#lastBlitRect) {
this.#lastBlitRect = rect;
} else {
unionBlitRect(this.#lastBlitRect, rect);
}
}

imageData(): Uint8Array | undefined {
return this.#lastBlitData?.data;
}

consumeBlitRect(): EmulatorWorkerVideoBlitRect | undefined {
const rect = this.#lastBlitRect;
this.#lastBlitRect = undefined;
return rect;
}
}

function unionBlitRect(
lastRect: EmulatorWorkerVideoBlitRect,
rect: EmulatorWorkerVideoBlitRect
) {
lastRect.top = Math.min(lastRect.top, rect.top);
lastRect.left = Math.min(lastRect.left, rect.left);
lastRect.bottom = Math.max(lastRect.bottom, rect.bottom);
lastRect.right = Math.max(lastRect.right, rect.right);
}
15 changes: 14 additions & 1 deletion src/emulator/emulator-ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,20 @@ export class Emulator {
return;
}
this.#screenImageData.data.set(imageData);
this.#screenCanvasContext.putImageData(this.#screenImageData, 0, 0);
const dirtyRect = this.#video.consumeBlitRect();
if (dirtyRect) {
this.#screenCanvasContext.putImageData(
this.#screenImageData,
0,
0,
dirtyRect.left,
dirtyRect.top,
dirtyRect.right - dirtyRect.left,
dirtyRect.bottom - dirtyRect.top
);
} else {
this.#screenCanvasContext.putImageData(this.#screenImageData, 0, 0);
}
}

#clearScreen() {
Expand Down
10 changes: 6 additions & 4 deletions src/emulator/emulator-worker-video.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import type {
EmulatorWorkerFallbackVideoConfig,
EmulatorWorkerSharedMemoryVideoConfig,
EmulatorWorkerVideoBlit,
EmulatorWorkerVideoBlitRect,
} from "./emulator-common";

export interface EmulatorWorkerVideo {
blit(data: Uint8Array): void;
blit(data: Uint8Array, rect?: EmulatorWorkerVideoBlitRect): void;
}

export type EmulatorWorkerVideoBlitSender = (
Expand Down Expand Up @@ -35,10 +36,10 @@ export class SharedMemoryEmulatorWorkerVideo implements EmulatorWorkerVideo {
this.#blitSender = blitSender;
}

blit(data: Uint8Array) {
blit(data: Uint8Array, rect?: EmulatorWorkerVideoBlitRect) {
this.#videoModeBufferView[0] = data.length;
this.#screenBufferView.set(data);
this.#blitSender({type: "shared-memory"});
this.#blitSender({type: "shared-memory", rect});
}
}

Expand All @@ -52,14 +53,15 @@ export class FallbackEmulatorWorkerVideo implements EmulatorWorkerVideo {
this.#blitSender = blitSender;
}

blit(data: Uint8Array) {
blit(data: Uint8Array, rect?: EmulatorWorkerVideoBlitRect) {
// Can't send the Wasm memory directly, need to make a copy. It's net
// neutral because we can use a Transferable for it.
data = new Uint8Array(data);
this.#blitSender(
{
type: "fallback",
data,
rect,
},
[data.buffer]
);
Expand Down
5 changes: 3 additions & 2 deletions src/emulator/emulator-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {
EmulatorInputEvent,
EmulatorWorkerConfig,
EmulatorWorkerVideoBlit,
EmulatorWorkerVideoBlitRect,
} from "./emulator-common";
import {
ethernetMacAddressFromString,
Expand Down Expand Up @@ -160,11 +161,11 @@ class EmulatorWorkerApi {
postMessage({type: "emulator_video_open", width, height});
}

blit(bufPtr: number, bufSize: number) {
blit(bufPtr: number, bufSize: number, rect?: EmulatorWorkerVideoBlitRect) {
this.#lastBlitFrameId++;
if (bufPtr) {
const data = Module.HEAPU8.subarray(bufPtr, bufPtr + bufSize);
this.#video.blit(data);
this.#video.blit(data, rect);
}
this.#nextExpectedBlitTime = performance.now() + 16;
}
Expand Down
23 changes: 12 additions & 11 deletions src/emulator/minivmac.jsz
Original file line number Diff line number Diff line change
Expand Up @@ -1729,17 +1729,18 @@ var tempI64;
var ASM_CONSTS = {
10692: function($0) {workerApi.idleWait($0);},
10720: function($0) {return workerApi.idleWait($0);},
10755: function($0, $1) {workerApi.blit($0, $1);},
10783: function() {return workerApi.acquireInputLock();},
10824: function() {return workerApi.getInputValue(workerApi.InputBufferAddresses.mouseButtonStateAddr);},
10913: function() {return workerApi.getInputValue(workerApi.InputBufferAddresses.mousePositionFlagAddr);},
11003: function() {return workerApi.getInputValue(workerApi.InputBufferAddresses.mousePositionXAddr);},
11090: function() {return workerApi.getInputValue(workerApi.InputBufferAddresses.mousePositionYAddr);},
11177: function() {return workerApi.getInputValue(workerApi.InputBufferAddresses.keyEventFlagAddr);},
11262: function() {return workerApi.getInputValue(workerApi.InputBufferAddresses.keyCodeAddr);},
11342: function() {return workerApi.getInputValue(workerApi.InputBufferAddresses.keyStateAddr);},
11423: function() {workerApi.releaseInputLock();},
11457: function($0, $1) {workerApi.didOpenVideo($0, $1);}
10755: function() {workerApi.blit(0, 0);},
10781: function($0, $1, $2, $3, $4, $5) {workerApi.blit($0, $1, {top: $2, left: $3, bottom: $4, right: $5});},
10853: function() {return workerApi.acquireInputLock();},
10894: function() {return workerApi.getInputValue(workerApi.InputBufferAddresses.mouseButtonStateAddr);},
10983: function() {return workerApi.getInputValue(workerApi.InputBufferAddresses.mousePositionFlagAddr);},
11073: function() {return workerApi.getInputValue(workerApi.InputBufferAddresses.mousePositionXAddr);},
11160: function() {return workerApi.getInputValue(workerApi.InputBufferAddresses.mousePositionYAddr);},
11247: function() {return workerApi.getInputValue(workerApi.InputBufferAddresses.keyEventFlagAddr);},
11332: function() {return workerApi.getInputValue(workerApi.InputBufferAddresses.keyCodeAddr);},
11412: function() {return workerApi.getInputValue(workerApi.InputBufferAddresses.keyStateAddr);},
11493: function() {workerApi.releaseInputLock();},
11527: function($0, $1) {workerApi.didOpenVideo($0, $1);}
};


Expand Down
Binary file modified src/emulator/minivmac.wasmz
Binary file not shown.

0 comments on commit fcb93e0

Please sign in to comment.