UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

97 lines (95 loc) 3.14 kB
class WebglUploadStream { constructor(uploadStream){ this.availablePBOs = []; this.pendingPBOs = []; this.uploadStream = uploadStream; this.useSingleBuffer = uploadStream.useSingleBuffer; } destroy() { const gl = this.uploadStream.device.gl; this.availablePBOs.forEach((info)=>gl.deleteBuffer(info.pbo)); this.pendingPBOs.forEach((item)=>{ if (item.sync) gl.deleteSync(item.sync); gl.deleteBuffer(item.pbo); }); } _onDeviceLost() { this.availablePBOs.length = 0; this.pendingPBOs.length = 0; } update(minByteSize) { const gl = this.uploadStream.device.gl; const pending = this.pendingPBOs; for(let i = pending.length - 1; i >= 0; i--){ const item = pending[i]; const result = gl.clientWaitSync(item.sync, 0, 0); if (result === gl.CONDITION_SATISFIED || result === gl.ALREADY_SIGNALED) { gl.deleteSync(item.sync); this.availablePBOs.push({ pbo: item.pbo, size: item.size }); pending.splice(i, 1); } } const available = this.availablePBOs; for(let i = available.length - 1; i >= 0; i--){ if (available[i].size < minByteSize) { gl.deleteBuffer(available[i].pbo); available.splice(i, 1); } } } upload(data, target, offset, size) { if (this.useSingleBuffer) { this.uploadDirect(data, target, offset, size); } else { this.uploadPBO(data, target, offset, size); } } uploadDirect(data, target, offset, size) { target._levels[0] = data; target.upload(); } uploadPBO(data, target, offset, size) { const device = this.uploadStream.device; const gl = device.gl; const width = target.width; const byteSize = size * data.BYTES_PER_ELEMENT; this.update(byteSize); const startY = offset / width; const height = size / width; const pboInfo = this.availablePBOs.pop() ?? (()=>{ const pbo = gl.createBuffer(); return { pbo, size: byteSize }; })(); gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, pboInfo.pbo); gl.bufferData(gl.PIXEL_UNPACK_BUFFER, byteSize, gl.STREAM_DRAW); gl.bufferSubData(gl.PIXEL_UNPACK_BUFFER, 0, new Uint8Array(data.buffer, data.byteOffset, byteSize)); gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, null); device.setTexture(target, 0); device.activeTexture(0); device.bindTexture(target); gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, pboInfo.pbo); device.setUnpackFlipY(false); device.setUnpackPremultiplyAlpha(false); gl.pixelStorei(gl.UNPACK_ALIGNMENT, data.BYTES_PER_ELEMENT); gl.pixelStorei(gl.UNPACK_ROW_LENGTH, 0); gl.pixelStorei(gl.UNPACK_SKIP_ROWS, 0); gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, 0); const impl = target.impl; gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, startY, width, height, impl._glFormat, impl._glPixelType, 0); gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, null); const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0); this.pendingPBOs.push({ pbo: pboInfo.pbo, size: byteSize, sync }); gl.flush(); } } export { WebglUploadStream };