webgpuCreateCubeTextureFromPixels function
faces in +X, −X, +Y, −Y, +Z, −Z order as one cube texture. See
GraphicsDevice.createCubeTextureFromPixels.
A cube is a six-layer 2D texture here, and a face is the z of an
origin rather than a target constant of its own. There is no six-argument
upload call and no face enumeration in this API, so the order the contract
documents is honoured by the loop's own index and by nothing else — which is
why the conformance check that draws six known directions against six known
colours is the thing that holds it.
A block-compressed cube is a null, and that is a scope line rather than a
limit of the API. WebGPU would take one — six layers of block rows is the
same writeTexture the 2D path makes — but nothing in this repository
uploads a compressed cube: the KTX2 loader hands over one 2D image and the
engine's own cubes are rendered rather than decoded. A path with no caller is
a path with no test, and the null is what webgpuTexelBytes already answers
for a format it has no texel size for.
Implementation
TextureHandle? webgpuCreateCubeTextureFromPixels(
GPUDevice gpu,
List<WebGpuTexture> tracked, {
required int size,
required TextureFormat format,
required List<ByteData> faces,
List<List<ByteData>>? mipLevels,
}) {
final spelling = gpuTextureFormat(format);
final texelBytes = webgpuTexelBytes(format);
if (spelling == null || texelBytes == null) return null;
if (faces.length != 6) return null;
for (final face in faces) {
if (face.lengthInBytes != size * size * texelBytes) return null;
}
final levels = mipLevels ?? const <List<ByteData>>[];
var side = size;
for (final level in levels) {
if (level.length != 6) return null;
side = side > 1 ? side >> 1 : 1;
for (final face in level) {
if (face.lengthInBytes != side * side * texelBytes) return null;
}
}
final texture = gpu.createTexture(
GPUTextureDescriptor(
size: GPUExtent3DDict(width: size, height: size, depthOrArrayLayers: 6),
format: spelling,
usage:
GpuTextureUsage.textureBinding |
GpuTextureUsage.copyDst |
GpuTextureUsage.copySrc,
sampleCount: 1,
mipLevelCount: 1 + levels.length,
dimension: '2d',
label: 'cube ${size}x$size $spelling',
),
);
for (var face = 0; face < 6; face++) {
_writeLevel(gpu, texture, 0, face, size, size, texelBytes, faces[face]);
}
side = size;
for (var level = 0; level < levels.length; level++) {
side = side > 1 ? side >> 1 : 1;
for (var face = 0; face < 6; face++) {
_writeLevel(
gpu,
texture,
level + 1,
face,
side,
side,
texelBytes,
levels[level][face],
);
}
}
final backend = WebGpuTexture(
texture: texture,
dimension: WebGpuTextureDimension.cube,
sampleable: true,
);
tracked.add(backend);
return TextureHandle(
backend: backend,
width: size,
height: size,
format: format,
type: TextureType.textureCube,
);
}