diff --git a/README.md b/README.md index b8866327f..dc8886873 100644 --- a/README.md +++ b/README.md @@ -213,7 +213,6 @@ OpenPencil is the alternative: open source (MIT), reads .fig files natively, eve - Grid child positioning UI — column/row span controls, grid overlay on canvas - Skewing and OkHCL color support - Windows code signing (Azure Authenticode certificates) -- Experimental WebGPU/Graphite rendering backend ## Contributing diff --git a/packages/core/src/canvaskit.ts b/packages/core/src/canvaskit.ts index 979f38b72..134c8fd38 100644 --- a/packages/core/src/canvaskit.ts +++ b/packages/core/src/canvaskit.ts @@ -4,67 +4,21 @@ import { IS_BROWSER } from './constants' let instance: CanvasKit | null = null -export type GpuBackend = 'webgl' | 'webgpu' - -let activeBackend: GpuBackend = 'webgl' - -export function getGpuBackend(): GpuBackend { - return activeBackend -} - export interface CanvasKitOptions { locateFile?: (file: string) => string - backend?: GpuBackend -} - -function detectBackend(): GpuBackend { - if (!IS_BROWSER) return 'webgl' - const params = new URLSearchParams(window.location.search) - if (params.get('gpu') === 'webgpu' && 'gpu' in navigator) return 'webgpu' - return 'webgl' -} - -function loadCanvasKitWebGPU(): Promise<(opts?: Record) => Promise> { - return new Promise((resolve, reject) => { - const script = document.createElement('script') - script.src = '/canvaskit-webgpu/canvaskit.js' - script.onload = () => { - const init = - 'CanvasKitInit' in globalThis - ? ((globalThis as typeof globalThis & { CanvasKitInit: unknown }) - .CanvasKitInit as (opts?: { - locateFile?: (file: string) => string - }) => Promise) - : null - if (!init) return reject(new Error('CanvasKitInit not found after loading WebGPU build')) - resolve(init) - } - script.onerror = () => reject(new Error('Failed to load canvaskit-webgpu/canvaskit.js')) - document.head.appendChild(script) - }) } export async function getCanvasKit(options?: CanvasKitOptions): Promise { if (instance) return instance - const backend = options?.backend ?? detectBackend() - activeBackend = backend - const defaultLocate = (file: string) => { if (IS_BROWSER) return `/${file}` return file } - if (backend === 'webgpu') { - const init = await loadCanvasKitWebGPU() - instance = await init({ - locateFile: options?.locateFile ?? ((file: string) => `/canvaskit-webgpu/${file}`) - }) - } else { - instance = await CanvasKitInit({ - locateFile: options?.locateFile ?? defaultLocate - }) - } + instance = await CanvasKitInit({ + locateFile: options?.locateFile ?? defaultLocate + }) return instance } diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 9baf5660f..f74138d83 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -133,7 +133,7 @@ export { export type { FrameCapture, NodeProfile } from './profiler' export { computeLayout, computeAllLayouts, setTextMeasurer } from './layout' export type { TextMeasurer } from './layout' -export { getCanvasKit, getGpuBackend, type CanvasKitOptions, type GpuBackend } from './canvaskit' +export { getCanvasKit, type CanvasKitOptions } from './canvaskit' export { FONT_WEIGHT_NAMES, collectFontKeys, diff --git a/packages/vue/src/shared/useCanvas.ts b/packages/vue/src/shared/useCanvas.ts index 5aa06d1b9..b0847fc78 100644 --- a/packages/vue/src/shared/useCanvas.ts +++ b/packages/vue/src/shared/useCanvas.ts @@ -1,44 +1,13 @@ import { useRafFn, useResizeObserver } from '@vueuse/core' import { onMounted, onScopeDispose, type Ref } from 'vue' -import { getCanvasKit, getGpuBackend, SkiaRenderer } from '@open-pencil/core' +import { getCanvasKit, SkiaRenderer } from '@open-pencil/core' import { useViewportKind } from '../viewport/useViewportKind' import type { Editor } from '@open-pencil/core/editor' import type { CanvasKit } from 'canvaskit-wasm' -interface WebGPUContext { - device: GPUDevice - deviceContext: unknown -} - -interface CanvasKitWebGPU { - MakeGPUDeviceContext(device: GPUDevice): unknown - MakeGPUCanvasContext(ctx: unknown, canvas: HTMLCanvasElement, opts?: unknown): unknown - MakeGPUCanvasSurface( - ctx: unknown, - colorSpace?: unknown, - width?: number, - height?: number - ): ReturnType -} - -function asWebGPU(ck: CanvasKit): CanvasKitWebGPU { - return ck as unknown as CanvasKitWebGPU -} - -async function initWebGPU(ck: CanvasKit): Promise { - if (!('gpu' in navigator)) return null - const adapter = await navigator.gpu.requestAdapter() - if (!adapter) return null - const device = await adapter.requestDevice() - // oxlint-disable-next-line typescript/no-unnecessary-condition -- WebGPU CanvasKit API may not exist at runtime - const deviceContext = asWebGPU(ck).MakeGPUDeviceContext?.(device) - if (!deviceContext) return null - return { device, deviceContext } -} - /** * Options for {@link useCanvas}. */ @@ -76,7 +45,6 @@ export function useCanvas( ) { let renderer: SkiaRenderer | null = null let ck: CanvasKit | null = null - let gpuCtx: WebGPUContext | null = null let glContext: ReturnType | null = null let destroyed = false let dirty = true @@ -88,17 +56,8 @@ export function useCanvas( if (!canvas || destroyed) return ck = await getCanvasKit() - // oxlint-disable-next-line typescript/no-unnecessary-condition -- async race: destroyed may change during await if (destroyed) return - if (getGpuBackend() === 'webgpu') { - gpuCtx = await initWebGPU(ck) - if (!gpuCtx) { - console.warn('WebGPU init failed, reload without ?gpu=webgpu to use WebGL') - return - } - } - await new Promise((r) => requestAnimationFrame(r)) createSurface(canvas) await renderer?.loadFonts() @@ -133,21 +92,10 @@ export function useCanvas( sizeCanvas(canvas) - let surface - if (getGpuBackend() === 'webgpu' && gpuCtx) { - const gpu = asWebGPU(ck) - const canvasCtx = gpu.MakeGPUCanvasContext(gpuCtx.deviceContext, canvas) - surface = gpu.MakeGPUCanvasSurface(canvasCtx, ck.ColorSpace.SRGB, canvas.width, canvas.height) - if (!surface) { - console.error('Failed to create WebGPU surface') - return - } - } else { - surface = makeGLSurface(canvas) - if (!surface) { - console.error('Failed to create WebGL surface') - return - } + const surface = makeGLSurface(canvas) + if (!surface) { + console.error('Failed to create WebGL surface') + return } const glCtx = canvas.getContext('webgl2') ?? null