UNPKG

molstar

Version:

A comprehensive macromolecular library.

183 lines 9.72 kB
/** * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> */ import { __assign, __awaiter, __generator } from "tslib"; import { UniformSpec, TextureSpec, DefineSpec } from '../renderable/schema'; import { getRegularGrid3dDelta } from '../../mol-math/geometry/common'; import { grid3dTemplate_frag } from '../shader/util/grid3d-template.frag'; import { quad_vert } from '../shader/quad.vert'; import { ShaderCode } from '../shader-code'; import { UUID, ValueCell } from '../../mol-util'; import { objectForEach } from '../../mol-util/object'; import { getUniformGlslType, isUniformValueScalar } from '../webgl/uniform'; import { QuadSchema, QuadValues } from './util'; import { createComputeRenderItem } from '../webgl/render-item'; import { createComputeRenderable } from '../renderable'; import { isLittleEndian } from '../../mol-util/is-little-endian'; export function canComputeGrid3dOnGPU(webgl) { return !!(webgl === null || webgl === void 0 ? void 0 : webgl.extensions.textureFloat); } var FrameBufferName = 'grid3d-computable'; var Texture0Name = 'grid3d-computable-0'; var Texture1Name = 'grid3d-computable-1'; var SchemaBase = __assign(__assign({}, QuadSchema), { uDimensions: UniformSpec('v3'), uMin: UniformSpec('v3'), uDelta: UniformSpec('v3'), uWidth: UniformSpec('f'), uLittleEndian: UniformSpec('b') }); var CumulativeSumSchema = { tCumulativeSum: TextureSpec('texture', 'rgba', 'ubyte', 'nearest') }; export function createGrid3dComputeRenderable(spec) { var _this = this; var _a; var id = UUID.create22(); var uniforms = []; objectForEach(spec.schema, function (u, k) { var _a, _b; if (u.type === 'define') return; if (u.kind.indexOf('[]') >= 0) throw new Error('array uniforms are not supported'); var isBound = ((_b = (_a = spec.loopBounds) === null || _a === void 0 ? void 0 : _a.indexOf(k)) !== null && _b !== void 0 ? _b : -1) >= 0; if (isBound) uniforms.push("#ifndef " + k); if (u.type === 'uniform') uniforms.push("uniform " + getUniformGlslType(u.kind) + " " + k + ";"); else if (u.type === 'texture') uniforms.push("uniform sampler2D " + k + ";"); if (isBound) uniforms.push("#endif"); }); var code = grid3dTemplate_frag .replace('{UNIFORMS}', uniforms.join('\n')) .replace('{UTILS}', (_a = spec.utilCode) !== null && _a !== void 0 ? _a : '') .replace('{MAIN}', spec.mainCode) .replace('{RETURN}', spec.returnCode); var shader = ShaderCode(id, quad_vert, code); return function (ctx, webgl, grid, params) { return __awaiter(_this, void 0, void 0, function () { var schema, _i, _a, b, framebuffer, tex, _b, nx, ny, nz, uWidth, values, renderable, cells, array, gl, states, yieldPeriod, i; var _c; return __generator(this, function (_d) { switch (_d.label) { case 0: schema = __assign(__assign(__assign({}, SchemaBase), (spec.cumulative ? CumulativeSumSchema : {})), spec.schema); if (!webgl.isWebGL2) { if (spec.loopBounds) { for (_i = 0, _a = spec.loopBounds; _i < _a.length; _i++) { b = _a[_i]; schema[b] = DefineSpec('number'); } } schema['WEBGL1'] = DefineSpec('boolean'); } if (spec.cumulative) { schema['CUMULATIVE'] = DefineSpec('boolean'); } if (!webgl.namedFramebuffers[FrameBufferName]) { webgl.namedFramebuffers[FrameBufferName] = webgl.resources.framebuffer(); } framebuffer = webgl.namedFramebuffers[FrameBufferName]; if (!webgl.namedTextures[Texture0Name]) { webgl.namedTextures[Texture0Name] = webgl.resources.texture('image-uint8', 'rgba', 'ubyte', 'nearest'); } if (spec.cumulative && !webgl.namedTextures[Texture1Name]) { webgl.namedTextures[Texture1Name] = webgl.resources.texture('image-uint8', 'rgba', 'ubyte', 'nearest'); } tex = [webgl.namedTextures[Texture0Name], webgl.namedTextures[Texture1Name]]; _b = grid.dimensions, nx = _b[0], ny = _b[1], nz = _b[2]; uWidth = Math.ceil(Math.sqrt(nx * ny * nz)); values = __assign({ uDimensions: grid.dimensions, uMin: grid.box.min, uDelta: getRegularGrid3dDelta(grid), uWidth: uWidth, uLittleEndian: isLittleEndian() }, spec.values(params, grid)); if (!webgl.isWebGL2) { values.WEBGL1 = true; } if (spec.cumulative) { values.tCumulativeSum = tex[0]; values.CUMULATIVE = true; } renderable = webgl.namedComputeRenderables[id]; if (renderable) { cells = renderable.values; objectForEach(values, function (c, k) { var s = schema[k]; if ((s === null || s === void 0 ? void 0 : s.type) === 'value' || (s === null || s === void 0 ? void 0 : s.type) === 'attribute') return; if (!s || !isUniformValueScalar(s.kind)) { ValueCell.update(cells[k], c); } else { ValueCell.updateIfChanged(cells[k], c); } }); } else { cells = {}; objectForEach(QuadValues, function (v, k) { return cells[k] = v; }); objectForEach(values, function (v, k) { return cells[k] = ValueCell.create(v); }); renderable = createComputeRenderable(createComputeRenderItem(webgl, 'triangles', shader, schema, cells), cells); } array = new Uint8Array(uWidth * uWidth * 4); if (!spec.cumulative) return [3 /*break*/, 7]; gl = webgl.gl; states = spec.cumulative.states(params); tex[0].define(uWidth, uWidth); tex[1].define(uWidth, uWidth); resetGl(webgl, uWidth); gl.clearColor(0, 0, 0, 0); tex[0].attachFramebuffer(framebuffer, 'color0'); gl.clear(gl.COLOR_BUFFER_BIT); tex[1].attachFramebuffer(framebuffer, 'color0'); gl.clear(gl.COLOR_BUFFER_BIT); if (!spec.cumulative.yieldPeriod) return [3 /*break*/, 2]; return [4 /*yield*/, ctx.update({ message: 'Computing...', isIndeterminate: false, current: 0, max: states.length })]; case 1: _d.sent(); _d.label = 2; case 2: yieldPeriod = Math.max(1, (_c = spec.cumulative.yieldPeriod) !== null && _c !== void 0 ? _c : 1 | 0); i = 0; _d.label = 3; case 3: if (!(i < states.length)) return [3 /*break*/, 6]; ValueCell.update(cells.tCumulativeSum, tex[(i + 1) % 2]); tex[i % 2].attachFramebuffer(framebuffer, 'color0'); resetGl(webgl, uWidth); spec.cumulative.update(params, states[i], cells); renderable.update(); renderable.render(); if (!(spec.cumulative.yieldPeriod && i !== states.length - 1)) return [3 /*break*/, 5]; if (i % yieldPeriod === yieldPeriod - 1) { webgl.readPixels(0, 0, 1, 1, array); } if (!ctx.shouldUpdate) return [3 /*break*/, 5]; return [4 /*yield*/, ctx.update({ current: i + 1 })]; case 4: _d.sent(); _d.label = 5; case 5: i++; return [3 /*break*/, 3]; case 6: return [3 /*break*/, 8]; case 7: tex[0].define(uWidth, uWidth); tex[0].attachFramebuffer(framebuffer, 'color0'); framebuffer.bind(); resetGl(webgl, uWidth); renderable.update(); renderable.render(); _d.label = 8; case 8: webgl.readPixels(0, 0, uWidth, uWidth, array); return [2 /*return*/, new Float32Array(array.buffer, array.byteOffset, nx * ny * nz)]; } }); }); }; } function resetGl(webgl, w) { var gl = webgl.gl, state = webgl.state; gl.viewport(0, 0, w, w); gl.scissor(0, 0, w, w); state.disable(gl.SCISSOR_TEST); state.disable(gl.BLEND); state.disable(gl.DEPTH_TEST); state.depthMask(false); } //# sourceMappingURL=grid3d.js.map