UNPKG

molstar

Version:

A comprehensive macromolecular library.

307 lines 12.8 kB
"use strict"; /** * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ Object.defineProperty(exports, "__esModule", { value: true }); exports.createContext = exports.readPixels = exports.checkError = exports.getErrorDescription = exports.getGLContext = void 0; var tslib_1 = require("tslib"); var compat_1 = require("./compat"); var framebuffer_1 = require("./framebuffer"); var mol_task_1 = require("../../mol-task"); var debug_1 = require("../../mol-util/debug"); var extensions_1 = require("./extensions"); var state_1 = require("./state"); var image_1 = require("../../mol-util/image"); var resources_1 = require("./resources"); var render_target_1 = require("./render-target"); var rxjs_1 = require("rxjs"); var now_1 = require("../../mol-util/now"); function getGLContext(canvas, attribs) { function get(id) { try { return canvas.getContext(id, attribs); } catch (e) { return null; } } var gl = ((attribs === null || attribs === void 0 ? void 0 : attribs.preferWebGl1) ? null : get('webgl2')) || get('webgl') || get('experimental-webgl'); if (debug_1.isDebugMode) console.log("isWebgl2: " + (0, compat_1.isWebGL2)(gl)); return gl; } exports.getGLContext = getGLContext; function getErrorDescription(gl, error) { switch (error) { case gl.NO_ERROR: return 'no error'; case gl.INVALID_ENUM: return 'invalid enum'; case gl.INVALID_VALUE: return 'invalid value'; case gl.INVALID_OPERATION: return 'invalid operation'; case gl.INVALID_FRAMEBUFFER_OPERATION: return 'invalid framebuffer operation'; case gl.OUT_OF_MEMORY: return 'out of memory'; case gl.CONTEXT_LOST_WEBGL: return 'context lost'; } return 'unknown error'; } exports.getErrorDescription = getErrorDescription; function checkError(gl) { var error = gl.getError(); if (error !== gl.NO_ERROR) { throw new Error("WebGL error: '" + getErrorDescription(gl, error) + "'"); } } exports.checkError = checkError; function unbindResources(gl) { // bind null to all texture units var maxTextureImageUnits = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS); for (var i = 0; i < maxTextureImageUnits; ++i) { gl.activeTexture(gl.TEXTURE0 + i); gl.bindTexture(gl.TEXTURE_2D, null); gl.bindTexture(gl.TEXTURE_CUBE_MAP, null); if ((0, compat_1.isWebGL2)(gl)) { gl.bindTexture(gl.TEXTURE_2D_ARRAY, null); gl.bindTexture(gl.TEXTURE_3D, null); } } // assign the smallest possible buffer to all attributes var buf = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buf); var maxVertexAttribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS); for (var i = 0; i < maxVertexAttribs; ++i) { gl.vertexAttribPointer(i, 1, gl.FLOAT, false, 0, 0); } // bind null to all buffers gl.bindBuffer(gl.ARRAY_BUFFER, null); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); gl.bindRenderbuffer(gl.RENDERBUFFER, null); unbindFramebuffer(gl); } function unbindFramebuffer(gl) { gl.bindFramebuffer(gl.FRAMEBUFFER, null); } var tmpPixel = new Uint8Array(1 * 4); function checkSync(gl, sync, resolve) { if (gl.getSyncParameter(sync, gl.SYNC_STATUS) === gl.SIGNALED) { gl.deleteSync(sync); resolve(); } else { mol_task_1.Scheduler.setImmediate(checkSync, gl, sync, resolve); } } function fence(gl, resolve) { var sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0); if (!sync) { console.warn('Could not create a WebGLSync object'); gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, tmpPixel); resolve(); } else { mol_task_1.Scheduler.setImmediate(checkSync, gl, sync, resolve); } } var SentWebglSyncObjectNotSupportedInWebglMessage = false; function waitForGpuCommandsComplete(gl) { return new Promise(function (resolve) { if ((0, compat_1.isWebGL2)(gl)) { // TODO seems quite slow fence(gl, resolve); } else { if (!SentWebglSyncObjectNotSupportedInWebglMessage) { console.info('Sync object not supported in WebGL'); SentWebglSyncObjectNotSupportedInWebglMessage = true; } waitForGpuCommandsCompleteSync(gl); resolve(); } }); } function waitForGpuCommandsCompleteSync(gl) { gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, tmpPixel); } function readPixels(gl, x, y, width, height, buffer) { if (debug_1.isDebugMode) (0, framebuffer_1.checkFramebufferStatus)(gl); if (buffer instanceof Uint8Array) { gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buffer); } else if (buffer instanceof Float32Array) { gl.readPixels(x, y, width, height, gl.RGBA, gl.FLOAT, buffer); } else if (buffer instanceof Int32Array && (0, compat_1.isWebGL2)(gl)) { gl.readPixels(x, y, width, height, gl.RGBA_INTEGER, gl.INT, buffer); } else { throw new Error('unsupported readPixels buffer type'); } if (debug_1.isDebugMode) checkError(gl); } exports.readPixels = readPixels; function getDrawingBufferPixelData(gl) { var w = gl.drawingBufferWidth; var h = gl.drawingBufferHeight; var buffer = new Uint8Array(w * h * 4); unbindFramebuffer(gl); gl.viewport(0, 0, w, h); readPixels(gl, 0, 0, w, h, buffer); return image_1.PixelData.flipY(image_1.PixelData.create(buffer, w, h)); } // function createStats() { return { resourceCounts: { attribute: 0, elements: 0, framebuffer: 0, program: 0, renderbuffer: 0, shader: 0, texture: 0, vertexArray: 0, }, drawCount: 0, instanceCount: 0, instancedDrawCount: 0, }; } function createContext(gl, props) { var _this = this; if (props === void 0) { props = {}; } var extensions = (0, extensions_1.createExtensions)(gl); var state = (0, state_1.createState)(gl); var stats = createStats(); var resources = (0, resources_1.createResources)(gl, state, stats, extensions); var parameters = { maxTextureSize: gl.getParameter(gl.MAX_TEXTURE_SIZE), max3dTextureSize: (0, compat_1.isWebGL2)(gl) ? gl.getParameter(gl.MAX_3D_TEXTURE_SIZE) : 0, maxRenderbufferSize: gl.getParameter(gl.MAX_RENDERBUFFER_SIZE), maxDrawBuffers: extensions.drawBuffers ? gl.getParameter(extensions.drawBuffers.MAX_DRAW_BUFFERS) : 0, maxTextureImageUnits: gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS), maxVertexTextureImageUnits: gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS), }; if (parameters.maxVertexTextureImageUnits < 8) { throw new Error('Need "MAX_VERTEX_TEXTURE_IMAGE_UNITS" >= 8'); } var isContextLost = false; var contextRestored = new rxjs_1.BehaviorSubject(0); var readPixelsAsync; if ((0, compat_1.isWebGL2)(gl)) { var pbo_1 = gl.createBuffer(); var _buffer_1 = void 0; var _resolve_1 = void 0; var _reading_1 = false; var bindPBO_1 = function () { gl.bindBuffer(gl.PIXEL_PACK_BUFFER, pbo_1); gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, _buffer_1); gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null); _reading_1 = false; _resolve_1(); _resolve_1 = void 0; _buffer_1 = void 0; }; readPixelsAsync = function (x, y, width, height, buffer) { return new Promise(function (resolve, reject) { if (_reading_1) { reject('Can not call multiple readPixelsAsync at the same time'); return; } _reading_1 = true; gl.bindBuffer(gl.PIXEL_PACK_BUFFER, pbo_1); gl.bufferData(gl.PIXEL_PACK_BUFFER, width * height * 4, gl.STREAM_READ); gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, 0); gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null); // need to unbind/bind PBO before/after async awaiting the fence _resolve_1 = resolve; _buffer_1 = buffer; fence(gl, bindPBO_1); }); }; } else { readPixelsAsync = function (x, y, width, height, buffer) { return (0, tslib_1.__awaiter)(_this, void 0, void 0, function () { return (0, tslib_1.__generator)(this, function (_a) { readPixels(gl, x, y, width, height, buffer); return [2 /*return*/]; }); }); }; } var renderTargets = new Set(); return { gl: gl, isWebGL2: (0, compat_1.isWebGL2)(gl), get pixelRatio() { var dpr = (typeof window !== 'undefined') ? window.devicePixelRatio : 1; return dpr * (props.pixelScale || 1); }, extensions: extensions, state: state, stats: stats, resources: resources, get maxTextureSize() { return parameters.maxTextureSize; }, get max3dTextureSize() { return parameters.max3dTextureSize; }, get maxRenderbufferSize() { return parameters.maxRenderbufferSize; }, get maxDrawBuffers() { return parameters.maxDrawBuffers; }, get maxTextureImageUnits() { return parameters.maxTextureImageUnits; }, namedComputeRenderables: Object.create(null), namedFramebuffers: Object.create(null), namedTextures: Object.create(null), get isContextLost() { return isContextLost || gl.isContextLost(); }, contextRestored: contextRestored, setContextLost: function () { isContextLost = true; }, handleContextRestored: function (extraResets) { Object.assign(extensions, (0, extensions_1.createExtensions)(gl)); state.reset(); state.currentMaterialId = -1; state.currentProgramId = -1; state.currentRenderItemId = -1; resources.reset(); renderTargets.forEach(function (rt) { return rt.reset(); }); extraResets === null || extraResets === void 0 ? void 0 : extraResets(); isContextLost = false; contextRestored.next((0, now_1.now)()); }, createRenderTarget: function (width, height, depth, type, filter) { var renderTarget = (0, render_target_1.createRenderTarget)(gl, resources, width, height, depth, type, filter); renderTargets.add(renderTarget); return (0, tslib_1.__assign)((0, tslib_1.__assign)({}, renderTarget), { destroy: function () { renderTarget.destroy(); renderTargets.delete(renderTarget); } }); }, unbindFramebuffer: function () { return unbindFramebuffer(gl); }, readPixels: function (x, y, width, height, buffer) { readPixels(gl, x, y, width, height, buffer); }, readPixelsAsync: readPixelsAsync, waitForGpuCommandsComplete: function () { return waitForGpuCommandsComplete(gl); }, waitForGpuCommandsCompleteSync: function () { return waitForGpuCommandsCompleteSync(gl); }, getDrawingBufferPixelData: function () { return getDrawingBufferPixelData(gl); }, clear: function (red, green, blue, alpha) { unbindFramebuffer(gl); state.enable(gl.SCISSOR_TEST); state.depthMask(true); state.colorMask(true, true, true, true); state.clearColor(red, green, blue, alpha); gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); gl.scissor(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); }, destroy: function (options) { var _a; resources.destroy(); unbindResources(gl); // to aid GC if (!(options === null || options === void 0 ? void 0 : options.doNotForceWebGLContextLoss)) (_a = gl.getExtension('WEBGL_lose_context')) === null || _a === void 0 ? void 0 : _a.loseContext(); } }; } exports.createContext = createContext; //# sourceMappingURL=context.js.map