molstar
Version:
A comprehensive macromolecular library.
326 lines • 16.9 kB
JavaScript
/**
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { __assign } from "tslib";
import { createAttributeBuffers } from './buffer';
import { createTextures } from './texture';
import { checkError } from './context';
import { AttributeSpec, getValueVersions, splitValues, DefineSpec } from '../renderable/schema';
import { idFactory } from '../../mol-util/id-factory';
import { ValueCell } from '../../mol-util';
import { checkFramebufferStatus } from './framebuffer';
import { isDebugMode } from '../../mol-util/debug';
import { fillSerial } from '../../mol-util/array';
import { deepClone } from '../../mol-util/object';
import { cloneUniformValues } from './uniform';
var getNextRenderItemId = idFactory();
export function getDrawMode(ctx, drawMode) {
var gl = ctx.gl;
switch (drawMode) {
case 'points': return gl.POINTS;
case 'lines': return gl.LINES;
case 'line-strip': return gl.LINE_STRIP;
case 'line-loop': return gl.LINE_LOOP;
case 'triangles': return gl.TRIANGLES;
case 'triangle-strip': return gl.TRIANGLE_STRIP;
case 'triangle-fan': return gl.TRIANGLE_FAN;
}
}
//
var GraphicsRenderVariant = { 'colorBlended': '', 'colorWboit': '', 'pickObject': '', 'pickInstance': '', 'pickGroup': '', 'depth': '', 'markingDepth': '', 'markingMask': '' };
var GraphicsRenderVariants = Object.keys(GraphicsRenderVariant);
var ComputeRenderVariant = { 'compute': '' };
var ComputeRenderVariants = Object.keys(ComputeRenderVariant);
function createProgramVariant(ctx, variant, defineValues, shaderCode, schema) {
defineValues = __assign(__assign({}, defineValues), { dRenderVariant: ValueCell.create(variant) });
if (schema.dRenderVariant === undefined) {
Object.defineProperty(schema, 'dRenderVariant', { value: DefineSpec('string') });
}
return ctx.resources.program(defineValues, shaderCode, schema);
}
function createValueChanges() {
return {
attributes: false,
defines: false,
elements: false,
textures: false,
};
}
function resetValueChanges(valueChanges) {
valueChanges.attributes = false;
valueChanges.defines = false;
valueChanges.elements = false;
valueChanges.textures = false;
}
export function createGraphicsRenderItem(ctx, drawMode, shaderCode, schema, values, materialId) {
return createRenderItem(ctx, drawMode, shaderCode, schema, values, materialId, GraphicsRenderVariants);
}
export function createComputeRenderItem(ctx, drawMode, shaderCode, schema, values, materialId) {
if (materialId === void 0) { materialId = -1; }
return createRenderItem(ctx, drawMode, shaderCode, schema, values, materialId, ComputeRenderVariants);
}
/**
* Creates a render item
*
* - assumes that `values.drawCount` and `values.instanceCount` exist
*/
export function createRenderItem(ctx, drawMode, shaderCode, schema, values, materialId, renderVariants) {
var id = getNextRenderItemId();
var stats = ctx.stats, state = ctx.state, resources = ctx.resources;
var _a = ctx.extensions, instancedArrays = _a.instancedArrays, vertexArrayObject = _a.vertexArrayObject;
// emulate gl_VertexID when needed
// if (!ctx.isWebGL2 && values.uVertexCount) {
// not using gl_VertexID in WebGL2 but aVertex to ensure there is an active attribute with divisor 0
// since FF 85 this is not needed anymore but lets keep it for backwards compatibility
// https://bugzilla.mozilla.org/show_bug.cgi?id=1679693
// see also note in src/mol-gl/shader/chunks/common-vert-params.glsl.ts
if (values.uVertexCount) {
var vertexCount = values.uVertexCount.ref.value;
values.aVertex = ValueCell.create(fillSerial(new Float32Array(vertexCount)));
schema.aVertex = AttributeSpec('float32', 1, 0);
}
var _b = splitValues(schema, values), attributeValues = _b.attributeValues, defineValues = _b.defineValues, textureValues = _b.textureValues, uniformValues = _b.uniformValues, materialUniformValues = _b.materialUniformValues, bufferedUniformValues = _b.bufferedUniformValues;
var uniformValueEntries = Object.entries(uniformValues);
var materialUniformValueEntries = Object.entries(materialUniformValues);
var backBufferUniformValueEntries = Object.entries(bufferedUniformValues);
var frontBufferUniformValueEntries = Object.entries(cloneUniformValues(bufferedUniformValues));
var defineValueEntries = Object.entries(defineValues);
var versions = getValueVersions(values);
var glDrawMode = getDrawMode(ctx, drawMode);
var programs = {};
for (var _i = 0, renderVariants_1 = renderVariants; _i < renderVariants_1.length; _i++) {
var k = renderVariants_1[_i];
programs[k] = createProgramVariant(ctx, k, defineValues, shaderCode, schema);
}
var textures = createTextures(ctx, schema, textureValues);
var attributeBuffers = createAttributeBuffers(ctx, schema, attributeValues);
var elementsBuffer;
var elements = values.elements;
if (elements && elements.ref.value) {
elementsBuffer = resources.elements(elements.ref.value);
}
var vertexArrays = {};
for (var _c = 0, renderVariants_2 = renderVariants; _c < renderVariants_2.length; _c++) {
var k = renderVariants_2[_c];
vertexArrays[k] = vertexArrayObject ? resources.vertexArray(programs[k], attributeBuffers, elementsBuffer) : null;
}
var drawCount = values.drawCount.ref.value;
var instanceCount = values.instanceCount.ref.value;
stats.drawCount += drawCount;
stats.instanceCount += instanceCount;
stats.instancedDrawCount += instanceCount * drawCount;
var valueChanges = createValueChanges();
var destroyed = false;
var currentProgramId = -1;
return {
id: id,
materialId: materialId,
getProgram: function (variant) { return programs[variant]; },
render: function (variant, sharedTexturesList) {
if (drawCount === 0 || instanceCount === 0 || ctx.isContextLost)
return;
var program = programs[variant];
if (program.id === currentProgramId && state.currentRenderItemId === id) {
program.setUniforms(uniformValueEntries);
if (sharedTexturesList && sharedTexturesList.length > 0) {
program.bindTextures(sharedTexturesList, 0);
program.bindTextures(textures, sharedTexturesList.length);
}
else {
program.bindTextures(textures, 0);
}
}
else {
var vertexArray = vertexArrays[variant];
if (program.id !== state.currentProgramId || program.id !== currentProgramId ||
materialId === -1 || materialId !== state.currentMaterialId) {
// console.log('program.id changed or materialId changed/-1', materialId)
if (program.id !== state.currentProgramId)
program.use();
program.setUniforms(materialUniformValueEntries);
state.currentMaterialId = materialId;
currentProgramId = program.id;
}
program.setUniforms(uniformValueEntries);
program.setUniforms(frontBufferUniformValueEntries);
if (sharedTexturesList && sharedTexturesList.length > 0) {
program.bindTextures(sharedTexturesList, 0);
program.bindTextures(textures, sharedTexturesList.length);
}
else {
program.bindTextures(textures, 0);
}
if (vertexArray) {
vertexArray.bind();
// need to bind elements buffer explicitly since it is not always recorded in the VAO
if (elementsBuffer)
elementsBuffer.bind();
}
else {
if (elementsBuffer)
elementsBuffer.bind();
program.bindAttributes(attributeBuffers);
}
state.currentRenderItemId = id;
}
if (isDebugMode) {
try {
checkFramebufferStatus(ctx.gl);
}
catch (e) {
throw new Error("Framebuffer error rendering item id " + id + ": '" + e + "'");
}
}
if (elementsBuffer) {
instancedArrays.drawElementsInstanced(glDrawMode, drawCount, elementsBuffer._dataType, 0, instanceCount);
}
else {
instancedArrays.drawArraysInstanced(glDrawMode, 0, drawCount, instanceCount);
}
if (isDebugMode) {
try {
checkError(ctx.gl);
}
catch (e) {
throw new Error("Draw error rendering item id " + id + ": '" + e + "'");
}
}
},
update: function () {
resetValueChanges(valueChanges);
if (values.aVertex) {
var vertexCount = values.uVertexCount.ref.value;
if (values.aVertex.ref.value.length < vertexCount) {
ValueCell.update(values.aVertex, fillSerial(new Float32Array(vertexCount)));
}
}
for (var i = 0, il = defineValueEntries.length; i < il; ++i) {
var _a = defineValueEntries[i], k = _a[0], value = _a[1];
if (value.ref.version !== versions[k]) {
// console.log('define version changed', k);
valueChanges.defines = true;
versions[k] = value.ref.version;
}
}
if (valueChanges.defines) {
// console.log('some defines changed, need to rebuild programs');
for (var _i = 0, renderVariants_3 = renderVariants; _i < renderVariants_3.length; _i++) {
var k = renderVariants_3[_i];
programs[k].destroy();
programs[k] = createProgramVariant(ctx, k, defineValues, shaderCode, schema);
}
}
if (values.drawCount.ref.version !== versions.drawCount) {
// console.log('drawCount version changed');
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');
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;
}
for (var i = 0, il = attributeBuffers.length; i < il; ++i) {
var _b = attributeBuffers[i], k = _b[0], buffer = _b[1];
var value = attributeValues[k];
if (value.ref.version !== versions[k]) {
if (buffer.length >= value.ref.value.length) {
// console.log('attribute array large enough to update', buffer.id, k, value.ref.id, value.ref.version);
buffer.updateSubData(value.ref.value, 0, buffer.length);
}
else {
// console.log('attribute array too small, need to create new attribute', buffer.id, k, value.ref.id, value.ref.version);
buffer.destroy();
var _c = schema[k], itemSize = _c.itemSize, divisor = _c.divisor;
attributeBuffers[i][1] = resources.attribute(value.ref.value, itemSize, divisor);
valueChanges.attributes = true;
}
versions[k] = value.ref.version;
}
}
if (elementsBuffer && values.elements.ref.version !== versions.elements) {
if (elementsBuffer.length >= values.elements.ref.value.length) {
// console.log('elements array large enough to update', values.elements.ref.id, values.elements.ref.version);
elementsBuffer.updateSubData(values.elements.ref.value, 0, elementsBuffer.length);
}
else {
// console.log('elements array to small, need to create new elements', values.elements.ref.id, values.elements.ref.version);
elementsBuffer.destroy();
elementsBuffer = resources.elements(values.elements.ref.value);
valueChanges.elements = true;
}
versions.elements = values.elements.ref.version;
}
if (valueChanges.attributes || valueChanges.defines || valueChanges.elements) {
// console.log('program/defines or buffers changed, update vaos');
for (var _d = 0, renderVariants_4 = renderVariants; _d < renderVariants_4.length; _d++) {
var k = renderVariants_4[_d];
var vertexArray = vertexArrays[k];
if (vertexArray)
vertexArray.destroy();
vertexArrays[k] = vertexArrayObject ? resources.vertexArray(programs[k], attributeBuffers, elementsBuffer) : null;
}
}
for (var i = 0, il = textures.length; i < il; ++i) {
var _e = textures[i], k = _e[0], texture = _e[1];
var value = textureValues[k];
if (value.ref.version !== versions[k]) {
// update of textures with kind 'texture' is done externally
if (schema[k].kind !== 'texture') {
// console.log('texture version changed, uploading image', k);
texture.load(value.ref.value);
valueChanges.textures = true;
}
else {
textures[i][1] = value.ref.value;
}
versions[k] = value.ref.version;
}
}
for (var i = 0, il = backBufferUniformValueEntries.length; i < il; ++i) {
var _f = backBufferUniformValueEntries[i], k = _f[0], uniform = _f[1];
if (uniform.ref.version !== versions[k]) {
// console.log('back-buffer uniform version changed, updating front-buffer', k);
ValueCell.update(frontBufferUniformValueEntries[i][1], deepClone(uniform.ref.value));
versions[k] = uniform.ref.version;
}
}
return valueChanges;
},
destroy: function () {
if (!destroyed) {
for (var _i = 0, renderVariants_5 = renderVariants; _i < renderVariants_5.length; _i++) {
var k = renderVariants_5[_i];
programs[k].destroy();
var vertexArray = vertexArrays[k];
if (vertexArray)
vertexArray.destroy();
}
textures.forEach(function (_a) {
var k = _a[0], texture = _a[1];
// lifetime of textures with kind 'texture' is defined externally
if (schema[k].kind !== 'texture') {
texture.destroy();
}
});
attributeBuffers.forEach(function (_a) {
var _ = _a[0], buffer = _a[1];
return buffer.destroy();
});
if (elementsBuffer)
elementsBuffer.destroy();
stats.drawCount -= drawCount;
stats.instanceCount -= instanceCount;
stats.instancedDrawCount -= instanceCount * drawCount;
destroyed = true;
}
}
};
}
//# sourceMappingURL=render-item.js.map