BREAKING(webgpu/unstable): move width and height options to UnsafeWindowSurface constructor (#24200)

Fixes https://github.com/denoland/deno/issues/23508

`width` and `height` are required to configure the wgpu surface because
Deno is headless and depends on user to create a window. The options
were non-standard extension of `GPUCanvasConfiguration#configure`.

This PR adds a required options parameter with the `width` and `height`
options to `Deno.UnsafeWindowSurface` constructor.

```typescript
// Old, non-standard extension of GPUCanvasConfiguration
const surface = new Deno.UnsafeWindowSurface("x11", displayHandle, windowHandle);

const context  = surface.getContext();
context.configure({ width: 600, height: 800, /* ... */ });
```

```typescript
// New
const surface = new Deno.UnsafeWindowSurface({
  system: "x11",
  windowHandle,
  displayHandle,
  width: 600,
  height: 800,
});

const context  = surface.getContext();
context.configure({ /* ... */ });
```
This commit is contained in:
Divy Srivastava 2024-09-22 09:10:54 +05:30 committed by GitHub
parent 9be8dce0c7
commit 0cb00a6e89
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 57 additions and 23 deletions

View File

@ -28,9 +28,13 @@ declare namespace Deno {
*/
export class UnsafeWindowSurface {
constructor(
system: "cocoa" | "win32" | "x11" | "wayland",
windowHandle: Deno.PointerValue<unknown>,
displayHandle: Deno.PointerValue<unknown>,
options: {
system: "cocoa" | "win32" | "x11" | "wayland";
windowHandle: Deno.PointerValue<unknown>;
displayHandle: Deno.PointerValue<unknown>;
width: number;
height: number;
},
);
getContext(context: "webgpu"): GPUCanvasContext;
present(): void;

View File

@ -1372,8 +1372,6 @@ declare interface GPUCanvasConfiguration {
viewFormats?: GPUTextureFormat[];
colorSpace?: "srgb" | "display-p3";
alphaMode?: GPUCanvasAlphaMode;
width: number;
height: number;
}
/** @category GPU */
declare interface GPUCanvasContext {

View File

@ -7434,16 +7434,6 @@ const dictMembersGPUCanvasConfiguration = [
key: "presentMode",
converter: webidl.converters["GPUPresentMode"],
},
{
key: "width",
converter: webidl.converters["long"],
required: true,
},
{
key: "height",
converter: webidl.converters["long"],
required: true,
},
{
key: "viewFormats",
converter: webidl.createSequenceConverter(

View File

@ -29,6 +29,8 @@ const _configuration = Symbol("[[configuration]]");
const _canvas = Symbol("[[canvas]]");
const _currentTexture = Symbol("[[currentTexture]]");
const _present = Symbol("[[present]]");
const _dim = Symbol("[[dimensions]]");
class GPUCanvasContext {
/** @type {number} */
[_surfaceRid];
@ -36,6 +38,7 @@ class GPUCanvasContext {
[_canvas];
/** @type {GPUTexture | undefined} */
[_currentTexture];
[_dim];
get canvas() {
webidl.assertBranded(this, GPUCanvasContextPrototype);
@ -69,8 +72,8 @@ class GPUCanvasContext {
format: configuration.format,
viewFormats: configuration.viewFormats,
usage: configuration.usage,
width: configuration.width,
height: configuration.height,
width: this[_dim].width,
height: this[_dim].height,
alphaMode: configuration.alphaMode,
});
@ -110,8 +113,8 @@ class GPUCanvasContext {
const texture = createGPUTexture(
{
size: {
width: this[_configuration].width,
height: this[_configuration].height,
width: this[_dim].width,
height: this[_dim].height,
depthOrArrayLayers: 1,
},
mipLevelCount: 1,
@ -163,6 +166,8 @@ function createCanvasContext(options) {
const canvasContext = webidl.createBranded(GPUCanvasContext);
canvasContext[_surfaceRid] = options.surfaceRid;
canvasContext[_canvas] = options.canvas;
canvasContext[_dim] = { width: options.width, height: options.height };
return canvasContext;
}
@ -172,16 +177,34 @@ function createCanvasContext(options) {
class UnsafeWindowSurface {
#ctx;
#surfaceRid;
#options;
constructor(system, win, display) {
this.#surfaceRid = op_webgpu_surface_create(system, win, display);
constructor(options) {
if (typeof options !== "object") {
throw new TypeError("options must be provided.");
}
if (
typeof options.width !== "number" || typeof options.height !== "number"
) {
throw new TypeError("width and height must be provided.");
}
this.#surfaceRid = op_webgpu_surface_create(
options.system,
options.windowHandle,
options.displayHandle,
);
this.#options = options;
}
getContext(context) {
if (context !== "webgpu") {
throw new TypeError("Only 'webgpu' context is supported");
}
this.#ctx = createCanvasContext({ surfaceRid: this.#surfaceRid });
this.#ctx = createCanvasContext({
surfaceRid: this.#surfaceRid,
...this.#options,
});
return this.#ctx;
}

View File

@ -236,13 +236,32 @@ Deno.test({
assertThrows(
() => {
new Deno.UnsafeWindowSurface("cocoa", null, null);
new Deno.UnsafeWindowSurface({
system: "cocoa",
windowHandle: null,
displayHandle: null,
width: 0,
height: 0,
});
},
);
device.destroy();
});
Deno.test(function webgpuWindowSurfaceNoWidthHeight() {
assertThrows(
() => {
// @ts-expect-error width and height are required
new Deno.UnsafeWindowSurface({
system: "x11",
windowHandle: null,
displayHandle: null,
});
},
);
});
Deno.test(function getPreferredCanvasFormat() {
const preferredFormat = navigator.gpu.getPreferredCanvasFormat();
assert(preferredFormat === "bgra8unorm" || preferredFormat === "rgba8unorm");