Add WebGPU renderer (#648)

This commit is contained in:
redphx
2025-02-02 21:37:21 +07:00
parent 39ecef976c
commit fd665b6fcd
31 changed files with 1428 additions and 841 deletions

View File

@@ -32,6 +32,8 @@ type ScriptEvents = {
'list.localCoOp.updated': {
ids: Set<string>;
};
'webgpu.ready': {},
};
type StreamEvents = {

View File

@@ -9,6 +9,7 @@ export let FeatureGates: { [key: string]: boolean } = {
EnableUpdateRequiredPage: false,
ShowForcedUpdateScreen: false,
EnableTakControlResizing: true, // Experimenting
EnableLazyLoadedHome: false,
};
// Enable Native Mouse & Keyboard

View File

@@ -1,3 +1,4 @@
import type { BxStates } from "@/types/states";
import { UserAgent } from "./user-agent";
export const SCRIPT_VERSION = Bun.env.SCRIPT_VERSION!;

View File

@@ -2,12 +2,13 @@ import { BxEvent } from "@utils/bx-event";
import { STATES } from "@utils/global";
import { BxLogger } from "@utils/bx-logger";
import { patchSdpBitrate, setCodecPreferences } from "./sdp";
import { StreamPlayer } from "@/modules/stream-player";
import { StreamPlayerManager } from "@/modules/stream-player-manager";
import { GlobalPref, StreamPref } from "@/enums/pref-keys";
import { CodecProfile } from "@/enums/pref-values";
import type { SettingDefinition } from "@/types/setting-definition";
import { BxEventBus } from "./bx-event-bus";
import { getGlobalPref, getGlobalPrefDefinition, getStreamPref } from "@/utils/pref-utils";
import type { StreamPlayerOptions } from "@/types/stream";
export function patchVideoApi() {
const PREF_SKIP_SPLASH_VIDEO = getGlobalPref(GlobalPref.UI_SKIP_SPLASH_VIDEO);
@@ -26,7 +27,13 @@ export function patchVideoApi() {
contrast: getStreamPref(StreamPref.VIDEO_CONTRAST),
brightness: getStreamPref(StreamPref.VIDEO_BRIGHTNESS),
} satisfies StreamPlayerOptions;
STATES.currentStream.streamPlayer = new StreamPlayer(this, getStreamPref(StreamPref.VIDEO_PLAYER_TYPE), playerOptions);
const streamPlayerManager= StreamPlayerManager.getInstance();
streamPlayerManager.setVideoElement(this);
streamPlayerManager.updateOptions(playerOptions, false);
streamPlayerManager.switchPlayerType(getStreamPref(StreamPref.VIDEO_PLAYER_TYPE));
STATES.currentStream.streamPlayerManager = streamPlayerManager;
BxEventBus.Stream.emit('state.playing', {
$video: this,
@@ -231,6 +238,7 @@ export function patchCanvasContext() {
}
}
// @ts-ignore
return nativeGetContext.apply(this, [contextType, contextAttributes]);
}
}

View File

@@ -2,8 +2,8 @@ import { AppInterface, STATES } from "./global";
import { CE } from "./html";
import { GlobalPref } from "@/enums/pref-keys";
import { BxLogger } from "./bx-logger";
import { StreamPlayerType } from "@/enums/pref-values";
import { getGlobalPref } from "@/utils/pref-utils";
import { StreamPlayerElement } from "@/modules/player/base-stream-player";
export class ScreenshotManager {
@@ -42,36 +42,36 @@ export class ScreenshotManager {
takeScreenshot(callback?: any) {
const currentStream = STATES.currentStream;
const streamPlayer = currentStream.streamPlayer;
const streamPlayerManager = currentStream.streamPlayerManager;
const $canvas = this.$canvas;
if (!streamPlayer || !$canvas) {
if (!streamPlayerManager || !$canvas) {
return;
}
let $player;
if (getGlobalPref(GlobalPref.SCREENSHOT_APPLY_FILTERS)) {
$player = streamPlayer.getPlayerElement();
$player = streamPlayerManager.getPlayerElement();
} else {
$player = streamPlayer.getPlayerElement(StreamPlayerType.VIDEO);
$player = streamPlayerManager.getPlayerElement(StreamPlayerElement.VIDEO);
}
if (!$player || !$player.isConnected) {
return;
}
const canvasContext = this.canvasContext;
if ($player instanceof HTMLCanvasElement) {
streamPlayerManager.getCanvasPlayer()?.updateFrame();
}
canvasContext.drawImage($player, 0, 0);
// Play animation
const $gameStream = $player.closest('#game-stream');
if ($gameStream) {
$gameStream.addEventListener('animationend', this.onAnimationEnd, { once: true });
$gameStream.classList.add('bx-taking-screenshot');
}
const canvasContext = this.canvasContext;
if ($player instanceof HTMLCanvasElement) {
streamPlayer.getWebGL2Player().forceDrawFrame();
}
canvasContext.drawImage($player, 0, 0, $canvas.width, $canvas.height);
// Get data URL and pass to parent app
if (AppInterface) {
const data = $canvas.toDataURL('image/png').split(';base64,')[1];

View File

@@ -12,6 +12,8 @@ import { GameSettingsStorage } from "./game-settings-storage";
import { BxLogger } from "../bx-logger";
import { ControllerCustomizationDefaultPresetId } from "../local-db/controller-customizations-table";
import { ControllerShortcutDefaultId } from "../local-db/controller-shortcuts-table";
import { BxEventBus } from "../bx-event-bus";
import { WebGPUPlayer } from "@/modules/player/webgpu/webgpu-player";
export class StreamSettingsStorage extends BaseSettingsStorage<StreamPref> {
@@ -150,11 +152,21 @@ export class StreamSettingsStorage extends BaseSettingsStorage<StreamPref> {
options: {
[StreamPlayerType.VIDEO]: t('default'),
[StreamPlayerType.WEBGL2]: t('webgl2'),
[StreamPlayerType.WEBGPU]: `${t('webgpu')} (${t('experimental')})`,
},
suggest: {
lowest: StreamPlayerType.VIDEO,
highest: StreamPlayerType.WEBGL2,
},
ready: (setting: any) => {
BxEventBus.Script.on('webgpu.ready', () => {
if (!navigator.gpu || !WebGPUPlayer.device) {
// Remove WebGPU option on unsupported browsers
delete setting.options[StreamPlayerType.WEBGPU];
}
}
);
},
},
[StreamPref.VIDEO_PROCESSING]: {
label: t('clarity-boost'),

View File

@@ -27,6 +27,7 @@ export const SUPPORTED_LANGUAGES = {
};
const Texts = {
"webgpu": "WebGPU",
"achievements": "Achievements",
"activate": "Activate",
"activated": "Activated",