Sitelet https://github.com/gpuweb/gpuweb/pull/650/files
Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions spec/index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -2391,6 +2391,13 @@ interface GPUCommandEncoder {
GPUTextureCopyView destination,
GPUExtent3D copySize);

void inlineUpdateBuffer(
ArrayBuffer source,
GPUSize64 sourceOffset,
GPUBuffer destination,
GPUSize64 destinationOffset,
GPUSize64 size);

void pushDebugGroup(DOMString groupLabel);
void popDebugGroup();
void insertDebugMarker(DOMString markerLabel);
Expand Down Expand Up @@ -2517,6 +2524,52 @@ dictionary GPUImageBitmapCopyView {
</div>
</div>

### <dfn method for=GPUCommandEncoder>inlineUpdateBuffer(source, sourceOffset, destination, destinationOffset, size)</dfn> ### {#GPUCommandEncoder-inlineUpdateBuffer}

It's often useful for applications to update buffer data prior to draw or compute operations.
For example, updating model-view and projection matrices before or interleaved with rendering of a scene.
When these uploads are small, it's viable to inline the update data into the command buffer.
This does require more copies than other upload paths, but for small data sizes this overhead is negligible.
Implementations are expected to warn against using this for medium-to-large buffer updates. (e.g. >64k)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Where do we draw the line of the "suboptimal" behavior? I.e. what if an application updates 64k of different multiple buffers? what if it updates 64k of data of the same buffer? does it matter if the updated range is the same? etc

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The problem with warnings here is that this size could easily be unknown at build/development time. Say, the developer loads a mesh and updates some vertices using this function, and everything works on their machine. But then later an user loads a bigger mesh, and not only they get a warning spam, it's also animating suspiciously slow, because of how many copies the data needs to go through (i.e. 4 on this path, as estimated by @Kangz).


In Vulkan, this is similar to |vkCmdUpdateBuffer|.
In D3D12, implementations can leverage |ID3D12GraphicsCommandList2::WriteBufferImmediate|.
Comment thread
kvark marked this conversation as resolved.
Metal might use |makeBuffer(bytesNoCopy:length:options:deallocator:)| around some section of shared command buffer serialization memory.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I wonder how this would work in practice. It requires page-size alignment for both the pointer and the size, and also:

The existing memory allocation must be covered by a single VM region, typically allocated with vm_allocate or mmap. Memory allocated by malloc is specifically disallowed.


<div algorithm="GPUCommandEncoder.inlineUpdateBuffer">

**Arguments:**
- {{ArrayBuffer}} |source|
- {{GPUSize64}} |sourceOffset|
- {{GPUBuffer}} |destination|
- {{GPUSize64}} |destinationOffset|
- {{GPUSize64}} |size|

**Returns:** void

Embed a copy of |source| from |sourceOffset| to |size| into the {{GPUCommandEncoder}}.
Encode a command into the {{GPUCommandEncoder}} that copies |size| bytes of data from embedded copy to the |destinationOffset| of another {{GPUBuffer}} |destination|.

<div class=validusage dfn-for=GPUCommandEncoder.inlineUpdateBuffer>
<dfn abstract-op>Valid Usage</dfn>

Given a {{GPUCommandEncoder}} |encoder| and the arguments {{ArrayBuffer}} |source|, {{GPUSize64}} |sourceOffset|, {{GPUBuffer}} |destination|, {{GPUSize64}} |destinationOffset|, {{GPUSize64}} |size|, the following validation rules apply:

- |encoder| must be a [=valid=] {{GPUCommandEncoder}}.
- |encoder|.{{GPUCommandEncoder/inlineUpdateBuffer()}} must not be called when a {{GPURenderPassEncoder}} is active on |encoder|.
- |encoder|.{{GPUCommandEncoder/inlineUpdateBuffer()}} must not be called when a {{GPUComputePassEncoder}} is active on |encoder|.
- |destination| must be a [=valid=] {{GPUBuffer}}.
- The {{GPUBuffer/[[usage]]}} of |destination| must contain {{GPUBufferUsage/COPY_DST}}.
- |size| must be a multiple of 4.
- |sourceOffset| must be a multiple of 4.
- |destinationOffset| must be a multiple of 4.
- (|sourceOffset| + |size|) must not overflow a {{GPUSize64}}.
- (|destinationOffset| + |size|) must not overflow a {{GPUSize64}}.
- The {{ArrayBuffer/byteLength}} of |source| must be greater than or equal to (|sourceOffset| + |size|).
- The {{GPUBuffer/[[size]]}} of |destination| must be greater than or equal to (|destinationOffset| + |size|).
</div>
</div>

## Programmable Passes ## {#programmable-passes}

<script type=idl>
Expand Down