Directory portal: juejin.cn/post/701059…
Chapter 11, part 12 and chapter 17 of the original text are introduced.
1 Instruction cache: GPUCommandBuffer
An instruction buffer (also known as a command buffer), GPUCommandBuffer, is a storage container that can store GPU instructions in advance. It can be submitted to the GPUQueue for execution. Each GPU instruction represents a task to be performed by the GPU, which can be drawing, setting up data, copying resources, etc.
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUCommandBuffer {
readonly attribute Promise<double> executionTime;
};
GPUCommandBuffer includes GPUObjectBase;
Copy the code
It has a Promise with a double resolve value, which is the execution time of the pre-stored GPU instruction on the instruction cache.
If the measureExecutionTime of an instruction encoder is true when it is created, and the Promise is reject when it is false, you can catch an OperationError.
How to create
Call the Finish method of [instruction encoder](#2 instruction encoder: GPUCommandEncoder) to get the instruction cache object. It is generally used to submit to a queue:
device.queue.submit([
commandEncoder.finish()
])
Copy the code
2 Instruction coder: GPUCommandEncoder
Purpose: ① create channel encoder; ② Duplicate GPUBuffer/GPUTexture; ③ Debugging, query and other functions (omitted)
This paper mainly introduces the common ①, ② two functions.
Note that after the instruction encoder is used up and submitted to the queue, it is no longer available.
Instruction encoders in Metal
Its WebIDL definition is as follows:
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUCommandEncoder {
GPURenderPassEncoder beginRenderPass(GPURenderPassDescriptor descriptor);
GPUComputePassEncoder beginComputePass(optional GPUComputePassDescriptor descriptor = {});
undefined copyBufferToBuffer(
GPUBuffer source,
GPUSize64 sourceOffset,
GPUBuffer destination,
GPUSize64 destinationOffset,
GPUSize64 size);
undefined copyBufferToTexture(
GPUImageCopyBuffer source,
GPUImageCopyTexture destination,
GPUExtent3D copySize);
undefined copyTextureToBuffer(
GPUImageCopyTexture source,
GPUImageCopyBuffer destination,
GPUExtent3D copySize);
undefined copyTextureToTexture(
GPUImageCopyTexture source,
GPUImageCopyTexture destination,
GPUExtent3D copySize);
undefined pushDebugGroup(USVString groupLabel);
undefined popDebugGroup();
undefined insertDebugMarker(USVString markerLabel);
undefined writeTimestamp(GPUQuerySet querySet, GPUSize32 queryIndex);
undefined resolveQuerySet(
GPUQuerySet querySet,
GPUSize32 firstQuery,
GPUSize32 queryCount,
GPUBuffer destination,
GPUSize64 destinationOffset);
GPUCommandBuffer finish(optional GPUCommandBufferDescriptor descriptor = {});
};
GPUCommandEncoder includes GPUObjectBase;
Copy the code
2.1 How can I Create a Vm?
Created by the device object’s createCommandEncoder method
const commandEncoder = device.createCommandEncoder()
Copy the code
It has an optional parameter Object, type is GPUCommandEncoderDescriptor, a JavaScript Object:
dictionary GPUCommandEncoderDescriptor : GPUObjectDescriptorBase {
boolean measureExecutionTime = false;
};
Copy the code
Its purpose was described in the instruction cache creation section, and the optional attribute measureExecutionTime indicates whether the running time of the instruction can be measured.
2.2 Purpose: Start/create a programmable channel
BeginRenderPass and beginComputePass of the instruction encoder can start/create a rendering channel or a calculation channel respectively. The return values of these two methods are naturally GPURenderPassEncoder and GPUComputePassEncoder.
// Render channel encoder
const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor)
// Calculate channel encoder
const computeEncoder = commandEncoder.beginComputePass()
Copy the code
See the channel encoder article for details of the parameter object renderPassDescriptor required by the channel encoder.
The instruction encoder is not responsible for the termination of the channel encoder, but rather the termination of the channel encoder itself.
2.2 Purpose: Cache Replication
The copyBufferToBuffer method is used for copying between GPUBuffers.
undefined copyBufferToBuffer(
GPUBuffer source,
GPUSize64 sourceOffset,
GPUBuffer destination,
GPUSize64 destinationOffset,
GPUSize64 size
);
Copy the code
That is, copy from source to destination. In the article Buffer, there is a brief mention of the difference between this method and direct map/unmap to assign data, that is, this method is operated on GPU. Map /unmap writes data directly to the GPUBuffer on the CPU side.
For example,
const gpuWriteBuffer = device.createBuffer({ /* is used to write */})
const gpuReadBuffer = device.createBuffer({ /* Used to read */})
// Copy from one to another
copyEncoder.copyBufferToBuffer(
gpuWriteBuffer /* Source video memory (object) */.0 /* Start byte (where to read from) */,
gpuReadBuffer /* Target video memory (object) */.0 /* Start byte (where to start writing) */.4 /* The size of the copy, in byte */
);
Copy the code
2.3 Purpose: Image/texture replication
The main methods are copyBufferToTexture, copyTextureToBuffer, copyTextureToTexture, Used for copying between GPUBuffer and GPUTexture, GPUTexture and GPUTexture.
The GPUImageCopyBuffer, GPUImageCopyTexture and GPUExtent3D dictionary definitions are used.
Method definition
Go to the trouble of copying the definition again from GPUCommandEncoder above.
undefined copyBufferToTexture(
GPUImageCopyBuffer source,
GPUImageCopyTexture destination,
GPUExtent3D copySize
);
undefined copyTextureToBuffer(
GPUImageCopyTexture source,
GPUImageCopyBuffer destination,
GPUExtent3D copySize
);
undefined copyTextureToTexture(
GPUImageCopyTexture source,
GPUImageCopyTexture destination,
GPUExtent3D copySize
);
Copy the code
They work at the instruction level and are arranged on instruction queues, i.e., operations on the GPU, not on the CPU, just like copyBufferToBuffer.
Each method has a compliance check, mainly to verify the parameters, will not expand. Three types are used here:
GPUImageCopyBuffer type
dictionary GPUImageCopyBuffer : GPUImageDataLayout {
required GPUBuffer buffer;
};
Copy the code
Quite simply, it’s just a normal JavaScript object with a buffer field of type GPUBuffer.
GPUImageCopyTexture type
dictionary GPUImageCopyTexture {
required GPUTexture texture;
GPUIntegerCoordinate mipLevel = 0;
GPUOrigin3D origin = {};
GPUTextureAspect aspect = "all";
};
Copy the code
In addition to the texture field of the mandatory GPUTexture type, there are three optional parameters:
mipLevel
, unsigned long, which copies the corresponding multilevel texture.origin
.GPUOrigin3D
Type, specify the texture copy starting point, here ignore the definition, there is a need for readers to consult the document, relatively simple;aspect
.GPUTextureAspect
Type that specifies what aspect of the texture to copy, as described in textures
GPUExtent3D type
dictionary GPUExtent3DDict {
required GPUIntegerCoordinate width;
GPUIntegerCoordinate height = 1;
GPUIntegerCoordinate depthOrArrayLayers = 1;
};
typedef (sequence<GPUIntegerCoordinate> or GPUExtent3DDict) GPUExtent3D;
Copy the code
It is defined in two ways: number[] in TypeScript;
The other is the GPUExtent3DDict type:
width
Represents the width of the range and must be passedheight
Indicates the range height. The default is 1depthOrArrayLayers
Indicates depth or number of layers. Default is 1
This means that you can pass an array directly, or you can pass a key-value object to represent the range required for each dimension.
3 Instruction queue: GPUQueue
It holds the instruction cache (#1 instruction cache: GPUCommandBuffer) and is responsible for submitting the instruction cache to the GPU.
The instruction queue object is a property of the device object and cannot be created by the user.
The definitions of the above three methods and the GPUQueue type are as follows:
[Exposed=(Window, DedicatedWorker), SecureContext]
interface GPUQueue {
undefined submit(sequence<GPUCommandBuffer> commandBuffers);
Promise<undefined> onSubmittedWorkDone();
undefined writeBuffer(
GPUBuffer buffer,
GPUSize64 bufferOffset,
[AllowShared] BufferSource data,
optional GPUSize64 dataOffset = 0,
optional GPUSize64 size
);
undefined writeTexture(
GPUImageCopyTexture destination,
[AllowShared] BufferSource data,
GPUImageDataLayout dataLayout,
GPUExtent3D size
);
undefined copyExternalImageToTexture(
GPUImageCopyExternalImage source,
GPUImageCopyTextureTagged destination,
GPUExtent3D copySize
);
};
GPUQueue includes GPUObjectBase;
Copy the code
Among them,
submit
The submit () method is used to submit an instruction cache array.onSubmittedWorkDone
Method returns a Promise that will resolve, but with no resolve value, once every instruction cache in the array of directives that have been submitted so far has been processed.
In addition to executing instructions on the instruction cache one by one, the queue objects themselves can perform some operations, such as:
- WriteTexture: Writes textures
- WriteBuffer: Write to the cache
- CopyExternalImageToTexture: from the external image to write data to the texture
Such operations.
Among them:
The writeTexture method requires additional GPUImageCopyTexture, GPUImageDataLayout, and GPUExtent3D types. CopyExternalImageToTexture need GPUImageCopyExternalImage, GPUImageCopyTextureTagged and GPUExtent3D type.
It is important to note that the three write operations are at the queue level and have equal status to the single encoded instruction (i.e., the instruction cache), except that the instruction commit execution is asynchronous, whereas the three operations are synchronous.
3.1 writeBuffer method: writeBuffer
It allows you to write data of type BufferSource to a GPUBuffer object.
Allows you to specify data offset, size, and GPUBuffer offset.
BufferSource is an associative type, defined in JavaScript as an ArrayBuffer, an array of all types, and a associative type of DataView.
3.2 Writing texture data
There are two methods for writing texture data:
writeTexture
Method will beBufferSource
(as mentioned in Section 3.1) data layout described by objects of type [GPUImageDataLayout](#GPUImageDataLayout type), Write to the texture object described by [GPUImageCopyTexture](#GPUImageCopyTexture type);copyExternalImageToTexture
Methods [GPUImageCopyExternalImage] (# GPUImageCopyExternalImage type) object description of external data sources (HTMLCanvasElement, ImageBitmap, etc.), Written to the [GPUImageCopyTextureTagged] (# GPUImageCopyTextureTagged type) object to describe texture in the object
GPUImageDataLayout type
dictionary GPUImageDataLayout {
GPUSize64 offset = 0;
GPUSize32 bytesPerRow;
GPUSize32 rowsPerImage;
};
Copy the code
It represents what an image looks like in a byte array. Offset indicates where an image is read from the data source; BytesPerRow indicates how many pixels are in a row of images; RowsPerImage indicates how many rows the image has.
GPUImageCopyExternalImage type
dictionary GPUImageCopyExternalImage {
required (ImageBitmap or HTMLCanvasElement or OffscreenCanvas) source;
GPUOrigin2D origin = {};
};
Copy the code
An object of this type describes an external image data. Where, source passes in external image objects, the first two are commonly used; Origin indicates the origin of replication, relative to source.
GPUImageCopyTextureTagged type
It inherits from the [GPUImageCopyTexture](#GPUImageCopyTexture type) type:
dictionary GPUImageCopyTextureTagged : GPUImageCopyTexture {
GPUPredefinedColorSpace colorSpace = "srgb";
boolean premultipliedAlpha = false;
};
Copy the code
Where, the colorSpace field describes the colorSpace of external data encoding data, which can only be “SRGB” at present. PremultipliedAlpha defaults to false, which means whether the transparency in the data source is multiplied by the RGB color before being written to the texture. Canvas using WebGL can be controlled by WebGLContextAttributes, Canvas2D canvas is always pre-multiplied, and ImageBitmap is controlled by ImageBitmapOptions.
However, both parameters are optional and have default values, so you usually just set the GPUImageCopyTexture section.
For example,
CopyExternalImageToTexture method, for example, write to external webp image texture:
const img = document.createElement('img')
img.src = 'texture.webp'
await img.decode()
const imageBitmap = await createImageBitmap(img)
const texture = device.createTexture({
size: [img.width, img.height], / / 256, 256
format: "rgba8unorm".usage: GPUTextureUsage.SAMPLED | GPUTextureUsage.COPY_DST
})
device.queue.copyExternalImageToTexture({
imageBitmap: imageBitmap
}, {
texture: texture
}, [img.width, img.height, 1])
Copy the code
Further reading
Metal instruction organization and execution mode