Skip to content

Commit

Permalink
fixes and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
kmamal committed Dec 22, 2022
1 parent a1628d0 commit 0a90d57
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 2 deletions.
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,16 @@
[![Vulnerabilities](https://img.shields.io/snyk/vulnerabilities/npm/%2540kmamal%252Fgpu)](https://snyk.io/test/npm/@kmamal/gpu)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

Builds and releases the [Google Dawn bindings for Node.js](https://dawn.googlesource.com/dawn/+/refs/heads/main/src/dawn/node/) for use with [@kmamal/gpu](https://github.com/kmamal/gpu).
> BEWARE: The [WebGPU specification](https://gpuweb.github.io/gpuweb/) is still a work-in-progress and could change at any time.
WebGPU for Node.js via [Google Dawn](https://dawn.googlesource.com/dawn/+/refs/heads/main/src/dawn/node/).
Allows you to use WebGPU without having to use a browser.

Check the [examples](https://github.com/kmamal/node-sdl/tree/master/examples) for how to use this package. You can use both [compute](https://github.com/kmamal/node-sdl/tree/master/examples/00-compute), and [render](https://github.com/kmamal/node-sdl/tree/master/examples/01-render) pipelines, just note that there's no surface to display the render result on, so you have to read it out into a buffer to use it.

It should work on Linux, Mac, and Windows. Prebuilt binaries are available for x64 architectures, and arm-based Macs.

### TODO

In the future you should be able to use this package together with [@kmamal/sdl](https://github.com/kmamal/node-sdl#readme) to get direct rendering to window surfaces.
The goal of this package is to be for WebGPU what [@kmamal/gl](https://github.com/kmamal/headless-gl#readme) is for WebGL.
1 change: 1 addition & 0 deletions examples/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
**/package-lock.json
5 changes: 5 additions & 0 deletions examples/00-compute/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import gpu from '@kmamal/gpu'

const instance = gpu.create([])
const adapter = await instance.requestAdapter()
const device = await adapter.requestDevice()
9 changes: 9 additions & 0 deletions examples/00-compute/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"version": "0.0.0",
"name": "gpu-example-compute",
"main": "index.js",
"type": "module",
"dependencies": {
"@kmamal/gpu": "*"
}
}
151 changes: 151 additions & 0 deletions examples/01-render/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import gpu from '@kmamal/gpu'
import sdl from '@kmamal/sdl'

const window = sdl.video.createWindow({ accelerated: false })
const { width, height } = window

const instance = gpu.create([])
const adapter = await instance.requestAdapter()
const device = await adapter.requestDevice()

const colorTexture = device.createTexture({
size: [ width, height, 1 ],
dimension: '2d',
format: 'rgba8unorm',
usage: gpu.TextureUsage.RENDER_ATTACHMENT | gpu.TextureUsage.COPY_SRC,
})
const colorTextureView = colorTexture.createView()

const bufferSize = width * height * 4
const readBuffer = device.createBuffer({
size: bufferSize,
usage: gpu.BufferUsage.COPY_DST | gpu.BufferUsage.MAP_READ,
})

const positions = new Float32Array([
...[ 1.0, -1.0, 0.0 ],
...[ -1.0, -1.0, 0.0 ],
...[ 0.0, 1.0, 0.0 ],
])

const colors = new Float32Array([
...[ 1.0, 0.0, 0.0 ],
...[ 0.0, 1.0, 0.0 ],
...[ 0.0, 0.0, 1.0 ],
])

const indices = new Uint16Array([ 0, 1, 2 ])

const createBuffer = (arr, usage) => {
const buffer = device.createBuffer({
size: (arr.byteLength + 3) & ~3,
usage,
mappedAtCreation: true,
})

const writeArray = arr instanceof Uint16Array
? new Uint16Array(buffer.getMappedRange())
: new Float32Array(buffer.getMappedRange())
writeArray.set(arr)
buffer.unmap()
return buffer
}

const positionBuffer = createBuffer(positions, gpu.BufferUsage.VERTEX)
const colorBuffer = createBuffer(colors, gpu.BufferUsage.VERTEX)
const indexBuffer = createBuffer(indices, gpu.BufferUsage.INDEX)

const vertexShader = `
struct VSOut {
@builtin(position) Position: vec4<f32>,
@location(0) color: vec3<f32>,
};
@vertex
fn main(@location(0) inPos: vec3<f32>, @location(1) inColor: vec3<f32> ) -> VSOut {
var vsOut: VSOut;
vsOut.Position = vec4<f32>(inPos, 1.0);
vsOut.color = inColor;
return vsOut;
}
`

const fragmentShader = `
@fragment
fn main(@location(0) inColor: vec3<f32>) -> @location(0) vec4<f32> {
return vec4<f32>(inColor, 1.0);
}
`

const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: {
module: device.createShaderModule({ code: vertexShader }),
entryPoint: 'main',
buffers: [
{
attributes: [
{
shaderLocation: 0,
offset: 0,
format: 'float32x3',
},
],
arrayStride: 3 * Float32Array.BYTES_PER_ELEMENT,
stepMode: 'vertex',
},
{
attributes: [
{
shaderLocation: 1,
offset: 0,
format: 'float32x3',
},
],
arrayStride: 3 * Float32Array.BYTES_PER_ELEMENT,
stepMode: 'vertex',
},
],
},
fragment: {
module: device.createShaderModule({ code: fragmentShader }),
entryPoint: 'main',
targets: [ { format: 'rgba8unorm' } ],
},
primitive: {
topology: 'triangle-list',
},
})

const commandEncoder = device.createCommandEncoder()

const renderPass = commandEncoder.beginRenderPass({
colorAttachments: [
{
view: colorTextureView,
clearValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },
loadOp: 'clear',
storeOp: 'store',
},
],
})
renderPass.setPipeline(pipeline)
renderPass.setViewport(0, 0, width, height, 0, 1)
renderPass.setScissorRect(0, 0, width, height)
renderPass.setVertexBuffer(0, positionBuffer)
renderPass.setVertexBuffer(1, colorBuffer)
renderPass.setIndexBuffer(indexBuffer, 'uint16')
renderPass.drawIndexed(3)
renderPass.end()

commandEncoder.copyTextureToBuffer(
{ texture: colorTexture },
{ buffer: readBuffer, bytesPerRow: width * 4 },
{ width, height },
)

device.queue.submit([ commandEncoder.finish() ])

await readBuffer.mapAsync(gpu.MapMode.READ)
const resultBuffer = new Uint8Array(readBuffer.getMappedRange())
window.render(width, height, width * 4, 'rgba32', Buffer.from(resultBuffer))
10 changes: 10 additions & 0 deletions examples/01-render/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"version": "0.0.0",
"name": "gpu-example-render",
"main": "index.js",
"type": "module",
"dependencies": {
"@kmamal/gpu": "*",
"@kmamal/sdl": "*"
}
}
12 changes: 12 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Examples

## [0. Compute Pipeline](https://github.com/kmamal/node-sdl/tree/master/examples/00-compute)

Multiplies two matrices together and prints the result.

## [1. Render Pipeline](https://github.com/kmamal/node-sdl/tree/master/examples/01-render)

Renders a triagle and displays it in a window.


// TODO: more
2 changes: 1 addition & 1 deletion scripts/util/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ dir.publish = Path.join(dir.root, 'publish')

const pkgPath = Path.join(dir.root, 'package.json')
const pkg = JSON.parse(Fs.readFileSync(pkgPath).toString())
const version = pkg.version.slice(0, pkg.version.indexOf('-'))
const version = pkg.version
const [ , owner, repo ] = pkg.repository.url.match(/([^/:]+)\/([^/]+).git$/u)

const { platform, arch } = process
Expand Down

0 comments on commit 0a90d57

Please sign in to comment.