diff --git a/cocos2dx/include/CCTexture2D.h b/cocos2dx/include/CCTexture2D.h index 19d5c94a42..9c3be77873 100644 --- a/cocos2dx/include/CCTexture2D.h +++ b/cocos2dx/include/CCTexture2D.h @@ -49,10 +49,18 @@ typedef enum { kCCTexture2DPixelFormat_RGB565, //! 8-bit textures used as masks kCCTexture2DPixelFormat_A8, + //! 8-bit intensity texture + kCCTexture2DPixelFormat_I8, + //! 16-bit textures used as masks + kCCTexture2DPixelFormat_AI88, //! 16-bit textures: RGBA4444 kCCTexture2DPixelFormat_RGBA4444, //! 16-bit textures: RGB5A1 kCCTexture2DPixelFormat_RGB5A1, + //! 4-bit PVRTC-compressed texture: PVRTC4 + kCCTexture2DPixelFormat_PVRTC4, + //! 2-bit PVRTC-compressed texture: PVRTC2 + kCCTexture2DPixelFormat_PVRTC2, //! Default texture format: RGBA8888 kCCTexture2DPixelFormat_Default = kCCTexture2DPixelFormat_RGBA8888, @@ -189,6 +197,11 @@ public: */ void generateMipmap(); + /** returns the bits-per-pixel of the in-memory OpenGL texture + @since v1.0 + */ + int bitsPerPixelForFormat(); + /** sets the default pixel format for UIImages that contains alpha channel. If the UIImage contains alpha channel, then the options are: diff --git a/cocos2dx/include/CCTextureAtlas.h b/cocos2dx/include/CCTextureAtlas.h index 869930562e..c8ca7353fa 100644 --- a/cocos2dx/include/CCTextureAtlas.h +++ b/cocos2dx/include/CCTextureAtlas.h @@ -1,6 +1,7 @@ /**************************************************************************** Copyright (c) 2010-2011 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada +Copyright (c) 2011 Zynga Inc. http://www.cocos2d-x.org @@ -52,6 +53,7 @@ protected: GLushort *m_pIndices; #if CC_USES_VBO GLuint m_pBuffersVBO[2]; //0: vertex 1: indices + bool m_bDirty; //indicates whether or not the array buffer of the VBO needs to be updated #endif // CC_USES_VBO /** quantity of quads that are going to be drawn */ @@ -128,7 +130,7 @@ public: void removeAllQuads(); - /** resize the capacity of the Texture Atlas. + /** resize the capacity of the CCTextureAtlas. * The new capacity can be lower or higher than the current one * It returns YES if the resize was successful. * If it fails to resize the capacity it will return NO with a new capacity of 0. diff --git a/cocos2dx/include/CCTextureCache.h b/cocos2dx/include/CCTextureCache.h index 3ca010b90f..3cc7d78626 100644 --- a/cocos2dx/include/CCTextureCache.h +++ b/cocos2dx/include/CCTextureCache.h @@ -1,6 +1,7 @@ /**************************************************************************** Copyright (c) 2010-2011 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada +Copyright (c) 2011 Zynga Inc. http://www.cocos2d-x.org @@ -134,6 +135,13 @@ public: */ void removeTextureForKey(const char *textureKeyName); + /** Output to CCLOG the current contents of this CCTextureCache + * This will attempt to calculate the size of each texture, and the total texture memory in use + * + * @since v1.0 + */ + void dumpCachedTextureInfo(); + #if _POWERVR_SUPPORT_ /** Returns a Texture2D object given an PVRTC RAW filename * If the file image was not previously loaded, it will create a new CCTexture2D diff --git a/cocos2dx/textures/CCTexture2D.cpp b/cocos2dx/textures/CCTexture2D.cpp index cb631674ab..ead88c92e7 100644 --- a/cocos2dx/textures/CCTexture2D.cpp +++ b/cocos2dx/textures/CCTexture2D.cpp @@ -167,22 +167,25 @@ bool CCTexture2D::initWithData(const void *data, CCTexture2DPixelFormat pixelFor switch(pixelFormat) { case kCCTexture2DPixelFormat_RGBA8888: - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pixelsWide, pixelsHigh, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); break; case kCCTexture2DPixelFormat_RGB888: - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, pixelsWide, pixelsHigh, 0, GL_RGB, GL_UNSIGNED_BYTE, data); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGB, GL_UNSIGNED_BYTE, data); break; case kCCTexture2DPixelFormat_RGBA4444: - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pixelsWide, pixelsHigh, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data); break; case kCCTexture2DPixelFormat_RGB5A1: - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pixelsWide, pixelsHigh, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, data); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, data); break; case kCCTexture2DPixelFormat_RGB565: - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, pixelsWide, pixelsHigh, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data); + break; + case kCCTexture2DPixelFormat_AI88: + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, data); break; case kCCTexture2DPixelFormat_A8: - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, pixelsWide, pixelsHigh, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data); + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data); break; default:; CCAssert(0, "NSInternalInconsistencyException"); @@ -629,4 +632,46 @@ CCTexture2DPixelFormat CCTexture2D::defaultAlphaPixelFormat() return g_defaultAlphaPixelFormat; } +int CCTexture2D::bitsPerPixelForFormat() +{ + int ret= -1; + + switch (m_ePixelFormat) + { + case kCCTexture2DPixelFormat_RGBA8888: + ret = 32; + break; + case kCCTexture2DPixelFormat_RGB565: + ret = 16; + break; + case kCCTexture2DPixelFormat_A8: + ret = 8; + break; + case kCCTexture2DPixelFormat_RGBA4444: + ret = 16; + break; + case kCCTexture2DPixelFormat_RGB5A1: + ret = 16; + break; + case kCCTexture2DPixelFormat_PVRTC4: + ret = 4; + break; + case kCCTexture2DPixelFormat_PVRTC2: + ret = 2; + break; + case kCCTexture2DPixelFormat_I8: + ret = 8; + break; + case kCCTexture2DPixelFormat_AI88: + ret = 16; + break; + default: + ret = -1; + assert(false); + CCLOG("bitsPerPixelForFormat: %d, cannot give useful result", m_ePixelFormat); + break; + } + return ret; +} + }//namespace cocos2d diff --git a/cocos2dx/textures/CCTextureAtlas.cpp b/cocos2dx/textures/CCTextureAtlas.cpp index cae335e700..d5534357b5 100644 --- a/cocos2dx/textures/CCTextureAtlas.cpp +++ b/cocos2dx/textures/CCTextureAtlas.cpp @@ -1,6 +1,7 @@ /**************************************************************************** Copyright (c) 2010-2011 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada +Copyright (c) 2011 Zynga Inc. http://www.cocos2d-x.org @@ -145,6 +146,9 @@ bool CCTextureAtlas::initWithTexture(CCTexture2D *texture, unsigned int capacity this->m_pTexture = texture; CC_SAFE_RETAIN(m_pTexture); + // Re-initialization is not allowed + assert(m_pQuads == NULL && m_pIndices == NULL); + m_pQuads = (ccV3F_C4B_T2F_Quad*)calloc( sizeof(ccV3F_C4B_T2F_Quad) * m_uCapacity, 1 ); m_pIndices = (GLushort *)calloc( sizeof(GLushort) * m_uCapacity * 6, 1 ); @@ -161,7 +165,8 @@ bool CCTextureAtlas::initWithTexture(CCTexture2D *texture, unsigned int capacity #if CC_USES_VBO // initial binding - glGenBuffers(2, &m_pBuffersVBO[0]); + glGenBuffers(2, &m_pBuffersVBO[0]); + m_bDirty = true; #endif // CC_USES_VBO this->initIndices(); @@ -222,6 +227,10 @@ void CCTextureAtlas::updateQuad(ccV3F_C4B_T2F_Quad *quad, unsigned int index) m_uTotalQuads = max( index+1, m_uTotalQuads); m_pQuads[index] = *quad; + +#if CC_USES_VBO + m_bDirty = true; +#endif } void CCTextureAtlas::insertQuad(ccV3F_C4B_T2F_Quad *quad, unsigned int index) @@ -241,6 +250,10 @@ void CCTextureAtlas::insertQuad(ccV3F_C4B_T2F_Quad *quad, unsigned int index) } m_pQuads[index] = *quad; + +#if CC_USES_VBO + m_bDirty = true; +#endif } void CCTextureAtlas::insertQuadFromIndex(unsigned int oldIndex, unsigned int newIndex) @@ -265,6 +278,10 @@ void CCTextureAtlas::insertQuadFromIndex(unsigned int oldIndex, unsigned int new ccV3F_C4B_T2F_Quad quadsBackup = m_pQuads[oldIndex]; memmove( &m_pQuads[dst],&m_pQuads[src], sizeof(m_pQuads[0]) * howMany ); m_pQuads[newIndex] = quadsBackup; + +#if CC_USES_VBO + m_bDirty = true; +#endif } void CCTextureAtlas::removeQuadAtIndex(unsigned int index) @@ -281,6 +298,10 @@ void CCTextureAtlas::removeQuadAtIndex(unsigned int index) } m_uTotalQuads--; + +#if CC_USES_VBO + m_bDirty = true; +#endif } void CCTextureAtlas::removeAllQuads() @@ -324,6 +345,10 @@ bool CCTextureAtlas::resizeCapacity(unsigned int newCapacity) this->initIndices(); +#if CC_USES_VBO + m_bDirty = true; +#endif + return true; } @@ -331,10 +356,15 @@ bool CCTextureAtlas::resizeCapacity(unsigned int newCapacity) void CCTextureAtlas::drawQuads() { - this->drawNumberOfQuads(m_uTotalQuads); + this->drawNumberOfQuads(m_uTotalQuads, 0); } void CCTextureAtlas::drawNumberOfQuads(unsigned int n) +{ + this->drawNumberOfQuads(m_uTotalQuads, 0); +} + +void CCTextureAtlas::drawNumberOfQuads(unsigned int n, unsigned int start) { // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY // Needed states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY @@ -354,7 +384,12 @@ void CCTextureAtlas::drawNumberOfQuads(unsigned int n) #endif // XXX: update is done in draw... perhaps it should be done in a timer - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(m_pQuads[0]) * n, m_pQuads); + if (m_bDirty) + { + glBufferSubData(GL_ARRAY_BUFFER, sizeof(m_pQuads[0]) * start, sizeof(m_pQuads[0]) * n, &m_pQuads[start]); + m_bDirty = false; + } + // vertices glVertexPointer(3, GL_FLOAT, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, vertices)); @@ -372,9 +407,9 @@ void CCTextureAtlas::drawNumberOfQuads(unsigned int n) #endif #if CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP - glDrawElements(GL_TRIANGLE_STRIP, n*6, GL_UNSIGNED_SHORT, (GLvoid*)0); + glDrawElements(GL_TRIANGLE_STRIP, (GLsizei)n*6, GL_UNSIGNED_SHORT, (GLvoid*)(start * 6 * sizeof(m_pIndices[0]))); #else - glDrawElements(GL_TRIANGLES, n*6, GL_UNSIGNED_SHORT, (GLvoid*)0); + glDrawElements(GL_TRIANGLES, (GLsizei)n*6, GL_UNSIGNED_SHORT, (GLvoid*)(start * 6 * sizeof(m_pIndices[0]))); #endif // CC_USES_VBO glBindBuffer(GL_ARRAY_BUFFER, 0); @@ -397,18 +432,13 @@ void CCTextureAtlas::drawNumberOfQuads(unsigned int n) glTexCoordPointer(2, GL_FLOAT, kQuadSize, (GLvoid*)(offset + diff)); #if CC_TEXTURE_ATLAS_USE_TRIANGLE_STRIP - glDrawElements(GL_TRIANGLE_STRIP, n*6, GL_UNSIGNED_SHORT, m_pIndices); + glDrawElements(GL_TRIANGLE_STRIP, n*6, GL_UNSIGNED_SHORT, m_pIndices + start * 6); #else - glDrawElements(GL_TRIANGLES, n*6, GL_UNSIGNED_SHORT, m_pIndices); + glDrawElements(GL_TRIANGLES, n*6, GL_UNSIGNED_SHORT, m_pIndices + start * 6); #endif #endif // CC_USES_VBO } -void CCTextureAtlas::drawNumberOfQuads(unsigned int n, unsigned int start) -{ - -} - }//namespace cocos2d diff --git a/cocos2dx/textures/CCTextureCache.cpp b/cocos2dx/textures/CCTextureCache.cpp index 316405ed17..d2010b4fd0 100644 --- a/cocos2dx/textures/CCTextureCache.cpp +++ b/cocos2dx/textures/CCTextureCache.cpp @@ -1,6 +1,7 @@ /**************************************************************************** Copyright (c) 2010-2011 cocos2d-x.org Copyright (c) 2008-2010 Ricardo Quesada +Copyright (c) 2011 Zynga Inc. http://www.cocos2d-x.org @@ -77,7 +78,7 @@ CCTextureCache::CCTextureCache() CCTextureCache::~CCTextureCache() { - CCLOG("cocos2d: deallocing CCTextureCache."); + CCLOGINFO("cocos2d: deallocing CCTextureCache."); CC_SAFE_RELEASE(m_pTextures); CC_SAFE_DELETE(m_pDictLock); @@ -225,7 +226,8 @@ CCTexture2D * CCTextureCache::addImage(const char * path) #endif m_pTextures->setObject(texture, pathKey); - texture->release(); + // autorelease prevents possible crash in multithreaded environments + texture->autorelease(); } else { @@ -252,7 +254,8 @@ CCTexture2D * CCTextureCache::addImage(const char * path) #endif m_pTextures->setObject(texture, pathKey); - texture->release(); + // autorelease prevents possible crash in multithreaded environments + texture->autorelease(); } else { @@ -447,6 +450,34 @@ void CCTextureCache::reloadAllTextures() #endif } +void CCTextureCache::dumpCachedTextureInfo() +{ + unsigned int count = 0; + unsigned int totalBytes = 0; + + vector keys = m_pTextures->allKeys(); + vector::iterator iter; + for (iter = keys.begin(); iter != keys.end(); iter++) + { + CCTexture2D *tex = m_pTextures->objectForKey(*iter); + unsigned int bpp = tex->bitsPerPixelForFormat(); + // Each texture takes up width * height * bytesPerPixel bytes. + unsigned int bytes = tex->getPixelsWide() * tex->getPixelsHigh() * bpp / 8; + totalBytes += bytes; + count++; + CCLOG("cocos2d: \"%s\" rc=%lu id=%lu %lu x %lu @ %ld bpp => %lu KB", + (*iter).c_str(), + (long)tex->retainCount(), + (long)tex->getName(), + (long)tex->getPixelsWide(), + (long)tex->getPixelsHigh(), + (long)bpp, + (long)bytes / 1024); + } + + CCLOG("cocos2d: CCTextureCache dumpDebugInfo: %ld textures, for %lu KB (%.2f MB)", (long)count, (long)totalBytes / 1024, totalBytes / (1024.0f*1024.0f)); +} + #if CC_ENABLE_CACHE_TEXTTURE_DATA std::list VolatileTexture::textures;