498 lines
16 KiB
JavaScript
498 lines
16 KiB
JavaScript
import Framebuffer from "./Framebuffer.js";
|
|
import MultisampleFramebuffer from "./MultisampleFramebuffer.js";
|
|
import PixelDatatype from "./PixelDatatype.js";
|
|
import Renderbuffer from "./Renderbuffer.js";
|
|
import RenderbufferFormat from "./RenderbufferFormat.js";
|
|
import Sampler from "./Sampler.js";
|
|
import Texture from "./Texture.js";
|
|
import defaultValue from "../Core/defaultValue.js";
|
|
import defined from "../Core/defined.js";
|
|
import DeveloperError from "../Core/DeveloperError.js";
|
|
import PixelFormat from "../Core/PixelFormat.js";
|
|
|
|
/**
|
|
* Creates a wrapper object around a framebuffer and its resources.
|
|
*
|
|
* @param {object} options Object with the following properties:
|
|
* @param {number} [options.numSamples=1] The multisampling rate of the render targets. Requires a WebGL2 context.
|
|
* @param {number} [options.colorAttachmentsLength=1] The number of color attachments this FramebufferManager will create.
|
|
* @param {boolean} [options.color=true] Whether the FramebufferManager will use color attachments.
|
|
* @param {boolean} [options.depth=false] Whether the FramebufferManager will use depth attachments.
|
|
* @param {boolean} [options.depthStencil=false] Whether the FramebufferManager will use depth-stencil attachments.
|
|
* @param {boolean} [options.supportsDepthTexture=false] Whether the FramebufferManager will create a depth texture when the extension is supported.
|
|
* @param {boolean} [options.createColorAttachments=true] Whether the FramebufferManager will construct its own color attachments.
|
|
* @param {boolean} [options.createDepthAttachments=true] Whether the FramebufferManager will construct its own depth attachments.
|
|
* @param {PixelDatatype} [options.pixelDatatype=undefined] The default pixel datatype to use when creating color attachments.
|
|
* @param {PixelFormat} [options.pixelFormat=undefined] The default pixel format to use when creating color attachments.
|
|
*
|
|
* @exception {DeveloperError} Must enable at least one type of framebuffer attachment.
|
|
* @exception {DeveloperError} Cannot have both a depth and depth-stencil attachment.
|
|
*
|
|
* @private
|
|
* @constructor
|
|
*/
|
|
function FramebufferManager(options) {
|
|
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
|
|
this._numSamples = defaultValue(options.numSamples, 1);
|
|
this._colorAttachmentsLength = defaultValue(
|
|
options.colorAttachmentsLength,
|
|
1
|
|
);
|
|
|
|
this._color = defaultValue(options.color, true);
|
|
this._depth = defaultValue(options.depth, false);
|
|
this._depthStencil = defaultValue(options.depthStencil, false);
|
|
this._supportsDepthTexture = defaultValue(
|
|
options.supportsDepthTexture,
|
|
false
|
|
);
|
|
//>>includeStart('debug', pragmas.debug);
|
|
if (!this._color && !this._depth && !this._depthStencil) {
|
|
throw new DeveloperError(
|
|
"Must enable at least one type of framebuffer attachment."
|
|
);
|
|
}
|
|
if (this._depth && this._depthStencil) {
|
|
throw new DeveloperError(
|
|
"Cannot have both a depth and depth-stencil attachment."
|
|
);
|
|
}
|
|
//>>includeEnd('debug');
|
|
|
|
this._createColorAttachments = defaultValue(
|
|
options.createColorAttachments,
|
|
true
|
|
);
|
|
this._createDepthAttachments = defaultValue(
|
|
options.createDepthAttachments,
|
|
true
|
|
);
|
|
|
|
this._pixelDatatype = options.pixelDatatype;
|
|
this._pixelFormat = options.pixelFormat;
|
|
|
|
this._width = undefined;
|
|
this._height = undefined;
|
|
|
|
this._framebuffer = undefined;
|
|
this._multisampleFramebuffer = undefined;
|
|
this._colorTextures = undefined;
|
|
if (this._color) {
|
|
this._colorTextures = new Array(this._colorAttachmentsLength);
|
|
this._colorRenderbuffers = new Array(this._colorAttachmentsLength);
|
|
}
|
|
this._colorRenderbuffer = undefined;
|
|
this._depthStencilRenderbuffer = undefined;
|
|
this._depthStencilTexture = undefined;
|
|
this._depthRenderbuffer = undefined;
|
|
this._depthTexture = undefined;
|
|
|
|
this._attachmentsDirty = false;
|
|
}
|
|
|
|
Object.defineProperties(FramebufferManager.prototype, {
|
|
framebuffer: {
|
|
get: function () {
|
|
if (this._numSamples > 1) {
|
|
return this._multisampleFramebuffer.getRenderFramebuffer();
|
|
}
|
|
return this._framebuffer;
|
|
},
|
|
},
|
|
numSamples: {
|
|
get: function () {
|
|
return this._numSamples;
|
|
},
|
|
},
|
|
status: {
|
|
get: function () {
|
|
return this.framebuffer.status;
|
|
},
|
|
},
|
|
});
|
|
|
|
FramebufferManager.prototype.isDirty = function (
|
|
width,
|
|
height,
|
|
numSamples,
|
|
pixelDatatype,
|
|
pixelFormat
|
|
) {
|
|
numSamples = defaultValue(numSamples, 1);
|
|
const dimensionChanged = this._width !== width || this._height !== height;
|
|
const samplesChanged = this._numSamples !== numSamples;
|
|
const pixelChanged =
|
|
(defined(pixelDatatype) && this._pixelDatatype !== pixelDatatype) ||
|
|
(defined(pixelFormat) && this._pixelFormat !== pixelFormat);
|
|
const framebufferDefined =
|
|
numSamples === 1
|
|
? defined(this._framebuffer)
|
|
: defined(this._multisampleFramebuffer);
|
|
|
|
return (
|
|
this._attachmentsDirty ||
|
|
dimensionChanged ||
|
|
samplesChanged ||
|
|
pixelChanged ||
|
|
!framebufferDefined ||
|
|
(this._color && !defined(this._colorTextures[0]))
|
|
);
|
|
};
|
|
|
|
FramebufferManager.prototype.update = function (
|
|
context,
|
|
width,
|
|
height,
|
|
numSamples,
|
|
pixelDatatype,
|
|
pixelFormat
|
|
) {
|
|
//>>includeStart('debug', pragmas.debug);
|
|
if (!defined(width) || !defined(height)) {
|
|
throw new DeveloperError("width and height must be defined.");
|
|
}
|
|
//>>includeEnd('debug');
|
|
numSamples = context.msaa ? defaultValue(numSamples, 1) : 1;
|
|
pixelDatatype = defaultValue(
|
|
pixelDatatype,
|
|
this._color
|
|
? defaultValue(this._pixelDatatype, PixelDatatype.UNSIGNED_BYTE)
|
|
: undefined
|
|
);
|
|
pixelFormat = defaultValue(
|
|
pixelFormat,
|
|
this._color ? defaultValue(this._pixelFormat, PixelFormat.RGBA) : undefined
|
|
);
|
|
|
|
if (this.isDirty(width, height, numSamples, pixelDatatype, pixelFormat)) {
|
|
this.destroy();
|
|
this._width = width;
|
|
this._height = height;
|
|
this._numSamples = numSamples;
|
|
this._pixelDatatype = pixelDatatype;
|
|
this._pixelFormat = pixelFormat;
|
|
this._attachmentsDirty = false;
|
|
|
|
// Create color texture
|
|
if (this._color && this._createColorAttachments) {
|
|
for (let i = 0; i < this._colorAttachmentsLength; ++i) {
|
|
this._colorTextures[i] = new Texture({
|
|
context: context,
|
|
width: width,
|
|
height: height,
|
|
pixelFormat: pixelFormat,
|
|
pixelDatatype: pixelDatatype,
|
|
sampler: Sampler.NEAREST,
|
|
});
|
|
if (this._numSamples > 1) {
|
|
const format = RenderbufferFormat.getColorFormat(pixelDatatype);
|
|
this._colorRenderbuffers[i] = new Renderbuffer({
|
|
context: context,
|
|
width: width,
|
|
height: height,
|
|
format: format,
|
|
numSamples: this._numSamples,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create depth stencil texture or renderbuffer
|
|
if (this._depthStencil && this._createDepthAttachments) {
|
|
if (this._supportsDepthTexture && context.depthTexture) {
|
|
this._depthStencilTexture = new Texture({
|
|
context: context,
|
|
width: width,
|
|
height: height,
|
|
pixelFormat: PixelFormat.DEPTH_STENCIL,
|
|
pixelDatatype: PixelDatatype.UNSIGNED_INT_24_8,
|
|
sampler: Sampler.NEAREST,
|
|
});
|
|
if (this._numSamples > 1) {
|
|
this._depthStencilRenderbuffer = new Renderbuffer({
|
|
context: context,
|
|
width: width,
|
|
height: height,
|
|
format: RenderbufferFormat.DEPTH24_STENCIL8,
|
|
numSamples: this._numSamples,
|
|
});
|
|
}
|
|
} else {
|
|
this._depthStencilRenderbuffer = new Renderbuffer({
|
|
context: context,
|
|
width: width,
|
|
height: height,
|
|
format: RenderbufferFormat.DEPTH_STENCIL,
|
|
});
|
|
}
|
|
}
|
|
|
|
// Create depth texture
|
|
if (this._depth && this._createDepthAttachments) {
|
|
if (this._supportsDepthTexture && context.depthTexture) {
|
|
this._depthTexture = new Texture({
|
|
context: context,
|
|
width: width,
|
|
height: height,
|
|
pixelFormat: PixelFormat.DEPTH_COMPONENT,
|
|
pixelDatatype: PixelDatatype.UNSIGNED_INT,
|
|
sampler: Sampler.NEAREST,
|
|
});
|
|
} else {
|
|
this._depthRenderbuffer = new Renderbuffer({
|
|
context: context,
|
|
width: width,
|
|
height: height,
|
|
format: RenderbufferFormat.DEPTH_COMPONENT16,
|
|
});
|
|
}
|
|
}
|
|
|
|
if (this._numSamples > 1) {
|
|
this._multisampleFramebuffer = new MultisampleFramebuffer({
|
|
context: context,
|
|
width: this._width,
|
|
height: this._height,
|
|
colorTextures: this._colorTextures,
|
|
colorRenderbuffers: this._colorRenderbuffers,
|
|
depthStencilTexture: this._depthStencilTexture,
|
|
depthStencilRenderbuffer: this._depthStencilRenderbuffer,
|
|
destroyAttachments: false,
|
|
});
|
|
} else {
|
|
this._framebuffer = new Framebuffer({
|
|
context: context,
|
|
colorTextures: this._colorTextures,
|
|
depthTexture: this._depthTexture,
|
|
depthRenderbuffer: this._depthRenderbuffer,
|
|
depthStencilTexture: this._depthStencilTexture,
|
|
depthStencilRenderbuffer: this._depthStencilRenderbuffer,
|
|
destroyAttachments: false,
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
FramebufferManager.prototype.getColorTexture = function (index) {
|
|
index = defaultValue(index, 0);
|
|
//>>includeStart('debug', pragmas.debug);
|
|
if (index >= this._colorAttachmentsLength) {
|
|
throw new DeveloperError(
|
|
"index must be smaller than total number of color attachments."
|
|
);
|
|
}
|
|
//>>includeEnd('debug');
|
|
return this._colorTextures[index];
|
|
};
|
|
|
|
FramebufferManager.prototype.setColorTexture = function (texture, index) {
|
|
index = defaultValue(index, 0);
|
|
//>>includeStart('debug', pragmas.debug);
|
|
if (this._createColorAttachments) {
|
|
throw new DeveloperError(
|
|
"createColorAttachments must be false if setColorTexture is called."
|
|
);
|
|
}
|
|
if (index >= this._colorAttachmentsLength) {
|
|
throw new DeveloperError(
|
|
"index must be smaller than total number of color attachments."
|
|
);
|
|
}
|
|
//>>includeEnd('debug');
|
|
this._attachmentsDirty = texture !== this._colorTextures[index];
|
|
this._colorTextures[index] = texture;
|
|
};
|
|
|
|
FramebufferManager.prototype.getColorRenderbuffer = function (index) {
|
|
index = defaultValue(index, 0);
|
|
//>>includeStart('debug', pragmas.debug);
|
|
if (index >= this._colorAttachmentsLength) {
|
|
throw new DeveloperError(
|
|
"index must be smaller than total number of color attachments."
|
|
);
|
|
}
|
|
//>>includeEnd('debug');
|
|
return this._colorRenderbuffers[index];
|
|
};
|
|
|
|
FramebufferManager.prototype.setColorRenderbuffer = function (
|
|
renderbuffer,
|
|
index
|
|
) {
|
|
index = defaultValue(index, 0);
|
|
//>>includeStart('debug', pragmas.debug);
|
|
if (this._createColorAttachments) {
|
|
throw new DeveloperError(
|
|
"createColorAttachments must be false if setColorRenderbuffer is called."
|
|
);
|
|
}
|
|
if (index >= this._colorAttachmentsLength) {
|
|
throw new DeveloperError(
|
|
"index must be smaller than total number of color attachments."
|
|
);
|
|
}
|
|
//>>includeEnd('debug');
|
|
this._attachmentsDirty = renderbuffer !== this._colorRenderbuffers[index];
|
|
this._colorRenderbuffers[index] = renderbuffer;
|
|
};
|
|
|
|
FramebufferManager.prototype.getDepthRenderbuffer = function () {
|
|
return this._depthRenderbuffer;
|
|
};
|
|
|
|
FramebufferManager.prototype.setDepthRenderbuffer = function (renderbuffer) {
|
|
//>>includeStart('debug', pragmas.debug);
|
|
if (this._createDepthAttachments) {
|
|
throw new DeveloperError(
|
|
"createDepthAttachments must be false if setDepthRenderbuffer is called."
|
|
);
|
|
}
|
|
//>>includeEnd('debug');
|
|
this._attachmentsDirty = renderbuffer !== this._depthRenderbuffer;
|
|
this._depthRenderbuffer = renderbuffer;
|
|
};
|
|
|
|
FramebufferManager.prototype.getDepthTexture = function () {
|
|
return this._depthTexture;
|
|
};
|
|
|
|
FramebufferManager.prototype.setDepthTexture = function (texture) {
|
|
//>>includeStart('debug', pragmas.debug);
|
|
if (this._createDepthAttachments) {
|
|
throw new DeveloperError(
|
|
"createDepthAttachments must be false if setDepthTexture is called."
|
|
);
|
|
}
|
|
//>>includeEnd('debug');
|
|
this._attachmentsDirty = texture !== this._depthTexture;
|
|
this._depthTexture = texture;
|
|
};
|
|
|
|
FramebufferManager.prototype.getDepthStencilRenderbuffer = function () {
|
|
return this._depthStencilRenderbuffer;
|
|
};
|
|
|
|
FramebufferManager.prototype.setDepthStencilRenderbuffer = function (
|
|
renderbuffer
|
|
) {
|
|
//>>includeStart('debug', pragmas.debug);
|
|
if (this._createDepthAttachments) {
|
|
throw new DeveloperError(
|
|
"createDepthAttachments must be false if setDepthStencilRenderbuffer is called."
|
|
);
|
|
}
|
|
//>>includeEnd('debug');
|
|
this._attachmentsDirty = renderbuffer !== this._depthStencilRenderbuffer;
|
|
this._depthStencilRenderbuffer = renderbuffer;
|
|
};
|
|
|
|
FramebufferManager.prototype.getDepthStencilTexture = function () {
|
|
return this._depthStencilTexture;
|
|
};
|
|
|
|
FramebufferManager.prototype.setDepthStencilTexture = function (texture) {
|
|
//>>includeStart('debug', pragmas.debug);
|
|
if (this._createDepthAttachments) {
|
|
throw new DeveloperError(
|
|
"createDepthAttachments must be false if setDepthStencilTexture is called."
|
|
);
|
|
}
|
|
//>>includeEnd('debug');
|
|
this._attachmentsDirty = texture !== this._depthStencilTexture;
|
|
this._depthStencilTexture = texture;
|
|
};
|
|
|
|
FramebufferManager.prototype.prepareTextures = function (context, blitStencil) {
|
|
if (this._numSamples > 1) {
|
|
this._multisampleFramebuffer.blitFramebuffers(context, blitStencil);
|
|
}
|
|
};
|
|
|
|
FramebufferManager.prototype.clear = function (
|
|
context,
|
|
clearCommand,
|
|
passState
|
|
) {
|
|
const framebuffer = clearCommand.framebuffer;
|
|
clearCommand.framebuffer = this.framebuffer;
|
|
clearCommand.execute(context, passState);
|
|
clearCommand.framebuffer = framebuffer;
|
|
};
|
|
|
|
FramebufferManager.prototype.destroyFramebuffer = function () {
|
|
this._framebuffer = this._framebuffer && this._framebuffer.destroy();
|
|
this._multisampleFramebuffer =
|
|
this._multisampleFramebuffer && this._multisampleFramebuffer.destroy();
|
|
};
|
|
|
|
FramebufferManager.prototype.destroy = function () {
|
|
if (this._color) {
|
|
let i;
|
|
const length = this._colorTextures.length;
|
|
for (i = 0; i < length; ++i) {
|
|
const texture = this._colorTextures[i];
|
|
if (this._createColorAttachments) {
|
|
if (defined(texture) && !texture.isDestroyed()) {
|
|
this._colorTextures[i].destroy();
|
|
this._colorTextures[i] = undefined;
|
|
}
|
|
}
|
|
if (defined(texture) && texture.isDestroyed()) {
|
|
this._colorTextures[i] = undefined;
|
|
}
|
|
const renderbuffer = this._colorRenderbuffers[i];
|
|
if (this._createColorAttachments) {
|
|
if (defined(renderbuffer) && !renderbuffer.isDestroyed()) {
|
|
this._colorRenderbuffers[i].destroy();
|
|
this._colorRenderbuffers[i] = undefined;
|
|
}
|
|
}
|
|
if (defined(renderbuffer) && renderbuffer.isDestroyed()) {
|
|
this._colorRenderbuffers[i] = undefined;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (this._depthStencil) {
|
|
if (this._createDepthAttachments) {
|
|
this._depthStencilTexture =
|
|
this._depthStencilTexture && this._depthStencilTexture.destroy();
|
|
this._depthStencilRenderbuffer =
|
|
this._depthStencilRenderbuffer &&
|
|
this._depthStencilRenderbuffer.destroy();
|
|
}
|
|
if (
|
|
defined(this._depthStencilTexture) &&
|
|
this._depthStencilTexture.isDestroyed()
|
|
) {
|
|
this._depthStencilTexture = undefined;
|
|
}
|
|
if (
|
|
defined(this._depthStencilRenderbuffer) &&
|
|
this._depthStencilRenderbuffer.isDestroyed()
|
|
) {
|
|
this._depthStencilRenderbuffer = undefined;
|
|
}
|
|
}
|
|
|
|
if (this._depth) {
|
|
if (this._createDepthAttachments) {
|
|
this._depthTexture = this._depthTexture && this._depthTexture.destroy();
|
|
this._depthRenderbuffer =
|
|
this._depthRenderbuffer && this._depthRenderbuffer.destroy();
|
|
}
|
|
if (defined(this._depthTexture) && this._depthTexture.isDestroyed()) {
|
|
this._depthTexture = undefined;
|
|
}
|
|
if (
|
|
defined(this._depthRenderbuffer) &&
|
|
this._depthRenderbuffer.isDestroyed()
|
|
) {
|
|
this._depthRenderbuffer = undefined;
|
|
}
|
|
}
|
|
|
|
this.destroyFramebuffer();
|
|
};
|
|
export default FramebufferManager;
|