From f28313fd2d3cdbefb2471a6171024abd5251f702 Mon Sep 17 00:00:00 2001 From: Alexander Rose <alex.rose@rcsb.org> Date: Wed, 3 Apr 2019 15:52:53 -0700 Subject: [PATCH] added graphics and compute render item variants --- src/mol-canvas3d/canvas3d.ts | 6 +-- src/mol-gl/renderable.ts | 18 ++++----- src/mol-gl/renderable/direct-volume.ts | 4 +- src/mol-gl/renderable/lines.ts | 4 +- src/mol-gl/renderable/mesh.ts | 4 +- src/mol-gl/renderable/points.ts | 4 +- src/mol-gl/renderable/spheres.ts | 4 +- src/mol-gl/renderable/text.ts | 4 +- src/mol-gl/renderer.ts | 8 ++-- src/mol-gl/webgl/render-item.ts | 53 ++++++++++++++++++-------- 10 files changed, 65 insertions(+), 44 deletions(-) diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts index e4491ed0f..09f1abea6 100644 --- a/src/mol-canvas3d/canvas3d.ts +++ b/src/mol-canvas3d/canvas3d.ts @@ -19,7 +19,7 @@ import { createContext, getGLContext, WebGLContext } from 'mol-gl/webgl/context' import { Representation } from 'mol-repr/representation'; import { createRenderTarget } from 'mol-gl/webgl/render-target'; import Scene from 'mol-gl/scene'; -import { RenderVariant } from 'mol-gl/webgl/render-item'; +import { GraphicsRenderVariant } from 'mol-gl/webgl/render-item'; import { PickingId } from 'mol-geo/geometry/picking'; import { MarkerAction } from 'mol-geo/geometry/marker-data'; import { Loci, EmptyLoci, isEmptyLoci } from 'mol-model/loci'; @@ -70,7 +70,7 @@ interface Canvas3D { resetCamera: () => void readonly camera: Camera downloadScreenshot: () => void - getImageData: (variant: RenderVariant) => ImageData + getImageData: (variant: GraphicsRenderVariant) => ImageData setProps: (props: Partial<Canvas3DProps>) => void /** Returns a copy of the current Canvas3D instance props */ @@ -388,7 +388,7 @@ namespace Canvas3D { downloadScreenshot: () => { // TODO }, - getImageData: (variant: RenderVariant) => { + getImageData: (variant: GraphicsRenderVariant) => { switch (variant) { case 'draw': return renderer.getImageData() case 'pickObject': return objectPickTarget.getImageData() diff --git a/src/mol-gl/renderable.ts b/src/mol-gl/renderable.ts index bd436980b..62817b1e0 100644 --- a/src/mol-gl/renderable.ts +++ b/src/mol-gl/renderable.ts @@ -6,7 +6,7 @@ import { Program } from './webgl/program'; import { RenderableValues, Values, RenderableSchema } from './renderable/schema'; -import { RenderVariant, RenderItem } from './webgl/render-item'; +import { GraphicsRenderItem, ComputeRenderItem, GraphicsRenderVariant } from './webgl/render-item'; import { ValueCell } from 'mol-util'; import { idFactory } from 'mol-util/id-factory'; import { clamp } from 'mol-math/interpolate'; @@ -26,20 +26,20 @@ export interface Renderable<T extends RenderableValues> { readonly values: T readonly state: RenderableState - render: (variant: RenderVariant) => void - getProgram: (variant: RenderVariant) => Program + render: (variant: GraphicsRenderVariant) => void + getProgram: (variant: GraphicsRenderVariant) => Program update: () => void dispose: () => void } -export function createRenderable<T extends Values<RenderableSchema>>(renderItem: RenderItem, values: T, state: RenderableState): Renderable<T> { +export function createRenderable<T extends Values<RenderableSchema>>(renderItem: GraphicsRenderItem, values: T, state: RenderableState): Renderable<T> { return { id: getNextRenderableId(), materialId: renderItem.materialId, values, state, - render: (variant: RenderVariant) => { + render: (variant: GraphicsRenderVariant) => { if (values.uAlpha && values.alpha) { ValueCell.updateIfChanged(values.uAlpha, clamp(values.alpha.ref.value * state.alphaFactor, 0, 1)) } @@ -48,7 +48,7 @@ export function createRenderable<T extends Values<RenderableSchema>>(renderItem: } renderItem.render(variant) }, - getProgram: (variant: RenderVariant) => renderItem.getProgram(variant), + getProgram: (variant: GraphicsRenderVariant) => renderItem.getProgram(variant), update: () => renderItem.update(), dispose: () => renderItem.destroy() } @@ -66,13 +66,13 @@ export interface ComputeRenderable<T extends RenderableValues> { dispose: () => void } -export function createComputeRenderable<T extends Values<RenderableSchema>>(renderItem: RenderItem, values: T): ComputeRenderable<T> { +export function createComputeRenderable<T extends Values<RenderableSchema>>(renderItem: ComputeRenderItem, values: T): ComputeRenderable<T> { return { id: getNextRenderableId(), values, - render: () => renderItem.render('draw'), - use: () => renderItem.getProgram('draw').use(), + render: () => renderItem.render('compute'), + use: () => renderItem.getProgram('compute').use(), update: () => renderItem.update(), dispose: () => renderItem.destroy() } diff --git a/src/mol-gl/renderable/direct-volume.ts b/src/mol-gl/renderable/direct-volume.ts index 53583cbdf..89b775278 100644 --- a/src/mol-gl/renderable/direct-volume.ts +++ b/src/mol-gl/renderable/direct-volume.ts @@ -6,7 +6,7 @@ import { Renderable, RenderableState, createRenderable } from '../renderable' import { WebGLContext } from '../webgl/context'; -import { createRenderItem } from '../webgl/render-item'; +import { createGraphicsRenderItem } from '../webgl/render-item'; import { AttributeSpec, Values, UniformSpec, GlobalUniformSchema, InternalSchema, TextureSpec, ValueSpec, ElementsSpec, DefineSpec, InternalValues } from './schema'; import { DirectVolumeShaderCode } from '../shader-code'; import { ValueCell } from 'mol-util'; @@ -79,6 +79,6 @@ export function DirectVolumeRenderable(ctx: WebGLContext, id: number, values: Di uPickable: ValueCell.create(state.pickable ? 1 : 0), } const shaderCode = DirectVolumeShaderCode - const renderItem = createRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId) + const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId) return createRenderable(renderItem, values, state); } \ No newline at end of file diff --git a/src/mol-gl/renderable/lines.ts b/src/mol-gl/renderable/lines.ts index 74fcca839..e44a62f72 100644 --- a/src/mol-gl/renderable/lines.ts +++ b/src/mol-gl/renderable/lines.ts @@ -6,7 +6,7 @@ import { Renderable, RenderableState, createRenderable } from '../renderable' import { WebGLContext } from '../webgl/context'; -import { createRenderItem } from '../webgl/render-item'; +import { createGraphicsRenderItem } from '../webgl/render-item'; import { GlobalUniformSchema, BaseSchema, AttributeSpec, DefineSpec, Values, InternalSchema, SizeSchema, ElementsSpec, InternalValues } from './schema'; import { ValueCell } from 'mol-util'; import { LinesShaderCode } from '../shader-code'; @@ -32,7 +32,7 @@ export function LinesRenderable(ctx: WebGLContext, id: number, values: LinesValu uPickable: ValueCell.create(state.pickable ? 1 : 0) } const shaderCode = LinesShaderCode - const renderItem = createRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId) + const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId) return createRenderable(renderItem, values, state); } \ No newline at end of file diff --git a/src/mol-gl/renderable/mesh.ts b/src/mol-gl/renderable/mesh.ts index a8ebba4b3..bcf65b9f0 100644 --- a/src/mol-gl/renderable/mesh.ts +++ b/src/mol-gl/renderable/mesh.ts @@ -6,7 +6,7 @@ import { Renderable, RenderableState, createRenderable } from '../renderable' import { WebGLContext } from '../webgl/context'; -import { createRenderItem } from '../webgl/render-item'; +import { createGraphicsRenderItem } from '../webgl/render-item'; import { GlobalUniformSchema, BaseSchema, AttributeSpec, ElementsSpec, DefineSpec, Values, InternalSchema, InternalValues } from './schema'; import { MeshShaderCode } from '../shader-code'; import { ValueCell } from 'mol-util'; @@ -30,7 +30,7 @@ export function MeshRenderable(ctx: WebGLContext, id: number, values: MeshValues uPickable: ValueCell.create(state.pickable ? 1 : 0) } const shaderCode = MeshShaderCode - const renderItem = createRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId) + const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId) return createRenderable(renderItem, values, state) } \ No newline at end of file diff --git a/src/mol-gl/renderable/points.ts b/src/mol-gl/renderable/points.ts index ff3726edb..6b2cf5e1a 100644 --- a/src/mol-gl/renderable/points.ts +++ b/src/mol-gl/renderable/points.ts @@ -6,7 +6,7 @@ import { Renderable, RenderableState, createRenderable } from '../renderable' import { WebGLContext } from '../webgl/context'; -import { createRenderItem } from '../webgl/render-item'; +import { createGraphicsRenderItem } from '../webgl/render-item'; import { GlobalUniformSchema, BaseSchema, AttributeSpec, UniformSpec, DefineSpec, Values, InternalSchema, SizeSchema, InternalValues } from './schema'; import { PointsShaderCode } from '../shader-code'; import { ValueCell } from 'mol-util'; @@ -29,6 +29,6 @@ export function PointsRenderable(ctx: WebGLContext, id: number, values: PointsVa uPickable: ValueCell.create(state.pickable ? 1 : 0) } const shaderCode = PointsShaderCode - const renderItem = createRenderItem(ctx, 'points', shaderCode, schema, { ...values, ...internalValues }, materialId) + const renderItem = createGraphicsRenderItem(ctx, 'points', shaderCode, schema, { ...values, ...internalValues }, materialId) return createRenderable(renderItem, values, state); } \ No newline at end of file diff --git a/src/mol-gl/renderable/spheres.ts b/src/mol-gl/renderable/spheres.ts index 3806cf183..1af5348ec 100644 --- a/src/mol-gl/renderable/spheres.ts +++ b/src/mol-gl/renderable/spheres.ts @@ -6,7 +6,7 @@ import { Renderable, RenderableState, createRenderable } from '../renderable' import { WebGLContext } from '../webgl/context'; -import { createRenderItem } from '../webgl/render-item'; +import { createGraphicsRenderItem } from '../webgl/render-item'; import { GlobalUniformSchema, BaseSchema, AttributeSpec, Values, InternalSchema, SizeSchema, InternalValues, ElementsSpec, ValueSpec, DefineSpec } from './schema'; import { SpheresShaderCode } from '../shader-code'; import { ValueCell } from 'mol-util'; @@ -31,6 +31,6 @@ export function SpheresRenderable(ctx: WebGLContext, id: number, values: Spheres uPickable: ValueCell.create(state.pickable ? 1 : 0) } const shaderCode = SpheresShaderCode - const renderItem = createRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId) + const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId) return createRenderable(renderItem, values, state); } \ No newline at end of file diff --git a/src/mol-gl/renderable/text.ts b/src/mol-gl/renderable/text.ts index 3e9a2c476..1bf43a856 100644 --- a/src/mol-gl/renderable/text.ts +++ b/src/mol-gl/renderable/text.ts @@ -6,7 +6,7 @@ import { Renderable, RenderableState, createRenderable } from '../renderable' import { WebGLContext } from '../webgl/context'; -import { createRenderItem } from '../webgl/render-item'; +import { createGraphicsRenderItem } from '../webgl/render-item'; import { GlobalUniformSchema, BaseSchema, AttributeSpec, UniformSpec, Values, InternalSchema, SizeSchema, InternalValues, TextureSpec, ElementsSpec, ValueSpec } from './schema'; import { TextShaderCode } from '../shader-code'; import { ValueCell } from 'mol-util'; @@ -41,6 +41,6 @@ export function TextRenderable(ctx: WebGLContext, id: number, values: TextValues uPickable: ValueCell.create(state.pickable ? 1 : 0) } const shaderCode = TextShaderCode - const renderItem = createRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId) + const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId) return createRenderable(renderItem, values, state); } \ No newline at end of file diff --git a/src/mol-gl/renderer.ts b/src/mol-gl/renderer.ts index d56dcbe1b..fbc6b146f 100644 --- a/src/mol-gl/renderer.ts +++ b/src/mol-gl/renderer.ts @@ -14,7 +14,7 @@ import { Renderable } from './renderable'; import { Color } from 'mol-util/color'; import { ValueCell } from 'mol-util'; import { RenderableValues, GlobalUniformValues, BaseValues } from './renderable/schema'; -import { RenderVariant } from './webgl/render-item'; +import { GraphicsRenderVariant } from './webgl/render-item'; export interface RendererStats { programCount: number @@ -36,7 +36,7 @@ interface Renderer { readonly props: RendererProps clear: () => void - render: (scene: Scene, variant: RenderVariant) => void + render: (scene: Scene, variant: GraphicsRenderVariant) => void setViewport: (x: number, y: number, width: number, height: number) => void setClearColor: (color: Color) => void setPickingAlphaThreshold: (value: number) => void @@ -108,7 +108,7 @@ namespace Renderer { const globalUniformList = Object.entries(globalUniforms) let globalUniformsNeedUpdate = true - const renderObject = (r: Renderable<RenderableValues & BaseValues>, variant: RenderVariant) => { + const renderObject = (r: Renderable<RenderableValues & BaseValues>, variant: GraphicsRenderVariant) => { const program = r.getProgram(variant) if (r.state.visible) { if (state.currentProgramId !== program.id) { @@ -152,7 +152,7 @@ namespace Renderer { } } - const render = (scene: Scene, variant: RenderVariant) => { + const render = (scene: Scene, variant: GraphicsRenderVariant) => { ValueCell.update(globalUniforms.uModel, scene.view) ValueCell.update(globalUniforms.uView, camera.view) ValueCell.update(globalUniforms.uInvView, Mat4.invert(invView, camera.view)) diff --git a/src/mol-gl/webgl/render-item.ts b/src/mol-gl/webgl/render-item.ts index 45c057d29..763a6e670 100644 --- a/src/mol-gl/webgl/render-item.ts +++ b/src/mol-gl/webgl/render-item.ts @@ -33,23 +33,34 @@ export function getDrawMode(ctx: WebGLContext, drawMode: DrawMode) { } } -export interface RenderItem { +export interface RenderItem<T extends string> { readonly id: number readonly materialId: number - getProgram: (variant: RenderVariant) => Program + getProgram: (variant: T) => Program - render: (variant: RenderVariant) => void + render: (variant: T) => void update: () => Readonly<ValueChanges> destroy: () => void } -const RenderVariantDefines = { +// + +const GraphicsRenderVariantDefines = { 'draw': {}, 'pickObject': { dColorType: ValueCell.create('objectPicking') }, 'pickInstance': { dColorType: ValueCell.create('instancePicking') }, 'pickGroup': { dColorType: ValueCell.create('groupPicking') } } -export type RenderVariant = keyof typeof RenderVariantDefines +export type GraphicsRenderVariant = keyof typeof GraphicsRenderVariantDefines + +const ComputeRenderVariantDefines = { + 'compute': {}, +} +export type ComputeRenderVariant = keyof typeof ComputeRenderVariantDefines + +type RenderVariantDefines = typeof GraphicsRenderVariantDefines | typeof ComputeRenderVariantDefines + +// type ProgramVariants = { [k: string]: ReferenceItem<Program> } type VertexArrayVariants = { [k: string]: WebGLVertexArrayObjectOES | null } @@ -75,14 +86,24 @@ function resetValueChanges(valueChanges: ValueChanges) { valueChanges.textures = false } -// TODO make `RenderVariantDefines` a parameter for `createRenderItem` +// + +export type GraphicsRenderItem = RenderItem<keyof typeof GraphicsRenderVariantDefines & string> +export function createGraphicsRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCode: ShaderCode, schema: RenderableSchema, values: RenderableValues, materialId: number) { + return createRenderItem(ctx, drawMode, shaderCode, schema, values, materialId, GraphicsRenderVariantDefines) +} + +export type ComputeRenderItem = RenderItem<keyof typeof ComputeRenderVariantDefines & string> +export function createComputeRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCode: ShaderCode, schema: RenderableSchema, values: RenderableValues) { + return createRenderItem(ctx, drawMode, shaderCode, schema, values, -1, ComputeRenderVariantDefines) +} /** * Creates a render item * * - assumes that `values.drawCount` and `values.instanceCount` exist */ -export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCode: ShaderCode, schema: RenderableSchema, values: RenderableValues, materialId: number): RenderItem { +export function createRenderItem<T extends RenderVariantDefines, S extends keyof T & string>(ctx: WebGLContext, drawMode: DrawMode, shaderCode: ShaderCode, schema: RenderableSchema, values: RenderableValues, materialId: number, renderVariantDefines: T): RenderItem<S> { const id = getNextRenderItemId() const { stats, state, programCache } = ctx const { instancedArrays, vertexArrayObject } = ctx.extensions @@ -98,8 +119,8 @@ export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCo const glDrawMode = getDrawMode(ctx, drawMode) const programs: ProgramVariants = {} - Object.keys(RenderVariantDefines).forEach(k => { - const variantDefineValues: Values<RenderableSchema> = (RenderVariantDefines as any)[k] + Object.keys(renderVariantDefines).forEach(k => { + const variantDefineValues: Values<RenderableSchema> = (renderVariantDefines as any)[k] programs[k] = programCache.get({ defineValues: { ...defineValues, ...variantDefineValues }, shaderCode, @@ -117,7 +138,7 @@ export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCo } const vertexArrays: VertexArrayVariants = {} - Object.keys(RenderVariantDefines).forEach(k => { + Object.keys(renderVariantDefines).forEach(k => { vertexArrays[k] = createVertexArray(ctx, programs[k].value, attributeBuffers, elementsBuffer) }) @@ -136,9 +157,9 @@ export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCo return { id, materialId, - getProgram: (variant: RenderVariant) => programs[variant].value, + getProgram: (variant: S) => programs[variant].value, - render: (variant: RenderVariant) => { + render: (variant: S) => { if (drawCount === 0 || instanceCount === 0) return const program = programs[variant].value const vertexArray = vertexArrays[variant] @@ -180,8 +201,8 @@ export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCo if (valueChanges.defines) { // console.log('some defines changed, need to rebuild programs') - Object.keys(RenderVariantDefines).forEach(k => { - const variantDefineValues: Values<RenderableSchema> = (RenderVariantDefines as any)[k] + Object.keys(renderVariantDefines).forEach(k => { + const variantDefineValues: Values<RenderableSchema> = (renderVariantDefines as any)[k] programs[k].free() programs[k] = programCache.get({ defineValues: { ...defineValues, ...variantDefineValues }, @@ -241,7 +262,7 @@ export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCo // console.log('program/defines or buffers changed, update vaos') const { vertexArrayObject } = ctx.extensions if (vertexArrayObject) { - Object.keys(RenderVariantDefines).forEach(k => { + Object.keys(renderVariantDefines).forEach(k => { vertexArrayObject.bindVertexArray(vertexArrays[k]) if (elementsBuffer && (valueChanges.defines || valueChanges.elements)) { elementsBuffer.bind() @@ -274,7 +295,7 @@ export function createRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCo }, destroy: () => { if (!destroyed) { - Object.keys(RenderVariantDefines).forEach(k => { + Object.keys(renderVariantDefines).forEach(k => { programs[k].free() deleteVertexArray(ctx, vertexArrays[k]) }) -- GitLab