@luma.gl/engine
Version:
3D Engine Components for luma.gl
98 lines • 3.87 kB
JavaScript
// 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