Revive the CTS job (#7675)

Includes the following minor functional fixes to deno_webgpu:

* Don't throw an error immediately when `create_buffer` is called with invalid usage flags.
* Implement `on_submitted_work_done`.
* Correct validation of GPUExtent3D element count.
* Run without tracing (instead of panic) if the DENO_WEBGPU_TRACE env var is not set.

Fixes #6838
This commit is contained in:
Andy Leiserson 2025-05-21 09:52:03 -07:00 committed by GitHub
parent d7e6a0e1fa
commit fd6f16f598
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 184 additions and 44 deletions

88
.github/workflows/cts.yml vendored Normal file
View File

@ -0,0 +1,88 @@
name: CTS
on:
pull_request:
types: [labeled, opened, synchronize]
schedule:
- cron: '33 2 * * *'
workflow_dispatch:
env:
CARGO_INCREMENTAL: false
CARGO_TERM_COLOR: always
RUST_BACKTRACE: full
MSRV: "1.84"
jobs:
cts:
# For pull requests, only run if we add the "PR: run CTS" label
if: "github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'PR: run CTS')"
strategy:
fail-fast: false
matrix:
include:
# Windows
- name: Windows x86_64
os: windows-2022
target: x86_64-pc-windows-msvc
backends: dx12
# Linux
#- name: Linux x86_64
# os: ubuntu-20.04
# target: x86_64-unknown-linux-gnu
# backends: vulkan # gl
name: CTS ${{ matrix.name }}
runs-on: ${{ matrix.os }}
steps:
- name: checkout repo
uses: actions/checkout@v4
with:
path: wgpu
- name: checkout cts
run: |
git clone https://github.com/gpuweb/cts.git
cd cts
git checkout $(cat ../wgpu/cts_runner/revision.txt)
- name: Install Repo MSRV toolchain
run: |
rustup toolchain install ${{ env.MSRV }} --no-self-update --profile=minimal --target ${{ matrix.target }}
rustup override set ${{ env.MSRV }}
cargo -V
- name: caching
uses: Swatinem/rust-cache@v2
with:
key: cts-b # suffix for cache busting
workspaces: wgpu
# We enable line numbers for panics, but that's it
- name: disable debug
shell: bash
run: |
mkdir -p wgpu/.cargo
echo """[profile.dev]
debug = 1" > wgpu/.cargo/config.toml
- name: build CTS runner
run: |
cargo build --manifest-path wgpu/cts_runner/Cargo.toml
- name: run CTS
shell: bash
run: |
cd cts;
for backend in ${{ matrix.backends }}; do
echo "======= CTS TESTS $backend ======";
grep -v '^//' ../wgpu/cts_runner/test.lst | while IFS=$' \t\r\n' read test; do
echo "=== Running $test ===";
DENO_WEBGPU_BACKEND=$backend cargo run --manifest-path ../wgpu/cts_runner/Cargo.toml --frozen -- ./tools/run_deno --verbose "$test";
done
done
echo;
echo "Note: Summary reflects only the last test suite, not the entire run."

40
Cargo.lock generated
View File

@ -1016,18 +1016,18 @@ dependencies = [
[[package]]
name = "deno_console"
version = "0.190.0"
version = "0.192.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94352b8d75c288a26ef748ad0ddae07e181109374a02c547850f96eef76b5389"
checksum = "ca40d9ecd49a0320c058eff8ad8b53c83b1b743e3087001afe2e14ec50197d34"
dependencies = [
"deno_core",
]
[[package]]
name = "deno_core"
version = "0.336.0"
version = "0.338.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdd50476c4325d5fa52bb906804a1e35b127d2a1dcf674e3447b53dcf25525bf"
checksum = "113f3f08bd5daf99f1a7876c0f99cd8c3c609439fa0b808311ec856a253e95f0"
dependencies = [
"anyhow",
"az",
@ -1095,9 +1095,9 @@ dependencies = [
[[package]]
name = "deno_ops"
version = "0.212.0"
version = "0.214.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2d328067139909aa81522a5d90f119368b541fbddd73ab630e4d9f777865f0d"
checksum = "6ad885bf882be535f7714c713042129acba6f31a8efb5e6b2298f6e40cab9b16"
dependencies = [
"indexmap",
"proc-macro-rules",
@ -1112,9 +1112,9 @@ dependencies = [
[[package]]
name = "deno_path_util"
version = "0.3.1"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c87b8996966ae1b13ee9c20219b1d10fc53905b9570faae6adfa34614fd15224"
checksum = "c238a664a0a6f1ce0ff2b73c6854811526d00f442a12f878cb8555b23fe13aa3"
dependencies = [
"deno_error",
"percent-encoding",
@ -1125,9 +1125,9 @@ dependencies = [
[[package]]
name = "deno_permissions"
version = "0.49.0"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abf879dff0b3de4dbcb78d6dda3a55e711369d5b9f479270a82853ef106c4176"
checksum = "a1ff15740ddc4626cc7f5d66a113e0f825073476d1e83af9fa693426516d07b7"
dependencies = [
"capacity_builder 0.5.0",
"deno_core",
@ -1168,9 +1168,9 @@ dependencies = [
[[package]]
name = "deno_url"
version = "0.190.0"
version = "0.192.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d79e743ad841f7826d46c6944580f5ba665fe9ab4c31a68c4eed8b5a78225da3"
checksum = "36a705094c7fbbb01338e89c12367da939cf831dd5b202e3a521f75a614a6082"
dependencies = [
"deno_core",
"deno_error",
@ -1180,9 +1180,9 @@ dependencies = [
[[package]]
name = "deno_web"
version = "0.221.0"
version = "0.224.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8041ba73bb2f238c61b5e4ed341d2fe1f9464a71115a240ab3390480b3c10e12"
checksum = "0ae1ba442b2c4b6116eb75e6e46968840693f2036d035bd45421c4a9beda6186"
dependencies = [
"async-trait",
"base64-simd 0.8.0",
@ -1218,9 +1218,9 @@ dependencies = [
[[package]]
name = "deno_webidl"
version = "0.190.0"
version = "0.192.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4ff81a990196bf3a80fe5d339b4eb8b411ef17634d60d399a63bae6e71a37c9"
checksum = "30d2d820d865651e0ce4eca898176577c8693bf2694af32545ab4b9ffb9934fa"
dependencies = [
"deno_core",
]
@ -3706,9 +3706,9 @@ dependencies = [
[[package]]
name = "serde_v8"
version = "0.245.0"
version = "0.247.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "945f93c91e0c7e4799b5fefff076756141aae92e262c4dc4833310dd3d2d845e"
checksum = "12bbfafb7b707cbed49d1eaf48f4aa41b5ff57f813d1a80f77244e6e2fa4507e"
dependencies = [
"deno_error",
"num-bigint",
@ -4410,9 +4410,9 @@ dependencies = [
[[package]]
name = "v8"
version = "130.0.7"
version = "134.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a511192602f7b435b0a241c1947aa743eb7717f20a9195f4b5e8ed1952e01db1"
checksum = "21c7a224a7eaf3f98c1bad772fbaee56394dce185ef7b19a2e0ca5e3d274165d"
dependencies = [
"bindgen",
"bitflags 2.9.0",

View File

@ -231,11 +231,11 @@ web-sys = { version = "0.3.77", default-features = false }
web-time = "1"
# deno dependencies
deno_console = "0.190.0"
deno_core = "0.336.0"
deno_url = "0.190.0"
deno_web = "0.221.0"
deno_webidl = "0.190.0"
deno_console = "0.192.0"
deno_core = "0.338.0"
deno_url = "0.192.0"
deno_web = "0.224.0"
deno_webidl = "0.192.0"
deno_webgpu = { version = "0.157.0", path = "./deno_webgpu" }
deno_unsync = "0.4.2"
deno_error = "0.5.5"

View File

@ -214,9 +214,12 @@ If you are a user and want a way to help contribute to wgpu, we always need more
WebGPU includes a Conformance Test Suite to validate that implementations are working correctly. We can run this CTS against wgpu.
To run the CTS, first, you need to check it out:
To have GitHub run the CTS against a pull request, you can add the `PR: run CTS` label to the PR.
To run the CTS locally, first, you need to check it out:
```
# In the root of your wgpu tree:
git clone https://github.com/gpuweb/cts.git
cd cts
# works in bash and powershell

View File

@ -1 +1 @@
7ea73ba6f44c9f6fedfffc06f14c73ea9f2eaa11
049916a6191725aad5a5692e5a22df47d45c88fa

View File

@ -29,6 +29,7 @@ import * as performance from "ext:deno_web/15_performance.js";
import { loadWebGPU } from "ext:deno_webgpu/00_init.js";
import * as imageData from "ext:deno_web/16_image_data.js";
const webgpu = loadWebGPU();
webgpu.initGPU();
// imports needed to pass module evaluation
import "ext:deno_url/01_urlpattern.js";

View File

@ -1,10 +1,15 @@
unittests:*
webgpu:api,operation,command_buffer,basic:*
webgpu:api,operation,compute,basic:*
webgpu:api,operation,compute,basic:memcpy:*
//FAIL: webgpu:api,operation,compute,basic:large_dispatch:*
webgpu:api,operation,device,lost:*
webgpu:api,operation,rendering,basic:clear:*
webgpu:api,operation,rendering,basic:fullscreen_quad:*
//FAIL: webgpu:api,operation,rendering,basic:large_draw:*
webgpu:api,operation,rendering,blending:*
webgpu:api,operation,rendering,blending:GPUBlendComponent:*
webgpu:api,operation,rendering,color_target_state:blending,GPUBlendComponent:*
webgpu:api,operation,rendering,color_target_state:blending,formats:*
webgpu:api,operation,rendering,color_target_state:blend_constant,setting:*
webgpu:api,operation,rendering,depth:*
webgpu:api,operation,rendering,draw:*
// https://github.com/gfx-rs/wgpu/issues/7391
//FAIL: webgpu:api,operation,uncapturederror:*

View File

@ -126,7 +126,9 @@ impl GPUAdapter {
let required_limits =
serde_json::from_value(serde_json::to_value(descriptor.required_limits)?)?;
let webgpu_trace = std::env::var_os("DENO_WEBGPU_TRACE").unwrap();
let trace = std::env::var_os("DENO_WEBGPU_TRACE")
.map(|path| wgpu_types::Trace::Directory(std::path::PathBuf::from(path)))
.unwrap_or_default();
let wgpu_descriptor = wgpu_types::DeviceDescriptor {
label: crate::transform_label(descriptor.label.clone()),
@ -135,7 +137,7 @@ impl GPUAdapter {
),
required_limits,
memory_hints: Default::default(),
trace: wgpu_types::Trace::Directory(std::path::PathBuf::from(webgpu_trace)),
trace,
};
let (device, queue) =

View File

@ -119,6 +119,7 @@ impl GPUDevice {
fn queue(&self, scope: &mut v8::HandleScope) -> v8::Global<v8::Object> {
self.queue_obj.get(scope, |_| GPUQueue {
id: self.queue,
device: self.id,
error_handler: self.error_handler.clone(),
instance: self.instance.clone(),
label: self.label.clone(),
@ -134,15 +135,17 @@ impl GPUDevice {
#[required(1)]
#[cppgc]
fn create_buffer(
&self,
#[webidl] descriptor: super::buffer::GPUBufferDescriptor,
) -> Result<GPUBuffer, JsErrorBox> {
fn create_buffer(&self, #[webidl] descriptor: super::buffer::GPUBufferDescriptor) -> GPUBuffer {
// Validation of the usage needs to happen on the device timeline, so
// don't raise an error immediately if it isn't valid. wgpu will
// reject `BufferUsages::empty()`.
let usage = wgpu_types::BufferUsages::from_bits(descriptor.usage)
.unwrap_or(wgpu_types::BufferUsages::empty());
let wgpu_descriptor = wgpu_core::resource::BufferDescriptor {
label: crate::transform_label(descriptor.label.clone()),
size: descriptor.size,
usage: wgpu_types::BufferUsages::from_bits(descriptor.usage)
.ok_or_else(|| JsErrorBox::type_error("usage is not valid"))?,
usage,
mapped_at_creation: descriptor.mapped_at_creation,
};
@ -152,7 +155,7 @@ impl GPUDevice {
self.error_handler.push_error(err);
Ok(GPUBuffer {
GPUBuffer {
instance: self.instance.clone(),
error_handler: self.error_handler.clone(),
id,
@ -171,7 +174,7 @@ impl GPUDevice {
None
}),
mapped_js_buffers: RefCell::new(vec![]),
})
}
}
#[required(1)]

View File

@ -1,6 +1,11 @@
// Copyright 2018-2025 the Deno authors. MIT license.
use std::cell::RefCell;
use std::rc::Rc;
use std::time::Duration;
use deno_core::cppgc::Ptr;
use deno_core::futures::channel::oneshot;
use deno_core::op2;
use deno_core::GarbageCollected;
use deno_core::WebIDL;
@ -21,6 +26,7 @@ pub struct GPUQueue {
pub label: String,
pub id: wgpu_core::id::QueueId,
pub device: wgpu_core::id::DeviceId,
}
impl Drop for GPUQueue {
@ -74,9 +80,41 @@ impl GPUQueue {
#[async_method]
async fn on_submitted_work_done(&self) -> Result<(), JsErrorBox> {
Err(JsErrorBox::generic(
"This operation is currently not supported",
))
let (sender, receiver) = oneshot::channel::<()>();
let callback = Box::new(move || {
sender.send(()).unwrap();
});
self.instance
.queue_on_submitted_work_done(self.id, callback);
let done = Rc::new(RefCell::new(false));
let done_ = done.clone();
let device_poll_fut = async move {
while !*done.borrow() {
{
self.instance
.device_poll(self.device, wgpu_types::PollType::wait())
.unwrap();
}
tokio::time::sleep(Duration::from_millis(10)).await;
}
Ok::<(), JsErrorBox>(())
};
let receiver_fut = async move {
receiver
.await
.map_err(|e| JsErrorBox::generic(e.to_string()))?;
let mut done = done_.borrow_mut();
*done = true;
Ok::<(), JsErrorBox>(())
};
tokio::try_join!(device_poll_fut, receiver_fut)?;
Ok(())
}
#[required(3)]

View File

@ -65,7 +65,7 @@ impl<'a> WebIdlConverter<'a> for GPUExtent3D {
enforce_range: true,
},
)?;
if !(conv.len() > 1 && conv.len() <= 3) {
if conv.is_empty() || conv.len() > 3 {
return Err(WebIdlError::other(prefix, context, JsErrorBox::type_error(format!("A sequence of number used as a GPUExtent3D must have between 1 and 3 elements, received {} elements", conv.len()))));
}