xgpu
Version:
XGPU is an extendable library for WebGPU that provides a higher-level, easy-to-use interface for building rendering engines or processing numeric data. It handles automatic data binding, buffer alignment, variable declarations in shaders, and more. XGPU i
104 lines (103 loc) • 4.06 kB
JavaScript
// Copyright (c) 2023 Thomas Le Coz. All rights reserved.
// This code is governed by an MIT license that can be found in the LICENSE file.
import { XGPU } from "../../XGPU";
import { ImageTexture } from "./ImageTexture";
export class ImageTextureArray extends ImageTexture {
_bitmaps = [];
mustUpdate = [];
constructor(descriptor) {
descriptor = { ...descriptor };
if (descriptor.source && !descriptor.size) {
descriptor.size = [descriptor.source[0].width, descriptor.source[0].height, descriptor.source.length];
}
if (!descriptor.dimension)
descriptor.dimension = "2d";
if (undefined === descriptor.usage)
descriptor.usage = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT;
super(descriptor);
if (descriptor.source)
this.bitmaps = descriptor.source;
}
clone() {
if (!this.descriptor.source)
this.descriptor.source = this._bitmaps;
return new ImageTextureArray(this.descriptor);
}
set bitmaps(images) {
for (let i = 0; i < images.length; i++) {
this._bitmaps[i] = images[i];
this.mustUpdate[i] = true;
}
this.mustBeTransfered = true;
this.update();
}
get bitmaps() { return this._bitmaps; }
setImageById(image, id) {
this._bitmaps[id] = image;
this.mustUpdate[id] = true;
this.mustBeTransfered = true;
}
createGpuResource() {
if (this.gpuResource)
this.gpuResource.destroy();
//console.log("cubemap createtexture ", this.descriptor)
this.gpuResource = XGPU.device.createTexture(this.descriptor);
this._view = this.gpuResource.createView({ dimension: '2d-array', arrayLayerCount: this._bitmaps.length });
for (let i = 0; i < this.mustUpdate.length; i++)
this.mustUpdate[i] = true;
this.mustBeTransfered = true;
}
updateInnerGpuTextures(commandEncoder) {
let bmp;
for (let i = 0; i < this._bitmaps.length; i++) {
bmp = this.bitmaps[i];
if (bmp instanceof GPUTexture) {
commandEncoder.copyTextureToTexture({ texture: bmp }, { texture: this.gpuResource }, [this.gpuResource.width, this.gpuResource.height, i]);
}
}
}
update() {
if (this.mustBeTransfered) {
//console.log("update textureArray")
if (!this.gpuResource)
this.createGpuResource();
let bmp;
for (let i = 0; i < this._bitmaps.length; i++) {
bmp = this.bitmaps[i];
if (!(bmp instanceof GPUTexture) && this.mustUpdate[i]) {
XGPU.device.queue.copyExternalImageToTexture({ source: bmp }, { texture: this.gpuResource, origin: [0, 0, i] }, [bmp.width, bmp.height]);
this.mustUpdate[i] = false;
}
}
this.mustBeTransfered = false;
}
}
//-----
createDeclaration(varName, bindingId, groupId = 0) {
return "@binding(" + bindingId + ") @group(" + groupId + ") var " + varName + ":texture_2d_array<" + this.sampledType + ">;\n";
}
createBindGroupLayoutEntry(bindingId) {
let sampleType = "float";
if (this.sampledType === "i32")
sampleType = "sint";
else if (this.sampledType === "u32")
sampleType = "uint";
return {
binding: bindingId,
visibility: GPUShaderStage.FRAGMENT,
texture: {
sampleType,
viewDimension: "2d-array",
multisampled: false
},
};
}
createBindGroupEntry(bindingId) {
if (!this.gpuResource)
this.createGpuResource();
return {
binding: bindingId,
resource: this._view,
};
}
}