Updated the webgpu stuff to have webgl as fallback

This commit is contained in:
Andreas Dahm committed 2026-04-16 10:04:48 +02:00
1 parent 4e24cb5df1
commit a349f630c6
17 files changed
+1350 -416

No files matched your search

@@ -1,7 +1,8 @@
import {AfterViewInit, Component, ElementRef, EventEmitter, inject, Input, NgZone, OnDestroy, Output, ViewChild} from '@angular/core';
import {MatSnackBar} from '@angular/material/snack-bar';
import {TranslateService} from '@ngx-translate/core';
import {ArcRotateCamera, Camera, MeshBuilder, Scene, ShaderLanguage, ShaderMaterial, Vector2, Vector3, WebGPUEngine} from '@babylonjs/core';
import {ArcRotateCamera, Camera, Engine, MeshBuilder, Scene, ShaderLanguage, ShaderMaterial, Vector2, Vector3, WebGPUEngine} from '@babylonjs/core';
import {GpuCapabilityService, GpuTier} from '../../../service/gpu-capability.service';
export interface RenderConfig {
mode: '2D' | '3D';
@@ -17,7 +18,8 @@ export type RenderCallback = (material: ShaderMaterial, camera: Camera, canvas:
export interface SceneEventData {
scene: Scene;
engine: WebGPUEngine;
engine: WebGPUEngine | Engine;
gpuTier: GpuTier;
}
@Component({
@@ -30,6 +32,7 @@ export class BabylonCanvas implements AfterViewInit, OnDestroy {
readonly ngZone = inject(NgZone);
private readonly snackBar = inject(MatSnackBar);
private readonly translate = inject(TranslateService);
private readonly gpuCapability = inject(GpuCapabilityService);
@ViewChild('renderCanvas', { static: true }) canvasRef!: ElementRef<HTMLCanvasElement>;
@@ -38,11 +41,13 @@ export class BabylonCanvas implements AfterViewInit, OnDestroy {
@Output() sceneReady = new EventEmitter<SceneEventData>();
@Output() sceneResized = new EventEmitter<SceneEventData>();
@Output() engineUnavailable = new EventEmitter<{ reason: string }>();
private engine!: WebGPUEngine;
private engine!: WebGPUEngine | Engine;
private scene!: Scene;
private shaderMaterial!: ShaderMaterial;
private camera!: Camera;
private gpuTier: GpuTier = 'none';
//Listener
private readonly resizeHandler = () => this.handleResize();
@@ -63,26 +68,60 @@ export class BabylonCanvas implements AfterViewInit, OnDestroy {
private async initBabylon(): Promise<void> {
const canvas = this.canvasRef.nativeElement;
const tmpEngine = new WebGPUEngine(canvas);
await tmpEngine.initAsync().then(() => {
this.engine = tmpEngine;
this.scene = new Scene(this.engine);
this.setupCamera(canvas);
this.addListener(canvas);
this.createShaderMaterial();
this.createFullScreenRect();
this.sceneReady.emit({
scene: this.scene,
engine: this.engine
});
this.addRenderLoop(canvas);
const tier = await this.gpuCapability.detect();
this.gpuTier = tier;
})
.catch(() => {
const message = this.translate.instant('WEBGPU.NOT_SUPPORTED');
this.snackBar.open(message, 'OK', { duration: 8000, horizontalPosition: "center", verticalPosition: "top" });
this.engine = null!;
});
if (tier === 'webgpu') {
await this.initWebGpuEngine(canvas);
return;
}
if (tier === 'webgl') {
this.showSnackBar('GPU.WEBGL_FALLBACK');
this.initWebGlEngine(canvas);
return;
}
this.showSnackBar('GPU.NOT_SUPPORTED');
this.engineUnavailable.emit({reason: 'no_gpu'});
}
private async initWebGpuEngine(canvas: HTMLCanvasElement): Promise<void> {
const tmpEngine = new WebGPUEngine(canvas);
try {
await tmpEngine.initAsync();
this.engine = tmpEngine;
this.setupScene(canvas);
} catch {
this.showSnackBar('GPU.WEBGL_FALLBACK');
this.gpuTier = 'webgl';
this.initWebGlEngine(canvas);
}
}
private initWebGlEngine(canvas: HTMLCanvasElement): void {
this.engine = new Engine(canvas, true);
this.setupScene(canvas);
}
private setupScene(canvas: HTMLCanvasElement): void {
this.scene = new Scene(this.engine);
this.setupCamera(canvas);
this.addListener(canvas);
this.createShaderMaterial();
this.createFullScreenRect();
this.sceneReady.emit({
scene: this.scene,
engine: this.engine,
gpuTier: this.gpuTier
});
this.addRenderLoop(canvas);
}
private showSnackBar(translationKey: string): void {
const message = this.translate.instant(translationKey);
this.snackBar.open(message, 'OK', {duration: 8000, horizontalPosition: 'center', verticalPosition: 'top'});
}
private addListener(canvas: HTMLCanvasElement) {
@@ -198,7 +237,8 @@ export class BabylonCanvas implements AfterViewInit, OnDestroy {
this.sceneResized?.emit({
scene: this.scene,
engine: this.engine
engine: this.engine,
gpuTier: this.gpuTier
});
}
}