From f0f7060dfdb21c27fa90b13a4c52eb8f65c0b7d9 Mon Sep 17 00:00:00 2001
From: Alexander Rose <alex.rose@rcsb.org>
Date: Mon, 15 Oct 2018 12:16:01 -0700
Subject: [PATCH] wip, mrt surface calc

---
 src/apps/canvas/index.ts                      |   2 +-
 src/apps/canvas/structure-view.ts             |   2 +-
 src/mol-gl/shader/gaussian-density.frag       |  32 +++--
 src/mol-gl/webgl/program.ts                   |   7 +-
 src/mol-math/geometry/gaussian-density/gpu.ts | 122 ++++++++++--------
 5 files changed, 98 insertions(+), 67 deletions(-)

diff --git a/src/apps/canvas/index.ts b/src/apps/canvas/index.ts
index aa7a8ff5d..45b617685 100644
--- a/src/apps/canvas/index.ts
+++ b/src/apps/canvas/index.ts
@@ -23,4 +23,4 @@ const assemblyId = urlQueryParameter('assembly')
 const pdbId = urlQueryParameter('pdb')
 if (pdbId) app.loadPdbIdOrMmcifUrl(pdbId, { assemblyId })
 
-app.loadCcp4Url('http://localhost:8091/ngl/data/betaGal.mrc')
\ No newline at end of file
+// app.loadCcp4Url('http://localhost:8091/ngl/data/betaGal.mrc')
\ No newline at end of file
diff --git a/src/apps/canvas/structure-view.ts b/src/apps/canvas/structure-view.ts
index 422487447..d13cae50b 100644
--- a/src/apps/canvas/structure-view.ts
+++ b/src/apps/canvas/structure-view.ts
@@ -70,7 +70,7 @@ export async function StructureView(app: App, viewer: Viewer, models: ReadonlyAr
     const active: { [k: string]: boolean } = {
         cartoon: true,
         point: false,
-        surface: false,
+        surface: true,
         ballAndStick: false,
         carbohydrate: false,
         spacefill: false,
diff --git a/src/mol-gl/shader/gaussian-density.frag b/src/mol-gl/shader/gaussian-density.frag
index 652b57980..ff0a48371 100644
--- a/src/mol-gl/shader/gaussian-density.frag
+++ b/src/mol-gl/shader/gaussian-density.frag
@@ -19,16 +19,17 @@ uniform float uCurrentX;
 uniform float uCurrentY;
 uniform float uAlpha;
 
-// #if dDrawBuffers == 8
-    // layout(location = 0) out vec4 out0;
+#if dDrawBuffers >= 4
     layout(location = 1) out vec4 out1;
     layout(location = 2) out vec4 out2;
     layout(location = 3) out vec4 out3;
+#endif
+#if dDrawBuffers >= 8
     layout(location = 4) out vec4 out4;
     layout(location = 5) out vec4 out5;
     layout(location = 6) out vec4 out6;
     layout(location = 7) out vec4 out7;
-// #endif
+#endif
 
 float calcDensity(float x, float y, float z) {
     vec3 fragPos = vec3(x, y, z) / uGridDim;
@@ -37,15 +38,20 @@ float calcDensity(float x, float y, float z) {
     return density;
 }
 
+const vec3 color = vec3(1.0, 1.0, 1.0);
+
 void main() {
-    vec2 tmpVec = gl_FragCoord.xy - vec2(uCurrentX, uCurrentY) - 0.5;
-    out_FragColor = vec4(1, 1, 1, calcDensity(tmpVec.x, tmpVec.y, uCurrentSlice + 0.0));
-    out1 = vec4(1, 1, 1, calcDensity(tmpVec.x, tmpVec.y, uCurrentSlice + 1.0));
-    out2 = vec4(1, 1, 1, calcDensity(tmpVec.x, tmpVec.y, uCurrentSlice + 2.0));
-    out3 = vec4(1, 1, 1, calcDensity(tmpVec.x, tmpVec.y, uCurrentSlice + 3.0));
-    out4 = vec4(1, 1, 1, calcDensity(tmpVec.x, tmpVec.y, uCurrentSlice + 4.0));
-    out5 = vec4(1, 1, 1, calcDensity(tmpVec.x, tmpVec.y, uCurrentSlice + 5.0));
-    out6 = vec4(1, 1, 1, calcDensity(tmpVec.x, tmpVec.y, uCurrentSlice + 6.0));
-    out7 = vec4(1, 1, 1, calcDensity(tmpVec.x, tmpVec.y, uCurrentSlice + 7.0));
-    // gl_FragColor = vec4(1, 1, 1, calcDensity(tmpVec.x, tmpVec.y, uCurrentSlice));
+    vec2 v = gl_FragCoord.xy - vec2(uCurrentX, uCurrentY) - 0.5;
+    gl_FragColor = vec4(color, calcDensity(v.x, v.y, uCurrentSlice));
+    #if dDrawBuffers >= 4
+        out1 = vec4(color, calcDensity(v.x, v.y, uCurrentSlice + 1.0));
+        out2 = vec4(color, calcDensity(v.x, v.y, uCurrentSlice + 2.0));
+        out3 = vec4(color, calcDensity(v.x, v.y, uCurrentSlice + 3.0));
+    #endif
+    #if dDrawBuffers >= 8
+        out4 = vec4(color, calcDensity(v.x, v.y, uCurrentSlice + 4.0));
+        out5 = vec4(color, calcDensity(v.x, v.y, uCurrentSlice + 5.0));
+        out6 = vec4(color, calcDensity(v.x, v.y, uCurrentSlice + 6.0));
+        out7 = vec4(color, calcDensity(v.x, v.y, uCurrentSlice + 7.0));
+    #endif
 }
\ No newline at end of file
diff --git a/src/mol-gl/webgl/program.ts b/src/mol-gl/webgl/program.ts
index 39a90f7c0..551f42abe 100644
--- a/src/mol-gl/webgl/program.ts
+++ b/src/mol-gl/webgl/program.ts
@@ -114,13 +114,18 @@ export function createProgram(ctx: Context, props: ProgramProps): Program {
 
 export type ProgramCache = ReferenceCache<Program, ProgramProps, Context>
 
+function defineValueHash(v: boolean | number | string): number {
+    return typeof v === 'boolean' ? (v ? 1 : 0) :
+        typeof v === 'number' ? v : hashString(v)
+}
+
 export function createProgramCache(): ProgramCache {
     return createReferenceCache(
         (props: ProgramProps) => {
             const array = [ props.shaderCode.id ]
             Object.keys(props.defineValues).forEach(k => {
                 const v = props.defineValues[k].ref.value
-                array.push(hashString(k), typeof v === 'boolean' ? v ? 1 : 0 : hashString(v))
+                array.push(hashString(k), defineValueHash(v))
             })
             return hashFnv32a(array).toString()
         },
diff --git a/src/mol-math/geometry/gaussian-density/gpu.ts b/src/mol-math/geometry/gaussian-density/gpu.ts
index 036baf03a..e10d12c21 100644
--- a/src/mol-math/geometry/gaussian-density/gpu.ts
+++ b/src/mol-math/geometry/gaussian-density/gpu.ts
@@ -72,7 +72,7 @@ async function prepareGaussianDensityData(ctx: RuntimeContext, position: Positio
         }
     }
 
-    
+
     const pad = maxRadius * 2 + resolution
     const expandedBox = Box3D.expand(Box3D.empty(), box, Vec3.create(pad, pad, pad));
     const extent = Vec3.sub(Vec3.zero(), expandedBox.max, expandedBox.min)
@@ -85,7 +85,7 @@ async function prepareGaussianDensityData(ctx: RuntimeContext, position: Positio
     return { drawCount: n, positions, radii, delta, expandedBox, dim }
 }
 
-function getGaussianDensityRenderObject(drawCount: number, positions: Float32Array, radii: Float32Array, box: Box3D, dimensions: Vec3, smoothness: number) {
+function getGaussianDensityRenderObject(webgl: Context, drawCount: number, positions: Float32Array, radii: Float32Array, box: Box3D, dimensions: Vec3, smoothness: number) {
     const extent = Vec3.sub(Vec3.zero(), box.max, box.min)
 
     const values: GaussianDensityValues = {
@@ -104,7 +104,7 @@ function getGaussianDensityRenderObject(drawCount: number, positions: Float32Arr
         uGridDim: ValueCell.create(dimensions),
         uAlpha: ValueCell.create(smoothness),
 
-        dDrawBuffers: ValueCell.create(0),
+        dDrawBuffers: ValueCell.create(Math.min(8, webgl.maxDrawBuffers)),
     }
     const state: RenderableState = {
         visible: true,
@@ -120,7 +120,7 @@ async function GaussianDensitySingleDrawBuffer(ctx: RuntimeContext, webgl: Conte
     const { readSlices, smoothness } = props
 
     const { drawCount, positions, radii, delta, expandedBox, dim } = await prepareGaussianDensityData(ctx, position, box, radius, props)
-    const renderObject = getGaussianDensityRenderObject(drawCount, positions, radii, expandedBox, dim, smoothness)
+    const renderObject = getGaussianDensityRenderObject(webgl, drawCount, positions, radii, expandedBox, dim, smoothness)
     const renderable = createRenderable(webgl, renderObject)
 
     //
@@ -166,11 +166,6 @@ async function GaussianDensitySingleDrawBuffer(ctx: RuntimeContext, webgl: Conte
     gl.frontFace(gl.CCW)
     gl.cullFace(gl.BACK)
 
-    gl.depthMask(true)
-    gl.clearColor(0, 0, 0, 0)
-    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
-    gl.depthMask(false)
-
     gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
     gl.blendEquation(gl.FUNC_ADD)
     gl.enable(gl.BLEND)
@@ -245,8 +240,9 @@ async function GaussianDensityMultiDrawBuffer(ctx: RuntimeContext, webgl: Contex
     const { smoothness } = props
 
     const { drawCount, positions, radii, delta, expandedBox, dim } = await prepareGaussianDensityData(ctx, position, box, radius, props)
-    const renderObject = getGaussianDensityRenderObject(drawCount, positions, radii, expandedBox, dim, smoothness)
+    const renderObject = getGaussianDensityRenderObject(webgl, drawCount, positions, radii, expandedBox, dim, smoothness)
     const renderable = createRenderable(webgl, renderObject)
+    const drawBuffers = Math.min(8, webgl.maxDrawBuffers)
 
     //
 
@@ -261,14 +257,9 @@ async function GaussianDensityMultiDrawBuffer(ctx: RuntimeContext, webgl: Contex
 
     //
 
-    console.log('webgl.maxDrawBuffers', webgl.maxDrawBuffers)
-
     const gl = webgl.gl as WebGL2RenderingContext
     const { uCurrentSlice } = renderObject.values
 
-    const program = renderable.getProgram('draw')
-    const renderTarget = createRenderTarget(webgl, dx, dy)
-
     const fb = gl.createFramebuffer()
     gl.bindFramebuffer(gl.FRAMEBUFFER, fb)
 
@@ -278,62 +269,85 @@ async function GaussianDensityMultiDrawBuffer(ctx: RuntimeContext, webgl: Contex
     gl.texParameteri(gl.TEXTURE_3D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
     gl.texImage3D(gl.TEXTURE_3D, 0, gl.RGBA8, dx, dy, dz, 0, gl.RGBA, gl.UNSIGNED_BYTE, null)
 
-    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,
-    ]);
+    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,
+        ]);
+    }
 
-    program.use()
     gl.viewport(0, 0, dx, dy)
 
-    // renderTarget.bind()
-
     gl.disable(gl.CULL_FACE)
     gl.frontFace(gl.CCW)
     gl.cullFace(gl.BACK)
 
-    gl.depthMask(true)
-    gl.clearColor(0, 0, 0, 0)
-    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
-    gl.depthMask(false)
-
     gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
     gl.blendEquation(gl.FUNC_ADD)
     gl.enable(gl.BLEND)
 
     const slice = new Uint8Array(dx * dy * 4)
 
-    const dzFactor = Math.floor(dz / webgl.maxDrawBuffers)
-    const dzFull = dzFactor * webgl.maxDrawBuffers
-    const dzRest = dz - dzFull
-    console.log(dz, webgl.maxDrawBuffers, dzFull, dzRest)
+    //
 
-    console.time('gpu gaussian density 3d texture slices')
-    let j = 0
-    for (let i = 0; i < dz; i += 8) {
+    const dzMulti = Math.floor(dz / drawBuffers) * drawBuffers
+
+    const programMulti = renderable.getProgram('draw')
+    programMulti.use()
+
+    console.time('gpu gaussian density 3d texture slices multi')
+    for (let i = 0; i < dzMulti; i += drawBuffers) {
         ValueCell.update(uCurrentSlice, i)
-        for (let k = 0; k < webgl.maxDrawBuffers && k + i < dz; ++k) {
+        for (let k = 0; k < drawBuffers; ++k) {
             gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + k, tex, 0, i + k)
         }
         renderable.render('draw')
-        for (let k = 0; k < webgl.maxDrawBuffers && k + i < dz; ++k) {
-            gl.readBuffer(gl.COLOR_ATTACHMENT0 + k);
-            gl.readPixels(0, 0, dx, dy, gl.RGBA, gl.UNSIGNED_BYTE, slice)
-            for (let iy = 0; iy < dim[1]; ++iy) {
-                for (let ix = 0; ix < dim[0]; ++ix) {
-                    data[j] = slice[4 * (iy * dim[0] + ix)] / 255
-                    ++j
-                }
+    }
+    console.timeEnd('gpu gaussian density 3d texture slices multi')
+
+    ValueCell.updateIfChanged(renderable.values.dDrawBuffers, 1)
+    renderable.update()
+    const programSingle = renderable.getProgram('draw')
+    programSingle.use()
+
+    console.time('gpu gaussian density 3d texture slices single')
+    for (let i = dzMulti; i < dz; ++i) {
+        ValueCell.update(uCurrentSlice, i)
+        gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, tex, 0, i)
+        renderable.render('draw')
+    }
+    console.timeEnd('gpu gaussian density 3d texture slices single')
+
+    console.time('gpu gaussian density 3d texture slices read')
+    // Must unset framebufferTextureLayer attachments before reading
+    for (let k = 0; k < drawBuffers; ++k) {
+        gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + k, null, 0, 0)
+    }
+
+    let j = 0
+    for (let i = 0; i < dz; ++i) {
+        gl.framebufferTextureLayer(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, tex, 0, i)
+        gl.readBuffer(gl.COLOR_ATTACHMENT0)
+        gl.readPixels(0, 0, dx, dy, gl.RGBA, gl.UNSIGNED_BYTE, slice)
+        for (let iy = 0; iy < dim[1]; ++iy) {
+            for (let ix = 0; ix < dim[0]; ++ix) {
+                data[j] = slice[4 * (iy * dim[0] + ix)] / 255
+                ++j
             }
         }
     }
-    console.timeEnd('gpu gaussian density 3d texture slices')
+    console.timeEnd('gpu gaussian density 3d texture slices read')
+
+    // clean up
+    gl.bindFramebuffer(gl.FRAMEBUFFER, null)
 
     //
 
@@ -341,5 +355,11 @@ async function GaussianDensityMultiDrawBuffer(ctx: RuntimeContext, webgl: Contex
     Mat4.fromScaling(transform, Vec3.inverse(Vec3.zero(), delta))
     Mat4.setTranslation(transform, expandedBox.min)
 
+    // throw new Error('foo')
+
+    const renderTarget = createRenderTarget(webgl, dx, dy)
+
     return { field, idField, transform, renderTarget, bbox: expandedBox, gridDimension: dim }
-}
\ No newline at end of file
+}
+
+// const wait = (ms: number) => new Promise(r => setTimeout(r, ms))
\ No newline at end of file
-- 
GitLab