diff --git a/src/mol-gl/_spec/renderer.spec.ts b/src/mol-gl/_spec/renderer.spec.ts index c2b5b3925a412b23955760131c5ee07c9c0dcac2..62cbb35e491404bd1e029c06fa1017eb4e8d24f2 100644 --- a/src/mol-gl/_spec/renderer.spec.ts +++ b/src/mol-gl/_spec/renderer.spec.ts @@ -117,9 +117,9 @@ describe('renderer', () => { expect(ctx.gl.canvas.width).toBe(32) expect(ctx.gl.canvas.height).toBe(32) - expect(ctx.bufferCount).toBe(0); - expect(ctx.textureCount).toBe(0); - expect(ctx.vaoCount).toBe(0); + expect(ctx.stats.bufferCount).toBe(0); + expect(ctx.stats.textureCount).toBe(0); + expect(ctx.stats.vaoCount).toBe(0); expect(ctx.programCache.count).toBe(0); expect(ctx.shaderCache.count).toBe(0); @@ -137,16 +137,16 @@ describe('renderer', () => { const points = createPoints() scene.add(points) - expect(ctx.bufferCount).toBe(4); - expect(ctx.textureCount).toBe(5); - expect(ctx.vaoCount).toBe(4); + expect(ctx.stats.bufferCount).toBe(4); + expect(ctx.stats.textureCount).toBe(5); + expect(ctx.stats.vaoCount).toBe(4); expect(ctx.programCache.count).toBe(4); expect(ctx.shaderCache.count).toBe(8); scene.remove(points) - expect(ctx.bufferCount).toBe(0); - expect(ctx.textureCount).toBe(0); - expect(ctx.vaoCount).toBe(0); + expect(ctx.stats.bufferCount).toBe(0); + expect(ctx.stats.textureCount).toBe(0); + expect(ctx.stats.vaoCount).toBe(0); expect(ctx.programCache.count).toBe(4); expect(ctx.shaderCache.count).toBe(8); diff --git a/src/mol-gl/renderable/util.ts b/src/mol-gl/renderable/util.ts index a8d4d0c8b0e74f52f05b3d70395380cde3f75040..32bf2ecbd4dd47e7cdb6351e71f8da4a595c47f7 100644 --- a/src/mol-gl/renderable/util.ts +++ b/src/mol-gl/renderable/util.ts @@ -65,7 +65,8 @@ export function printImageData(imageData: ImageData, scale = 1) { const img = document.createElement('img') img.src = objectURL img.style.width = imageData.width * scale + 'px' - img.style.height = imageData.height * scale + 'px' + img.style.height = imageData.height * scale + 'px'; + (img.style as any).imageRendering = 'pixelated' // works in Chrome img.style.position = 'absolute' img.style.top = '0px' img.style.left = '0px' diff --git a/src/mol-gl/renderer.ts b/src/mol-gl/renderer.ts index 7c6831489246a6aebe4c38633518c05a211fe5f4..d56dcbe1bb409a0237b84a8da06452f683f3bba1 100644 --- a/src/mol-gl/renderer.ts +++ b/src/mol-gl/renderer.ts @@ -53,7 +53,7 @@ export type RendererProps = typeof DefaultRendererProps namespace Renderer { export function create(ctx: WebGLContext, camera: Camera, props: Partial<RendererProps> = {}): Renderer { - const { gl } = ctx + const { gl, state, stats } = ctx let { clearColor, viewport: _viewport, pickingAlphaThreshold } = { ...DefaultRendererProps, ...props } const viewport = Viewport.clone(_viewport) @@ -111,7 +111,7 @@ namespace Renderer { const renderObject = (r: Renderable<RenderableValues & BaseValues>, variant: RenderVariant) => { const program = r.getProgram(variant) if (r.state.visible) { - if (ctx.currentProgramId !== program.id) { + if (state.currentProgramId !== program.id) { // console.log('new program') globalUniformsNeedUpdate = true } @@ -238,15 +238,15 @@ namespace Renderer { programCount: ctx.programCache.count, shaderCount: ctx.shaderCache.count, - bufferCount: ctx.bufferCount, - framebufferCount: ctx.framebufferCount, - renderbufferCount: ctx.renderbufferCount, - textureCount: ctx.textureCount, - vaoCount: ctx.vaoCount, + bufferCount: stats.bufferCount, + framebufferCount: stats.framebufferCount, + renderbufferCount: stats.renderbufferCount, + textureCount: stats.textureCount, + vaoCount: stats.vaoCount, - drawCount: ctx.drawCount, - instanceCount: ctx.instanceCount, - instancedDrawCount: ctx.instancedDrawCount, + drawCount: stats.drawCount, + instanceCount: stats.instanceCount, + instancedDrawCount: stats.instancedDrawCount, } }, dispose: () => { diff --git a/src/mol-gl/shader-code.ts b/src/mol-gl/shader-code.ts index a78083e9ad9d4e1b6fe54c5ec7d45d2479f0abc7..3a23f56b35d8962b64b342dacf42895baba3472d 100644 --- a/src/mol-gl/shader-code.ts +++ b/src/mol-gl/shader-code.ts @@ -6,7 +6,8 @@ import { ValueCell } from 'mol-util'; import { idFactory } from 'mol-util/id-factory'; -import { WebGLContext } from './webgl/context'; +import { WebGLExtensions } from './webgl/context'; +import { isWebGL2, GLRenderingContext } from './webgl/compat'; export type DefineKind = 'boolean' | 'string' | 'number' export type DefineType = boolean | string @@ -66,6 +67,8 @@ export const DirectVolumeShaderCode = ShaderCode( { standardDerivatives: false, fragDepth: true } ) + + export type ShaderDefines = { [k: string]: ValueCell<DefineType> } @@ -91,16 +94,18 @@ function getDefinesCode (defines: ShaderDefines) { return lines.join('\n') + '\n' } -function getGlsl100FragPrefix(ctx: WebGLContext, extensions: ShaderExtensions) { +function getGlsl100FragPrefix(extensions: WebGLExtensions, shaderExtensions: ShaderExtensions) { const prefix: string[] = [] - if (extensions.standardDerivatives) { + if (shaderExtensions.standardDerivatives) { prefix.push('#extension GL_OES_standard_derivatives : enable') prefix.push('#define enabledStandardDerivatives') } - if (extensions.fragDepth) { - if (ctx.extensions.fragDepth) { + if (shaderExtensions.fragDepth) { + if (extensions.fragDepth) { prefix.push('#extension GL_EXT_frag_depth : enable') prefix.push('#define enabledFragDepth') + } else { + throw new Error(`requested 'GL_EXT_frag_depth' extension is unavailable`) } } return prefix.join('\n') + '\n' @@ -123,11 +128,11 @@ layout(location = 0) out highp vec4 out_FragColor; #define enabledFragDepth ` -export function addShaderDefines(ctx: WebGLContext, defines: ShaderDefines, shaders: ShaderCode): ShaderCode { - const { isWebGL2 } = ctx +export function addShaderDefines(gl: GLRenderingContext, extensions: WebGLExtensions, defines: ShaderDefines, shaders: ShaderCode): ShaderCode { + const webgl2 = isWebGL2(gl) const header = getDefinesCode(defines) - const vertPrefix = isWebGL2 ? glsl300VertPrefix : '' - const fragPrefix = isWebGL2 ? glsl300FragPrefix : getGlsl100FragPrefix(ctx, shaders.extensions) + const vertPrefix = webgl2 ? glsl300VertPrefix : '' + const fragPrefix = webgl2 ? glsl300FragPrefix : getGlsl100FragPrefix(extensions, shaders.extensions) return { id: shaderCodeId(), vert: `${vertPrefix}${header}${shaders.vert}`, diff --git a/src/mol-gl/webgl/buffer.ts b/src/mol-gl/webgl/buffer.ts index cac6c2946b01e75ba5f62626e9ac3a6c593613b0..eb2c4f43553aea7e69c117c5d3e2169b800d01c2 100644 --- a/src/mol-gl/webgl/buffer.ts +++ b/src/mol-gl/webgl/buffer.ts @@ -9,6 +9,7 @@ import { ValueCell } from 'mol-util'; import { RenderableSchema } from '../renderable/schema'; import { idFactory } from 'mol-util/id-factory'; import { ValueOf } from 'mol-util/type-helpers'; +import { GLRenderingContext } from './compat'; const getNextBufferId = idFactory() @@ -97,7 +98,7 @@ export interface Buffer { } export function createBuffer(ctx: WebGLContext, array: ArrayType, usageHint: UsageHint, bufferType: BufferType): Buffer { - const { gl } = ctx + const { gl, stats } = ctx const _buffer = gl.createBuffer() if (_buffer === null) { throw new Error('Could not create WebGL buffer') @@ -116,7 +117,7 @@ export function createBuffer(ctx: WebGLContext, array: ArrayType, usageHint: Usa updateData(array) let destroyed = false - ctx.bufferCount += 1 + stats.bufferCount += 1 return { id: getNextBufferId(), @@ -139,7 +140,7 @@ export function createBuffer(ctx: WebGLContext, array: ArrayType, usageHint: Usa if (destroyed) return gl.deleteBuffer(_buffer) destroyed = true - ctx.bufferCount -= 1 + stats.bufferCount -= 1 } } } @@ -149,8 +150,7 @@ export function createBuffer(ctx: WebGLContext, array: ArrayType, usageHint: Usa export type AttributeItemSize = 1 | 2 | 3 | 4 | 16 export type AttributeKind = 'float32' | 'int32' -export function getAttribType(ctx: WebGLContext, kind: AttributeKind, itemSize: AttributeItemSize) { - const { gl } = ctx +export function getAttribType(gl: GLRenderingContext, kind: AttributeKind, itemSize: AttributeItemSize) { switch (kind) { case 'int32': switch (itemSize) { diff --git a/src/mol-gl/webgl/context.ts b/src/mol-gl/webgl/context.ts index b849f9f9ae06d4120d3576d4f6be6936d128708d..375a1dd75037b3b65c9a87700de41b038acd5c1d 100644 --- a/src/mol-gl/webgl/context.ts +++ b/src/mol-gl/webgl/context.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -113,7 +113,7 @@ export function createImageData(buffer: ArrayLike<number>, width: number, height // -type Extensions = { +export type WebGLExtensions = { instancedArrays: COMPAT_instanced_arrays standardDerivatives: COMPAT_standard_derivatives blendMinMax: COMPAT_blend_minmax @@ -124,20 +124,7 @@ type Extensions = { fragDepth: COMPAT_frag_depth | null } -/** A WebGL context object, including the rendering context, resource caches and counts */ -export interface WebGLContext { - readonly gl: GLRenderingContext - readonly isWebGL2: boolean - readonly extensions: Extensions - readonly pixelRatio: number - - readonly shaderCache: ShaderCache - readonly programCache: ProgramCache - readonly framebufferCache: FramebufferCache - - currentProgramId: number - currentMaterialId: number - +export type WebGLStats = { bufferCount: number framebufferCount: number renderbufferCount: number @@ -147,6 +134,26 @@ export interface WebGLContext { drawCount: number instanceCount: number instancedDrawCount: number +} + +export type WebGLState = { + currentProgramId: number + currentMaterialId: number +} + +/** A WebGL context object, including the rendering context, resource caches and counts */ +export interface WebGLContext { + readonly gl: GLRenderingContext + readonly isWebGL2: boolean + readonly pixelRatio: number + + readonly extensions: WebGLExtensions + readonly state: WebGLState + readonly stats: WebGLStats + + readonly shaderCache: ShaderCache + readonly programCache: ProgramCache + readonly framebufferCache: FramebufferCache readonly maxTextureSize: number readonly maxDrawBuffers: number @@ -193,9 +200,37 @@ export function createContext(gl: GLRenderingContext): WebGLContext { console.log('Could not find support for "frag_depth"') } - const shaderCache = createShaderCache() - const programCache = createProgramCache() - const framebufferCache = createFramebufferCache() + const state: WebGLState = { + currentProgramId: -1, + currentMaterialId: -1, + } + + const stats: WebGLStats = { + bufferCount: 0, + framebufferCount: 0, + renderbufferCount: 0, + textureCount: 0, + vaoCount: 0, + + drawCount: 0, + instanceCount: 0, + instancedDrawCount: 0, + } + + const extensions: WebGLExtensions = { + instancedArrays, + standardDerivatives, + blendMinMax, + textureFloat, + textureFloatLinear, + elementIndexUint, + vertexArrayObject, + fragDepth + } + + const shaderCache: ShaderCache = createShaderCache(gl) + const programCache: ProgramCache = createProgramCache(gl, state, extensions, shaderCache) + const framebufferCache: FramebufferCache = createFramebufferCache(gl, stats) const parameters = { maxTextureSize: gl.getParameter(gl.MAX_TEXTURE_SIZE), @@ -247,35 +282,19 @@ export function createContext(gl: GLRenderingContext): WebGLContext { return { gl, isWebGL2: isWebGL2(gl), - extensions: { - instancedArrays, - standardDerivatives, - blendMinMax, - textureFloat, - textureFloatLinear, - elementIndexUint, - vertexArrayObject, - fragDepth + get pixelRatio () { + // this can change during the lifetime of a rendering context, so need to re-obtain on access + return getPixelRatio() }, - get pixelRatio () { return getPixelRatio() }, + + extensions, + state, + stats, shaderCache, programCache, framebufferCache, - currentProgramId: -1, - currentMaterialId: -1, - - bufferCount: 0, - framebufferCount: 0, - renderbufferCount: 0, - textureCount: 0, - vaoCount: 0, - - drawCount: 0, - instanceCount: 0, - instancedDrawCount: 0, - get maxTextureSize () { return parameters.maxTextureSize }, get maxDrawBuffers () { return parameters.maxDrawBuffers }, diff --git a/src/mol-gl/webgl/framebuffer.ts b/src/mol-gl/webgl/framebuffer.ts index ef3439b723e5eb243281da27e83d78d0d74241b6..1a7475a7997dd3bf9ddb136b59e891d09ba919d6 100644 --- a/src/mol-gl/webgl/framebuffer.ts +++ b/src/mol-gl/webgl/framebuffer.ts @@ -1,12 +1,13 @@ /** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { WebGLContext } from './context' +import { WebGLStats } from './context' import { idFactory } from 'mol-util/id-factory'; import { ReferenceCache, createReferenceCache } from 'mol-util/reference-cache'; +import { GLRenderingContext } from './compat'; const getNextFramebufferId = idFactory() @@ -17,15 +18,14 @@ export interface Framebuffer { destroy: () => void } -export function createFramebuffer (ctx: WebGLContext): Framebuffer { - const { gl } = ctx +export function createFramebuffer (gl: GLRenderingContext, stats: WebGLStats): Framebuffer { const _framebuffer = gl.createFramebuffer() if (_framebuffer === null) { throw new Error('Could not create WebGL framebuffer') } let destroyed = false - ctx.framebufferCount += 1 + stats.framebufferCount += 1 return { id: getNextFramebufferId(), @@ -35,17 +35,17 @@ export function createFramebuffer (ctx: WebGLContext): Framebuffer { if (destroyed) return gl.deleteFramebuffer(_framebuffer) destroyed = true - ctx.framebufferCount -= 1 + stats.framebufferCount -= 1 } } } -export type FramebufferCache = ReferenceCache<Framebuffer, string, WebGLContext> +export type FramebufferCache = ReferenceCache<Framebuffer, string> -export function createFramebufferCache(): FramebufferCache { +export function createFramebufferCache(gl: GLRenderingContext, stats: WebGLStats): FramebufferCache { return createReferenceCache( (name: string) => name, - (ctx: WebGLContext) => createFramebuffer(ctx), + () => createFramebuffer(gl, stats), (framebuffer: Framebuffer) => { framebuffer.destroy() } ) } \ No newline at end of file diff --git a/src/mol-gl/webgl/program.ts b/src/mol-gl/webgl/program.ts index a4d842095d53599ac90d116b3909ebe41ca0ae40..4ecbec2d6b916c05562ee34a7176e893067a5698 100644 --- a/src/mol-gl/webgl/program.ts +++ b/src/mol-gl/webgl/program.ts @@ -5,7 +5,7 @@ */ import { ShaderCode, DefineValues, addShaderDefines } from '../shader-code' -import { WebGLContext } from './context'; +import { WebGLExtensions, WebGLState } from './context'; import { getUniformSetters, UniformsList, getUniformType } from './uniform'; import { AttributeBuffers, getAttribType } from './buffer'; import { TextureId, Textures } from './texture'; @@ -14,6 +14,8 @@ import { idFactory } from 'mol-util/id-factory'; import { RenderableSchema } from '../renderable/schema'; import { hashFnv32a, hashString } from 'mol-data/util'; import { isProductionMode } from 'mol-util/debug'; +import { GLRenderingContext } from './compat'; +import { ShaderCache } from './shader'; const getNextProgramId = idFactory() @@ -30,8 +32,7 @@ export interface Program { type Locations = { [k: string]: number } -function getLocations(ctx: WebGLContext, program: WebGLProgram, schema: RenderableSchema) { - const { gl } = ctx +function getLocations(gl: GLRenderingContext, program: WebGLProgram, schema: RenderableSchema) { const locations: Locations = {} Object.keys(schema).forEach(k => { const spec = schema[k] @@ -48,8 +49,7 @@ function getLocations(ctx: WebGLContext, program: WebGLProgram, schema: Renderab return locations } -function checkActiveAttributes(ctx: WebGLContext, program: WebGLProgram, schema: RenderableSchema) { - const { gl } = ctx +function checkActiveAttributes(gl: GLRenderingContext, program: WebGLProgram, schema: RenderableSchema) { const attribCount = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES); for (let i = 0; i < attribCount; ++i) { const info = gl.getActiveAttrib(program, i); @@ -66,7 +66,7 @@ function checkActiveAttributes(ctx: WebGLContext, program: WebGLProgram, schema: if (spec.type !== 'attribute') { throw new Error(`'${name}' must be of type 'attribute' but is '${spec.type}'`) } - const attribType = getAttribType(ctx, spec.kind, spec.itemSize) + const attribType = getAttribType(gl, spec.kind, spec.itemSize) if (attribType !== type) { throw new Error(`unexpected attribute type for ${name}`) } @@ -74,8 +74,7 @@ function checkActiveAttributes(ctx: WebGLContext, program: WebGLProgram, schema: } } -function checkActiveUniforms(ctx: WebGLContext, program: WebGLProgram, schema: RenderableSchema) { - const { gl } = ctx +function checkActiveUniforms(gl: GLRenderingContext, program: WebGLProgram, schema: RenderableSchema) { const attribCount = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); for (let i = 0; i < attribCount; ++i) { const info = gl.getActiveUniform(program, i); @@ -119,8 +118,7 @@ export interface ProgramProps { schema: RenderableSchema } -export function createProgram(ctx: WebGLContext, props: ProgramProps): Program { - const { gl, shaderCache } = ctx +export function createProgram(gl: GLRenderingContext, state: WebGLState, extensions: WebGLExtensions, shaderCache: ShaderCache, props: ProgramProps): Program { const { defineValues, shaderCode: _shaderCode, schema } = props const program = gl.createProgram() @@ -129,9 +127,9 @@ export function createProgram(ctx: WebGLContext, props: ProgramProps): Program { } const programId = getNextProgramId() - const shaderCode = addShaderDefines(ctx, defineValues, _shaderCode) - const vertShaderRef = shaderCache.get(ctx, { type: 'vert', source: shaderCode.vert }) - const fragShaderRef = shaderCache.get(ctx, { type: 'frag', source: shaderCode.frag }) + const shaderCode = addShaderDefines(gl, extensions, defineValues, _shaderCode) + const vertShaderRef = shaderCache.get({ type: 'vert', source: shaderCode.vert }) + const fragShaderRef = shaderCache.get({ type: 'frag', source: shaderCode.frag }) vertShaderRef.value.attach(program) fragShaderRef.value.attach(program) @@ -140,12 +138,12 @@ export function createProgram(ctx: WebGLContext, props: ProgramProps): Program { throw new Error(`Could not compile WebGL program. \n\n${gl.getProgramInfoLog(program)}`); } - const locations = getLocations(ctx, program, schema) + const locations = getLocations(gl, program, schema) const uniformSetters = getUniformSetters(schema) if (!isProductionMode) { - checkActiveAttributes(ctx, program, schema) - checkActiveUniforms(ctx, program, schema) + checkActiveAttributes(gl, program, schema) + checkActiveUniforms(gl, program, schema) } let destroyed = false @@ -155,7 +153,7 @@ export function createProgram(ctx: WebGLContext, props: ProgramProps): Program { use: () => { // console.log('use', programId) - ctx.currentProgramId = programId + state.currentProgramId = programId gl.useProgram(program) }, setUniforms: (uniformValues: UniformsList) => { @@ -191,14 +189,14 @@ export function createProgram(ctx: WebGLContext, props: ProgramProps): Program { } } -export type ProgramCache = ReferenceCache<Program, ProgramProps, WebGLContext> +export type ProgramCache = ReferenceCache<Program, ProgramProps> function defineValueHash(v: boolean | number | string): number { return typeof v === 'boolean' ? (v ? 1 : 0) : typeof v === 'number' ? v : hashString(v) } -export function createProgramCache(): ProgramCache { +export function createProgramCache(gl: GLRenderingContext, state: WebGLState, extensions: WebGLExtensions, shaderCache: ShaderCache): ProgramCache { return createReferenceCache( (props: ProgramProps) => { const array = [ props.shaderCode.id ] @@ -208,7 +206,7 @@ export function createProgramCache(): ProgramCache { }) return hashFnv32a(array).toString() }, - (ctx: WebGLContext, props: ProgramProps) => createProgram(ctx, props), + (props: ProgramProps) => createProgram(gl, state, extensions, shaderCache, props), (program: Program) => { program.destroy() } ) } \ No newline at end of file diff --git a/src/mol-gl/webgl/render-item.ts b/src/mol-gl/webgl/render-item.ts index 0840d619d2035ee3e6cd1e28c53c62577238f86c..45c057d29f0b4038f1954e5e1d909fdd7ea4508f 100644 --- a/src/mol-gl/webgl/render-item.ts +++ b/src/mol-gl/webgl/render-item.ts @@ -5,7 +5,7 @@ */ import { createAttributeBuffers, createElementsBuffer, ElementsBuffer, createAttributeBuffer, AttributeKind } from './buffer'; -import { createTextures } from './texture'; +import { createTextures, Texture } from './texture'; import { WebGLContext } from './context'; import { ShaderCode } from '../shader-code'; import { Program } from './program'; @@ -84,7 +84,7 @@ function resetValueChanges(valueChanges: ValueChanges) { */ export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCode: ShaderCode, schema: RenderableSchema, values: RenderableValues, materialId: number): RenderItem { const id = getNextRenderItemId() - const { programCache } = ctx + const { stats, state, programCache } = ctx const { instancedArrays, vertexArrayObject } = ctx.extensions const { attributeValues, defineValues, textureValues, uniformValues, materialUniformValues } = splitValues(schema, values) @@ -100,7 +100,7 @@ export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCo const programs: ProgramVariants = {} Object.keys(RenderVariantDefines).forEach(k => { const variantDefineValues: Values<RenderableSchema> = (RenderVariantDefines as any)[k] - programs[k] = programCache.get(ctx, { + programs[k] = programCache.get({ defineValues: { ...defineValues, ...variantDefineValues }, shaderCode, schema @@ -124,9 +124,9 @@ export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCo let drawCount = values.drawCount.ref.value let instanceCount = values.instanceCount.ref.value - ctx.drawCount += drawCount - ctx.instanceCount += instanceCount - ctx.instancedDrawCount += instanceCount * drawCount + stats.drawCount += drawCount + stats.instanceCount += instanceCount + stats.instancedDrawCount += instanceCount * drawCount const valueChanges = createValueChanges() @@ -144,12 +144,12 @@ export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCo const vertexArray = vertexArrays[variant] program.setUniforms(uniformValueEntries) if (program.id !== currentProgramId || - materialId === -1 || materialId !== ctx.currentMaterialId + materialId === -1 || materialId !== state.currentMaterialId ) { // console.log('program.id changed or materialId changed/-1', materialId) program.setUniforms(materialUniformValueEntries) currentProgramId = program.id - ctx.currentMaterialId = materialId + state.currentMaterialId = materialId } program.bindTextures(textures) if (vertexArrayObject && vertexArray) { @@ -183,7 +183,7 @@ export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCo Object.keys(RenderVariantDefines).forEach(k => { const variantDefineValues: Values<RenderableSchema> = (RenderVariantDefines as any)[k] programs[k].free() - programs[k] = programCache.get(ctx, { + programs[k] = programCache.get({ defineValues: { ...defineValues, ...variantDefineValues }, shaderCode, schema @@ -193,15 +193,15 @@ export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCo if (values.drawCount.ref.version !== versions.drawCount) { // console.log('drawCount version changed') - ctx.drawCount += values.drawCount.ref.value - drawCount - ctx.instancedDrawCount += instanceCount * values.drawCount.ref.value - instanceCount * drawCount + stats.drawCount += values.drawCount.ref.value - drawCount + stats.instancedDrawCount += instanceCount * values.drawCount.ref.value - instanceCount * drawCount drawCount = values.drawCount.ref.value versions.drawCount = values.drawCount.ref.version } if (values.instanceCount.ref.version !== versions.instanceCount) { // console.log('instanceCount version changed') - ctx.instanceCount += values.instanceCount.ref.value - instanceCount - ctx.instancedDrawCount += values.instanceCount.ref.value * drawCount - instanceCount * drawCount + stats.instanceCount += values.instanceCount.ref.value - instanceCount + stats.instancedDrawCount += values.instanceCount.ref.value * drawCount - instanceCount * drawCount instanceCount = values.instanceCount.ref.value versions.instanceCount = values.instanceCount.ref.version } @@ -217,7 +217,7 @@ export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCo // console.log('attribute array to small, need to create new attribute', k, value.ref.id, value.ref.version) buffer.destroy() const { itemSize, divisor } = schema[k] as AttributeSpec<AttributeKind> - attributeBuffers[i] = [k, createAttributeBuffer(ctx, value.ref.value, itemSize, divisor)] + attributeBuffers[i][1] = createAttributeBuffer(ctx, value.ref.value, itemSize, divisor) valueChanges.attributes = true } versions[k] = value.ref.version @@ -264,6 +264,8 @@ export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCo texture.load(value.ref.value as TextureImage<any> | TextureVolume<any>) versions[k] = value.ref.version valueChanges.textures = true + } else { + textures[i][1] = value.ref.value as Texture } } } diff --git a/src/mol-gl/webgl/render-target.ts b/src/mol-gl/webgl/render-target.ts index d26ec40b136d87c9669b32d2ddfca8ee55c7285c..01f623ecc8658f02fbf14b913a23a8332197929a 100644 --- a/src/mol-gl/webgl/render-target.ts +++ b/src/mol-gl/webgl/render-target.ts @@ -31,7 +31,7 @@ export interface RenderTarget { } export function createRenderTarget (ctx: WebGLContext, _width: number, _height: number): RenderTarget { - const { gl } = ctx + const { gl, stats } = ctx const image: Mutable<TextureImage<Uint8Array>> = { array: new Uint8Array(_width * _height * 4), @@ -42,7 +42,7 @@ export function createRenderTarget (ctx: WebGLContext, _width: number, _height: const targetTexture = createTexture(ctx, 'image-uint8', 'rgba', 'ubyte', 'linear') targetTexture.load(image) - const framebuffer = createFramebuffer(ctx) + const framebuffer = createFramebuffer(gl, stats) // attach the texture as the first color attachment targetTexture.attachFramebuffer(framebuffer, 'color0') diff --git a/src/mol-gl/webgl/renderbuffer.ts b/src/mol-gl/webgl/renderbuffer.ts index 8cc41d487b06dcdcfc1adc8f5bea866f5e960a32..86eea102485f89f7b01a6910dc572d42b1b99223 100644 --- a/src/mol-gl/webgl/renderbuffer.ts +++ b/src/mol-gl/webgl/renderbuffer.ts @@ -42,7 +42,7 @@ export interface Renderbuffer { } export function createRenderbuffer (ctx: WebGLContext, format: RenderbufferFormat, attachment: RenderbufferAttachment, _width: number, _height: number): Renderbuffer { - const { gl } = ctx + const { gl, stats } = ctx const _renderbuffer = gl.createRenderbuffer() if (_renderbuffer === null) { throw new Error('Could not create WebGL renderbuffer') @@ -57,7 +57,7 @@ export function createRenderbuffer (ctx: WebGLContext, format: RenderbufferForma gl.framebufferRenderbuffer(gl.FRAMEBUFFER, _attachment, gl.RENDERBUFFER, _renderbuffer) let destroyed = false - ctx.renderbufferCount += 1 + stats.renderbufferCount += 1 return { id: getNextRenderbufferId(), @@ -72,7 +72,7 @@ export function createRenderbuffer (ctx: WebGLContext, format: RenderbufferForma if (destroyed) return gl.deleteRenderbuffer(_renderbuffer) destroyed = true - ctx.framebufferCount -= 1 + stats.framebufferCount -= 1 } } } \ No newline at end of file diff --git a/src/mol-gl/webgl/shader.ts b/src/mol-gl/webgl/shader.ts index a209cd017546234b711b4b3069275ed5c015417a..2a4231d0b7804deb7c452d5b446bd7e3bd527d24 100644 --- a/src/mol-gl/webgl/shader.ts +++ b/src/mol-gl/webgl/shader.ts @@ -1,12 +1,12 @@ /** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { createReferenceCache, ReferenceCache } from 'mol-util/reference-cache'; -import { WebGLContext } from './context'; import { idFactory } from 'mol-util/id-factory'; +import { GLRenderingContext } from './compat'; const getNextShaderId = idFactory() @@ -26,8 +26,7 @@ export interface Shader { destroy: () => void } -function createShader(ctx: WebGLContext, props: ShaderProps): Shader { - const { gl } = ctx +function createShader(gl: GLRenderingContext, props: ShaderProps): Shader { const { type, source } = props const shader = gl.createShader(type === 'vert' ? gl.VERTEX_SHADER : gl.FRAGMENT_SHADER) @@ -54,12 +53,12 @@ function createShader(ctx: WebGLContext, props: ShaderProps): Shader { } } -export type ShaderCache = ReferenceCache<Shader, ShaderProps, WebGLContext> +export type ShaderCache = ReferenceCache<Shader, ShaderProps> -export function createShaderCache(): ShaderCache { +export function createShaderCache(gl: GLRenderingContext): ShaderCache { return createReferenceCache( (props: ShaderProps) => JSON.stringify(props), - (ctx: WebGLContext, props: ShaderProps) => createShader(ctx, props), + (props: ShaderProps) => createShader(gl, props), (shader: Shader) => { shader.destroy() } ) } \ No newline at end of file diff --git a/src/mol-gl/webgl/texture.ts b/src/mol-gl/webgl/texture.ts index 5a24bf8bf38fcdf90470cae98e82c2d8b0092b2e..40edd4e72b5fe857f0f945a9ff2bface3bc78707 100644 --- a/src/mol-gl/webgl/texture.ts +++ b/src/mol-gl/webgl/texture.ts @@ -42,7 +42,7 @@ export function getTarget(ctx: WebGLContext, kind: TextureKind): number { case 'volume-float32': return gl.TEXTURE_3D } } - throw new Error('unknown texture kind') + throw new Error(`unknown texture kind '${kind}'`) } export function getFormat(ctx: WebGLContext, format: TextureFormat): number { @@ -143,7 +143,7 @@ export type Textures = [string, Texture][] export function createTexture(ctx: WebGLContext, kind: TextureKind, _format: TextureFormat, _type: TextureType, _filter: TextureFilter): Texture { const id = getNextTextureId() - const { gl } = ctx + const { gl, stats } = ctx const texture = gl.createTexture() if (texture === null) { throw new Error('Could not create WebGL texture') @@ -166,7 +166,7 @@ export function createTexture(ctx: WebGLContext, kind: TextureKind, _format: Tex let width = 0, height = 0, depth = 0 let destroyed = false - ctx.textureCount += 1 + stats.textureCount += 1 return { id, @@ -238,7 +238,7 @@ export function createTexture(ctx: WebGLContext, kind: TextureKind, _format: Tex if (destroyed) return gl.deleteTexture(texture) destroyed = true - ctx.textureCount -= 1 + stats.textureCount -= 1 } } } diff --git a/src/mol-gl/webgl/vertex-array.ts b/src/mol-gl/webgl/vertex-array.ts index b6bd48a8bdfef9f3a328f1be4bcf83d3014e944c..f008d8c26159999e674d61113f25944b66c62401 100644 --- a/src/mol-gl/webgl/vertex-array.ts +++ b/src/mol-gl/webgl/vertex-array.ts @@ -16,7 +16,7 @@ export function createVertexArray(ctx: WebGLContext, program: Program, attribute vertexArrayObject.bindVertexArray(vertexArray) if (elementsBuffer) elementsBuffer.bind() program.bindAttributes(attributeBuffers) - ctx.vaoCount += 1 + ctx.stats.vaoCount += 1 vertexArrayObject.bindVertexArray(null) } return vertexArray @@ -36,6 +36,6 @@ export function deleteVertexArray(ctx: WebGLContext, vertexArray: WebGLVertexArr const { vertexArrayObject } = ctx.extensions if (vertexArrayObject && vertexArray) { vertexArrayObject.deleteVertexArray(vertexArray) - ctx.vaoCount -= 1 + ctx.stats.vaoCount -= 1 } } \ No newline at end of file diff --git a/src/mol-math/geometry/gaussian-density/gpu.ts b/src/mol-math/geometry/gaussian-density/gpu.ts index 2ec368a7a98b95d0c45f4fb0eaa047bd6d7e8937..f79793fc01e55729cbc76722c30af9e2368170aa 100644 --- a/src/mol-math/geometry/gaussian-density/gpu.ts +++ b/src/mol-math/geometry/gaussian-density/gpu.ts @@ -110,7 +110,7 @@ async function calcGaussianDensityTexture2d(ctx: RuntimeContext, webgl: WebGLCon const { gl, framebufferCache } = webgl const { uCurrentSlice, uCurrentX, uCurrentY } = renderable.values - const framebuffer = framebufferCache.get(webgl, FramebufferName).value + const framebuffer = framebufferCache.get(FramebufferName).value framebuffer.bind() setRenderingDefaults(gl) @@ -168,7 +168,7 @@ async function calcGaussianDensityTexture3d(ctx: RuntimeContext, webgl: WebGLCon const { gl, framebufferCache } = webgl const { uCurrentSlice } = renderable.values - const framebuffer = framebufferCache.get(webgl, FramebufferName).value + const framebuffer = framebufferCache.get(FramebufferName).value framebuffer.bind() setRenderingDefaults(gl) gl.viewport(0, 0, dx, dy) @@ -312,6 +312,7 @@ function setupGroupIdRendering(webgl: WebGLContext, renderable: ComputeRenderabl } function getTexture2dSize(maxTexSize: number, gridDim: Vec3) { + maxTexSize = 256 let texDimX = 0 let texDimY = gridDim[1] let texRows = 1 @@ -342,7 +343,7 @@ async function fieldFromTexture2d(ctx: WebGLContext, texture: Texture, dim: Vec3 const image = new Uint8Array(width * height * 4) - const framebuffer = framebufferCache.get(ctx, FramebufferName).value + const framebuffer = framebufferCache.get(FramebufferName).value framebuffer.bind() texture.attachFramebuffer(framebuffer, 0) // TODO too slow, why? Too many checks if gpu ready??? diff --git a/src/mol-util/_spec/reference-cache.spec.ts b/src/mol-util/_spec/reference-cache.spec.ts index 544b642ecfb686d638c8f718f890f5271a552007..0dc3bf4b03d870ca162a5773a12e5ce438efdbd5 100644 --- a/src/mol-util/_spec/reference-cache.spec.ts +++ b/src/mol-util/_spec/reference-cache.spec.ts @@ -10,20 +10,19 @@ describe('reference-cache', () => { it('basic', () => { const refCache = createReferenceCache( (x: number) => x.toString(), - (ctx: {}, x) => x, + (x) => x, () => {} ) expect(refCache.count).toBe(0) - const ctx = {} - const ref2a = refCache.get(ctx, 2) + const ref2a = refCache.get(2) expect(refCache.count).toBe(1) - const ref2b = refCache.get(ctx, 2) + const ref2b = refCache.get(2) expect(refCache.count).toBe(1) expect(ref2b.value).toBe(2) - const ref3 = refCache.get(ctx, 3) + const ref3 = refCache.get(3) expect(refCache.count).toBe(2) expect(ref3.value).toBe(3) diff --git a/src/mol-util/float-packing.ts b/src/mol-util/float-packing.ts index 42087b10738d71adb4e1913c187cf5fd460b38cf..e75d31a6bc815612f561069aae7bffbf1c9998fb 100644 --- a/src/mol-util/float-packing.ts +++ b/src/mol-util/float-packing.ts @@ -15,7 +15,7 @@ export function encodeFloatLog(value: number) { return Math.log(value + 1.0) / f /** decode logarithmically encoded float */ export function decodeFloatLog(value: number) { return Math.exp(value * floatLogFactor) - 1.0 } -/** encode float as rgb triplet */ +/** encode float as normalized rgb triplet */ export function encodeFloatRGB(value: number) { value = clamp(value, 0.0, 16777216.0 - 1.0) + 1.0 const b = (value % 256) / 255.0 diff --git a/src/mol-util/reference-cache.ts b/src/mol-util/reference-cache.ts index aa5f341c1349a1e656b5b11ffdcdbbc389604cbd..e383416cf487b5fdfd493418c1f76515984161e7 100644 --- a/src/mol-util/reference-cache.ts +++ b/src/mol-util/reference-cache.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -24,22 +24,22 @@ export function createReferenceItem<T>(ref: Reference<T>) { } } -export interface ReferenceCache<T, P, C> { - get: (ctx: C, props: P) => ReferenceItem<T> +export interface ReferenceCache<T, P> { + get: (props: P) => ReferenceItem<T> clear: () => void readonly count: number dispose: () => void } -export function createReferenceCache<T, P, C>(hashFn: (props: P) => string, ctor: (ctx: C, props: P) => T, deleteFn: (v: T) => void): ReferenceCache<T, P, C> { +export function createReferenceCache<T, P, C>(hashFn: (props: P) => string, ctor: (props: P) => T, deleteFn: (v: T) => void): ReferenceCache<T, P> { const map: Map<string, Reference<T>> = new Map() return { - get: (ctx: C, props: P) => { + get: (props: P) => { const id = hashFn(props) let ref = map.get(id) if (!ref) { - ref = createReference<T>(ctor(ctx, props)) + ref = createReference<T>(ctor(props)) map.set(id, ref) } ref.usageCount += 1