Pārlūkot izejas kodu

tweaked gpu gaussian density calculation

Alexander Rose 6 gadi atpakaļ
vecāks
revīzija
3a1befb54e

+ 1 - 1
src/mol-gl/shader/gaussian-density.frag

@@ -43,7 +43,7 @@ const vec3 color = vec3(1.0, 1.0, 1.0);
 void main() {
     float radiusSq = radius * radius;
     vec2 v = gl_FragCoord.xy - vec2(uCurrentX, uCurrentY) - 0.5;
-    out_FragColor = vec4(color, calcDensity(v.x, v.y, uCurrentSlice, radiusSq));
+    gl_FragColor = vec4(color, calcDensity(v.x, v.y, uCurrentSlice, radiusSq));
     #if dDrawBuffers >= 4
         out1 = vec4(color, calcDensity(v.x, v.y, uCurrentSlice + 1.0, radiusSq));
         out2 = vec4(color, calcDensity(v.x, v.y, uCurrentSlice + 2.0, radiusSq));

+ 33 - 2
src/mol-gl/webgl/context.ts

@@ -51,6 +51,35 @@ function unbindFramebuffer(gl: GLRenderingContext) {
     gl.bindFramebuffer(gl.FRAMEBUFFER, null)
 }
 
+const tmpPixel = new Uint8Array(1 * 4);
+async function waitForGpuCommandsComplete(gl: GLRenderingContext) {
+    if (isWebGL2(gl)) {
+        const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
+        if (sync) {
+            // TODO too slow in Firefox
+            // await new Promise(resolve => {
+            //     const check = async () => {
+            //         if (gl.getSyncParameter(sync, gl.SYNC_STATUS) === gl.SIGNALED) {
+            //             gl.deleteSync(sync)
+            //             resolve();
+            //         } else {
+            //             setTimeout(check, 50)
+            //         }
+            //     };
+            //     setTimeout(check, 10)
+            // })
+            gl.deleteSync(sync)
+            gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, tmpPixel)
+        } else {
+            console.warn('unable to get webgl sync object')
+            gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, tmpPixel)
+        }
+    } 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
@@ -66,6 +95,8 @@ export function createImageData(buffer: ArrayLike<number>, width: number, height
     return new ImageData(data, width, height);
 }
 
+//
+
 type Extensions = {
     instancedArrays: COMPAT_instanced_arrays
     standardDerivatives: COMPAT_standard_derivatives
@@ -100,11 +131,10 @@ export interface Context {
 
     unbindFramebuffer: () => void
     readPixels: (x: number, y: number, width: number, height: number, buffer: Uint8Array) => void
+    waitForGpuCommandsComplete: () => Promise<void>
     destroy: () => void
 }
 
-
-
 export function createContext(gl: GLRenderingContext): Context {
     const instancedArrays = getInstancedArrays(gl)
     if (instancedArrays === null) {
@@ -178,6 +208,7 @@ export function createContext(gl: GLRenderingContext): Context {
             //     console.error('Reading pixels failed. Framebuffer not complete.')
             // }
         },
+        waitForGpuCommandsComplete: () => waitForGpuCommandsComplete(gl),
 
         destroy: () => {
             unbindResources(gl)

+ 28 - 19
src/mol-math/geometry/gaussian-density/gpu.ts

@@ -113,6 +113,9 @@ async function GaussianDensitySingleDrawBuffer(ctx: RuntimeContext, webgl: Conte
 
     framebuffer.destroy() // clean up
 
+    await ctx.update({ message: 'gpu gaussian density calculation' });
+    await webgl.waitForGpuCommandsComplete()
+
     return { texture, scale: Vec3.inverse(Vec3.zero(), delta), bbox: expandedBox, dim }
 }
 
@@ -133,29 +136,15 @@ async function GaussianDensityMultiDrawBuffer(ctx: RuntimeContext, webgl: Contex
     const framebuffer = createFramebuffer(webgl)
     framebuffer.bind()
 
+    setDrawBuffers(gl, drawBuffers)
+    gl.viewport(0, 0, dx, dy)
+    setRenderingDefaults(gl)
+
     if (!texture) {
         texture = createTexture(webgl, 'volume-uint8', 'rgba', 'ubyte', 'linear')
     }
     texture.define(dx, dy, dz)
 
-    if (drawBuffers === 1) {
-        gl.drawBuffers([
-            gl.COLOR_ATTACHMENT0,
-        ]);
-    } else if (drawBuffers === 4) {
-        gl.drawBuffers([
-            gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2, gl.COLOR_ATTACHMENT3,
-        ]);
-    } else if (drawBuffers === 8) {
-        gl.drawBuffers([
-            gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2, gl.COLOR_ATTACHMENT3,
-            gl.COLOR_ATTACHMENT4, gl.COLOR_ATTACHMENT5, gl.COLOR_ATTACHMENT6, gl.COLOR_ATTACHMENT7,
-        ]);
-    }
-
-    gl.viewport(0, 0, dx, dy)
-    setRenderingDefaults(gl)
-
     // z-slices to be render with multi render targets
     const dzMulti = Math.floor(dz / drawBuffers) * drawBuffers
 
@@ -167,7 +156,7 @@ async function GaussianDensityMultiDrawBuffer(ctx: RuntimeContext, webgl: Contex
         for (let k = 0; k < drawBuffers; ++k) {
             texture.attachFramebuffer(framebuffer, k as TextureAttachment, i + k)
         }
-        renderable.render('draw')
+        renderable.render('draw');
     }
 
     // render single target
@@ -188,6 +177,9 @@ async function GaussianDensityMultiDrawBuffer(ctx: RuntimeContext, webgl: Contex
 
     framebuffer.destroy() // clean up
 
+    await ctx.update({ message: 'gpu gaussian density calculation' });
+    await webgl.waitForGpuCommandsComplete()
+
     return { texture, scale: Vec3.inverse(Vec3.zero(), delta), bbox: expandedBox, dim }
 }
 
@@ -288,6 +280,23 @@ function setRenderingDefaults(gl: GLRenderingContext) {
     gl.enable(gl.BLEND)
 }
 
+function setDrawBuffers(gl: WebGL2RenderingContext, drawBuffers: number) {
+    if (drawBuffers === 1) {
+        gl.drawBuffers([
+            gl.COLOR_ATTACHMENT0,
+        ]);
+    } else if (drawBuffers === 4) {
+        gl.drawBuffers([
+            gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2, gl.COLOR_ATTACHMENT3,
+        ]);
+    } else if (drawBuffers === 8) {
+        gl.drawBuffers([
+            gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2, gl.COLOR_ATTACHMENT3,
+            gl.COLOR_ATTACHMENT4, gl.COLOR_ATTACHMENT5, gl.COLOR_ATTACHMENT6, gl.COLOR_ATTACHMENT7,
+        ]);
+    }
+}
+
 function fieldFromTexture2d(ctx: Context, texture: Texture, dim: Vec3) {
     console.time('fieldFromTexture2d')
     const { gl } = ctx