diff --git a/src/mol-gl/shader/gaussian-density.frag b/src/mol-gl/shader/gaussian-density.frag index 547840a30a93c92bcf78951ce0d37925f11b3d56..546267b47df69a4640019cd537ffad4ba96b4272 100644 --- a/src/mol-gl/shader/gaussian-density.frag +++ b/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)); diff --git a/src/mol-gl/webgl/context.ts b/src/mol-gl/webgl/context.ts index f9b70a3c0bc72f480cca045f8649740ff8ac8e7a..869526c5fe3c76e8364ccb09c8a9c312502b1f3b 100644 --- a/src/mol-gl/webgl/context.ts +++ b/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) diff --git a/src/mol-math/geometry/gaussian-density/gpu.ts b/src/mol-math/geometry/gaussian-density/gpu.ts index 170170fc0204e5d8d72f4d775d305f8846125fcd..259d3ff576a1acd61ff554f271dfa287bca332b7 100644 --- a/src/mol-math/geometry/gaussian-density/gpu.ts +++ b/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