Repository navigation
Add reference Web GPU Spinning Cube Demo and glMatrix - #209
Conversation
|
|
||
| const verticesBufferDescriptor = { | ||
| size: vertexArray.byteLength, | ||
| usage: GPUBufferUsage.VERTEX | GPUBufferUsage.TRANSFER_DST |
There was a problem hiding this comment.
It's kind of unfortunate that setSubData requires TRANSFER_DST and nothing else. On UMA, setSubData might be able to write directly into the buffer (if the stars align correctly).
| depthCompare: "less" | ||
| }; | ||
|
|
||
| /* Render Pipeline */ |
There was a problem hiding this comment.
I'd move this comment to above line 150.
| clearColor: { r: 0.5, g: 1.0, b: 1.0, a: 1.0 } | ||
| }; | ||
|
|
||
| // GPUExtent3D |
There was a problem hiding this comment.
I wish we could do something more type-safe here. It seems silly to attach a 3D size to a 2D texture.
There was a problem hiding this comment.
Yeah, maybe we need GPUSize2D and GPUSize3D (I prefer both of them over "Extent")
| mipLevelCount: 1, | ||
| sampleCount: 1, | ||
| dimension: "2d", | ||
| format: "d32-float-s8-uint", |
There was a problem hiding this comment.
At a glance, this looks like a UUID. 🤮
There was a problem hiding this comment.
We should at least make them consistent with the other texture formats.
There was a problem hiding this comment.
I think I missed this one when updating the names.
There was a problem hiding this comment.
Oh, you forgot to include depth and stencil formats when you updated the list of texture formats in the IDL. I'll make a PR in a bit to add them.
| clearDepth: 1.0 | ||
| }; | ||
|
|
||
| renderPassDescriptor = { |
There was a problem hiding this comment.
Instead of writing into globals, it's probably better style to return a collection of all the variables.
There was a problem hiding this comment.
That sounds very functional indeed.
| }; | ||
| } | ||
|
|
||
| class MappedBufferBindGroup { |
There was a problem hiding this comment.
I think if we're going to add classes as helpers, we could do the same for the transform array matrix. e.g. a class that holds the mappedGroup and exposes the arrayBuffer.
| queue.submit([commandEncoder.finish()]); | ||
|
|
||
| // Ready the current buffer for update after GPU is done with it. | ||
| mappedGroup.buffer.mapWriteAsync().then((arrayBuffer) => { |
There was a problem hiding this comment.
The right thing will happen here, but we might not wants apps to rely on the specific timeline that the mapWriteAsync promise resolves. It may be better to explicitly handle the dependency of "the mapping should happen after the command buffer finishes" by using fences. I'm not sure which behavior we want to promote.
There was a problem hiding this comment.
If this does the right thing, it's probably more readable than barriers.
The thing that I think is a bit weird is that mappedGroups could grow infinitely (if some other part of the code appends to it outside this loop). It's a shame we can't attach the group to the queue or something.
There was a problem hiding this comment.
I have this example working with my mapWriteAsync() prototype. I could use a class to control access to the mappedGroups queue, if that's what you mean?
There was a problem hiding this comment.
Oh, I understand what you're saying now. Shouldn't mapWriteAsync only resolve after the GPU is done with the buffer?
There was a problem hiding this comment.
Yes, but it means that we don't have any pipelining here based on how I understand it. We cannot upload the data for the second frame until the GPU is done with the data for the first. Our example should support double-buffering.
| mappedGroup.buffer.unmap(); | ||
|
|
||
| const commandEncoder = device.createCommandEncoder(); | ||
| renderPassDescriptor.colorAttachments[0].attachment = swapChain.getTexture().createDefaultTextureView(); |
There was a problem hiding this comment.
You've got a single render pass descriptor that every render pass uses. This implicitly requires that beginRenderPass copy the contents of the descriptor so that the next frame doesn't clobber the current frame's execution. This might be okay, but it might not be. If it isn't okay, the group should decide on a mechanism to make it obvious to authors what is going wrong when they write the same code you have here.
|
|
||
| const vertexSize = 4 * 8; | ||
| const colorOffset = 4 * 4; | ||
| const vertexArray = new Float32Array([ |
There was a problem hiding this comment.
I have no idea whether this giant array is correct. Can't you compute it at runtime?
There was a problem hiding this comment.
This is fairly standard in all spinning cube demos. I don't think it is a big deal. Computing it at runtime would probably be an equally confusing set of for loops.
Maybe the best thing to do would be to name the variables cubeVertices, and provide comments for the 4 * 8 and 4 * 4 values.
| <script src="gl-matrix-min.js"></script> | ||
| </head> | ||
| <body> | ||
| <canvas height=1000 width=1000></canvas> |
There was a problem hiding this comment.
You set a 600px viewport above, so 1000x1000 would be mostly offscreen.
|
|
||
| vertex FragmentData vertex_main(float4 position : attribute(0), | ||
| float4 color : attribute(1), | ||
| constant float4x4* modelViewProjectionMatrix : register(b0)) { |
There was a problem hiding this comment.
Why is the input a pointer to a float4x4?
There was a problem hiding this comment.
Do you mean as opposed to a reference or copy?
There was a problem hiding this comment.
As opposed to the more normal HLSL mechanism of defining a cbuffer/ConstantBuffer with your input variables.
|
|
||
| const depthTexture = device.createTexture(depthTextureDescriptor); | ||
|
|
||
| // GPURenderPassDepthStencilAttachmentDescriptor |
There was a problem hiding this comment.
I don't understand this comment.
| this.bindGroup = bindGroup; | ||
| } | ||
| } | ||
| const mappedGroups = []; |
There was a problem hiding this comment.
This should probably go at the top.
| const { buffer, arrayBuffer } = device.createMappedBuffer(transformBufferDescriptor); | ||
| const bindGroup = device.createBindGroup(createTransformBindGroupDescriptor(buffer)); | ||
|
|
||
| mappedGroup = new MappedBufferBindGroup(buffer, arrayBuffer, bindGroup); |
There was a problem hiding this comment.
Since a MappedBufferBindGroup doesn't have anything other than a constructor, it's basically equivalent to an anonymous object. i.e. you could omit the class and just say:
mappedGroup = { buffer, arrayBuffer, bindGroup };
| init(); | ||
| </script> | ||
| </body> | ||
| </html> No newline at end of file |
| } else | ||
| mappedGroup = mappedGroups.shift(); | ||
|
|
||
| updateTransformArray(mappedGroup.arrayBuffer); |
There was a problem hiding this comment.
Leaving myself a note here to fix: updateTransformArray takes a Float32Array, not an ArrayBuffer.
kdashg
left a comment
There was a problem hiding this comment.
Can we link to an external source for the library?
https://cdnjs.com/libraries/gl-matrix
|
I've updated the file to match our API changes and removed the library file in favor of an external source. It does not work in current Safari since WHLSL is not the default ingestion format yet. Feel free to make a PR after merging to feature-detect and use SPIR-V shaders, or other API updates I may have missed @kainino0x @austinEng |
* Add reference demo files * Add shading language notice * Addressed basic review issues * Small fixes * Add some clarifying comments * Update to IDL commit e137ea9 * Attempt to get WHLSL shaders working * whoops * Update reference for submission * Delete gl-matrix-min.js
Using npm slightly reduces unnecessary dependencies of the project.
This demo serves as a reference for a Web GPU implementation. It reflects the current API as well as approved pull requests.
Also included is the glMatrix matrix math library by Brandon Jones.