diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts index c884fc4fdf7f653a496510db7b205f8c8604ec37..faa487b8063cc6f0cec9875d9b2f540846d05786 100644 --- a/src/mol-canvas3d/canvas3d.ts +++ b/src/mol-canvas3d/canvas3d.ts @@ -244,7 +244,7 @@ namespace Canvas3D { } async function identify(x: number, y: number): Promise<PickingId | undefined> { - if (pickDirty) return undefined + if (pickDirty || isPicking) return undefined isPicking = true @@ -259,23 +259,21 @@ namespace Canvas3D { objectPickTarget.bind() await webgl.readPixelsAsync(xp, yp, 1, 1, buffer) const objectId = decodeIdRGB(buffer[0], buffer[1], buffer[2]) + if (objectId === -1) return instancePickTarget.bind() - await webgl.readPixels(xp, yp, 1, 1, buffer) + await webgl.readPixelsAsync(xp, yp, 1, 1, buffer) const instanceId = decodeIdRGB(buffer[0], buffer[1], buffer[2]) + if (instanceId === -1) return groupPickTarget.bind() - await webgl.readPixels(xp, yp, 1, 1, buffer) + await webgl.readPixelsAsync(xp, yp, 1, 1, buffer) const groupId = decodeIdRGB(buffer[0], buffer[1], buffer[2]) + if (groupId === -1) return isPicking = false - // TODO - if (objectId === -1 || instanceId === -1 || groupId === -1) { - return { objectId: -1, instanceId: -1, groupId: -1 } - } else { - return { objectId, instanceId, groupId } - } + return { objectId, instanceId, groupId } } function add(repr: Representation.Any) { diff --git a/src/mol-gl/webgl/context.ts b/src/mol-gl/webgl/context.ts index fd74e707c6e300b2de593f1dd52fe63d0591c242..588c63936ddc7cd59b27a6853f4b684e09847b82 100644 --- a/src/mol-gl/webgl/context.ts +++ b/src/mol-gl/webgl/context.ts @@ -55,39 +55,42 @@ function unbindFramebuffer(gl: GLRenderingContext) { const tmpPixel = new Uint8Array(1 * 4); -function fence(gl: WebGL2RenderingContext) { +function checkSync(gl: WebGL2RenderingContext, sync: WebGLSync, resolve: () => void) { + if (gl.getSyncParameter(sync, gl.SYNC_STATUS) === gl.SIGNALED) { + gl.deleteSync(sync) + resolve() + } else { + Scheduler.setImmediate(checkSync, gl, sync, resolve) + } +} + +function fence(gl: WebGL2RenderingContext, resolve: () => void) { + const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0) + if (!sync) { + console.warn('Could not create a WebGLSync object') + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, tmpPixel) + resolve() + } else { + Scheduler.setImmediate(checkSync, gl, sync, resolve) + } +} + +let SentWebglSyncObjectNotSupportedInWebglMessage = false +function waitForGpuCommandsComplete(gl: GLRenderingContext): Promise<void> { return new Promise(resolve => { - gl.finish() - const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0) - if (!sync) { - console.warn('could not create a WebGL2 sync object') - gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, tmpPixel) - resolve() + if (isWebGL2(gl)) { + fence(gl, resolve) } else { - gl.flush(); // Ensure the fence is submitted. - const check = () => { - const status = gl.getSyncParameter(sync, gl.SYNC_STATUS) - if (status === gl.SIGNALED) { - gl.deleteSync(sync) - resolve() - } else { - Scheduler.setImmediate(check, 0) - } + if (!SentWebglSyncObjectNotSupportedInWebglMessage) { + console.info('Sync object not supported in WebGL') + SentWebglSyncObjectNotSupportedInWebglMessage = true } - Scheduler.setImmediate(check, 0) + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, tmpPixel) + resolve() } }) } -async function waitForGpuCommandsComplete(gl: GLRenderingContext) { - if (isWebGL2(gl)) { - await fence(gl) - } else { - console.info('webgl sync object not supported in webgl 1') - gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, tmpPixel) - } -} - export function createImageData(buffer: ArrayLike<number>, width: number, height: number) { const w = width * 4 const h = height @@ -198,17 +201,34 @@ export function createContext(gl: GLRenderingContext): WebGLContext { let readPixelsAsync: (x: number, y: number, width: number, height: number, buffer: Uint8Array) => Promise<void> if (isWebGL2(gl)) { const pbo = gl.createBuffer() - readPixelsAsync = async (x: number, y: number, width: number, height: number, buffer: Uint8Array) => { + let _buffer: Uint8Array | undefined = void 0 + let _resolve: (() => void) | undefined = void 0 + let _reading = false + + const bindPBO = () => { + gl.bindBuffer(gl.PIXEL_PACK_BUFFER, pbo) + gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, _buffer!) + gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null) + _reading = false + _resolve!() + _resolve = void 0 + _buffer = void 0 + } + readPixelsAsync = (x: number, y: number, width: number, height: number, buffer: Uint8Array): Promise<void> => new Promise<void>((resolve, reject) => { + if (_reading) { + reject('Can not call multiple readPixelsAsync at the same time') + return + } + _reading = true; gl.bindBuffer(gl.PIXEL_PACK_BUFFER, pbo) gl.bufferData(gl.PIXEL_PACK_BUFFER, width * height * 4, gl.STREAM_READ) gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, 0) gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null) // need to unbind/bind PBO before/after async awaiting the fence - await fence(gl) - gl.bindBuffer(gl.PIXEL_PACK_BUFFER, pbo) - gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, buffer) - gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null) - } + _resolve = resolve + _buffer = buffer + fence(gl, bindPBO) + }) } else { readPixelsAsync = async (x: number, y: number, width: number, height: number, buffer: Uint8Array) => { gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buffer) diff --git a/src/mol-math/geometry/gaussian-density/cpu.ts b/src/mol-math/geometry/gaussian-density/cpu.ts index 1e1d0cdb35a16c476c17f3071c1f669d847573ad..ad8020c5b545b00ff3a376494a2dda572320fc72 100644 --- a/src/mol-math/geometry/gaussian-density/cpu.ts +++ b/src/mol-math/geometry/gaussian-density/cpu.ts @@ -38,7 +38,7 @@ export async function GaussianDensityCPU(ctx: RuntimeContext, position: Position const delta = getDelta(Box3D.expand(Box3D.empty(), box, Vec3.create(pad, pad, pad)), resolution) const dim = Vec3.zero() Vec3.ceil(dim, Vec3.mul(dim, extent, delta)) - console.log('grid dim', dim) + // console.log('grid dim', dim) const space = Tensor.Space(dim, [0, 1, 2], Float32Array) const data = space.create() @@ -63,7 +63,7 @@ export async function GaussianDensityCPU(ctx: RuntimeContext, position: Position const gridPad = 1 / Math.max(...delta) - console.time('gaussian density cpu') + // console.time('gaussian density cpu') for (let i = 0; i < n; ++i) { const j = OrderedSet.getAt(indices, i) @@ -105,7 +105,7 @@ export async function GaussianDensityCPU(ctx: RuntimeContext, position: Position await ctx.update({ message: 'filling density grid', current: i, max: n }) } } - console.timeEnd('gaussian density cpu') + // console.timeEnd('gaussian density cpu') const transform = Mat4.identity() Mat4.fromScaling(transform, Vec3.inverse(Vec3.zero(), delta))