Quellcode durchsuchen

fixes for readPixelsAsync

Alexander Rose vor 6 Jahren
Ursprung
Commit
5ab1de67ea

+ 7 - 9
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) {

+ 52 - 32
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)

+ 3 - 3
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))