Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,8 @@ jobs:

- name: Run headless browser tests
run: yarn test-headless
env:
DECK_GL_COMMUNITY_SOFTWARE_WEBGPU: 'true'

website-build:
runs-on: ubuntu-22.04
Expand Down
2 changes: 2 additions & 0 deletions docs/whats-new.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ Scope tracked in the [v9.4 milestone](https://github.com/visgl/deck.gl-community
including its picking-width shader customization.
- `TraceGraphLayer`, `TracePreparedStateLayer`, and `TraceProcessLayer`: ported trace backgrounds, binary span blocks, outlines, labels, overflow labels, separators, and straight dependencies by reusing dual-backend community layers.
- Trace counter sparklines now preserve their full geometry using portable `LineLayer` segments.
- Headless CI enables Chromium's software WebGPU adapter, so native WebGPU validation tests run
even on runners without hardware adapters instead of being skipped.
- Every website gallery example and live layer-reference example now receives a standalone
`DeviceTabsWidget` from the shared imperative host, with an independent device manager, WebGPU
preference, WebGL2 fallback, renderer remounting, and preserved view state.
Expand Down
3 changes: 2 additions & 1 deletion modules/arrow-layers/test/webgpu-layers.browser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
} from 'apache-arrow';
import {describe, expect, it} from 'vitest';

import {releaseBrowserTestDevice} from '../../../test/browser-test-device';
import {GeoArrowPathLayer, GeoArrowSolidPolygonLayer} from '../src';

type BrowserGpu = {requestAdapter: () => Promise<unknown>};
Expand Down Expand Up @@ -104,7 +105,7 @@

await new Promise<void>((resolve, reject) => {
const timeout = window.setTimeout(() => {
reject(new Error(`Timed out while rendering GeoArrow layers with ${type}.`));

Check failure on line 108 in modules/arrow-layers/test/webgpu-layers.browser.spec.ts

View workflow job for this annotation

GitHub Actions / test-headless

[headless (chromium)] modules/arrow-layers/test/webgpu-layers.browser.spec.ts > GeoArrow graphics backend compatibility > renders binary path and polygon attributes on WebGPU

Error: Timed out while rendering GeoArrow layers with webgpu. ❯ modules/arrow-layers/test/webgpu-layers.browser.spec.ts:108:15
}, 10_000);

deck = new Deck({
Expand Down Expand Up @@ -136,7 +137,7 @@
} finally {
nativeDevice?.removeEventListener('uncapturederror', captureValidationError);
deck?.finalize();
device?.destroy();
releaseBrowserTestDevice(device);
parent.remove();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {webgl2Adapter} from '@luma.gl/webgl';
import {webgpuAdapter} from '@luma.gl/webgpu';
import {describe, expect, it} from 'vitest';

import {releaseBrowserTestDevice} from '../../../../test/browser-test-device';
import {GpuParticleSimulation} from '../../src/wind-layer/gpu-particle-simulation';
import {
createWindField,
Expand Down Expand Up @@ -213,7 +214,7 @@ async function renderWindLayers(type: 'webgl' | 'webgpu'): Promise<void> {
} finally {
nativeDevice?.removeEventListener('uncapturederror', captureValidationError);
deck?.finalize();
device?.destroy();
releaseBrowserTestDevice(device);
parent.remove();
}
}
Expand Down
3 changes: 2 additions & 1 deletion modules/infovis-layers/test/fast-text-layer.browser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {webgl2Adapter} from '@luma.gl/webgl';
import {webgpuAdapter} from '@luma.gl/webgpu';
import {describe, expect, it} from 'vitest';

import {releaseBrowserTestDevice} from '../../../test/browser-test-device';
import {FastTextLayer} from '../src';

type BrowserGpu = {requestAdapter: () => Promise<unknown>};
Expand Down Expand Up @@ -88,7 +89,7 @@ async function renderFastText(type: 'webgl' | 'webgpu', sdf: boolean): Promise<v
} finally {
nativeDevice?.removeEventListener('uncapturederror', captureValidationError);
deck?.finalize();
device?.destroy();
releaseBrowserTestDevice(device);
parent.remove();
}
}
Expand Down
7 changes: 4 additions & 3 deletions modules/layers/test/webgpu-layers.browser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {webgl2Adapter} from '@luma.gl/webgl';
import {webgpuAdapter} from '@luma.gl/webgpu';
import {describe, expect, it} from 'vitest';

import {releaseBrowserTestDevice} from '../../../test/browser-test-device';
import {
HorizonGraphLayer,
MultiHorizonGraphLayer,
Expand Down Expand Up @@ -417,15 +418,15 @@ async function renderPortableLayers(type: 'webgl' | 'webgpu'): Promise<void> {
} finally {
nativeDevice?.removeEventListener('uncapturederror', captureValidationError);
deck?.finalize();
device?.destroy();
releaseBrowserTestDevice(device);
parent.remove();
}
}

describe('community graphics backend compatibility', () => {
it('renders custom shaders, paths, polygons, graph, timeline, and editing on WebGL2', async () => {
await renderPortableLayers('webgl');
}, 20_000);
}, 30_000);

it('renders custom shaders, paths, polygons, graph, timeline, and editing on WebGPU', async ({
skip
Expand All @@ -436,5 +437,5 @@ describe('community graphics backend compatibility', () => {
}

await renderPortableLayers('webgpu');
}, 20_000);
}, 30_000);
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {webgl2Adapter} from '@luma.gl/webgl';
import {webgpuAdapter} from '@luma.gl/webgpu';
import {describe, expect, it} from 'vitest';

import {releaseBrowserTestDevice} from '../../../../../test/browser-test-device';
import {
buildJSONTrace,
buildTraceGraphDataFromJSONTrace,
Expand Down Expand Up @@ -212,7 +213,7 @@ async function renderTraceGraph(
} finally {
nativeGpuDevice?.removeEventListener('uncapturederror', handleValidationError);
deck?.finalize();
device?.destroy();
releaseBrowserTestDevice(device);
parent.remove();
}
}
Expand Down
18 changes: 18 additions & 0 deletions test/browser-test-device.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// deck.gl-community
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors

import type {Device} from '@luma.gl/core';

/**
* Releases a graphics device created by a browser test.
*
* Deck finalization destroys each test's WebGPU resources. The Playwright browser process owns
* final WebGPU device teardown because explicitly destroying a Linux SwiftShader device can drop
* the external WebGPU instance shared by parallel Vitest browser files.
*/
export function releaseBrowserTestDevice(device: Device | undefined): void {
if (device?.type !== 'webgpu') {
device?.destroy();
}
}
32 changes: 19 additions & 13 deletions vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,20 +82,25 @@ const BROWSER_OPTIMIZE_DEPS_CONFIG = {

const BROWSER_TEST_EXCLUDE = ['modules/**/dist/**', 'dev/**/dist/**'];

const SOFTWARE_WEBGPU_ENABLED = process.env.DECK_GL_COMMUNITY_SOFTWARE_WEBGPU === 'true';

const HEADLESS_BROWSER_PROVIDER =
process.env.GITHUB_ACTIONS === 'true'
? playwright({launchOptions: {channel: 'chrome'}})
: process.env.DECK_GL_COMMUNITY_SOFTWARE_WEBGPU === 'true'
? playwright({
launchOptions: {
args: [
'--enable-unsafe-webgpu',
'--enable-unsafe-swiftshader',
'--use-angle=swiftshader',
'--enable-features=Vulkan,WebGPU'
]
}
})
SOFTWARE_WEBGPU_ENABLED
? playwright({
launchOptions: {
...(process.env.GITHUB_ACTIONS === 'true' ? {channel: 'chrome'} : {}),
args: [
'--enable-unsafe-webgpu',
'--enable-unsafe-swiftshader',
'--use-gl=angle',
'--use-angle=swiftshader',
'--use-webgpu-adapter=swiftshader',
'--use-gpu-in-tests'
]
}
})
: process.env.GITHUB_ACTIONS === 'true'
? playwright({launchOptions: {channel: 'chrome'}})
: playwright();

const CONFIG = defineConfig({
Expand Down Expand Up @@ -167,6 +172,7 @@ const CONFIG = defineConfig({
browser: {
enabled: true,
headless: true,
fileParallelism: !SOFTWARE_WEBGPU_ENABLED,
provider: HEADLESS_BROWSER_PROVIDER,
instances: [{browser: 'chromium'}]
}
Expand Down
Loading