webgpuCreateTextureFromPixels function
TextureHandle?
webgpuCreateTextureFromPixels(})
A texture already holding pixels, and mipLevels below it. See
GraphicsDevice.createTextureFromPixels.
Null where the bytes are not the size the description says, which is the contract's answer for a decoder that disagreed about the dimensions.
A block-compressed format goes to _webgpuCreateCompressedTextureFromPixels,
which measures in blocks rather than texels. It is still a null here for a
family the device was not granted, because gpuTextureFormat has a spelling
for all of them and only supportsTextureFormat knows which were asked for —
so the split is: a spelling that exists and a feature that was not granted is
a texture the browser would refuse, and the caller is meant to have asked
first.
Implementation
TextureHandle? webgpuCreateTextureFromPixels(
GPUDevice gpu,
List<WebGpuTexture> tracked, {
required int width,
required int height,
required TextureFormat format,
required ByteData pixels,
List<ByteData>? mipLevels,
}) {
final spelling = gpuTextureFormat(format);
if (spelling == null) return null;
if (format.isCompressed) {
return _webgpuCreateCompressedTextureFromPixels(
gpu,
tracked,
spelling: spelling,
width: width,
height: height,
format: format,
pixels: pixels,
mipLevels: mipLevels,
);
}
final texelBytes = webgpuTexelBytes(format);
if (texelBytes == null) return null;
if (pixels.lengthInBytes != width * height * texelBytes) return null;
// Every level measured before a single byte is uploaded, the way the WebGL2
// backend measures its chain: `writeTexture` reads as many bytes as the
// rectangle needs and ignores the rest, so a level built with the wrong
// arithmetic is a plausible, wrong picture the moment anything minifies.
final levels = mipLevels ?? const <ByteData>[];
var w = width;
var h = height;
for (final level in levels) {
w = w > 1 ? w >> 1 : 1;
h = h > 1 ? h >> 1 : 1;
if (level.lengthInBytes != w * h * texelBytes) return null;
}
final texture = gpu.createTexture(
GPUTextureDescriptor(
size: GPUExtent3DDict(
width: width,
height: height,
depthOrArrayLayers: 1,
),
format: spelling,
usage:
GpuTextureUsage.textureBinding |
GpuTextureUsage.copyDst |
GpuTextureUsage.copySrc,
sampleCount: 1,
mipLevelCount: 1 + levels.length,
dimension: '2d',
label: 'image ${width}x$height $spelling',
),
);
_writeLevel(gpu, texture, 0, 0, width, height, texelBytes, pixels);
w = width;
h = height;
for (var i = 0; i < levels.length; i++) {
w = w > 1 ? w >> 1 : 1;
h = h > 1 ? h >> 1 : 1;
_writeLevel(gpu, texture, i + 1, 0, w, h, texelBytes, levels[i]);
}
final backend = WebGpuTexture(
texture: texture,
dimension: WebGpuTextureDimension.twoDimensional,
sampleable: true,
);
tracked.add(backend);
return TextureHandle(
backend: backend,
width: width,
height: height,
format: format,
);
}