partial interface GPUDevice {
GPUSurface createSurface(GPUSurfaceDescriptor descriptor);
};
interface GPUSurface : GPUTexture {
ImageBitmap transferToImageBitmap();
};
dictionary GPUSurfaceDescriptor : GPUObjectDescriptorBase {
ImageBitmapRenderingContext context;
GPUExtent3D size;
required GPUTextureFormat format;
GPUTextureUsageFlags usage = 0x10; // GPUTextureUsage.OUTPUT_ATTACHMENT
};
Either context
or size
is required (not both).
If context
is specified, then its canvas's size is used.
The surface may be optimized for display to that canvas.
Note:
For example, this may mean the surface points at an image in an IDXGISwapChain
created for this canvas.
However, such optimizations are not observable.
An ImageBitmap
created from a GPUSurface
can be used just like any other ImageBitmap
, regardless of the context
specified.
The ImageBitmapRenderingContext
can still receive any ImageBitmap
.
Internally, any necessary copies-on-write or moves-on-write will occur.
For example, on D3D12/DXGI, with a canvas that has had control transferred to an OffscreenCanvas
,
and an ImageBitmapRenderingContext
ibrc
created from it:
- A
GPUSurface
s
could be allocated inside a swap chain buffer. - An
ImageBitmap
ib
created froms
would still point at the same allocation.
If this is done, then:
- Transferring
ib
intoibrc
would cause a swap chain present. - Transferring another unrelated
ImageBitmap
,ib2
, intoibrc
would causeib
to be moved into a new backing store andib2
to be copied into the swap chain and presented. - Consuming
ib
in another way would cause the swap chain buffer to be freed for reuse by another surface. - Using
ib
in a non-consuming way would just read-back from its allocation in the swap chain buffer. - Creating another
GPUSurface
s2
would do a normal allocation (not inside the swap chain buffer, because that space is already used).
Any deoptimization cases could issue warnings.
Also note that any canvas which is synchronized with DOM rendering (i.e. any non-transferred-to-offscreen canvas)
cannot be presented via IDXGISwapChain
, because IDXGISwapChain::Present
does not guarantee which frame the result will appear on.
[1] refers to the "swap chain's zero-index buffer", which seems to be wrong with D3D12 since it doesn't renumber the swap chain buffers on present.
[3] says that only FLIP_SEQUENTIAL can be used, but we are using DISCARD already in Dawn.
I'm not sure how I feel about adding a new RAF-like feature. It's really really hard to provide this signal without being attached to the document's animation (and probably will be a worse signal than RAF).
I like the initial proposal. There are a few cases you are missing here:
What happens when the
canvas
element resizes? Do you need to say "its canvas's size at creation time is used"? What is the process to update the size?About this:
TransferedToOffscreen canvases are also synchronized with the DOM rendering (for some value of "synchronized"). I don't know if
IDXGISwapChain
is a special thing, but probably nothing that you can do will guarantee which frame the result will appear on. There will always be a compositing step, and you should embrace that on your definition. Both for Offscreen and regular Canvas,IDXGISwapChain
could mean "make the frame ready to be composited".Of course, we have
desynchronized
(hardware surfaces) canvas, in which yourPresent
will present immediately. But this should be a property of the canvas, not of WebGPU, I think.