webgpuCreateTexture function
TextureHandle
webgpuCreateTexture(
- GPUDevice gpu,
- List<
WebGpuTexture> tracked, - RenderTargetSpec spec, {
- int levels = 1,
A texture matching spec, with a chain levels deep. See
GraphicsDevice.createTexture.
deviceTransient is Impeller's tile memory, which WebGPU does not have. The
honest translation is an attachment allocated without TEXTURE_BINDING: not
sampleable, attachment only, which is exactly what the storage mode already
promises. Multisampled targets go the same way — this engine resolves them
rather than sampling them, and a texture that cannot be sampled is one fewer
usage flag for the implementation to plan around.
Implementation
TextureHandle webgpuCreateTexture(
GPUDevice gpu,
List<WebGpuTexture> tracked,
RenderTargetSpec spec, {
int levels = 1,
}) {
final format = gpuTextureFormat(spec.format);
if (format == null) {
throw ArgumentError.value(
spec.format,
'format',
'has no WebGPU spelling; ask supportsTextureFormat first',
);
}
// **A block-compressed target is refused here rather than by the browser.**
// Every one of these has a spelling now that the compression features are
// asked for, so a spelling is no longer the thing that stops one becoming a
// render target — and `RENDER_ATTACHMENT` on a compressed format is a
// validation error whose message names a usage flag rather than the call that
// wanted it. The contract already says a compressed format is sample-only
// everywhere (`TextureFormatCompression.isCompressed`), which is the same
// refusal the WebGL2 backend gives by having no non-compressed table entry to
// hand back.
if (spec.format.isCompressed) {
throw ArgumentError.value(
spec.format,
'format',
'is block-compressed, and a compressed texture cannot be a render '
'target on any backend. Upload one through createTextureFromPixels',
);
}
final attachmentOnly =
spec.sampleCount > 1 || spec.storageMode == StorageMode.deviceTransient;
final texture = gpu.createTexture(
GPUTextureDescriptor(
size: GPUExtent3DDict(
width: spec.width,
height: spec.height,
depthOrArrayLayers: 1,
),
format: format,
usage: attachmentOnly
? GpuTextureUsage.renderAttachment
: GpuTextureUsage.renderAttachment |
GpuTextureUsage.textureBinding |
GpuTextureUsage.copyDst |
(webgpuIsDepthStencil(spec.format)
? 0
: GpuTextureUsage.copySrc),
sampleCount: spec.sampleCount,
mipLevelCount: levels,
dimension: '2d',
label: 'target ${spec.width}x${spec.height} $format',
),
);
final backend = WebGpuTexture(
texture: texture,
dimension: WebGpuTextureDimension.twoDimensional,
sampleable: !attachmentOnly,
);
tracked.add(backend);
return TextureHandle(
backend: backend,
width: spec.width,
height: spec.height,
format: spec.format,
sampleCount: spec.sampleCount,
storageMode: spec.storageMode,
);
}