Skip to content

Commit

Permalink
feat: new std/webgpu sub-module (#3119)
Browse files Browse the repository at this point in the history
* work

* lint fix

* fmt

* tweaks

* doc

* housekeeping

* fix up, add tests

* remove web compatible

* tweaks

* fix test names

* add examples

* fix up

* remove debug

* Update webgpu/mod.ts

Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com>

---------

Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com>
  • Loading branch information
crowlKats and iuioiua authored Dec 12, 2023
1 parent c3a0086 commit cd7cbb2
Show file tree
Hide file tree
Showing 13 changed files with 1,012 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
* @kt3k
/streams @kt3k @crowlKats
/webgpu @kt3k @crowlKats
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ Check out the documentation [here](https://deno.land/std?doc).
| ulid | Unstable |
| url | Unstable |
| uuid | Stable |
| webgpu | Unstable |
| yaml | Stable |

> For background and discussions regarding the stability of the following
Expand Down
1 change: 1 addition & 0 deletions _tools/check_circular_submodule_dependencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ deps["toml"] = await check("toml", "ready");
deps["ulid"] = await check("ulid", "not ready");
deps["url"] = await check("url", "not ready");
deps["uuid"] = await check("uuid", "ready");
deps["webgpu"] = await check("webgpu", "not ready");
deps["yaml"] = await check("yaml", "ready");

/** Checks circular deps between sub modules */
Expand Down
40 changes: 40 additions & 0 deletions webgpu/_test_util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

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;
}
}
}

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();

export const ignore = isWsl || isLinuxOrMacCI;

export function cleanUp(device: GPUDevice) {
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]));
}
90 changes: 90 additions & 0 deletions webgpu/create_capture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

import { getRowPadding } from "./row_padding.ts";

/** Return value for {@linkcode createCapture}. */
export interface CreateCapture {
/**
* Texture to be used as view to render to.
*/
texture: GPUTexture;

/**
* Represents the output buffer of the rendered texture.
* Can then be used to access and retrieve raw image data.
*/
outputBuffer: GPUBuffer;
}

/**
* Creates a texture and buffer to use as a capture.
*
* @example
* ```ts
* import { createCapture } from "https://deno.land/std@$STD_VERSION/webgpu/create_capture.ts";
* import { getRowPadding } from "https://deno.land/std@$STD_VERSION/webgpu/row_padding.ts";
*
* const adapter = await navigator.gpu.requestAdapter();
* const device = await adapter?.requestDevice()!;
*
* const dimensions = {
* width: 200,
* height: 200,
* };
*
* const { texture, outputBuffer } = createCapture(device, dimensions.width, dimensions.height);
*
* const encoder = device.createCommandEncoder();
* encoder.beginRenderPass({
* colorAttachments: [
* {
* view: texture.createView(),
* storeOp: "store",
* loadOp: "clear",
* clearValue: [1, 0, 0, 1],
* },
* ],
* }).end();
*
* const { padded } = getRowPadding(dimensions.width);
*
* encoder.copyTextureToBuffer(
* {
* texture,
* },
* {
* buffer: outputBuffer,
* bytesPerRow: padded,
* },
* dimensions,
* );
*
* device.queue.submit([encoder.finish()]);
*
* // outputBuffer contains the raw image data, can then be used
* // to save as png or other formats.
* ```
*/
export function createCapture(
device: GPUDevice,
width: number,
height: number,
): CreateCapture {
const { padded } = getRowPadding(width);
const outputBuffer = device.createBuffer({
label: "Capture",
size: padded * height,
usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
});
const texture = device.createTexture({
label: "Capture",
size: {
width,
height,
},
format: "rgba8unorm-srgb",
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC,
});

return { texture, outputBuffer };
}
35 changes: 35 additions & 0 deletions webgpu/create_capture_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

import { assert, assertEquals } from "../assert/mod.ts";
import { cleanUp, ignore } from "./_test_util.ts";
import { createCapture } from "./create_capture.ts";

Deno.test({
ignore,
name: "createCapture()",
fn: async () => {
const adapter = await navigator.gpu.requestAdapter();
assert(adapter);
const device = await adapter.requestDevice();
assert(device);

const { texture, outputBuffer } = createCapture(device, 2, 2);

assertEquals(texture.width, 2);
assertEquals(texture.height, 2);
assertEquals(texture.depthOrArrayLayers, 1);
assertEquals(texture.dimension, "2d");
assertEquals(
texture.usage,
GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC,
);

assertEquals(outputBuffer.size, 512);
assertEquals(
outputBuffer.usage,
GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
);

cleanUp(device);
},
});
Loading

0 comments on commit cd7cbb2

Please sign in to comment.