这是indexloc提供的服务,不要输入任何密码
Skip to content

Conversation

@JusSn
Copy link
Contributor

@JusSn JusSn commented Feb 11, 2019

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.


const verticesBufferDescriptor = {
size: vertexArray.byteLength,
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.TRANSFER_DST
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd move this comment to above line 150.

clearColor: { r: 0.5, g: 1.0, b: 1.0, a: 1.0 }
};

// GPUExtent3D
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wish we could do something more type-safe here. It seems silly to attach a 3D size to a 2D texture.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At a glance, this looks like a UUID. 🤮

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should at least make them consistent with the other texture formats.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I missed this one when updating the names.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of writing into globals, it's probably better style to return a collection of all the variables.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds very functional indeed.

};
}

class MappedBufferBindGroup {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I understand what you're saying now. Shouldn't mapWriteAsync only resolve after the GPU is done with the buffer?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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([
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no idea whether this giant array is correct. Can't you compute it at runtime?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the input a pointer to a float4x4?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean as opposed to a reference or copy?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As opposed to the more normal HLSL mechanism of defining a cbuffer/ConstantBuffer with your input variables.


const depthTexture = device.createTexture(depthTextureDescriptor);

// GPURenderPassDepthStencilAttachmentDescriptor
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this comment.

this.bindGroup = bindGroup;
}
}
const mappedGroups = [];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a newline.

} else
mappedGroup = mappedGroups.shift();

updateTransformArray(mappedGroup.arrayBuffer);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving myself a note here to fix: updateTransformArray takes a Float32Array, not an ArrayBuffer.

Copy link
Contributor

@kdashg kdashg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we link to an external source for the library?
https://cdnjs.com/libraries/gl-matrix

@JusSn
Copy link
Contributor Author

JusSn commented Jul 1, 2019

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

@JusSn JusSn merged commit 627d096 into gpuweb:master Jul 1, 2019
Kangz pushed a commit to Kangz/gpuweb that referenced this pull request Jul 9, 2019
* 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
ben-clayton pushed a commit to ben-clayton/gpuweb that referenced this pull request Sep 6, 2022
Using npm slightly reduces unnecessary dependencies of the project.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants