summaryrefslogtreecommitdiff
path: root/cli/tests
diff options
context:
space:
mode:
Diffstat (limited to 'cli/tests')
-rw-r--r--cli/tests/integration/js_unit_tests.rs1
-rw-r--r--cli/tests/integration/run_tests.rs11
-rw-r--r--cli/tests/integration/shared_library_tests.rs27
-rw-r--r--cli/tests/testdata/run/unstable_webgpu.disabled.out2
-rw-r--r--cli/tests/testdata/run/unstable_webgpu.enabled.out2
-rw-r--r--cli/tests/testdata/run/unstable_webgpu.js10
-rw-r--r--cli/tests/testdata/webgpu/computepass_shader.wgsl38
-rw-r--r--cli/tests/testdata/webgpu/hellotriangle.outbin0 -> 204800 bytes
-rw-r--r--cli/tests/testdata/webgpu/hellotriangle_shader.wgsl11
-rw-r--r--cli/tests/unit/webgpu_test.ts242
10 files changed, 336 insertions, 8 deletions
diff --git a/cli/tests/integration/js_unit_tests.rs b/cli/tests/integration/js_unit_tests.rs
index 165ab25bf..10bd137d9 100644
--- a/cli/tests/integration/js_unit_tests.rs
+++ b/cli/tests/integration/js_unit_tests.rs
@@ -101,6 +101,7 @@ util::unit_test_factory!(
version_test,
wasm_test,
webcrypto_test,
+ webgpu_test,
websocket_test,
webstorage_test,
worker_permissions_test,
diff --git a/cli/tests/integration/run_tests.rs b/cli/tests/integration/run_tests.rs
index c96d68b93..32df04483 100644
--- a/cli/tests/integration/run_tests.rs
+++ b/cli/tests/integration/run_tests.rs
@@ -1660,6 +1660,17 @@ itest!(unstable_kv_enabled {
output: "run/unstable_kv.enabled.out",
});
+itest!(unstable_webgpu_disabled {
+ args: "run --quiet --reload --allow-read run/unstable_webgpu.js",
+ output: "run/unstable_webgpu.disabled.out",
+});
+
+itest!(unstable_webgpu_enabled {
+ args:
+ "run --quiet --reload --allow-read --unstable-webgpu run/unstable_webgpu.js",
+ output: "run/unstable_webgpu.enabled.out",
+});
+
itest!(import_compression {
args: "run --quiet --reload --allow-net run/import_compression/main.ts",
output: "run/import_compression/main.out",
diff --git a/cli/tests/integration/shared_library_tests.rs b/cli/tests/integration/shared_library_tests.rs
index 506c537f6..3e05f8efc 100644
--- a/cli/tests/integration/shared_library_tests.rs
+++ b/cli/tests/integration/shared_library_tests.rs
@@ -45,14 +45,25 @@ fn macos_shared_libraries() {
// target/release/deno:
// /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1953.1.0)
// /System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices (compatibility version 1.0.0, current version 1228.0.0)
+ // /System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore (compatibility version 1.2.0, current version 1.11.0, weak)
+ // /System/Library/Frameworks/Metal.framework/Versions/A/Metal (compatibility version 1.0.0, current version 341.16.0, weak)
+ // /System/Library/Frameworks/CoreGraphics.framework/Versions/A/CoreGraphics (compatibility version 64.0.0, current version 1774.0.4, weak)
+ // /System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/MetalPerformanceShaders (compatibility version 1.0.0, current version 127.0.19, weak)
// /usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)
// /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.0.0)
- const EXPECTED: [&str; 5] = [
- "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation",
- "/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices",
- "/usr/lib/libiconv.2.dylib",
- "/usr/lib/libSystem.B.dylib",
- "/usr/lib/libobjc.A.dylib",
+ // /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
+
+ // path and whether its weak or not
+ const EXPECTED: [(&str, bool); 9] = [
+ ("/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation", false),
+ ("/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices", false),
+ ("/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore", true),
+ ("/System/Library/Frameworks/Metal.framework/Versions/A/Metal", true),
+ ("/System/Library/Frameworks/CoreGraphics.framework/Versions/A/CoreGraphics", true),
+ ("/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/MetalPerformanceShaders", true),
+ ("/usr/lib/libiconv.2.dylib", false),
+ ("/usr/lib/libSystem.B.dylib", false),
+ ("/usr/lib/libobjc.A.dylib", false),
];
let otool = std::process::Command::new("otool")
@@ -64,9 +75,9 @@ fn macos_shared_libraries() {
let output = std::str::from_utf8(&otool.stdout).unwrap();
// Ensure that the output contains only the expected shared libraries.
for line in output.lines().skip(1) {
- let path = line.split_whitespace().next().unwrap();
+ let (path, attributes) = line.trim().split_once(' ').unwrap();
assert!(
- EXPECTED.contains(&path),
+ EXPECTED.contains(&(path, attributes.ends_with("weak)"))),
"Unexpected shared library: {}",
path
);
diff --git a/cli/tests/testdata/run/unstable_webgpu.disabled.out b/cli/tests/testdata/run/unstable_webgpu.disabled.out
new file mode 100644
index 000000000..775866352
--- /dev/null
+++ b/cli/tests/testdata/run/unstable_webgpu.disabled.out
@@ -0,0 +1,2 @@
+main undefined
+worker undefined
diff --git a/cli/tests/testdata/run/unstable_webgpu.enabled.out b/cli/tests/testdata/run/unstable_webgpu.enabled.out
new file mode 100644
index 000000000..e2cc915ba
--- /dev/null
+++ b/cli/tests/testdata/run/unstable_webgpu.enabled.out
@@ -0,0 +1,2 @@
+main [class GPU]
+worker [class GPU]
diff --git a/cli/tests/testdata/run/unstable_webgpu.js b/cli/tests/testdata/run/unstable_webgpu.js
new file mode 100644
index 000000000..a796b1c4d
--- /dev/null
+++ b/cli/tests/testdata/run/unstable_webgpu.js
@@ -0,0 +1,10 @@
+const scope = import.meta.url.slice(-7) === "#worker" ? "worker" : "main";
+
+console.log(scope, globalThis.GPU);
+
+if (scope === "worker") {
+ postMessage("done");
+} else {
+ const worker = new Worker(`${import.meta.url}#worker`, { type: "module" });
+ worker.onmessage = () => Deno.exit(0);
+}
diff --git a/cli/tests/testdata/webgpu/computepass_shader.wgsl b/cli/tests/testdata/webgpu/computepass_shader.wgsl
new file mode 100644
index 000000000..41af4363a
--- /dev/null
+++ b/cli/tests/testdata/webgpu/computepass_shader.wgsl
@@ -0,0 +1,38 @@
+@group(0)
+@binding(0)
+var<storage, read_write> v_indices: array<u32>; // this is used as both input and output for convenience
+
+// The Collatz Conjecture states that for any integer n:
+// If n is even, n = n/2
+// If n is odd, n = 3n+1
+// And repeat this process for each new n, you will always eventually reach 1.
+// Though the conjecture has not been proven, no counterexample has ever been found.
+// This function returns how many times this recurrence needs to be applied to reach 1.
+fn collatz_iterations(n_base: u32) -> u32{
+ var n: u32 = n_base;
+ var i: u32 = 0u;
+ loop {
+ if (n <= 1u) {
+ break;
+ }
+ if (n % 2u == 0u) {
+ n = n / 2u;
+ }
+ else {
+ // Overflow? (i.e. 3*n + 1 > 0xffffffffu?)
+ if (n >= 1431655765u) { // 0x55555555u
+ return 4294967295u; // 0xffffffffu
+ }
+
+ n = 3u * n + 1u;
+ }
+ i = i + 1u;
+ }
+ return i;
+}
+
+@compute
+@workgroup_size(1)
+fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
+ v_indices[global_id.x] = collatz_iterations(v_indices[global_id.x]);
+}
diff --git a/cli/tests/testdata/webgpu/hellotriangle.out b/cli/tests/testdata/webgpu/hellotriangle.out
new file mode 100644
index 000000000..52972ec9e
--- /dev/null
+++ b/cli/tests/testdata/webgpu/hellotriangle.out
Binary files differ
diff --git a/cli/tests/testdata/webgpu/hellotriangle_shader.wgsl b/cli/tests/testdata/webgpu/hellotriangle_shader.wgsl
new file mode 100644
index 000000000..f84ccfe94
--- /dev/null
+++ b/cli/tests/testdata/webgpu/hellotriangle_shader.wgsl
@@ -0,0 +1,11 @@
+@vertex
+fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4<f32> {
+ let x = f32(i32(in_vertex_index) - 1);
+ let y = f32(i32(in_vertex_index & 1u) * 2 - 1);
+ return vec4<f32>(x, y, 0.0, 1.0);
+}
+
+@fragment
+fn fs_main() -> @location(0) vec4<f32> {
+ return vec4<f32>(1.0, 0.0, 0.0, 1.0);
+}
diff --git a/cli/tests/unit/webgpu_test.ts b/cli/tests/unit/webgpu_test.ts
new file mode 100644
index 000000000..2d98167cf
--- /dev/null
+++ b/cli/tests/unit/webgpu_test.ts
@@ -0,0 +1,242 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+
+import { assert, assertEquals } from "./test_util.ts";
+
+let isCI: boolean;
+try {
+ isCI = (Deno.env.get("CI")?.length ?? 0) > 0;
+} catch {
+ isCI = true;
+}
+
+// Skip these tests on linux CI, because the vulkan emulator is not good enough
+// yet, and skip on macOS CI because these do not have virtual GPUs.
+const isLinuxOrMacCI =
+ (Deno.build.os === "linux" || Deno.build.os === "darwin") && isCI;
+// Skip these tests in WSL because it doesn't have good GPU support.
+const isWsl = await checkIsWsl();
+
+Deno.test({
+ permissions: { read: true, env: true },
+ ignore: isWsl || isLinuxOrMacCI,
+}, async function webgpuComputePass() {
+ const adapter = await navigator.gpu.requestAdapter();
+ assert(adapter);
+
+ const numbers = [1, 4, 3, 295];
+
+ const device = await adapter.requestDevice();
+ assert(device);
+
+ const shaderCode = await Deno.readTextFile(
+ "cli/tests/testdata/webgpu/computepass_shader.wgsl",
+ );
+
+ const shaderModule = device.createShaderModule({
+ code: shaderCode,
+ });
+
+ const size = new Uint32Array(numbers).byteLength;
+
+ const stagingBuffer = device.createBuffer({
+ size: size,
+ usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
+ });
+
+ const storageBuffer = device.createBuffer({
+ label: "Storage Buffer",
+ size: size,
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST |
+ GPUBufferUsage.COPY_SRC,
+ mappedAtCreation: true,
+ });
+
+ const buf = new Uint32Array(storageBuffer.getMappedRange());
+
+ buf.set(numbers);
+
+ storageBuffer.unmap();
+
+ const computePipeline = device.createComputePipeline({
+ layout: "auto",
+ compute: {
+ module: shaderModule,
+ entryPoint: "main",
+ },
+ });
+ const bindGroupLayout = computePipeline.getBindGroupLayout(0);
+
+ const bindGroup = device.createBindGroup({
+ layout: bindGroupLayout,
+ entries: [
+ {
+ binding: 0,
+ resource: {
+ buffer: storageBuffer,
+ },
+ },
+ ],
+ });
+
+ const encoder = device.createCommandEncoder();
+
+ const computePass = encoder.beginComputePass();
+ computePass.setPipeline(computePipeline);
+ computePass.setBindGroup(0, bindGroup);
+ computePass.insertDebugMarker("compute collatz iterations");
+ computePass.dispatchWorkgroups(numbers.length);
+ computePass.end();
+
+ encoder.copyBufferToBuffer(storageBuffer, 0, stagingBuffer, 0, size);
+
+ device.queue.submit([encoder.finish()]);
+
+ await stagingBuffer.mapAsync(1);
+
+ const data = stagingBuffer.getMappedRange();
+
+ assertEquals(new Uint32Array(data), new Uint32Array([0, 2, 7, 55]));
+
+ stagingBuffer.unmap();
+
+ device.destroy();
+
+ // TODO(lucacasonato): webgpu spec should add a explicit destroy method for
+ // adapters.
+ const resources = Object.keys(Deno.resources());
+ Deno.close(Number(resources[resources.length - 1]));
+});
+
+Deno.test({
+ permissions: { read: true, env: true },
+ ignore: isWsl || isLinuxOrMacCI,
+}, async function webgpuHelloTriangle() {
+ const adapter = await navigator.gpu.requestAdapter();
+ assert(adapter);
+
+ const device = await adapter.requestDevice();
+ assert(device);
+
+ const shaderCode = await Deno.readTextFile(
+ "cli/tests/testdata/webgpu/hellotriangle_shader.wgsl",
+ );
+
+ const shaderModule = device.createShaderModule({
+ code: shaderCode,
+ });
+
+ const pipelineLayout = device.createPipelineLayout({
+ bindGroupLayouts: [],
+ });
+
+ const renderPipeline = device.createRenderPipeline({
+ layout: pipelineLayout,
+ vertex: {
+ module: shaderModule,
+ entryPoint: "vs_main",
+ },
+ fragment: {
+ module: shaderModule,
+ entryPoint: "fs_main",
+ targets: [
+ {
+ format: "rgba8unorm-srgb",
+ },
+ ],
+ },
+ });
+
+ const dimensions = {
+ width: 200,
+ height: 200,
+ };
+ const unpaddedBytesPerRow = dimensions.width * 4;
+ const align = 256;
+ const paddedBytesPerRowPadding = (align - unpaddedBytesPerRow % align) %
+ align;
+ const paddedBytesPerRow = unpaddedBytesPerRow + paddedBytesPerRowPadding;
+
+ const outputBuffer = device.createBuffer({
+ label: "Capture",
+ size: paddedBytesPerRow * dimensions.height,
+ usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
+ });
+ const texture = device.createTexture({
+ label: "Capture",
+ size: dimensions,
+ format: "rgba8unorm-srgb",
+ usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC,
+ });
+
+ const encoder = device.createCommandEncoder();
+ const view = texture.createView();
+ const renderPass = encoder.beginRenderPass({
+ colorAttachments: [
+ {
+ view,
+ storeOp: "store",
+ loadOp: "clear",
+ clearValue: [0, 1, 0, 1],
+ },
+ ],
+ });
+ renderPass.setPipeline(renderPipeline);
+ renderPass.draw(3, 1);
+ renderPass.end();
+
+ encoder.copyTextureToBuffer(
+ {
+ texture,
+ },
+ {
+ buffer: outputBuffer,
+ bytesPerRow: paddedBytesPerRow,
+ rowsPerImage: 0,
+ },
+ dimensions,
+ );
+
+ const bundle = encoder.finish();
+ device.queue.submit([bundle]);
+
+ await outputBuffer.mapAsync(1);
+ const data = new Uint8Array(outputBuffer.getMappedRange());
+
+ assertEquals(
+ data,
+ await Deno.readFile("cli/tests/testdata/webgpu/hellotriangle.out"),
+ );
+
+ outputBuffer.unmap();
+
+ device.destroy();
+
+ // TODO(lucacasonato): webgpu spec should add a explicit destroy method for
+ // adapters.
+ const resources = Object.keys(Deno.resources());
+ Deno.close(Number(resources[resources.length - 1]));
+});
+
+Deno.test({
+ ignore: isWsl || isLinuxOrMacCI,
+}, async function webgpuAdapterHasFeatures() {
+ const adapter = await navigator.gpu.requestAdapter();
+ assert(adapter);
+ assert(adapter.features);
+ const resources = Object.keys(Deno.resources());
+ Deno.close(Number(resources[resources.length - 1]));
+});
+
+async function checkIsWsl() {
+ return Deno.build.os === "linux" && await hasMicrosoftProcVersion();
+
+ async function hasMicrosoftProcVersion() {
+ // https://github.com/microsoft/WSL/issues/423#issuecomment-221627364
+ try {
+ const procVersion = await Deno.readTextFile("/proc/version");
+ return /microsoft/i.test(procVersion);
+ } catch {
+ return false;
+ }
+ }
+}