From 811ca72104bbd5ef860924510c997249c18b3848 Mon Sep 17 00:00:00 2001 From: pandamicro Date: Tue, 9 May 2017 11:32:50 +0800 Subject: [PATCH] Use imagePool to reduce image memory usage in WebGL mode --- CCBoot.js | 55 ++++++++++++++----- .../labelttf/CCLabelTTFCanvasRenderCmd.js | 10 +++- cocos2d/core/platform/CCLoaders.js | 10 +++- cocos2d/core/textures/CCTexture2D.js | 4 +- cocos2d/core/textures/CCTextureCache.js | 9 +-- cocos2d/core/textures/TexturesWebGL.js | 11 ++-- 6 files changed, 67 insertions(+), 32 deletions(-) diff --git a/CCBoot.js b/CCBoot.js index a366001d74..cbd4628a78 100644 --- a/CCBoot.js +++ b/CCBoot.js @@ -583,6 +583,33 @@ cc.path = /** @lends cc.path# */{ * @see cc.loader */ +var imagePool = { + _pool: new Array(10), + _MAX: 10, + _smallImg: "data:image/gif;base64,R0lGODlhAQABAAAAACwAAAAAAQABAAA=", + + count: 0, + get: function () { + if (this.count > 0) { + this.count--; + var result = this._pool[this.count]; + this._pool[this.count] = null; + return result; + } + else { + return new Image(); + } + }, + put: function (img) { + var pool = this._pool; + if (img instanceof HTMLImageElement && this.count < this._MAX) { + img.src = this._smallImg; + pool[this.count] = img; + this.count++; + } + } +}; + /** * Singleton instance of cc.Loader. * @name cc.loader @@ -867,7 +894,7 @@ cc.loader = (function () { * @param {function} callback * @returns {Image} */ - loadImg: function (url, option, callback) { + loadImg: function (url, option, callback, img) { var opt = { isCrossOrigin: true }; @@ -876,30 +903,22 @@ cc.loader = (function () { else if (option !== undefined) callback = option; - var img = this.getRes(url); - if (img) { - callback && callback(null, img); - return img; - } - var queue = _queue[url]; if (queue) { queue.callbacks.push(callback); return queue.img; } - img = new Image(); + img = img || imagePool.get(); if (opt.isCrossOrigin && location.origin !== "file://") img.crossOrigin = "Anonymous"; + else + img.crossOrigin = null; var loadCallback = function () { this.removeEventListener('load', loadCallback, false); this.removeEventListener('error', errorCallback, false); - if (!_urlRegExp.test(url)) { - cc.loader.cache[url] = img; - } - var queue = _queue[url]; if (queue) { var callbacks = queue.callbacks; @@ -912,6 +931,10 @@ cc.loader = (function () { queue.img = null; delete _queue[url]; } + + if (cc._renderType === cc.game.RENDER_TYPE_WEBGL) { + imagePool.put(img); + } }; var self = this; @@ -919,10 +942,10 @@ cc.loader = (function () { this.removeEventListener('load', loadCallback, false); this.removeEventListener('error', errorCallback, false); - if (img.crossOrigin && img.crossOrigin.toLowerCase() === "anonymous") { + if (window.location.protocol !== 'https:' && img.crossOrigin && img.crossOrigin.toLowerCase() === "anonymous") { opt.isCrossOrigin = false; self.release(url); - cc.loader.loadImg(url, opt, callback); + cc.loader.loadImg(url, opt, callback, img); } else { var queue = _queue[url]; if (queue) { @@ -936,6 +959,10 @@ cc.loader = (function () { queue.img = null; delete _queue[url]; } + + if (cc._renderType === cc.game.RENDER_TYPE_WEBGL) { + imagePool.put(img); + } } }; diff --git a/cocos2d/core/labelttf/CCLabelTTFCanvasRenderCmd.js b/cocos2d/core/labelttf/CCLabelTTFCanvasRenderCmd.js index 51fb3888b4..d6d691265d 100644 --- a/cocos2d/core/labelttf/CCLabelTTFCanvasRenderCmd.js +++ b/cocos2d/core/labelttf/CCLabelTTFCanvasRenderCmd.js @@ -418,7 +418,10 @@ cc.LabelTTF._firsrEnglish = /^[a-zA-Z0-9ÄÖÜäöüßéèçàùêâîôû]/; if (node._string.length === 0) { locLabelCanvas.width = 1; locLabelCanvas.height = locContentSize.height || 1; - node._texture && node._texture.handleLoadedTexture(); + if (node._texture) { + node._texture._htmlElementObj = this._labelCanvas; + node._texture.handleLoadedTexture(); + } node.setTextureRect(cc.rect(0, 0, 1, locContentSize.height)); return true; } @@ -432,7 +435,10 @@ cc.LabelTTF._firsrEnglish = /^[a-zA-Z0-9ÄÖÜäöüßéèçàùêâîôû]/; if (flag) locContext.clearRect(0, 0, width, height); this._saveStatus(); this._drawTTFInCanvas(locContext); - node._texture && node._texture.handleLoadedTexture(); + if (node._texture) { + node._texture._htmlElementObj = this._labelCanvas; + node._texture.handleLoadedTexture(); + } node.setTextureRect(cc.rect(0, 0, width, height)); return true; }; diff --git a/cocos2d/core/platform/CCLoaders.js b/cocos2d/core/platform/CCLoaders.js index 69c8e9430f..9d91344a23 100644 --- a/cocos2d/core/platform/CCLoaders.js +++ b/cocos2d/core/platform/CCLoaders.js @@ -54,9 +54,13 @@ cc._imgLoader = { callback = function (err, img) { if (err) return cb(err); - cc.loader.cache[url] = img; - cc.textureCache.handleLoadedTexture(url); - cb(null, img); + + var tex = cc.textureCache.getTextureForKey(url) || new cc.Texture2D(); + tex.url = url; + tex.initWithElement(img); + tex.handleLoadedTexture(); + cc.textureCache.cacheImage(url, tex); + cb(null, tex); }; } cc.loader.loadImg(realUrl, callback); diff --git a/cocos2d/core/textures/CCTexture2D.js b/cocos2d/core/textures/CCTexture2D.js index cd0a9ff153..687a5e3929 100644 --- a/cocos2d/core/textures/CCTexture2D.js +++ b/cocos2d/core/textures/CCTexture2D.js @@ -192,9 +192,7 @@ cc.game.addEventListener(cc.game.EVENT_RENDERER_INITED, function () { var self = this; if (self._textureLoaded) return; if (!self._htmlElementObj) { - var img = cc.loader.getRes(self.url); - if (!img) return; - self.initWithElement(img); + return; } var locElement = self._htmlElementObj; diff --git a/cocos2d/core/textures/CCTextureCache.js b/cocos2d/core/textures/CCTextureCache.js index 2099565eb3..afd8af3e61 100644 --- a/cocos2d/core/textures/CCTextureCache.js +++ b/cocos2d/core/textures/CCTextureCache.js @@ -313,7 +313,7 @@ cc.game.addEventListener(cc.game.EVENT_RENDERER_INITED, function () { var _p = cc.textureCache; - _p.handleLoadedTexture = function (url) { + _p.handleLoadedTexture = function (url, img) { var locTexs = this._textures; //remove judge var tex = locTexs[url]; @@ -321,6 +321,7 @@ cc.game.addEventListener(cc.game.EVENT_RENDERER_INITED, function () { tex = locTexs[url] = new cc.Texture2D(); tex.url = url; } + tex.initWithElement(img); tex.handleLoadedTexture(); }; @@ -365,12 +366,12 @@ cc.game.addEventListener(cc.game.EVENT_RENDERER_INITED, function () { if (err) return cb && cb.call(target, err); + cc.textureCache.handleLoadedTexture(url, img); + var texResult = locTexs[url]; if (!cc.loader.cache[url]) { - cc.loader.cache[url] = img; + cc.loader.cache[url] = texResult; } - cc.textureCache.handleLoadedTexture(url); - var texResult = locTexs[url]; cb && cb.call(target, texResult); }); diff --git a/cocos2d/core/textures/TexturesWebGL.js b/cocos2d/core/textures/TexturesWebGL.js index bcec5bfb53..5d704e25df 100644 --- a/cocos2d/core/textures/TexturesWebGL.js +++ b/cocos2d/core/textures/TexturesWebGL.js @@ -457,11 +457,8 @@ cc._tmp.WebGLTexture2D = function () { // Not sure about this ! Some texture need to be updated even after loaded if (!cc.game._rendererInitialized) return; - if (!self._htmlElementObj) { - var img = cc.loader.getRes(self.url); - if (!img) return; - self.initWithElement(img); - } + if (!self._htmlElementObj) + return; if (!self._htmlElementObj.width || !self._htmlElementObj.height) return; @@ -498,6 +495,7 @@ cc._tmp.WebGLTexture2D = function () { self._hasPremultipliedAlpha = premultiplied; self._hasMipmaps = false; + self._htmlElementObj = null; //dispatch load event to listener. self.dispatchEvent("load"); @@ -854,7 +852,7 @@ cc._tmp.WebGLTextureAtlas = function () { cc._tmp.WebGLTextureCache = function () { var _p = cc.textureCache; - _p.handleLoadedTexture = function (url) { + _p.handleLoadedTexture = function (url, img) { var locTexs = this._textures, tex, ext; //remove judge(webgl) if (!cc.game._rendererInitialized) { @@ -865,6 +863,7 @@ cc._tmp.WebGLTextureCache = function () { tex = locTexs[url] = new cc.Texture2D(); tex.url = url; } + tex.initWithElement(img); ext = cc.path.extname(url); if (ext === ".png") { tex.handleLoadedTexture(true);