Compare commits

...

1 Commits

Author SHA1 Message Date
dsehnal
df26bde255 prototype parallel shader linking 2025-09-09 09:04:02 +02:00
10 changed files with 107 additions and 20 deletions

View File

@@ -106,6 +106,7 @@ export class DrawPass {
this.depthTextureOpaque.define(width, height);
}
// TODO: link programs in parallel
this.wboit = new WboitPass(webgl, width, height);
this.dpoit = new DpoitPass(webgl, width, height);
this.marking = new MarkingPass(webgl, width, height);

View File

@@ -23,6 +23,12 @@ export class CommitQueue {
return this.removeMap.size + this.addMap.size;
}
forEachAdd(cb: (o: GraphicsRenderObject) => void) {
for (let n = this.addList.first; n; n = n.next) {
cb(n.value);
}
}
add(o: GraphicsRenderObject) {
if (this.removeMap.has(o)) {
const a = this.removeMap.get(o)!;

View File

@@ -8,14 +8,14 @@ import { RenderableState, Renderable } from './renderable';
import { idFactory } from '../mol-util/id-factory';
import { WebGLContext } from './webgl/context';
import { DirectVolumeValues, DirectVolumeRenderable } from './renderable/direct-volume';
import { MeshValues, MeshRenderable } from './renderable/mesh';
import { MeshValues, MeshRenderable, linkMeshRenderableShader } from './renderable/mesh';
import { PointsValues, PointsRenderable } from './renderable/points';
import { LinesValues, LinesRenderable } from './renderable/lines';
import { SpheresValues, SpheresRenderable } from './renderable/spheres';
import { SpheresValues, SpheresRenderable, linkSpheresRenderableShader } from './renderable/spheres';
import { TextValues, TextRenderable } from './renderable/text';
import { TextureMeshValues, TextureMeshRenderable } from './renderable/texture-mesh';
import { ImageValues, ImageRenderable } from './renderable/image';
import { CylindersRenderable, CylindersValues } from './renderable/cylinders';
import { CylindersRenderable, CylindersValues, linkCylindersRenderableShader } from './renderable/cylinders';
import { Transparency } from './webgl/render-item';
const getNextId = idFactory(0, 0x7FFFFFFF);
@@ -63,3 +63,13 @@ export function createRenderable<T extends RenderObjectType>(ctx: WebGLContext,
}
throw new Error('unsupported type');
}
export function linkRenderableShader<T extends RenderObjectType>(ctx: WebGLContext, o: GraphicsRenderObject<T>, transparency: Transparency) {
switch (o.type) {
case 'mesh': return linkMeshRenderableShader(ctx, o.id, o.values as MeshValues, o.state, o.materialId, transparency);
case 'spheres': return linkSpheresRenderableShader(ctx, o.id, o.values as SpheresValues, o.state, o.materialId, transparency);
case 'cylinders': return linkCylindersRenderableShader(ctx, o.id, o.values as CylindersValues, o.state, o.materialId, transparency);
}
console.log(o.type);
// throw new Error('unsupported type');
}

View File

@@ -6,7 +6,7 @@
import { Renderable, RenderableState, createRenderable } from '../renderable';
import { WebGLContext } from '../webgl/context';
import { createGraphicsRenderItem, Transparency } from '../webgl/render-item';
import { createGraphicsRenderItem, GraphicsRenderVariants, linkRenderItemProgram, Transparency } from '../webgl/render-item';
import { GlobalUniformSchema, BaseSchema, AttributeSpec, Values, InternalSchema, SizeSchema, InternalValues, ElementsSpec, ValueSpec, DefineSpec, GlobalTextureSchema, UniformSpec } from './schema';
import { CylindersShaderCode } from '../shader-code';
import { ValueCell } from '../../mol-util';
@@ -45,4 +45,13 @@ export function CylindersRenderable(ctx: WebGLContext, id: number, values: Cylin
const shaderCode = CylindersShaderCode;
const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId, transparency);
return createRenderable(renderItem, values, state);
}
export function linkCylindersRenderableShader(ctx: WebGLContext, id: number, values: CylindersValues, state: RenderableState, materialId: number, transparency: Transparency) {
const schema = { ...GlobalUniformSchema, ...GlobalTextureSchema, ...InternalSchema, ...CylindersSchema };
const internalValues: InternalValues = {
uObjectId: ValueCell.create(id),
};
const shaderCode = CylindersShaderCode;
linkRenderItemProgram(ctx, shaderCode, schema, { ...values, ...internalValues }, GraphicsRenderVariants, transparency);
}

View File

@@ -6,7 +6,7 @@
import { Renderable, RenderableState, createRenderable } from '../renderable';
import { WebGLContext } from '../webgl/context';
import { createGraphicsRenderItem, Transparency } from '../webgl/render-item';
import { createGraphicsRenderItem, GraphicsRenderVariants, linkRenderItemProgram, Transparency } from '../webgl/render-item';
import { GlobalUniformSchema, BaseSchema, AttributeSpec, ElementsSpec, DefineSpec, Values, InternalSchema, InternalValues, GlobalTextureSchema, ValueSpec, UniformSpec } from './schema';
import { MeshShaderCode } from '../shader-code';
import { ValueCell } from '../../mol-util';
@@ -41,4 +41,13 @@ export function MeshRenderable(ctx: WebGLContext, id: number, values: MeshValues
const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId, transparency);
return createRenderable(renderItem, values, state);
}
export function linkMeshRenderableShader(ctx: WebGLContext, id: number, values: MeshValues, state: RenderableState, materialId: number, transparency: Transparency) {
const schema = { ...GlobalUniformSchema, ...GlobalTextureSchema, ...InternalSchema, ...MeshSchema };
const internalValues: InternalValues = {
uObjectId: ValueCell.create(id),
};
const shaderCode = MeshShaderCode;
linkRenderItemProgram(ctx, shaderCode, schema, { ...values, ...internalValues }, GraphicsRenderVariants, transparency);
}

View File

@@ -6,7 +6,7 @@
import { Renderable, RenderableState, createRenderable } from '../renderable';
import { WebGLContext } from '../webgl/context';
import { createGraphicsRenderItem, Transparency } from '../webgl/render-item';
import { createGraphicsRenderItem, GraphicsRenderVariants, linkRenderItemProgram, Transparency } from '../webgl/render-item';
import { GlobalUniformSchema, BaseSchema, Values, InternalSchema, SizeSchema, InternalValues, ValueSpec, DefineSpec, GlobalTextureSchema, UniformSpec, TextureSpec } from './schema';
import { SpheresShaderCode } from '../shader-code';
import { ValueCell } from '../../mol-util';
@@ -46,4 +46,13 @@ export function SpheresRenderable(ctx: WebGLContext, id: number, values: Spheres
const shaderCode = SpheresShaderCode;
const renderItem = createGraphicsRenderItem(ctx, 'triangles', shaderCode, schema, { ...values, ...internalValues }, materialId, transparency);
return createRenderable(renderItem, values, state);
}
export function linkSpheresRenderableShader(ctx: WebGLContext, id: number, values: SpheresValues, state: RenderableState, materialId: number, transparency: Transparency) {
const schema = { ...GlobalUniformSchema, ...GlobalTextureSchema, ...InternalSchema, ...SpheresSchema };
const internalValues: InternalValues = {
uObjectId: ValueCell.create(id),
};
const shaderCode = SpheresShaderCode;
linkRenderItemProgram(ctx, shaderCode, schema, { ...values, ...internalValues }, GraphicsRenderVariants, transparency);
}

View File

@@ -6,7 +6,7 @@
*/
import { WebGLContext } from './webgl/context';
import { GraphicsRenderObject, createRenderable } from './render-object';
import { GraphicsRenderObject, createRenderable, linkRenderableShader as linkRenderableProgram } from './render-object';
import { Object3D } from './object3d';
import { Sphere3D } from '../mol-math/geometry/primitives/sphere3d';
import { CommitQueue } from './commit-queue';
@@ -130,7 +130,9 @@ namespace Scene {
function add(o: GraphicsRenderObject) {
if (!renderableMap.has(o)) {
console.time(`create renderable ${o.type}`);
const renderable = createRenderable(ctx, o, transparency);
console.timeEnd(`create renderable ${o.type}`);
renderables.push(renderable);
if (o.type === 'direct-volume') {
volumes.push(renderable);
@@ -164,6 +166,10 @@ namespace Scene {
let i = 0;
// TODO: have to destroy programs that were not added (=removed before added)
commitQueue.forEachAdd(o => linkRenderableProgram(ctx, o, transparency));
// there could also be a separate queue just for program linking that calls program.finalize()
while (true) {
const o = commitQueue.tryGetRemove();
if (!o) break;

View File

@@ -22,6 +22,7 @@ export interface Program {
readonly id: number
use: () => void
finalize: () => void
setUniforms: (uniformValues: UniformsList) => void
uniform: (k: string, v: UniformType) => void
bindAttributes: (attribueBuffers: AttributeBuffers) => void
@@ -175,29 +176,38 @@ export function createProgram(gl: GLRenderingContext, state: WebGLState, extensi
let locations: Locations;
let uniformSetters: UniformSetters;
function init() {
function link() {
vertShader.attach(program);
fragShader.attach(program);
console.log('linking', programId)
gl.linkProgram(program);
if (isDebugMode) {
checkProgram(gl, program);
}
locations = getLocations(gl, program, schema);
uniformSetters = getUniformSetters(schema);
// if (isDebugMode) {
// checkProgram(gl, program);
// }
if (isDebugMode) {
checkActiveAttributes(gl, program, schema);
checkActiveUniforms(gl, program, schema);
}
// locations = getLocations(gl, program, schema);
// uniformSetters = getUniformSetters(schema);
// if (isDebugMode) {
// checkActiveAttributes(gl, program, schema);
// checkActiveUniforms(gl, program, schema);
// }
}
init();
link();
let destroyed = false;
return {
id: programId,
finalize: () => {
if (locations) return;
console.log('finalizing', programId)
locations = getLocations(gl, program, schema);
uniformSetters = getUniformSetters(schema);
},
use: () => {
// console.log('use', programId)
state.currentProgramId = programId;
@@ -245,7 +255,7 @@ export function createProgram(gl: GLRenderingContext, state: WebGLState, extensi
reset: () => {
program = getProgram(gl);
init();
link();
},
destroy: () => {
if (destroyed) return;

View File

@@ -128,6 +128,26 @@ export function createComputeRenderItem(ctx: WebGLContext, drawMode: DrawMode, s
return createRenderItem(ctx, drawMode, shaderCode, schema, values, materialId, ComputeRenderVariants, undefined);
}
export function linkRenderItemProgram<T extends string>(ctx: WebGLContext, shaderCode: ShaderCode, schema: RenderableSchema, values: RenderableValues, renderVariants: T[], transparency: Transparency) {
// filter out unsupported variants
renderVariants = renderVariants.filter(v => {
if (v === 'tracing') return !!ctx.extensions.drawBuffers;
return true;
});
// TODO: optimize
const { defineValues } = splitValues(schema, values);
for (const rv of renderVariants) {
const defs = { ...defineValues, dRenderVariant: ValueCell.create(getRenderVariant(rv, transparency)) };
if (schema.dRenderVariant === undefined) {
Object.defineProperty(schema, 'dRenderVariant', { value: DefineSpec('string') });
}
ctx.resources.linkProgram(defs, shaderCode, schema);
}
}
/**
* Creates a render item
*

View File

@@ -56,6 +56,7 @@ export interface WebGLResources {
elements: (array: ElementsType, usageHint?: UsageHint) => ElementsBuffer
pixelPack: (format: TextureFormat, type: TextureType) => PixelPackBuffer
framebuffer: () => Framebuffer
linkProgram: (defineValues: DefineValues, shaderCode: ShaderCode, schema: RenderableSchema) => Program
program: (defineValues: DefineValues, shaderCode: ShaderCode, schema: RenderableSchema) => Program
renderbuffer: (format: RenderbufferFormat, attachment: RenderbufferAttachment, width: number, height: number) => Renderbuffer
shader: (type: ShaderType, source: string) => Shader
@@ -137,9 +138,15 @@ export function createResources(gl: GLRenderingContext, state: WebGLState, stats
framebuffer: () => {
return wrap('framebuffer', createFramebuffer(gl));
},
program: (defineValues: DefineValues, shaderCode: ShaderCode, schema: RenderableSchema) => {
linkProgram: (defineValues: DefineValues, shaderCode: ShaderCode, schema: RenderableSchema) => {
return wrapCached(programCache.get({ defineValues, shaderCode, schema }));
},
program: (defineValues: DefineValues, shaderCode: ShaderCode, schema: RenderableSchema) => {
// TODO: create function
const linked = wrapCached(programCache.get({ defineValues, shaderCode, schema }));
linked.finalize();
return linked;
},
renderbuffer: (format: RenderbufferFormat, attachment: RenderbufferAttachment, width: number, height: number) => {
return wrap('renderbuffer', createRenderbuffer(gl, format, attachment, width, height));
},