Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebGPU: "Error: Invalid Surface Status" triggered randomly #23407

Open
Tracked by #23563
chirsz-ever opened this issue Apr 16, 2024 · 2 comments
Open
Tracked by #23563

WebGPU: "Error: Invalid Surface Status" triggered randomly #23407

chirsz-ever opened this issue Apr 16, 2024 · 2 comments
Labels
webgpu WebGPU API

Comments

@chirsz-ever
Copy link
Contributor

chirsz-ever commented Apr 16, 2024

Environment:

  • x86_64 ArchLinux
  • Plasma 6.0.3 wayland
  • Deno 1.42.1

Repuroducable code:

// https://deno.com/blog/v1.40#webgpu-windowing--bring-your-own-window

import {
    EventType,
    WindowBuilder,
} from "jsr:@divy/sdl2@0.10.5";

const width = 800;
const height = 600;

const win = new WindowBuilder("Hello, World!", width, height).build();

const adapter = await navigator.gpu.requestAdapter();
if (!adapter) {
    console.error("WebGPU not supported!");
    Deno.exit(1);
}
const device = await adapter.requestDevice();

/* Returns a Deno.UnsafeWindowSurface */
const surface = win.windowSurface();
/* Returns a WebGPU GPUCanvasContext */
const context = surface.getContext("webgpu");

context.configure({
    device,
    format: navigator.gpu.getPreferredCanvasFormat(),
    width,
    height,
});

for await (const event of win.events()) {
    if (event.type === EventType.Quit) break;
    if (event.type !== EventType.Draw) continue;

    // Sine wave
    const r = Math.sin(Date.now() / 1000) / 2 + 0.5;
    const g = Math.sin(Date.now() / 1000 + 2) / 2 + 0.5;
    const b = Math.sin(Date.now() / 1000 + 4) / 2 + 0.5;

    const textureView = context.getCurrentTexture().createView();

    const commandEncoder = device.createCommandEncoder();
    const passEncoder = commandEncoder.beginRenderPass({
        colorAttachments: [
            {
                view: textureView,
                clearValue: { r, g, b, a: 1.0 },
                loadOp: "clear",
                storeOp: "store",
            },
        ],
    });
    passEncoder.end();

    device.queue.submit([commandEncoder.finish()]);
    surface.present();
}

Save it as "example.ts" and run (SDL needs to be installed in advance):

deno run --unstable-webgpu --unstable-ffi -A example.ts

Got:

picture

Only one success.

If replacing deno_sdl2 with dwm, the same error would occur:

// https://deno.com/blog/v1.40#webgpu-windowing--bring-your-own-window

import {
    createWindow,
    mainloop,
} from "https://deno.land/x/dwm@0.3.6/mod.ts";

const width = 800;
const height = 600;

const adapter = await navigator.gpu.requestAdapter();
if (!adapter) {
    console.error("WebGPU not supported!");
    Deno.exit(1);
}
const device = await adapter.requestDevice();

const win = createWindow({
    title: "Deno Dwm WebGL",
    width,
    height,
});

/* Returns a Deno.UnsafeWindowSurface */
const surface = win.windowSurface();
/* Returns a WebGPU GPUCanvasContext */
const context = surface.getContext("webgpu");

context.configure({
    device,
    format: navigator.gpu.getPreferredCanvasFormat(),
    width,
    height,
});

function frame() {
    // Sine wave
    console.log("Draw!");
    const r = Math.sin(Date.now() / 1000) / 2 + 0.5;
    const g = Math.sin(Date.now() / 1000 + 2) / 2 + 0.5;
    const b = Math.sin(Date.now() / 1000 + 4) / 2 + 0.5;

    const textureView = context.getCurrentTexture().createView();

    const commandEncoder = device.createCommandEncoder();
    const passEncoder = commandEncoder.beginRenderPass({
        colorAttachments: [
            {
                view: textureView,
                clearValue: { r, g, b, a: 1.0 },
                loadOp: "clear",
                storeOp: "store",
            },
        ],
    });
    passEncoder.end();

    device.queue.submit([commandEncoder.finish()]);
    surface.present();
}

mainloop(frame);

Maybe this is a wgpu bug on Xwayland? When I start my desktop environment with X11, this problem disappears.

By the way, I think it worthy of adding a "wayland" backend for Deno.UnsafeWindowSurface

@chirsz-ever
Copy link
Contributor Author

The error raised from a SurfaceError::Outdated at ext/webgpu/surface.rs:

deno/ext/webgpu/surface.rs

Lines 100 to 102 in ab2ab0f

}
_ => Err(AnyError::msg("Invalid Surface Status")),
}

I found that reconfiguration can fix the problem:

// https://deno.com/blog/v1.40#webgpu-windowing--bring-your-own-window

import {
    createWindow,
    mainloop,
} from "https://deno.land/x/dwm@0.3.6/mod.ts";

const width = 800;
const height = 600;

const adapter = await navigator.gpu.requestAdapter();
if (!adapter) {
    console.error("WebGPU not supported!");
    Deno.exit(1);
}
const device = await adapter.requestDevice();

const win = createWindow({
    title: "Deno Dwm WebGL",
    width,
    height,
});

/* Returns a Deno.UnsafeWindowSurface */
const surface = win.windowSurface();
/* Returns a WebGPU GPUCanvasContext */
const context = surface.getContext("webgpu");

context.configure({
    device,
    format: navigator.gpu.getPreferredCanvasFormat(),
    width,
    height,
});

function frame() {
    // Sine wave
    // console.log("Draw!");
    const r = Math.sin(Date.now() / 1000) / 2 + 0.5;
    const g = Math.sin(Date.now() / 1000 + 2) / 2 + 0.5;
    const b = Math.sin(Date.now() / 1000 + 4) / 2 + 0.5;

    let textureView;
    try {
        textureView = context.getCurrentTexture().createView();
    } catch (e) {
        console.error(e);
        context.configure({
            device,
            format: navigator.gpu.getPreferredCanvasFormat(),
            width,
            height,
        });
        console.log("reconfigured");
        return;
    }

    const commandEncoder = device.createCommandEncoder();
    const passEncoder = commandEncoder.beginRenderPass({
        colorAttachments: [
            {
                view: textureView,
                clearValue: { r, g, b, a: 1.0 },
                loadOp: "clear",
                storeOp: "store",
            },
        ],
    });
    passEncoder.end();

    device.queue.submit([commandEncoder.finish()]);
    surface.present();
}

mainloop(frame);

@crowlKats Do you have any suggestions? Can we just add code in op_webgpu_surface_get_current_texture to reconfigure the context when SurfaceError::Outdated occured?

@littledivy
Copy link
Member

User should manually reconfigure the surface when a resize event occurs. Example

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
webgpu WebGPU API
Projects
None yet
Development

No branches or pull requests

3 participants