/*global define*/ define(['Core/defined', 'Core/destroyObject', 'Core/DeveloperError', 'Renderer/PixelDatatype', 'Renderer/PixelFormat', 'Renderer/Texture'], function( defined, destroyObject, DeveloperError, PixelDatatype, PixelFormat, Texture) { "use strict"; var PooledTexture; function createPooledTexture(texture, textureTypeKey, pool) { if (!defined(PooledTexture)) { // define the class only when needed, so we can use modern // language features without breaking legacy browsers at setup time. PooledTexture = function(texture, textureTypeKey, pool) { this._texture = texture; this._textureTypeKey = textureTypeKey; this._pool = pool; }; // pass through all methods to the underlying texture Object.keys(Texture.prototype).forEach(function(methodName) { PooledTexture.prototype[methodName] = function() { var texture = this._texture; return texture[methodName].apply(texture, arguments); }; }); // except for destroy, which releases back into the pool PooledTexture.prototype.destroy = function() { var freeList = this._pool._free[this._textureTypeKey]; if (!defined(freeList)) { freeList = this._pool._free[this._textureTypeKey] = []; } if (freeList.length >= 8) { this._texture.destroy(); } else { freeList.push(this); } }; } return new PooledTexture(texture, textureTypeKey, pool); } /** * A pool of textures. Textures created from the pool will be released back into the pool * when destroy() is called, so future calls to create may re-use a released texture. * <br/><br/> * Texture pools are useful when textures are being created and destroyed repeatedly. * * @alias Texture2DPool * @constructor * * @see Texture */ var TexturePool = function() { this._free = {}; }; /** * Create a texture. This function takes the same arguments as {@link Context#createTexture2D}, * but may return a pooled texture if there are any available. If a pooled texture is re-used, * and no source is provided, the new texture will still retain its old contents. * * @memberof TexturePool * * @param {Context} context The context to use to create textures when needed. * * @exception {DeveloperError} description is required. * * @see Context#createTexture2D */ TexturePool.prototype.createTexture2D = function(context, description) { //>>includeStart('debug', pragmas.debug); if (!description) { throw new DeveloperError('description is required.'); } //>>includeEnd('debug'); var source = description.source; var width = defined(source) ? source.width : description.width; var height = defined(source) ? source.height : description.height; //coerce values to primitive numbers to make textureTypeKey smaller. var pixelFormat = (description.pixelFormat || PixelFormat.RGBA); var pixelDatatype = +(description.pixelDatatype || PixelDatatype.UNSIGNED_BYTE); var preMultiplyAlpha = +(description.preMultiplyAlpha || pixelFormat === PixelFormat.RGB || pixelFormat === PixelFormat.LUMINANCE); var textureTypeKey = JSON.stringify([width, height, pixelFormat, pixelDatatype, preMultiplyAlpha]); var freeList = this._free[textureTypeKey]; if (defined(freeList) && freeList.length > 0) { var texture = freeList.pop(); if (defined(source)) { texture.copyFrom(source); } return texture; } return createPooledTexture(context.createTexture2D(description), textureTypeKey, this); }; /** * Returns true if this object was destroyed; otherwise, false. * <br /><br /> * 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. * * @memberof TexturePool * * @returns {Boolean} True if this object was destroyed; otherwise, false. * * @see TexturePool#destroy */ TexturePool.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. * <br /><br /> * 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. * * @memberof TexturePool * * @returns {undefined} * * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called. * * @see TexturePool#isDestroyed * * @example * pool = pool && pool.destroy(); */ TexturePool.prototype.destroy = function() { var free = this._free; Object.keys(free).forEach(function(textureTypeKey) { free[textureTypeKey].forEach(function(texture) { texture._texture.destroy(); }); }); return destroyObject(this); }; return TexturePool; });