playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
83 lines (82 loc) • 2.37 kB
JavaScript
let id = 0;
class WebgpuUploadStream {
availableStagingBuffers = [];
pendingStagingBuffers = [];
_destroyed = false;
_lastUploadSubmitVersion = -1;
constructor(uploadStream) {
this.uploadStream = uploadStream;
this.useSingleBuffer = uploadStream.useSingleBuffer;
}
_onDeviceLost() {
}
destroy() {
this._destroyed = true;
this.availableStagingBuffers.forEach((buffer) => buffer.destroy());
this.pendingStagingBuffers.forEach((buffer) => buffer.destroy());
}
update(minByteSize) {
const pending = this.pendingStagingBuffers;
for (let i = 0; i < pending.length; i++) {
const buffer = pending[i];
buffer.mapAsync(GPUMapMode.WRITE).then(() => {
if (!this._destroyed) {
this.availableStagingBuffers.push(buffer);
} else {
buffer.destroy();
}
});
}
pending.length = 0;
const available = this.availableStagingBuffers;
for (let i = available.length - 1; i >= 0; i--) {
if (available[i].size < minByteSize) {
available[i].destroy();
available.splice(i, 1);
}
}
}
upload(data, target, offset, size) {
if (this.useSingleBuffer) {
this.uploadDirect(data, target, offset, size);
} else {
this.uploadStaging(data, target, offset, size);
}
}
uploadDirect(data, target, offset, size) {
const byteOffset = offset * data.BYTES_PER_ELEMENT;
const byteSize = size * data.BYTES_PER_ELEMENT;
target.write(byteOffset, data, 0, size);
}
uploadStaging(data, target, offset, size) {
const device = this.uploadStream.device;
const byteOffset = offset * data.BYTES_PER_ELEMENT;
const byteSize = size * data.BYTES_PER_ELEMENT;
if (this.pendingStagingBuffers.length > 0) {
}
this.update(byteSize);
const buffer = this.availableStagingBuffers.pop() ?? (() => {
const newBuffer = this.uploadStream.device.wgpu.createBuffer({
size: byteSize,
usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.COPY_SRC,
mappedAtCreation: true
});
return newBuffer;
})();
const mappedRange = buffer.getMappedRange();
new Uint8Array(mappedRange).set(new Uint8Array(data.buffer, data.byteOffset, byteSize));
buffer.unmap();
device.getCommandEncoder().copyBufferToBuffer(
buffer,
0,
target.impl.buffer,
byteOffset,
byteSize
);
this.pendingStagingBuffers.push(buffer);
this._lastUploadSubmitVersion = device.submitVersion;
}
}
export {
WebgpuUploadStream
};