UNPKG

@luma.gl/engine

Version:

3D Engine Components for luma.gl

98 lines 3.87 kB
// luma.gl // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors const DEBUG_FRAMEBUFFER_STATE_KEY = '__debugFramebufferState'; const DEFAULT_MARGIN_PX = 8; /** * Debug utility to blit queued offscreen framebuffers into the default framebuffer * without CPU readback. Currently implemented for WebGL only. */ export function debugFramebuffer(renderPass, source, options) { if (renderPass.device.type !== 'webgl') { return; } const state = getDebugFramebufferState(renderPass.device); if (state.flushing) { return; } if (isDefaultRenderPass(renderPass)) { flushDebugFramebuffers(renderPass, options, state); return; } if (source && isFramebuffer(source) && source.handle !== null) { if (!state.queuedFramebuffers.includes(source)) { state.queuedFramebuffers.push(source); } } } function flushDebugFramebuffers(renderPass, options, state) { if (state.queuedFramebuffers.length === 0) { return; } const webglDevice = renderPass.device; const { gl } = webglDevice; const previousReadFramebuffer = gl.getParameter(36010); const previousDrawFramebuffer = gl.getParameter(36006); const [targetWidth, targetHeight] = renderPass.device .getDefaultCanvasContext() .getDrawingBufferSize(); let topPx = parseCssPixel(options.top, DEFAULT_MARGIN_PX); const leftPx = parseCssPixel(options.left, DEFAULT_MARGIN_PX); state.flushing = true; try { for (const framebuffer of state.queuedFramebuffers) { const [targetX0, targetY0, targetX1, targetY1, previewHeight] = getOverlayRect({ framebuffer, targetWidth, targetHeight, topPx, leftPx, minimap: options.minimap }); gl.bindFramebuffer(36008, framebuffer.handle); gl.bindFramebuffer(36009, null); gl.blitFramebuffer(0, 0, framebuffer.width, framebuffer.height, targetX0, targetY0, targetX1, targetY1, 16384, 9728); topPx += previewHeight + DEFAULT_MARGIN_PX; } } finally { gl.bindFramebuffer(36008, previousReadFramebuffer); gl.bindFramebuffer(36009, previousDrawFramebuffer); state.flushing = false; } } function getOverlayRect(options) { const { framebuffer, targetWidth, targetHeight, topPx, leftPx, minimap } = options; const maxWidth = minimap ? Math.max(Math.floor(targetWidth / 4), 1) : targetWidth; const maxHeight = minimap ? Math.max(Math.floor(targetHeight / 4), 1) : targetHeight; const scale = Math.min(maxWidth / framebuffer.width, maxHeight / framebuffer.height); const previewWidth = Math.max(Math.floor(framebuffer.width * scale), 1); const previewHeight = Math.max(Math.floor(framebuffer.height * scale), 1); const targetX0 = leftPx; const targetY0 = Math.max(targetHeight - topPx - previewHeight, 0); const targetX1 = targetX0 + previewWidth; const targetY1 = targetY0 + previewHeight; return [targetX0, targetY0, targetX1, targetY1, previewHeight]; } function getDebugFramebufferState(device) { device.userData[DEBUG_FRAMEBUFFER_STATE_KEY] ||= { flushing: false, queuedFramebuffers: [] }; return device.userData[DEBUG_FRAMEBUFFER_STATE_KEY]; } function isFramebuffer(value) { return 'colorAttachments' in value; } function isDefaultRenderPass(renderPass) { const framebuffer = renderPass.props.framebuffer; return !framebuffer || framebuffer.handle === null; } function parseCssPixel(value, defaultValue) { if (!value) { return defaultValue; } const parsedValue = Number.parseInt(value, 10); return Number.isFinite(parsedValue) ? parsedValue : defaultValue; } //# sourceMappingURL=debug-framebuffer.js.map