@pixi/core
Version:
Core PixiJS
363 lines (358 loc) • 13.4 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var constants = require('@pixi/constants');
var extensions = require('@pixi/extensions');
var math = require('@pixi/math');
var settings = require('@pixi/settings');
var Framebuffer = require('./Framebuffer.js');
var GLFramebuffer = require('./GLFramebuffer.js');
const tempRectangle = new math.Rectangle();
class FramebufferSystem {
constructor(renderer) {
this.renderer = renderer;
this.managedFramebuffers = [];
this.unknownFramebuffer = new Framebuffer.Framebuffer(10, 10);
this.msaaSamples = null;
}
contextChange() {
this.disposeAll(true);
const gl = this.gl = this.renderer.gl;
this.CONTEXT_UID = this.renderer.CONTEXT_UID;
this.current = this.unknownFramebuffer;
this.viewport = new math.Rectangle();
this.hasMRT = true;
this.writeDepthTexture = true;
if (this.renderer.context.webGLVersion === 1) {
let nativeDrawBuffersExtension = this.renderer.context.extensions.drawBuffers;
let nativeDepthTextureExtension = this.renderer.context.extensions.depthTexture;
if (settings.settings.PREFER_ENV === constants.ENV.WEBGL_LEGACY) {
nativeDrawBuffersExtension = null;
nativeDepthTextureExtension = null;
}
if (nativeDrawBuffersExtension) {
gl.drawBuffers = (activeTextures) => nativeDrawBuffersExtension.drawBuffersWEBGL(activeTextures);
} else {
this.hasMRT = false;
gl.drawBuffers = () => {
};
}
if (!nativeDepthTextureExtension) {
this.writeDepthTexture = false;
}
} else {
this.msaaSamples = gl.getInternalformatParameter(gl.RENDERBUFFER, gl.RGBA8, gl.SAMPLES);
}
}
bind(framebuffer, frame, mipLevel = 0) {
const { gl } = this;
if (framebuffer) {
const fbo = framebuffer.glFramebuffers[this.CONTEXT_UID] || this.initFramebuffer(framebuffer);
if (this.current !== framebuffer) {
this.current = framebuffer;
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo.framebuffer);
}
if (fbo.mipLevel !== mipLevel) {
framebuffer.dirtyId++;
framebuffer.dirtyFormat++;
fbo.mipLevel = mipLevel;
}
if (fbo.dirtyId !== framebuffer.dirtyId) {
fbo.dirtyId = framebuffer.dirtyId;
if (fbo.dirtyFormat !== framebuffer.dirtyFormat) {
fbo.dirtyFormat = framebuffer.dirtyFormat;
fbo.dirtySize = framebuffer.dirtySize;
this.updateFramebuffer(framebuffer, mipLevel);
} else if (fbo.dirtySize !== framebuffer.dirtySize) {
fbo.dirtySize = framebuffer.dirtySize;
this.resizeFramebuffer(framebuffer);
}
}
for (let i = 0; i < framebuffer.colorTextures.length; i++) {
const tex = framebuffer.colorTextures[i];
this.renderer.texture.unbind(tex.parentTextureArray || tex);
}
if (framebuffer.depthTexture) {
this.renderer.texture.unbind(framebuffer.depthTexture);
}
if (frame) {
const mipWidth = frame.width >> mipLevel;
const mipHeight = frame.height >> mipLevel;
const scale = mipWidth / frame.width;
this.setViewport(frame.x * scale, frame.y * scale, mipWidth, mipHeight);
} else {
const mipWidth = framebuffer.width >> mipLevel;
const mipHeight = framebuffer.height >> mipLevel;
this.setViewport(0, 0, mipWidth, mipHeight);
}
} else {
if (this.current) {
this.current = null;
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
}
if (frame) {
this.setViewport(frame.x, frame.y, frame.width, frame.height);
} else {
this.setViewport(0, 0, this.renderer.width, this.renderer.height);
}
}
}
setViewport(x, y, width, height) {
const v = this.viewport;
x = Math.round(x);
y = Math.round(y);
width = Math.round(width);
height = Math.round(height);
if (v.width !== width || v.height !== height || v.x !== x || v.y !== y) {
v.x = x;
v.y = y;
v.width = width;
v.height = height;
this.gl.viewport(x, y, width, height);
}
}
get size() {
if (this.current) {
return { x: 0, y: 0, width: this.current.width, height: this.current.height };
}
return { x: 0, y: 0, width: this.renderer.width, height: this.renderer.height };
}
clear(r, g, b, a, mask = constants.BUFFER_BITS.COLOR | constants.BUFFER_BITS.DEPTH) {
const { gl } = this;
gl.clearColor(r, g, b, a);
gl.clear(mask);
}
initFramebuffer(framebuffer) {
const { gl } = this;
const fbo = new GLFramebuffer.GLFramebuffer(gl.createFramebuffer());
fbo.multisample = this.detectSamples(framebuffer.multisample);
framebuffer.glFramebuffers[this.CONTEXT_UID] = fbo;
this.managedFramebuffers.push(framebuffer);
framebuffer.disposeRunner.add(this);
return fbo;
}
resizeFramebuffer(framebuffer) {
const { gl } = this;
const fbo = framebuffer.glFramebuffers[this.CONTEXT_UID];
if (fbo.stencil) {
gl.bindRenderbuffer(gl.RENDERBUFFER, fbo.stencil);
if (fbo.msaaBuffer) {
gl.renderbufferStorageMultisample(gl.RENDERBUFFER, fbo.multisample, gl.DEPTH24_STENCIL8, framebuffer.width, framebuffer.height);
} else {
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, framebuffer.width, framebuffer.height);
}
}
const colorTextures = framebuffer.colorTextures;
let count = colorTextures.length;
if (!gl.drawBuffers) {
count = Math.min(count, 1);
}
for (let i = 0; i < count; i++) {
const texture = colorTextures[i];
const parentTexture = texture.parentTextureArray || texture;
this.renderer.texture.bind(parentTexture, 0);
if (i === 0 && fbo.msaaBuffer) {
gl.bindRenderbuffer(gl.RENDERBUFFER, fbo.msaaBuffer);
gl.renderbufferStorageMultisample(gl.RENDERBUFFER, fbo.multisample, parentTexture._glTextures[this.CONTEXT_UID].internalFormat, framebuffer.width, framebuffer.height);
}
}
if (framebuffer.depthTexture && this.writeDepthTexture) {
this.renderer.texture.bind(framebuffer.depthTexture, 0);
}
}
updateFramebuffer(framebuffer, mipLevel) {
const { gl } = this;
const fbo = framebuffer.glFramebuffers[this.CONTEXT_UID];
const colorTextures = framebuffer.colorTextures;
let count = colorTextures.length;
if (!gl.drawBuffers) {
count = Math.min(count, 1);
}
if (fbo.multisample > 1 && this.canMultisampleFramebuffer(framebuffer)) {
fbo.msaaBuffer = fbo.msaaBuffer || gl.createRenderbuffer();
} else if (fbo.msaaBuffer) {
gl.deleteRenderbuffer(fbo.msaaBuffer);
fbo.msaaBuffer = null;
if (fbo.blitFramebuffer) {
fbo.blitFramebuffer.dispose();
fbo.blitFramebuffer = null;
}
}
const activeTextures = [];
for (let i = 0; i < count; i++) {
const texture = colorTextures[i];
const parentTexture = texture.parentTextureArray || texture;
this.renderer.texture.bind(parentTexture, 0);
if (i === 0 && fbo.msaaBuffer) {
gl.bindRenderbuffer(gl.RENDERBUFFER, fbo.msaaBuffer);
gl.renderbufferStorageMultisample(gl.RENDERBUFFER, fbo.multisample, parentTexture._glTextures[this.CONTEXT_UID].internalFormat, framebuffer.width, framebuffer.height);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, fbo.msaaBuffer);
} else {
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + i, texture.target, parentTexture._glTextures[this.CONTEXT_UID].texture, mipLevel);
activeTextures.push(gl.COLOR_ATTACHMENT0 + i);
}
}
if (activeTextures.length > 1) {
gl.drawBuffers(activeTextures);
}
if (framebuffer.depthTexture) {
const writeDepthTexture = this.writeDepthTexture;
if (writeDepthTexture) {
const depthTexture = framebuffer.depthTexture;
this.renderer.texture.bind(depthTexture, 0);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depthTexture._glTextures[this.CONTEXT_UID].texture, mipLevel);
}
}
if ((framebuffer.stencil || framebuffer.depth) && !(framebuffer.depthTexture && this.writeDepthTexture)) {
fbo.stencil = fbo.stencil || gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, fbo.stencil);
if (fbo.msaaBuffer) {
gl.renderbufferStorageMultisample(gl.RENDERBUFFER, fbo.multisample, gl.DEPTH24_STENCIL8, framebuffer.width, framebuffer.height);
} else {
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, framebuffer.width, framebuffer.height);
}
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, fbo.stencil);
} else if (fbo.stencil) {
gl.deleteRenderbuffer(fbo.stencil);
fbo.stencil = null;
}
}
canMultisampleFramebuffer(framebuffer) {
return this.renderer.context.webGLVersion !== 1 && framebuffer.colorTextures.length <= 1 && !framebuffer.depthTexture;
}
detectSamples(samples) {
const { msaaSamples } = this;
let res = constants.MSAA_QUALITY.NONE;
if (samples <= 1 || msaaSamples === null) {
return res;
}
for (let i = 0; i < msaaSamples.length; i++) {
if (msaaSamples[i] <= samples) {
res = msaaSamples[i];
break;
}
}
if (res === 1) {
res = constants.MSAA_QUALITY.NONE;
}
return res;
}
blit(framebuffer, sourcePixels, destPixels) {
const { current, renderer, gl, CONTEXT_UID } = this;
if (renderer.context.webGLVersion !== 2) {
return;
}
if (!current) {
return;
}
const fbo = current.glFramebuffers[CONTEXT_UID];
if (!fbo) {
return;
}
if (!framebuffer) {
if (!fbo.msaaBuffer) {
return;
}
const colorTexture = current.colorTextures[0];
if (!colorTexture) {
return;
}
if (!fbo.blitFramebuffer) {
fbo.blitFramebuffer = new Framebuffer.Framebuffer(current.width, current.height);
fbo.blitFramebuffer.addColorTexture(0, colorTexture);
}
framebuffer = fbo.blitFramebuffer;
if (framebuffer.colorTextures[0] !== colorTexture) {
framebuffer.colorTextures[0] = colorTexture;
framebuffer.dirtyId++;
framebuffer.dirtyFormat++;
}
if (framebuffer.width !== current.width || framebuffer.height !== current.height) {
framebuffer.width = current.width;
framebuffer.height = current.height;
framebuffer.dirtyId++;
framebuffer.dirtySize++;
}
}
if (!sourcePixels) {
sourcePixels = tempRectangle;
sourcePixels.width = current.width;
sourcePixels.height = current.height;
}
if (!destPixels) {
destPixels = sourcePixels;
}
const sameSize = sourcePixels.width === destPixels.width && sourcePixels.height === destPixels.height;
this.bind(framebuffer);
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo.framebuffer);
gl.blitFramebuffer(sourcePixels.left, sourcePixels.top, sourcePixels.right, sourcePixels.bottom, destPixels.left, destPixels.top, destPixels.right, destPixels.bottom, gl.COLOR_BUFFER_BIT, sameSize ? gl.NEAREST : gl.LINEAR);
}
disposeFramebuffer(framebuffer, contextLost) {
const fbo = framebuffer.glFramebuffers[this.CONTEXT_UID];
const gl = this.gl;
if (!fbo) {
return;
}
delete framebuffer.glFramebuffers[this.CONTEXT_UID];
const index = this.managedFramebuffers.indexOf(framebuffer);
if (index >= 0) {
this.managedFramebuffers.splice(index, 1);
}
framebuffer.disposeRunner.remove(this);
if (!contextLost) {
gl.deleteFramebuffer(fbo.framebuffer);
if (fbo.msaaBuffer) {
gl.deleteRenderbuffer(fbo.msaaBuffer);
}
if (fbo.stencil) {
gl.deleteRenderbuffer(fbo.stencil);
}
}
if (fbo.blitFramebuffer) {
this.disposeFramebuffer(fbo.blitFramebuffer, contextLost);
}
}
disposeAll(contextLost) {
const list = this.managedFramebuffers;
this.managedFramebuffers = [];
for (let i = 0; i < list.length; i++) {
this.disposeFramebuffer(list[i], contextLost);
}
}
forceStencil() {
const framebuffer = this.current;
if (!framebuffer) {
return;
}
const fbo = framebuffer.glFramebuffers[this.CONTEXT_UID];
if (!fbo || fbo.stencil) {
return;
}
framebuffer.stencil = true;
const w = framebuffer.width;
const h = framebuffer.height;
const gl = this.gl;
const stencil = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, stencil);
if (fbo.msaaBuffer) {
gl.renderbufferStorageMultisample(gl.RENDERBUFFER, fbo.multisample, gl.DEPTH24_STENCIL8, w, h);
} else {
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, w, h);
}
fbo.stencil = stencil;
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, stencil);
}
reset() {
this.current = this.unknownFramebuffer;
this.viewport = new math.Rectangle();
}
destroy() {
this.renderer = null;
}
}
FramebufferSystem.extension = {
type: extensions.ExtensionType.RendererSystem,
name: "framebuffer"
};
extensions.extensions.add(FramebufferSystem);
exports.FramebufferSystem = FramebufferSystem;
//# sourceMappingURL=FramebufferSystem.js.map