123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374 |
- import Color from '../Core/Color.js';
- import defined from '../Core/defined.js';
- import destroyObject from '../Core/destroyObject.js';
- import CesiumMath from '../Core/Math.js';
- import ClearCommand from '../Renderer/ClearCommand.js';
- import Framebuffer from '../Renderer/Framebuffer.js';
- import Texture from '../Renderer/Texture.js';
- /**
- * Creates a minimal amount of textures and framebuffers.
- *
- * @alias PostProcessStageTextureCache
- * @constructor
- *
- * @param {PostProcessStageCollection} postProcessStageCollection The post process collection.
- *
- * @private
- */
- function PostProcessStageTextureCache(postProcessStageCollection) {
- this._collection = postProcessStageCollection;
- this._framebuffers = [];
- this._stageNameToFramebuffer = {};
- this._width = undefined;
- this._height = undefined;
- this._updateDependencies = false;
- }
- function getLastStageName(stage) {
- while (defined(stage.length)) {
- stage = stage.get(stage.length - 1);
- }
- return stage.name;
- }
- function getStageDependencies(collection, context, dependencies, stage, previousName) {
- if (!stage.enabled || !stage._isSupported(context)) {
- return previousName;
- }
- var stageDependencies = dependencies[stage.name] = {};
- if (defined(previousName)) {
- var previous = collection.getStageByName(previousName);
- stageDependencies[getLastStageName(previous)] = true;
- }
- var uniforms = stage.uniforms;
- if (defined(uniforms)) {
- var uniformNames = Object.getOwnPropertyNames(uniforms);
- var uniformNamesLength = uniformNames.length;
- for (var i = 0; i < uniformNamesLength; ++i) {
- var value = uniforms[uniformNames[i]];
- if (typeof value === 'string') {
- var dependent = collection.getStageByName(value);
- if (defined(dependent)) {
- stageDependencies[getLastStageName(dependent)] = true;
- }
- }
- }
- }
- return stage.name;
- }
- function getCompositeDependencies(collection, context, dependencies, composite, previousName) {
- if ((defined(composite.enabled) && !composite.enabled) || (defined(composite._isSupported) && !composite._isSupported(context))) {
- return previousName;
- }
- var originalDependency = previousName;
- var inSeries = !defined(composite.inputPreviousStageTexture) || composite.inputPreviousStageTexture;
- var currentName = previousName;
- var length = composite.length;
- for (var i = 0; i < length; ++i) {
- var stage = composite.get(i);
- if (defined(stage.length)) {
- currentName = getCompositeDependencies(collection, context, dependencies, stage, previousName);
- } else {
- currentName = getStageDependencies(collection, context, dependencies, stage, previousName);
- }
- // Stages in a series only depend on the previous stage
- if (inSeries) {
- previousName = currentName;
- }
- }
- // Stages not in a series depend on every stage executed before it since it could reference it as a uniform.
- // This prevents looking at the dependencies of each stage in the composite, but might create more framebuffers than necessary.
- // In practice, there are only 2-3 stages in these composites.
- var j;
- var name;
- if (!inSeries) {
- for (j = 1; j < length; ++j) {
- name = getLastStageName(composite.get(j));
- var currentDependencies = dependencies[name];
- for (var k = 0; k < j; ++k) {
- currentDependencies[getLastStageName(composite.get(k))] = true;
- }
- }
- } else {
- for (j = 1; j < length; ++j) {
- name = getLastStageName(composite.get(j));
- if (!defined(dependencies[name])) {
- dependencies[name] = {};
- }
- dependencies[name][originalDependency] = true;
- }
- }
- return currentName;
- }
- function getDependencies(collection, context) {
- var dependencies = {};
- if (defined(collection.ambientOcclusion)) {
- var ao = collection.ambientOcclusion;
- var bloom = collection.bloom;
- var tonemapping = collection._tonemapping;
- var fxaa = collection.fxaa;
- var previousName = getCompositeDependencies(collection, context, dependencies, ao, undefined);
- previousName = getCompositeDependencies(collection, context, dependencies, bloom, previousName);
- previousName = getStageDependencies(collection, context, dependencies, tonemapping, previousName);
- previousName = getCompositeDependencies(collection, context, dependencies, collection, previousName);
- getStageDependencies(collection, context, dependencies, fxaa, previousName);
- } else {
- getCompositeDependencies(collection, context, dependencies, collection, undefined);
- }
- return dependencies;
- }
- function getFramebuffer(cache, stageName, dependencies) {
- var collection = cache._collection;
- var stage = collection.getStageByName(stageName);
- var textureScale = stage._textureScale;
- var forcePowerOfTwo = stage._forcePowerOfTwo;
- var pixelFormat = stage._pixelFormat;
- var pixelDatatype = stage._pixelDatatype;
- var clearColor = stage._clearColor;
- var i;
- var framebuffer;
- var framebuffers = cache._framebuffers;
- var length = framebuffers.length;
- for (i = 0; i < length; ++i) {
- framebuffer = framebuffers[i];
- if (textureScale !== framebuffer.textureScale || forcePowerOfTwo !== framebuffer.forcePowerOfTwo ||
- pixelFormat !== framebuffer.pixelFormat || pixelDatatype !== framebuffer.pixelDatatype ||
- !Color.equals(clearColor, framebuffer.clearColor)) {
- continue;
- }
- var stageNames = framebuffer.stages;
- var stagesLength = stageNames.length;
- var foundConflict = false;
- for (var j = 0; j < stagesLength; ++j) {
- if (dependencies[stageNames[j]]) {
- foundConflict = true;
- break;
- }
- }
- if (!foundConflict) {
- break;
- }
- }
- if (defined(framebuffer) && i < length) {
- framebuffer.stages.push(stageName);
- return framebuffer;
- }
- framebuffer = {
- textureScale : textureScale,
- forcePowerOfTwo : forcePowerOfTwo,
- pixelFormat : pixelFormat,
- pixelDatatype : pixelDatatype,
- clearColor : clearColor,
- stages : [stageName],
- buffer : undefined,
- clear : undefined
- };
- framebuffers.push(framebuffer);
- return framebuffer;
- }
- function createFramebuffers(cache, context) {
- var dependencies = getDependencies(cache._collection, context);
- for (var stageName in dependencies) {
- if (dependencies.hasOwnProperty(stageName)) {
- cache._stageNameToFramebuffer[stageName] = getFramebuffer(cache, stageName, dependencies[stageName]);
- }
- }
- }
- function releaseResources(cache) {
- var framebuffers = cache._framebuffers;
- var length = framebuffers.length;
- for (var i = 0; i < length; ++i) {
- var framebuffer = framebuffers[i];
- framebuffer.buffer = framebuffer.buffer && framebuffer.buffer.destroy();
- framebuffer.buffer = undefined;
- }
- }
- function updateFramebuffers(cache, context) {
- var width = cache._width;
- var height = cache._height;
- var framebuffers = cache._framebuffers;
- var length = framebuffers.length;
- for (var i = 0; i < length; ++i) {
- var framebuffer = framebuffers[i];
- var scale = framebuffer.textureScale;
- var textureWidth = Math.ceil(width * scale);
- var textureHeight = Math.ceil(height * scale);
- var size = Math.min(textureWidth, textureHeight);
- if (framebuffer.forcePowerOfTwo) {
- if (!CesiumMath.isPowerOfTwo(size)) {
- size = CesiumMath.nextPowerOfTwo(size);
- }
- textureWidth = size;
- textureHeight = size;
- }
- framebuffer.buffer = new Framebuffer({
- context : context,
- colorTextures : [new Texture({
- context : context,
- width : textureWidth,
- height : textureHeight,
- pixelFormat : framebuffer.pixelFormat,
- pixelDatatype : framebuffer.pixelDatatype
- })]
- });
- framebuffer.clear = new ClearCommand({
- color : framebuffer.clearColor,
- framebuffer : framebuffer.buffer
- });
- }
- }
- PostProcessStageTextureCache.prototype.updateDependencies = function() {
- this._updateDependencies = true;
- };
- /**
- * Called before the stages in the collection are executed. Creates the minimum amount of framebuffers for a post-process collection.
- *
- * @param {Context} context The context.
- */
- PostProcessStageTextureCache.prototype.update = function(context) {
- var collection = this._collection;
- var updateDependencies = this._updateDependencies;
- var aoEnabled = defined(collection.ambientOcclusion) && collection.ambientOcclusion.enabled && collection.ambientOcclusion._isSupported(context);
- var bloomEnabled = defined(collection.bloom) && collection.bloom.enabled && collection.bloom._isSupported(context);
- var tonemappingEnabled = defined(collection._tonemapping) && collection._tonemapping.enabled && collection._tonemapping._isSupported(context);
- var fxaaEnabled = defined(collection.fxaa) && collection.fxaa.enabled && collection.fxaa._isSupported(context);
- var needsCheckDimensionsUpdate = !defined(collection._activeStages) || collection._activeStages.length > 0 || aoEnabled || bloomEnabled || tonemappingEnabled || fxaaEnabled;
- if (updateDependencies || (!needsCheckDimensionsUpdate && this._framebuffers.length > 0)) {
- releaseResources(this);
- this._framebuffers.length = 0;
- this._stageNameToFramebuffer = {};
- this._width = undefined;
- this._height = undefined;
- }
- if (!updateDependencies && !needsCheckDimensionsUpdate) {
- return;
- }
- if (this._framebuffers.length === 0) {
- createFramebuffers(this, context);
- }
- var width = context.drawingBufferWidth;
- var height = context.drawingBufferHeight;
- var dimensionsChanged = this._width !== width || this._height !== height;
- if (!updateDependencies && !dimensionsChanged) {
- return;
- }
- this._width = width;
- this._height = height;
- this._updateDependencies = false;
- releaseResources(this);
- updateFramebuffers(this, context);
- };
- /**
- * Clears all of the framebuffers.
- *
- * @param {Context} context The context.
- */
- PostProcessStageTextureCache.prototype.clear = function(context) {
- var framebuffers = this._framebuffers;
- for (var i = 0; i < framebuffers.length; ++i) {
- framebuffers[i].clear.execute(context);
- }
- };
- /**
- * Gets the stage with the given name.
- * @param {String} name The name of the stage.
- * @return {PostProcessStage|PostProcessStageComposite}
- */
- PostProcessStageTextureCache.prototype.getStageByName = function(name) {
- return this._collection.getStageByName(name);
- };
- /**
- * Gets the output texture for a stage with the given name.
- * @param {String} name The name of the stage.
- * @return {Texture|undefined} The output texture of the stage with the given name.
- */
- PostProcessStageTextureCache.prototype.getOutputTexture = function(name) {
- return this._collection.getOutputTexture(name);
- };
- /**
- * Gets the framebuffer for a stage with the given name.
- *
- * @param {String} name The name of the stage.
- * @return {Framebuffer|undefined} The framebuffer for the stage with the given name.
- */
- PostProcessStageTextureCache.prototype.getFramebuffer = function(name) {
- var framebuffer = this._stageNameToFramebuffer[name];
- if (!defined(framebuffer)) {
- return undefined;
- }
- return framebuffer.buffer;
- };
- /**
- * Returns true if this object was destroyed; otherwise, false.
- * <p>
- * If this object was destroyed, it should not be used; calling any function other than
- * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
- * </p>
- *
- * @returns {Boolean} <code>true</code> if this object was destroyed; otherwise, <code>false</code>.
- *
- * @see PostProcessStageTextureCache#destroy
- */
- PostProcessStageTextureCache.prototype.isDestroyed = function() {
- return false;
- };
- /**
- * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
- * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
- * <p>
- * Once an object is destroyed, it should not be used; calling any function other than
- * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
- * assign the return value (<code>undefined</code>) to the object as done in the example.
- * </p>
- *
- * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
- *
- * @see PostProcessStageTextureCache#isDestroyed
- */
- PostProcessStageTextureCache.prototype.destroy = function() {
- releaseResources(this);
- return destroyObject(this);
- };
- export default PostProcessStageTextureCache;
|