UNPKG

@luma.gl/gltools

Version:

WebGL2 API Polyfills for WebGL1 WebGLRenderingContext

254 lines (216 loc) 7.56 kB
import { isBrowser as getIsBrowser } from '@probe.gl/env'; import { trackContextState } from '../state-tracker/track-context-state'; import { log } from '../utils/log'; import { assert } from '../utils/assert'; import { getDevicePixelRatio } from '../utils/device-pixels'; import { isWebGL2 } from '../utils/webgl-checks'; const isBrowser = getIsBrowser(); const isPage = isBrowser && typeof document !== 'undefined'; const CONTEXT_DEFAULTS = { webgl2: true, webgl1: true, throwOnError: true, manageState: true, canvas: null, debug: false, width: 800, height: 600 }; export function createGLContext() { let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; assert(isBrowser, "createGLContext only available in the browser.\nCreate your own headless context or use 'createHeadlessContext' from @luma.gl/test-utils"); options = Object.assign({}, CONTEXT_DEFAULTS, options); const { width, height } = options; function onError(message) { if (options.throwOnError) { throw new Error(message); } console.error(message); return null; } options.onError = onError; let gl; const { canvas } = options; const targetCanvas = getCanvas({ canvas, width, height, onError }); gl = createBrowserContext(targetCanvas, options); if (!gl) { return null; } gl = instrumentGLContext(gl, options); logInfo(gl); return gl; } export function instrumentGLContext(gl) { let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; if (!gl || gl._instrumented) { return gl; } gl._version = gl._version || getVersion(gl); gl.luma = gl.luma || {}; gl.luma.canvasSizeInfo = gl.luma.canvasSizeInfo || {}; options = Object.assign({}, CONTEXT_DEFAULTS, options); const { manageState, debug } = options; if (manageState) { trackContextState(gl, { copyState: false, log: function () { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return log.log(1, ...args)(); } }); } if (isBrowser && debug) { if (!globalThis.makeDebugContext) { log.warn('WebGL debug mode not activated. import "@luma.gl/debug" to enable.')(); } else { gl = globalThis.makeDebugContext(gl, options); log.level = Math.max(log.level, 1); } } gl._instrumented = true; return gl; } export function getContextDebugInfo(gl) { const vendorMasked = gl.getParameter(7936); const rendererMasked = gl.getParameter(7937); const ext = gl.getExtension('WEBGL_debug_renderer_info'); const vendorUnmasked = ext && gl.getParameter(ext.UNMASKED_VENDOR_WEBGL || 7936); const rendererUnmasked = ext && gl.getParameter(ext.UNMASKED_RENDERER_WEBGL || 7937); return { vendor: vendorUnmasked || vendorMasked, renderer: rendererUnmasked || rendererMasked, vendorMasked, rendererMasked, version: gl.getParameter(7938), shadingLanguageVersion: gl.getParameter(35724) }; } export function resizeGLContext(gl) { let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; if (gl.canvas) { const devicePixelRatio = getDevicePixelRatio(options.useDevicePixels); setDevicePixelRatio(gl, devicePixelRatio, options); return; } const ext = gl.getExtension('STACKGL_resize_drawingbuffer'); if (ext && "width" in options && "height" in options) { ext.resize(options.width, options.height); } } function createBrowserContext(canvas, options) { const { onError } = options; let errorMessage = null; const onCreateError = error => errorMessage = error.statusMessage || errorMessage; canvas.addEventListener('webglcontextcreationerror', onCreateError, false); const { webgl1 = true, webgl2 = true } = options; let gl = null; if (webgl2) { gl = gl || canvas.getContext('webgl2', options); gl = gl || canvas.getContext('experimental-webgl2', options); } if (webgl1) { gl = gl || canvas.getContext('webgl', options); gl = gl || canvas.getContext('experimental-webgl', options); } canvas.removeEventListener('webglcontextcreationerror', onCreateError, false); if (!gl) { return onError("Failed to create ".concat(webgl2 && !webgl1 ? 'WebGL2' : 'WebGL', " context: ").concat(errorMessage || 'Unknown error')); } if (options.onContextLost) { canvas.addEventListener('webglcontextlost', options.onContextLost, false); } if (options.onContextRestored) { canvas.addEventListener('webglcontextrestored', options.onContextRestored, false); } return gl; } function getCanvas(_ref) { let { canvas, width = 800, height = 600, onError } = _ref; let targetCanvas; if (typeof canvas === 'string') { const isPageLoaded = isPage && document.readyState === 'complete'; if (!isPageLoaded) { onError("createGLContext called on canvas '".concat(canvas, "' before page was loaded")); } targetCanvas = document.getElementById(canvas); } else if (canvas) { targetCanvas = canvas; } else { targetCanvas = document.createElement('canvas'); targetCanvas.id = 'lumagl-canvas'; targetCanvas.style.width = Number.isFinite(width) ? "".concat(width, "px") : '100%'; targetCanvas.style.height = Number.isFinite(height) ? "".concat(height, "px") : '100%'; document.body.insertBefore(targetCanvas, document.body.firstChild); } return targetCanvas; } function logInfo(gl) { const webGL = isWebGL2(gl) ? 'WebGL2' : 'WebGL1'; const info = getContextDebugInfo(gl); const driver = info ? "(".concat(info.vendor, ",").concat(info.renderer, ")") : ''; const debug = gl.debug ? ' debug' : ''; log.info(1, "".concat(webGL).concat(debug, " context ").concat(driver))(); } function getVersion(gl) { if (typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext) { return 2; } return 1; } function setDevicePixelRatio(gl, devicePixelRatio, options) { let clientWidth = 'width' in options ? options.width : gl.canvas.clientWidth; let clientHeight = 'height' in options ? options.height : gl.canvas.clientHeight; if (!clientWidth || !clientHeight) { log.log(1, 'Canvas clientWidth/clientHeight is 0')(); devicePixelRatio = 1; clientWidth = gl.canvas.width || 1; clientHeight = gl.canvas.height || 1; } gl.luma = gl.luma || {}; gl.luma.canvasSizeInfo = gl.luma.canvasSizeInfo || {}; const cachedSize = gl.luma.canvasSizeInfo; if (cachedSize.clientWidth !== clientWidth || cachedSize.clientHeight !== clientHeight || cachedSize.devicePixelRatio !== devicePixelRatio) { let clampedPixelRatio = devicePixelRatio; const canvasWidth = Math.floor(clientWidth * clampedPixelRatio); const canvasHeight = Math.floor(clientHeight * clampedPixelRatio); gl.canvas.width = canvasWidth; gl.canvas.height = canvasHeight; if (gl.drawingBufferWidth !== canvasWidth || gl.drawingBufferHeight !== canvasHeight) { log.warn("Device pixel ratio clamped")(); clampedPixelRatio = Math.min(gl.drawingBufferWidth / clientWidth, gl.drawingBufferHeight / clientHeight); gl.canvas.width = Math.floor(clientWidth * clampedPixelRatio); gl.canvas.height = Math.floor(clientHeight * clampedPixelRatio); } Object.assign(gl.luma.canvasSizeInfo, { clientWidth, clientHeight, devicePixelRatio }); } } //# sourceMappingURL=context.js.map