diff --git a/src/mol-gl/renderable/mesh.ts b/src/mol-gl/renderable/mesh.ts index 94115e6c84e0716aa43ab2b86962dcb19d3311d2..3b6a0a63af928a641656423b6372dd521c470367 100644 --- a/src/mol-gl/renderable/mesh.ts +++ b/src/mol-gl/renderable/mesh.ts @@ -60,7 +60,7 @@ namespace Mesh { console.log('Updating mesh renderable') }, dispose: () => { - renderItem.dispose() + renderItem.destroy() } } } diff --git a/src/mol-gl/renderable/point.ts b/src/mol-gl/renderable/point.ts index 4591eff38d7f9336d4057c73a2230bb4b0aca098..7ff653779138a7afd7275f48bc2e0df0143c255a 100644 --- a/src/mol-gl/renderable/point.ts +++ b/src/mol-gl/renderable/point.ts @@ -62,7 +62,7 @@ namespace Point { console.log('Updating point renderable') }, dispose: () => { - renderItem.dispose() + renderItem.destroy() } } } diff --git a/src/mol-gl/renderer.ts b/src/mol-gl/renderer.ts index b13ffa7a1bb74cd3ee738b0a60cd970087516d26..8fe4c2707afacaaf4762aa3cd6a2c227a1c51b0b 100644 --- a/src/mol-gl/renderer.ts +++ b/src/mol-gl/renderer.ts @@ -13,11 +13,12 @@ import { Context } from './webgl/context'; import { Mat4, Vec3 } from 'mol-math/linear-algebra'; export interface RendererStats { - elementsCount: number + renderableCount: number + programCount: number + shaderCount: number bufferCount: number textureCount: number - shaderCount: number - renderableCount: number + vaoCount: number } interface Renderer { @@ -98,10 +99,15 @@ namespace Renderer { Viewport.copy(viewport, newViewport) gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height) }, - get stats() { + get stats(): RendererStats { return { - renderableCount: scene.count - } as any + renderableCount: scene.count, + programCount: ctx.programCache.count, + shaderCount: ctx.shaderCache.count, + bufferCount: ctx.bufferCount, + textureCount: ctx.textureCount, + vaoCount: ctx.vaoCount, + } }, dispose: () => { scene.clear() diff --git a/src/mol-gl/webgl/buffer.ts b/src/mol-gl/webgl/buffer.ts index 054ecc3454f245ffb114a1f3a31b8b1d955d14f8..0e79d368c5dd6ef03f3efb98ff399a0e1848d417 100644 --- a/src/mol-gl/webgl/buffer.ts +++ b/src/mol-gl/webgl/buffer.ts @@ -105,6 +105,9 @@ export function createBuffer(ctx: Context, array: ArrayType, itemSize: BufferIte } updateData(array) + let destroyed = false + ctx.bufferCount += 1 + return { _buffer, _usageHint, @@ -119,10 +122,13 @@ export function createBuffer(ctx: Context, array: ArrayType, itemSize: BufferIte }, destroy: () => { + if (destroyed) return gl.bindBuffer(_bufferType, _buffer) // set size to 1 before deleting gl.bufferData(_bufferType, 1, _usageHint) gl.deleteBuffer(_buffer) + destroyed = true + ctx.bufferCount -= 1 } } } diff --git a/src/mol-gl/webgl/context.ts b/src/mol-gl/webgl/context.ts index f6600407aa7e43acf4afab7ed0e3695a1dccb3ce..b7162e29377e2977373b8649f817b67f0c4f8f87 100644 --- a/src/mol-gl/webgl/context.ts +++ b/src/mol-gl/webgl/context.ts @@ -7,14 +7,6 @@ import { createProgramCache, ProgramCache } from './program' import { createShaderCache, ShaderCache } from './shader' -// const extensions = [ -// 'OES_element_index_uint', -// 'ANGLE_instanced_arrays' -// ] -// const optionalExtensions = [ -// 'EXT_disjoint_timer_query' -// ] - function unbindResources (gl: WebGLRenderingContext) { // bind null to all texture units const maxTextureImageUnits = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS) @@ -50,6 +42,9 @@ export interface Context { extensions: Extensions shaderCache: ShaderCache programCache: ProgramCache + bufferCount: number + textureCount: number + vaoCount: number destroy: () => void } @@ -67,13 +62,21 @@ export function createContext(gl: WebGLRenderingContext): Context { console.log('Could not get "OES_vertex_array_object" extension') } + const shaderCache = createShaderCache() + const programCache = createProgramCache() + return { gl, extensions: { angleInstancedArrays, oesElementIndexUint, oesVertexArrayObject }, - shaderCache: createShaderCache(), - programCache: createProgramCache(), + shaderCache, + programCache, + bufferCount: 0, + textureCount: 0, + vaoCount: 0, destroy: () => { unbindResources(gl) + programCache.dispose() + shaderCache.dispose() // TODO destroy buffers and textures } } diff --git a/src/mol-gl/webgl/render-item.ts b/src/mol-gl/webgl/render-item.ts index 352733cd315ba7b276d02929d3ba3a38486f3f85..82868a3899a152bb2f475220695bbc815f58e6ce 100644 --- a/src/mol-gl/webgl/render-item.ts +++ b/src/mol-gl/webgl/render-item.ts @@ -55,7 +55,7 @@ export interface RenderItem { update: (state: RenderItemState) => void draw: () => void - dispose: () => void + destroy: () => void } export function createRenderItem(ctx: Context, props: RenderItemProps, state: RenderItemState): RenderItem { @@ -77,6 +77,7 @@ export function createRenderItem(ctx: Context, props: RenderItemProps, state: Re vertexArray = oesVertexArrayObject.createVertexArrayOES() oesVertexArrayObject.bindVertexArrayOES(vertexArray) program.bindAttributes(attributeBuffers) + ctx.vaoCount += 1 } let elementsBuffer: ElementsBuffer @@ -84,7 +85,13 @@ export function createRenderItem(ctx: Context, props: RenderItemProps, state: Re elementsBuffer = createElementsBuffer(ctx, elements) } + // needs to come after elements buffer creation to include it in the vao + if (oesVertexArrayObject) { + oesVertexArrayObject.bindVertexArrayOES(null!) + } + let { drawCount, instanceCount } = state + let destroyed = false return { hash, @@ -97,6 +104,7 @@ export function createRenderItem(ctx: Context, props: RenderItemProps, state: Re oesVertexArrayObject.bindVertexArrayOES(vertexArray) } else { program.bindAttributes(attributeBuffers) + elementsBuffer.bind() } program.bindTextures(textures) if (elementsBuffer) { @@ -113,9 +121,19 @@ export function createRenderItem(ctx: Context, props: RenderItemProps, state: Re if (value !== undefined) attributeBuffers[k].updateData(value) }) }, - dispose: () => { - // TODO + destroy: () => { + if (destroyed) return programRef.free() + Object.keys(textures).forEach(k => textures[k].destroy()) + Object.keys(attributeBuffers).forEach(k => attributeBuffers[k].destroy()) + if (elements && elementsKind) { + elementsBuffer.destroy() + } + if (oesVertexArrayObject) { + oesVertexArrayObject.deleteVertexArrayOES(vertexArray) + ctx.vaoCount -= 1 + } + destroyed = true } } } \ No newline at end of file diff --git a/src/mol-gl/webgl/texture.ts b/src/mol-gl/webgl/texture.ts index 26f17fdf2043f768e75bde6c4de79d4a259dba35..6f86b433e3034686c99a5fbd281ae4eb9ffb5ff0 100644 --- a/src/mol-gl/webgl/texture.ts +++ b/src/mol-gl/webgl/texture.ts @@ -11,6 +11,7 @@ export interface Texture { load: (image: TextureImage) => void bind: (id: TextureId) => void unbind: (id: TextureId) => void + destroy: () => void } export type TextureId = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 @@ -33,6 +34,9 @@ export function createTexture(ctx: Context): Texture { const _format = gl.RGB const _arrayType = gl.UNSIGNED_BYTE + let destroyed = false + ctx.textureCount += 1 + return { load: (image: TextureImage) => { const { array, width, height } = image @@ -54,6 +58,13 @@ export function createTexture(ctx: Context): Texture { unbind: (id: TextureId) => { gl.activeTexture(gl.TEXTURE0 + id) gl.bindTexture(_textureType, null) + }, + + destroy: () => { + if (destroyed) return + gl.deleteTexture(texture) + destroyed = true + ctx.textureCount -= 1 } } } diff --git a/src/mol-util/reference-cache.ts b/src/mol-util/reference-cache.ts index 38c09d87a0e986a786a2cdd5fca178cb1ddb1a71..a58346ca12ee5a38fc7110e4ba5b7c6c4f634733 100644 --- a/src/mol-util/reference-cache.ts +++ b/src/mol-util/reference-cache.ts @@ -28,11 +28,12 @@ export interface ReferenceCache<T, P, C> { get: (ctx: C, props: P) => ReferenceItem<T> clear: () => void 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> { const map: Map<string, Reference<T>> = new Map() - + return { get: (ctx: C, props: P) => { const id = hashFn(props) @@ -56,6 +57,9 @@ export function createReferenceCache<T, P, C>(hashFn: (props: P) => string, ctor }, get count () { return map.size - } + }, + dispose: () => { + map.forEach(ref => deleteFn(ref.value)) + }, } } \ No newline at end of file