From f9f0c5c70432f694b2cd3c55f96d18953d4dd516 Mon Sep 17 00:00:00 2001 From: Kearwood Gilbert Date: Mon, 13 May 2013 18:44:58 -0700 Subject: [PATCH] Texture streaming has improved performance by taking advantage of the APPLE_copy_texture_levels and EXT_texture_storage extensions. --- KREngine/kraken/KREngine.mm | 2 +- KREngine/kraken/KRTexture.cpp | 3 - KREngine/kraken/KRTexture2D.cpp | 52 ++++++++++++----- KREngine/kraken/KRTexture2D.h | 2 +- KREngine/kraken/KRTextureCube.cpp | 4 +- KREngine/kraken/KRTexturePVR.cpp | 92 ++++++++++++++++++++++++++----- KREngine/kraken/KRTexturePVR.h | 2 +- KREngine/kraken/KRTextureTGA.cpp | 4 +- KREngine/kraken/KRTextureTGA.h | 2 +- 9 files changed, 125 insertions(+), 38 deletions(-) diff --git a/KREngine/kraken/KREngine.mm b/KREngine/kraken/KREngine.mm index 999fbd9..d772443 100644 --- a/KREngine/kraken/KREngine.mm +++ b/KREngine/kraken/KREngine.mm @@ -90,7 +90,7 @@ void kraken::set_parameter(const std::string ¶meter_name, float parameter_va KRContext::KRENGINE_MAX_TEXTURE_DIM = 2048; KRContext::KRENGINE_MIN_TEXTURE_DIM = 64; - KRContext::KRENGINE_MAX_TEXTURE_THROUGHPUT = 32000000; + KRContext::KRENGINE_MAX_TEXTURE_THROUGHPUT = 4000000; KRContext::KRENGINE_MAX_VBO_MEM = total_ram * 2 / 4; diff --git a/KREngine/kraken/KRTexture.cpp b/KREngine/kraken/KRTexture.cpp index 95b30ab..24aee65 100644 --- a/KREngine/kraken/KRTexture.cpp +++ b/KREngine/kraken/KRTexture.cpp @@ -66,9 +66,6 @@ void KRTexture::resize(int max_dim) } if(m_current_lod_max_dim != target_dim || m_iHandle == 0) { - releaseHandle(); - } - if(m_iHandle == 0) { if(!createGLTexture(target_dim)) { assert(false); } diff --git a/KREngine/kraken/KRTexture2D.cpp b/KREngine/kraken/KRTexture2D.cpp index 549e0be..61b75a4 100644 --- a/KREngine/kraken/KRTexture2D.cpp +++ b/KREngine/kraken/KRTexture2D.cpp @@ -43,28 +43,52 @@ KRTexture2D::~KRTexture2D() { } bool KRTexture2D::createGLTexture(int lod_max_dim) { + bool success = true; + GLuint prev_handle = 0; + int prev_lod_max_dim = 0; + long prev_mem_size = 0; +#if GL_APPLE_copy_texture_levels && GL_EXT_texture_storage + + if(m_iHandle != 0) { + prev_handle = m_iHandle; + prev_mem_size = getMemSize(); + m_iHandle = 0; + m_textureMemUsed = 0; + prev_lod_max_dim = m_current_lod_max_dim; + } + + +#else + releaseHandle(); +#endif m_current_lod_max_dim = 0; GLDEBUG(glGenTextures(1, &m_iHandle)); + if(m_iHandle == 0) { - return false; - } - - GLDEBUG(glBindTexture(GL_TEXTURE_2D, m_iHandle)); - if (hasMipmaps()) { - GLDEBUG(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)); + success = false; } else { - GLDEBUG(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - } + + GLDEBUG(glBindTexture(GL_TEXTURE_2D, m_iHandle)); + if (hasMipmaps()) { + GLDEBUG(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)); + } else { + GLDEBUG(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + } - if(!uploadTexture(GL_TEXTURE_2D, lod_max_dim, m_current_lod_max_dim, m_textureMemUsed)) { - GLDEBUG(glDeleteTextures(1, &m_iHandle)); - m_iHandle = 0; - m_current_lod_max_dim = 0; - return false; + if(!uploadTexture(GL_TEXTURE_2D, lod_max_dim, m_current_lod_max_dim, m_textureMemUsed, prev_lod_max_dim, prev_handle)) { + GLDEBUG(glDeleteTextures(1, &m_iHandle)); + m_iHandle = 0; + m_current_lod_max_dim = 0; + success = false; + } } + if(prev_handle != 0) { + getContext().getTextureManager()->memoryChanged(-prev_mem_size); + GLDEBUG(glDeleteTextures(1, &prev_handle)); + } - return true; + return success; } void KRTexture2D::bind(GLuint texture_unit) { diff --git a/KREngine/kraken/KRTexture2D.h b/KREngine/kraken/KRTexture2D.h index d6421b7..f3e8684 100644 --- a/KREngine/kraken/KRTexture2D.h +++ b/KREngine/kraken/KRTexture2D.h @@ -46,7 +46,7 @@ public: virtual bool save(const std::string& path); virtual bool save(KRDataBlock &data); - virtual bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, long &textureMemUsed) = 0; + virtual bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, long &textureMemUsed, int prev_lod_max_dim, GLuint prev_handle) = 0; virtual void bind(GLuint texture_unit); protected: diff --git a/KREngine/kraken/KRTextureCube.cpp b/KREngine/kraken/KRTextureCube.cpp index 100167c..b7e9e43 100644 --- a/KREngine/kraken/KRTextureCube.cpp +++ b/KREngine/kraken/KRTextureCube.cpp @@ -55,6 +55,8 @@ KRTextureCube::~KRTextureCube() bool KRTextureCube::createGLTexture(int lod_max_dim) { + releaseHandle(); + m_current_lod_max_dim = 0; GLDEBUG(glGenTextures(1, &m_iHandle)); if(m_iHandle == 0) { @@ -70,7 +72,7 @@ bool KRTextureCube::createGLTexture(int lod_max_dim) KRTexture2D *faceTexture = (KRTexture2D *)getContext().getTextureManager()->getTexture(faceName); if(faceTexture) { if(faceTexture->hasMipmaps()) bMipMaps = true; - faceTexture->uploadTexture(TARGETS[i], lod_max_dim, m_current_lod_max_dim, m_textureMemUsed); + faceTexture->uploadTexture(TARGETS[i], lod_max_dim, m_current_lod_max_dim, m_textureMemUsed, 0, 0); } } diff --git a/KREngine/kraken/KRTexturePVR.cpp b/KREngine/kraken/KRTexturePVR.cpp index 70a5004..67a5897 100644 --- a/KREngine/kraken/KRTexturePVR.cpp +++ b/KREngine/kraken/KRTexturePVR.cpp @@ -171,7 +171,7 @@ long KRTexturePVR::getMemRequiredForSize(int max_dim) return memoryRequired; } -bool KRTexturePVR::uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, long &textureMemUsed) +bool KRTexturePVR::uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, long &textureMemUsed, int prev_lod_max_dim, GLuint prev_handle) { int target_dim = lod_max_dim; if(target_dim < m_min_lod_max_dim) target_dim = m_min_lod_max_dim; @@ -186,29 +186,93 @@ bool KRTexturePVR::uploadTexture(GLenum target, int lod_max_dim, int ¤t_lo int width = m_iWidth; int height = m_iHeight; long memoryRequired = 0; + long memoryTransferred = 0; - // Upload texture data - int i=0; +#if GL_EXT_texture_storage + //void TexStorage2DEXT(enum target, sizei levels, enum internalformat, sizei width, sizei height); + //TexStorage2DEXT(target, ) + + int level_count=0; + int max_lod_width=0; + int max_lod_height=0; for(std::list::iterator itr = m_blocks.begin(); itr != m_blocks.end(); itr++) { - dataBlockStruct block = *itr; if(width <= target_dim && height <= target_dim) { - memoryRequired += block.length; + if(max_lod_width == 0) { + max_lod_width = width; + max_lod_height = height; + } if(width > current_lod_max_dim) { current_lod_max_dim = width; } if(height > current_lod_max_dim) { current_lod_max_dim = height; } - glCompressedTexImage2D(target, i, m_internalFormat, width, height, 0, block.length, block.start); - err = glGetError(); - if (err != GL_NO_ERROR) { - assert(false); - return false; + + level_count++; + } + + width = width >> 1; + if(width < 1) { + width = 1; + } + height = height >> 1; + if(height < 1) { + height = 1; + } + } + width = m_iWidth; + height = m_iHeight; + + glTexStorage2DEXT(target, level_count, m_internalFormat, max_lod_width, max_lod_height); +#endif + + // Upload texture data + int destination_level=0; + int source_level = 0; + for(std::list::iterator itr = m_blocks.begin(); itr != m_blocks.end(); itr++) { + dataBlockStruct block = *itr; + if(width <= target_dim && height <= target_dim) { + + if(width > current_lod_max_dim) { + current_lod_max_dim = width; } + if(height > current_lod_max_dim) { + current_lod_max_dim = height; + } +#if GL_APPLE_copy_texture_levels && GL_EXT_texture_storage + if(target == GL_TEXTURE_2D && width <= prev_lod_max_dim && height <= prev_lod_max_dim) { + //GLDEBUG(glCompressedTexImage2D(target, i, m_internalFormat, width, height, 0, block.length, NULL)); // Allocate, but don't copy +// GLDEBUG(glTexImage2D(target, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL)); + GLDEBUG(glCopyTextureLevelsAPPLE(m_iHandle, prev_handle, source_level, 1)); + } else { + // glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data); + GLDEBUG(glCompressedTexSubImage2D(target, destination_level, 0, 0, width, height, m_internalFormat, block.length, block.start)); +// GLDEBUG(glCompressedTexImage2D(target, destination_level, m_internalFormat, width, height, 0, block.length, block.start)); + memoryTransferred += block.length; // memoryTransferred does not include throughput of mipmap levels copied through glCopyTextureLevelsAPPLE + } +#else + #if GL_EXT_texture_storage + GLDEBUG(glCompressedTexSubImage2D(target, destination_level, 0, 0, width, height, m_internalFormat, block.length, block.start)); + #else + GLDEBUG(glCompressedTexImage2D(target, destination_level, m_internalFormat, width, height, 0, block.length, block.start)); + #endif + memoryTransferred += block.length; // memoryTransferred does not include throughput of mipmap levels copied through glCopyTextureLevelsAPPLE +#endif + memoryRequired += block.length; +// +// err = glGetError(); +// if (err != GL_NO_ERROR) { +// assert(false); +// return false; +// } +// - - i++; + destination_level++; + } + + if(width <= prev_lod_max_dim && height <= prev_lod_max_dim) { + source_level++; } width = width >> 1; @@ -222,8 +286,8 @@ bool KRTexturePVR::uploadTexture(GLenum target, int lod_max_dim, int ¤t_lo } textureMemUsed += memoryRequired; - getContext().getTextureManager()->memoryChanged(memoryRequired); - getContext().getTextureManager()->addMemoryTransferredThisFrame(memoryRequired); + getContext().getTextureManager()->memoryChanged(memoryTransferred); + getContext().getTextureManager()->addMemoryTransferredThisFrame(memoryTransferred); return true; diff --git a/KREngine/kraken/KRTexturePVR.h b/KREngine/kraken/KRTexturePVR.h index b6eddb8..db7f9c7 100644 --- a/KREngine/kraken/KRTexturePVR.h +++ b/KREngine/kraken/KRTexturePVR.h @@ -18,7 +18,7 @@ public: virtual ~KRTexturePVR(); virtual std::string getExtension(); - bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, long &textureMemUsed); + bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, long &textureMemUsed, int prev_lod_max_dim, GLuint prev_handle); virtual long getMemRequiredForSize(int max_dim); diff --git a/KREngine/kraken/KRTextureTGA.cpp b/KREngine/kraken/KRTextureTGA.cpp index fc2c0e5..5c6bb71 100644 --- a/KREngine/kraken/KRTextureTGA.cpp +++ b/KREngine/kraken/KRTextureTGA.cpp @@ -39,8 +39,8 @@ KRTextureTGA::~KRTextureTGA() } -bool KRTextureTGA::uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, long &textureMemUsed) -{ +bool KRTextureTGA::uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, long &textureMemUsed, int prev_lod_max_dim, GLuint prev_handle) +{ TGA_HEADER *pHeader = (TGA_HEADER *)m_pData->getStart(); unsigned char *pData = (unsigned char *)pHeader + (long)pHeader->idlength + (long)pHeader->colourmaplength * (long)pHeader->colourmaptype + sizeof(TGA_HEADER); diff --git a/KREngine/kraken/KRTextureTGA.h b/KREngine/kraken/KRTextureTGA.h index d31508b..458ca3a 100644 --- a/KREngine/kraken/KRTextureTGA.h +++ b/KREngine/kraken/KRTextureTGA.h @@ -18,7 +18,7 @@ public: virtual ~KRTextureTGA(); virtual std::string getExtension(); - bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, long &textureMemUsed); + bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, long &textureMemUsed, int prev_lod_max_dim, GLuint prev_handle); virtual long getMemRequiredForSize(int max_dim); };