diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts index 8324d44065765de47563331dd12b4f909328799e..0f11398973e50847495c123383c40f05f7b590e2 100644 --- a/src/mol-canvas3d/canvas3d.ts +++ b/src/mol-canvas3d/canvas3d.ts @@ -118,10 +118,9 @@ namespace Canvas3D { const groupPickTarget = createRenderTarget(webgl, pickWidth, pickHeight) let pickDirty = true - let isPicking = false + let isIdentifying = false let isUpdating = false let drawPending = false - let lastRenderTime = -1 const debugHelper = new BoundingSphereHelper(webgl, scene, p.debug) @@ -148,8 +147,9 @@ namespace Canvas3D { }) if (changed) { scene.update(true) + const prevPickDirty = pickDirty draw(true) - pickDirty = false // picking buffers should not have changed + pickDirty = prevPickDirty // picking buffers should not have changed } } @@ -175,7 +175,7 @@ namespace Canvas3D { } function render(variant: 'pick' | 'draw', force: boolean) { - if (isPicking || isUpdating) return false + if (isIdentifying || isUpdating) return false let didRender = false controls.update() @@ -205,7 +205,6 @@ namespace Canvas3D { debugHelper.syncVisibility() renderer.render(debugHelper.scene, 'draw') } - lastRenderTime = now() pickDirty = true break; } @@ -235,25 +234,21 @@ namespace Canvas3D { const t = now(); camera.transition.tick(t); draw(false) - if (t - lastRenderTime > 1000 / 12 /** picking at 12 fps */ && pickDirty) { - // TODO would it not be better to call pick in identify? - // because currently for example highlighting something - // sets pickDirty = true that is not true - // there should definitely be a better "dirty" mechanism - pick(); - } window.requestAnimationFrame(animate) } function pick() { - render('pick', pickDirty) - pickDirty = false + if (pickDirty) { + render('pick', true) + pickDirty = false + } } async function identify(x: number, y: number): Promise<PickingId | undefined> { - if (pickDirty || isPicking) return; + if (isIdentifying) return - isPicking = true + pick() // must be called before setting `isIdentifying = true` + isIdentifying = true x *= webgl.pixelRatio y *= webgl.pixelRatio @@ -268,21 +263,21 @@ namespace Canvas3D { // await webgl.readPixelsAsync(xp, yp, 1, 1, buffer) webgl.readPixels(xp, yp, 1, 1, buffer) const objectId = decodeIdRGB(buffer[0], buffer[1], buffer[2]) - if (objectId === -1) { isPicking = false; return; } + if (objectId === -1) { isIdentifying = false; return; } instancePickTarget.bind() // await webgl.readPixelsAsync(xp, yp, 1, 1, buffer) webgl.readPixels(xp, yp, 1, 1, buffer) const instanceId = decodeIdRGB(buffer[0], buffer[1], buffer[2]) - if (instanceId === -1) { isPicking = false; return; } + if (instanceId === -1) { isIdentifying = false; return; } groupPickTarget.bind() // await webgl.readPixelsAsync(xp, yp, 1, 1, buffer) webgl.readPixels(xp, yp, 1, 1, buffer) const groupId = decodeIdRGB(buffer[0], buffer[1], buffer[2]) - if (groupId === -1) { isPicking = false; return; } + if (groupId === -1) { isIdentifying = false; return; } - isPicking = false + isIdentifying = false return { objectId, instanceId, groupId } } diff --git a/src/mol-gl/renderer.ts b/src/mol-gl/renderer.ts index 432d186404215f3b24feacd47ff4bd464e64c979..fca8f0fdba9e1ae075e7b5c02d7db87ad827574c 100644 --- a/src/mol-gl/renderer.ts +++ b/src/mol-gl/renderer.ts @@ -106,15 +106,19 @@ namespace Renderer { uPickingAlphaThreshold: ValueCell.create(pickingAlphaThreshold), } - let currentProgramId = -1 + let globalUniformsNeedUpdate = true const renderObject = (r: Renderable<RenderableValues & BaseValues>, variant: RenderVariant, opaque: boolean) => { if (r.state.opaque !== opaque) return const program = r.getProgram(variant) - if (r.state.visible) { - if (currentProgramId !== program.id) { - program.use() + if (r.state.visible) { + if (ctx.currentProgramId !== program.id) { + globalUniformsNeedUpdate = true + } + + program.use() + if (globalUniformsNeedUpdate) { program.setUniforms(globalUniforms) - currentProgramId = program.id + globalUniformsNeedUpdate = false } if (r.values.dDoubleSided) { @@ -162,8 +166,9 @@ namespace Renderer { ValueCell.update(globalUniforms.uFogFar, camera.state.fogFar) ValueCell.update(globalUniforms.uFogNear, camera.state.fogNear) + globalUniformsNeedUpdate = true + const { renderables } = scene - currentProgramId = -1 gl.disable(gl.BLEND) gl.enable(gl.DEPTH_TEST) diff --git a/src/mol-gl/webgl/context.ts b/src/mol-gl/webgl/context.ts index afffafe8f2b1c911933a99dc22cf6d449799b440..c8577f30cb0c1831130c92614c9c35ecf56389e9 100644 --- a/src/mol-gl/webgl/context.ts +++ b/src/mol-gl/webgl/context.ts @@ -135,6 +135,8 @@ export interface WebGLContext { readonly programCache: ProgramCache readonly framebufferCache: FramebufferCache + currentProgramId: number + bufferCount: number framebufferCount: number renderbufferCount: number @@ -260,6 +262,8 @@ export function createContext(gl: GLRenderingContext): WebGLContext { programCache, framebufferCache, + currentProgramId: -1, + bufferCount: 0, framebufferCount: 0, renderbufferCount: 0, diff --git a/src/mol-gl/webgl/program.ts b/src/mol-gl/webgl/program.ts index 6825b47bba9b1c4dafd4e8d5aa5da7585cbeec24..b834889c3c882f728a0d1f5d25bb2d692ab5eb83 100644 --- a/src/mol-gl/webgl/program.ts +++ b/src/mol-gl/webgl/program.ts @@ -6,7 +6,7 @@ import { ShaderCode, DefineValues, addShaderDefines } from '../shader-code' import { WebGLContext } from './context'; -import { getUniformUpdaters, getTextureUniformUpdaters, UniformValues } from './uniform'; +import { getUniformUpdaters, getTextureUniformUpdaters, UniformValues, UniformUpdater } from './uniform'; import { AttributeBuffers } from './buffer'; import { TextureId, Textures } from './texture'; import { createReferenceCache, ReferenceCache } from 'mol-util/reference-cache'; @@ -60,6 +60,7 @@ export function createProgram(ctx: WebGLContext, props: ProgramProps): Program { if (program === null) { throw new Error('Could not create WebGL program') } + const programId = getNextProgramId() const shaderCode = addShaderDefines(ctx, defineValues, _shaderCode) const vertShaderRef = shaderCache.get(ctx, { type: 'vert', source: shaderCode.vert }) @@ -76,21 +77,27 @@ export function createProgram(ctx: WebGLContext, props: ProgramProps): Program { const attributeLocations = getAttributeLocations(ctx, program, schema) const textureUniformUpdaters = getTextureUniformUpdaters(ctx, program, schema) + const _uniformUpdaters: [string, UniformUpdater][] = [] + Object.keys(uniformUpdaters).forEach(k => { + _uniformUpdaters.push([k, uniformUpdaters[k]]) + }) + let destroyed = false return { - id: getNextProgramId(), + id: programId, use: () => { - Object.keys(uniformUpdaters).forEach(k => uniformUpdaters[k].clear()) - Object.keys(textureUniformUpdaters).forEach(k => textureUniformUpdaters[k].clear()) + // console.log('use', programId) + ctx.currentProgramId = programId gl.useProgram(program) }, setUniforms: (uniformValues: UniformValues) => { - Object.keys(uniformValues).forEach(k => { + for (let i = 0, il = _uniformUpdaters.length; i < il; ++i) { + const [k, uu] = _uniformUpdaters[i] const uv = uniformValues[k] - if (uv !== undefined) uniformUpdaters[k].set(uv.ref.value) - }) + if (uv !== undefined) uu.set(uv.ref.value) + } }, bindAttributes: (attribueBuffers: AttributeBuffers) => { Object.keys(attribueBuffers).forEach(k => { diff --git a/src/mol-gl/webgl/uniform.ts b/src/mol-gl/webgl/uniform.ts index d04ad1069d9b7dbe6a45f65ce21f17ec2409981a..f4ea53eb0aa3dfbdfa1604d10c7f2bfd91228c3e 100644 --- a/src/mol-gl/webgl/uniform.ts +++ b/src/mol-gl/webgl/uniform.ts @@ -6,7 +6,7 @@ import { Mat3, Mat4, Vec2, Vec3, Vec4 } from 'mol-math/linear-algebra' import { WebGLContext } from './context'; -import { ValueCell } from 'mol-util'; +import { ValueCell, arrayEqual } from 'mol-util'; import { RenderableSchema } from '../renderable/schema'; export type UniformKindValue = { @@ -51,14 +51,12 @@ function createUniformUpdater(ctx: WebGLContext, program: WebGLProgram, name: st let _value: UniformType | undefined = undefined return { set: value => { - if (_value !== value) { + if (_value !== value || (Array.isArray(_value) && Array.isArray(value) && arrayEqual(_value, value))) { setter(value) - _value = value + _value = value } }, - clear: () => { - _value = undefined - } + clear: () => { _value = undefined } } }