playcanvas
Version:
PlayCanvas WebGL game engine
70 lines (68 loc) • 2.34 kB
JavaScript
class WebgpuUploadStream {
constructor(uploadStream){
this.availableStagingBuffers = [];
this.pendingStagingBuffers = [];
this._destroyed = false;
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;
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;
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);
}
}
export { WebgpuUploadStream };