diff --git a/KREngine/kraken/KRAnimation.cpp b/KREngine/kraken/KRAnimation.cpp index f5db97b..d8ef8de 100644 --- a/KREngine/kraken/KRAnimation.cpp +++ b/KREngine/kraken/KRAnimation.cpp @@ -297,3 +297,31 @@ void KRAnimation::deleteCurves() } } +void KRAnimation::_lockData() +{ + for(unordered_map::iterator layer_itr = m_layers.begin(); layer_itr != m_layers.end(); layer_itr++) { + KRAnimationLayer *layer = (*layer_itr).second; + for(std::vector::iterator attribute_itr = layer->getAttributes().begin(); attribute_itr != layer->getAttributes().end(); attribute_itr++) { + KRAnimationAttribute *attribute = *attribute_itr; + KRAnimationCurve *curve = attribute->getCurve(); + if(curve) { + curve->_lockData(); + } + } + } +} + +void KRAnimation::_unlockData() +{ + for(unordered_map::iterator layer_itr = m_layers.begin(); layer_itr != m_layers.end(); layer_itr++) { + KRAnimationLayer *layer = (*layer_itr).second; + for(std::vector::iterator attribute_itr = layer->getAttributes().begin(); attribute_itr != layer->getAttributes().end(); attribute_itr++) { + KRAnimationAttribute *attribute = *attribute_itr; + KRAnimationCurve *curve = attribute->getCurve(); + if(curve) { + curve->_unlockData(); + } + } + } +} + diff --git a/KREngine/kraken/KRAnimation.h b/KREngine/kraken/KRAnimation.h index a052177..2c731ea 100644 --- a/KREngine/kraken/KRAnimation.h +++ b/KREngine/kraken/KRAnimation.h @@ -71,6 +71,9 @@ public: KRAnimation *split(const std::string &name, float start_time, float duration, bool strip_unchanging_attributes = true, bool clone_curves = true); void deleteCurves(); + void _lockData(); + void _unlockData(); + private: unordered_map m_layers; bool m_auto_play; diff --git a/KREngine/kraken/KRAnimationCurve.cpp b/KREngine/kraken/KRAnimationCurve.cpp index a99138e..366ae26 100644 --- a/KREngine/kraken/KRAnimationCurve.cpp +++ b/KREngine/kraken/KRAnimationCurve.cpp @@ -228,3 +228,13 @@ KRAnimationCurve *KRAnimationCurve::split(const std::string &name, int start_fra getContext().getAnimationCurveManager()->addAnimationCurve(new_curve); return new_curve; } + +void KRAnimationCurve::_lockData() +{ + m_pData->lock(); +} + +void KRAnimationCurve::_unlockData() +{ + m_pData->unlock(); +} diff --git a/KREngine/kraken/KRAnimationCurve.h b/KREngine/kraken/KRAnimationCurve.h index ff5309c..2a2beda 100644 --- a/KREngine/kraken/KRAnimationCurve.h +++ b/KREngine/kraken/KRAnimationCurve.h @@ -67,6 +67,9 @@ public: KRAnimationCurve *split(const std::string &name, float start_time, float duration); KRAnimationCurve *split(const std::string &name, int start_frame, int frame_count); + void _lockData(); + void _unlockData(); + private: KRDataBlock *m_pData; diff --git a/KREngine/kraken/KRAnimationManager.cpp b/KREngine/kraken/KRAnimationManager.cpp index 76224e7..40e3667 100644 --- a/KREngine/kraken/KRAnimationManager.cpp +++ b/KREngine/kraken/KRAnimationManager.cpp @@ -38,6 +38,11 @@ KRAnimationManager::KRAnimationManager(KRContext &context) : KRContextObject(con } KRAnimationManager::~KRAnimationManager() { + for(std::set::iterator itr = m_activeAnimations.begin(); itr != m_activeAnimations.end(); itr++) { + KRAnimation *animation = *itr; + animation->_unlockData(); + } + for(unordered_map::iterator itr = m_animations.begin(); itr != m_animations.end(); ++itr){ delete (*itr).second; } @@ -52,11 +57,13 @@ void KRAnimationManager::startFrame(float deltaTime) // Add playing animations to the active animations list if(active_animations_itr == m_activeAnimations.end()) { m_activeAnimations.insert(animation); + animation->_lockData(); } } else { // Remove stopped animations from the active animations list if(active_animations_itr != m_activeAnimations.end()) { m_activeAnimations.erase(active_animations_itr); + animation->_unlockData(); } } } diff --git a/KREngine/kraken/KRContext.cpp b/KREngine/kraken/KRContext.cpp index ffa113a..fa4d2b9 100644 --- a/KREngine/kraken/KRContext.cpp +++ b/KREngine/kraken/KRContext.cpp @@ -17,7 +17,6 @@ int KRContext::KRENGINE_MAX_SHADER_HANDLES; int KRContext::KRENGINE_MAX_TEXTURE_HANDLES; int KRContext::KRENGINE_MAX_TEXTURE_MEM; int KRContext::KRENGINE_TARGET_TEXTURE_MEM_MAX; -int KRContext::KRENGINE_TARGET_TEXTURE_MEM_MIN; int KRContext::KRENGINE_MAX_TEXTURE_DIM; int KRContext::KRENGINE_MIN_TEXTURE_DIM; int KRContext::KRENGINE_MAX_TEXTURE_THROUGHPUT; @@ -281,3 +280,26 @@ void KRContext::setStreamingEnabled(bool enable) { m_streamingEnabled = enable; } + +void KRContext::getMemoryStats(long &free_memory) +{ + free_memory = 0; +#if TARGET_OS_IPHONE + mach_port_t host_port = mach_host_self(); + mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t); + vm_size_t pagesize = 0; + vm_statistics_data_t vm_stat; + int total_ram = 256 * 1024 * 1024; + if(host_page_size(host_port, &pagesize) != KERN_SUCCESS) { + fprintf(stderr, "ERROR: Could not get VM page size.\n"); + } else if(host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size) != KERN_SUCCESS) { + fprintf(stderr, "ERROR: Could not get VM stats.\n"); + } else { + total_ram = (vm_stat.wire_count + vm_stat.active_count + vm_stat.inactive_count + vm_stat.free_count) * pagesize; + + free_memory = vm_stat.free_count * pagesize; + } +#else +#error Unsupported Platform +#endif +} diff --git a/KREngine/kraken/KRContext.h b/KREngine/kraken/KRContext.h index 824afbd..c75f846 100644 --- a/KREngine/kraken/KRContext.h +++ b/KREngine/kraken/KRContext.h @@ -29,7 +29,6 @@ public: static int KRENGINE_MAX_TEXTURE_HANDLES; static int KRENGINE_MAX_TEXTURE_MEM; static int KRENGINE_TARGET_TEXTURE_MEM_MAX; - static int KRENGINE_TARGET_TEXTURE_MEM_MIN; static int KRENGINE_MAX_TEXTURE_DIM; static int KRENGINE_MIN_TEXTURE_DIM; static int KRENGINE_MAX_TEXTURE_THROUGHPUT; @@ -76,6 +75,8 @@ public: bool getStreamingEnabled(); void setStreamingEnabled(bool enable); + void getMemoryStats(long &free_memory); + private: KRBundleManager *m_pBundleManager; KRSceneManager *m_pSceneManager; diff --git a/KREngine/kraken/KRDataBlock.cpp b/KREngine/kraken/KRDataBlock.cpp index 7331f70..fe7d522 100644 --- a/KREngine/kraken/KRDataBlock.cpp +++ b/KREngine/kraken/KRDataBlock.cpp @@ -146,6 +146,7 @@ KRDataBlock *KRDataBlock::getSubBlock(int start, int length) new_block->m_data = (unsigned char *)m_data + start + m_data_offset; } new_block->m_bReadOnly = true; + return new_block; } @@ -289,55 +290,58 @@ std::string KRDataBlock::getString() // Lock the memory, forcing it to be loaded into a contiguous block of address space void KRDataBlock::lock() { - - m_lockCount++; - - if(m_lockCount == 1) { + if(m_lockCount == 0) { // Memory mapped file; ensure data is mapped to ram if(m_fdPackFile) { - //fprintf(stderr, "KRDataBlock::lock - \"%s\" (%i)\n", m_fileOwnerDataBlock->m_fileName.c_str(), m_lockCount); - - // Round m_data_offset down to the next memory page, as required by mmap - size_t alignment_offset = m_data_offset & (KRAKEN_MEM_PAGE_SIZE - 1); - if ((m_mmapData = mmap(0, m_data_size + alignment_offset, m_bReadOnly ? PROT_READ : PROT_WRITE, MAP_SHARED, m_fdPackFile, m_data_offset - alignment_offset)) == (caddr_t) -1) { - int iError = errno; - switch(iError) { - case EACCES: - fprintf(stderr, "mmap failed with EACCES\n"); - break; - case EBADF: - fprintf(stderr, "mmap failed with EBADF\n"); - break; - case EMFILE: - fprintf(stderr, "mmap failed with EMFILE\n"); - break; - case EINVAL: - fprintf(stderr, "mmap failed with EINVAL\n"); - break; - case ENOMEM: - fprintf(stderr, "mmap failed with ENOMEM\n"); - break; - case ENXIO: - fprintf(stderr, "mmap failed with ENXIO\n"); - break; - case EOVERFLOW: - fprintf(stderr, "mmap failed with EOVERFLOW\n"); - break; - default: - fprintf(stderr, "mmap failed with errno: %i\n", iError); - break; + if(m_data_size < KRENGINE_MIN_MMAP) { + m_data = malloc(m_data_size); + assert(m_data != NULL); + copy(m_data); + } else { + //fprintf(stderr, "KRDataBlock::lock - \"%s\" (%i)\n", m_fileOwnerDataBlock->m_fileName.c_str(), m_lockCount); + + // Round m_data_offset down to the next memory page, as required by mmap + size_t alignment_offset = m_data_offset & (KRAKEN_MEM_PAGE_SIZE - 1); + if ((m_mmapData = mmap(0, m_data_size + alignment_offset, m_bReadOnly ? PROT_READ : PROT_WRITE, MAP_SHARED, m_fdPackFile, m_data_offset - alignment_offset)) == (caddr_t) -1) { + int iError = errno; + switch(iError) { + case EACCES: + fprintf(stderr, "mmap failed with EACCES\n"); + break; + case EBADF: + fprintf(stderr, "mmap failed with EBADF\n"); + break; + case EMFILE: + fprintf(stderr, "mmap failed with EMFILE\n"); + break; + case EINVAL: + fprintf(stderr, "mmap failed with EINVAL\n"); + break; + case ENOMEM: + fprintf(stderr, "mmap failed with ENOMEM\n"); + break; + case ENXIO: + fprintf(stderr, "mmap failed with ENXIO\n"); + break; + case EOVERFLOW: + fprintf(stderr, "mmap failed with EOVERFLOW\n"); + break; + default: + fprintf(stderr, "mmap failed with errno: %i\n", iError); + break; + } + assert(false); // mmap() failed. } - assert(false); // mmap() failed. + m_mapCount++; + m_mapSize += m_data_size; + m_mapOverhead += alignment_offset + KRAKEN_MEM_ROUND_UP_PAGE(m_data_size + alignment_offset) - m_data_size + alignment_offset; + fprintf(stderr, "Mapped: %i Size: %d Overhead: %d\n", m_mapCount, m_mapSize, m_mapOverhead); + m_data = (unsigned char *)m_mmapData + alignment_offset; } - m_mapCount++; - m_mapSize += m_data_size; - m_mapOverhead += alignment_offset + KRAKEN_MEM_ROUND_UP_PAGE(m_data_size + alignment_offset) - m_data_size + alignment_offset; - fprintf(stderr, "Mapped: %i Size: %d Overhead: %d\n", m_mapCount, m_mapSize, m_mapOverhead); - m_data = (unsigned char *)m_mmapData + alignment_offset; } - } + m_lockCount++; } // Unlock the memory, releasing the address space for use by other allocations @@ -346,24 +350,29 @@ void KRDataBlock::unlock() // We expect that the data block was previously locked assertLocked(); - m_lockCount--; - if(m_lockCount == 0) { + + if(m_lockCount == 1) { // Memory mapped file; ensure data is unmapped from ram if(m_fdPackFile) { - //fprintf(stderr, "KRDataBlock::unlock - \"%s\" (%i)\n", m_fileOwnerDataBlock->m_fileName.c_str(), m_lockCount); - - munmap(m_mmapData, m_data_size); - m_data = NULL; - m_mmapData = NULL; - m_mapCount--; - m_mapSize -= m_data_size; - size_t alignment_offset = m_data_offset & (KRAKEN_MEM_PAGE_SIZE - 1); - m_mapOverhead -= alignment_offset + KRAKEN_MEM_ROUND_UP_PAGE(m_data_size + alignment_offset) - m_data_size + alignment_offset; - fprintf(stderr, "Mapped: %i Size: %d Overhead: %d\n", m_mapCount, m_mapSize, m_mapOverhead); + if(m_data_size < KRENGINE_MIN_MMAP) { + free(m_data); + m_data = NULL; + } else { + //fprintf(stderr, "KRDataBlock::unlock - \"%s\" (%i)\n", m_fileOwnerDataBlock->m_fileName.c_str(), m_lockCount); + + munmap(m_mmapData, m_data_size); + m_data = NULL; + m_mmapData = NULL; + m_mapCount--; + m_mapSize -= m_data_size; + size_t alignment_offset = m_data_offset & (KRAKEN_MEM_PAGE_SIZE - 1); + m_mapOverhead -= alignment_offset + KRAKEN_MEM_ROUND_UP_PAGE(m_data_size + alignment_offset) - m_data_size + alignment_offset; + fprintf(stderr, "Mapped: %i Size: %d Overhead: %d\n", m_mapCount, m_mapSize, m_mapOverhead); + } } - } + m_lockCount--; } // Assert if not locked diff --git a/KREngine/kraken/KRDataBlock.h b/KREngine/kraken/KRDataBlock.h index 5198375..c1db34c 100644 --- a/KREngine/kraken/KRDataBlock.h +++ b/KREngine/kraken/KRDataBlock.h @@ -34,6 +34,8 @@ #include "KREngine-common.h" +#define KRENGINE_MIN_MMAP 327680000 + class KRDataBlock { public: KRDataBlock(); diff --git a/KREngine/kraken/KREngine.mm b/KREngine/kraken/KREngine.mm index b5fbb11..e1c8eb6 100644 --- a/KREngine/kraken/KREngine.mm +++ b/KREngine/kraken/KREngine.mm @@ -101,7 +101,6 @@ void kraken::set_debug_text(const std::string &print_text) KRContext::KRENGINE_MAX_VBO_MEM = total_ram * 2 / 4; KRContext::KRENGINE_MAX_TEXTURE_MEM = total_ram * 1 / 8; KRContext::KRENGINE_TARGET_TEXTURE_MEM_MAX = KRContext::KRENGINE_MAX_TEXTURE_MEM * 3 / 4; - KRContext::KRENGINE_TARGET_TEXTURE_MEM_MIN = KRContext::KRENGINE_MAX_TEXTURE_MEM / 2; @@ -115,7 +114,6 @@ void kraken::set_debug_text(const std::string &print_text) KRContext::KRENGINE_MAX_TEXTURE_HANDLES = 10000; KRContext::KRENGINE_MAX_TEXTURE_MEM = 64000000 * 2; KRContext::KRENGINE_TARGET_TEXTURE_MEM_MAX = 48000000 * 2; - KRContext::KRENGINE_TARGET_TEXTURE_MEM_MIN = 32000000 * 2; KRContext::KRENGINE_MAX_TEXTURE_DIM = 2048; KRContext::KRENGINE_MIN_TEXTURE_DIM = 64; KRContext::KRENGINE_MAX_TEXTURE_THROUGHPUT = 32000000; @@ -126,7 +124,6 @@ void kraken::set_debug_text(const std::string &print_text) KRContext::KRENGINE_MAX_TEXTURE_HANDLES = 10000; KRContext::KRENGINE_MAX_TEXTURE_MEM = 64000000; KRContext::KRENGINE_TARGET_TEXTURE_MEM_MAX = 48000000; - KRContext::KRENGINE_TARGET_TEXTURE_MEM_MIN = 32000000; KRContext::KRENGINE_MAX_TEXTURE_DIM = 2048; KRContext::KRENGINE_MIN_TEXTURE_DIM = 64; KRContext::KRENGINE_MAX_TEXTURE_THROUGHPUT = 32000000; @@ -139,7 +136,6 @@ void kraken::set_debug_text(const std::string &print_text) KRContext::KRENGINE_MAX_TEXTURE_HANDLES = 10000; KRContext::KRENGINE_MAX_TEXTURE_MEM = 512000000; KRContext::KRENGINE_TARGET_TEXTURE_MEM_MAX = 384000000; - KRContext::KRENGINE_TARGET_TEXTURE_MEM_MIN = 256000000; KRContext::KRENGINE_MAX_TEXTURE_DIM = 2048; KRContext::KRENGINE_MIN_TEXTURE_DIM = 64; KRContext::KRENGINE_MAX_TEXTURE_THROUGHPUT = 128000000; diff --git a/KREngine/kraken/KRMeshStreamer.mm b/KREngine/kraken/KRMeshStreamer.mm index ec30a22..1940386 100644 --- a/KREngine/kraken/KRMeshStreamer.mm +++ b/KREngine/kraken/KRMeshStreamer.mm @@ -32,6 +32,8 @@ KRMeshStreamer::~KRMeshStreamer() void KRMeshStreamer::run() { + pthread_setname_np("Kraken - Mesh Streamer"); + std::chrono::microseconds sleep_duration( 100 ); [EAGLContext setCurrentContext: gMeshStreamerContext]; diff --git a/KREngine/kraken/KRTexture.cpp b/KREngine/kraken/KRTexture.cpp index 1588ff1..8eb872d 100644 --- a/KREngine/kraken/KRTexture.cpp +++ b/KREngine/kraken/KRTexture.cpp @@ -28,6 +28,8 @@ KRTexture::~KRTexture() } void KRTexture::releaseHandles() { + long mem_size = getMemSize(); + if(m_iNewHandle != 0) { GLDEBUG(glDeleteTextures(1, &m_iNewHandle)); m_iNewHandle = 0; @@ -35,10 +37,10 @@ void KRTexture::releaseHandles() { } if(m_iHandle != 0) { GLDEBUG(glDeleteTextures(1, &m_iHandle)); - getContext().getTextureManager()->memoryChanged(-getMemSize()); m_iHandle = 0; m_textureMemUsed = 0; } + getContext().getTextureManager()->memoryChanged(-mem_size); } long KRTexture::getMemSize() { @@ -52,45 +54,36 @@ long KRTexture::getReferencedMemSize() { void KRTexture::resize(int max_dim) { - if(m_iHandle != m_iNewHandle) return; // Only allow one resize() per frame - - if(max_dim == 0) { - m_iNewHandle = 0; - } else { - int target_dim = max_dim; - if(target_dim < m_min_lod_max_dim) target_dim = m_min_lod_max_dim; -/* - int requiredMemoryTransfer = getThroughputRequiredForResize(target_dim); - int requiredMemoryDelta = getMemRequiredForSize(target_dim) - getMemSize() - getReferencedMemSize(); + if(m_handle_lock.test_and_set()) + { + if(m_iHandle == m_iNewHandle) { + if(max_dim == 0) { + m_iNewHandle = 0; + } else { + int target_dim = max_dim; + if(target_dim < m_min_lod_max_dim) target_dim = m_min_lod_max_dim; - if(requiredMemoryDelta) { - // Only resize / regenerate the texture if it actually changes the size of the texture (Assumption: textures of different sizes will always consume different amounts of memory) - - if(getContext().getTextureManager()->getMemoryTransferedThisFrame() + requiredMemoryTransfer > getContext().KRENGINE_MAX_TEXTURE_THROUGHPUT) { - // Exceeding per-frame transfer throughput; can't resize now - return; - } - - if(getContext().getTextureManager()->getMemUsed() + requiredMemoryDelta > getContext().KRENGINE_MAX_TEXTURE_MEM) { - // Exceeding total memory allocated to textures; can't resize now - return; - } -*/ - if(m_current_lod_max_dim != target_dim || (m_iHandle == 0 && m_iNewHandle == 0)) { - if(!createGLTexture(target_dim)) { - assert(false); + if(m_current_lod_max_dim != target_dim || (m_iHandle == 0 && m_iNewHandle == 0)) { + assert(m_newTextureMemUsed == 0); + m_newTextureMemUsed = getMemRequiredForSize(target_dim); + + getContext().getTextureManager()->memoryChanged(m_newTextureMemUsed); + getContext().getTextureManager()->addMemoryTransferredThisFrame(m_newTextureMemUsed); + + if(!createGLTexture(target_dim)) { + getContext().getTextureManager()->memoryChanged(-m_newTextureMemUsed); + m_newTextureMemUsed = 0; + assert(false); + } } } -// } + } + + m_handle_lock.clear(); } } GLuint KRTexture::getHandle() { - /* - if(m_iHandle == 0 && m_iNewHandle == 0) { - resize(m_min_lod_max_dim); - } - */ resetPoolExpiry(); return m_iHandle; } @@ -100,34 +93,6 @@ void KRTexture::resetPoolExpiry() m_last_frame_used = getContext().getCurrentFrame(); } -long KRTexture::getThroughputRequiredForResize(int max_dim) -{ - // Calculate the throughput required for GPU texture upload if the texture is resized to max_dim. - // This default behaviour assumes that the texture will need to be deleted and regenerated to change the maximum mip-map level. - // If an OpenGL extension is present that allows a texture to be resized incrementally, then this method should be overridden - - if(max_dim == 0) { - return 0; - } else { - int target_dim = max_dim; - if(target_dim < m_min_lod_max_dim) target_dim = target_dim; - - - if(target_dim != m_current_lod_max_dim) { - int requiredMemory = getMemRequiredForSize(target_dim); - int requiredMemoryDelta = requiredMemory - getMemSize() - getReferencedMemSize(); - - if(requiredMemoryDelta == 0) { - // Only resize / regenerate the texture if it actually changes the size of the texture (Assumption: textures of different sizes will always consume different amounts of memory) - return 0; - } - return requiredMemory; - } else { - return 0; - } - } -} - long KRTexture::getLastFrameUsed() { return m_last_frame_used; @@ -169,14 +134,18 @@ bool KRTexture::canStreamOut() const { void KRTexture::_swapHandles() { - if(m_iNewHandle != m_iHandle) { - if(m_iHandle != 0) { - GLDEBUG(glDeleteTextures(1, &m_iHandle)); - getContext().getTextureManager()->memoryChanged(m_newTextureMemUsed - m_textureMemUsed); - m_textureMemUsed = m_newTextureMemUsed; + if(m_handle_lock.test_and_set()) + { + if(m_iHandle != m_iNewHandle) { + if(m_iHandle != 0) { + GLDEBUG(glDeleteTextures(1, &m_iHandle)); + getContext().getTextureManager()->memoryChanged(-m_textureMemUsed); + } + m_textureMemUsed = (long)m_newTextureMemUsed; m_newTextureMemUsed = 0; + m_iHandle = m_iNewHandle; } - m_iHandle = m_iNewHandle; + m_handle_lock.clear(); } } diff --git a/KREngine/kraken/KRTexture.h b/KREngine/kraken/KRTexture.h index 8ecd169..592ac14 100644 --- a/KREngine/kraken/KRTexture.h +++ b/KREngine/kraken/KRTexture.h @@ -52,7 +52,6 @@ public: virtual long getReferencedMemSize(); virtual long getMemRequiredForSize(int max_dim) = 0; - virtual long getThroughputRequiredForResize(int max_dim); virtual void resize(int max_dim); long getLastFrameUsed(); @@ -74,10 +73,9 @@ protected: GLuint getHandle(); - GLuint m_iHandle; + GLuint m_iHandle; GLuint m_iNewHandle; - long m_textureMemUsed; - long m_newTextureMemUsed; + std::atomic_flag m_handle_lock; int m_current_lod_max_dim; @@ -86,6 +84,10 @@ protected: long m_last_frame_used; long m_last_frame_bound; + +private: + std::atomic m_textureMemUsed; + std::atomic m_newTextureMemUsed; }; diff --git a/KREngine/kraken/KRTexture2D.cpp b/KREngine/kraken/KRTexture2D.cpp index e5d6138..11918d9 100644 --- a/KREngine/kraken/KRTexture2D.cpp +++ b/KREngine/kraken/KRTexture2D.cpp @@ -49,12 +49,9 @@ bool KRTexture2D::createGLTexture(int lod_max_dim) { bool success = true; 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_mem_size = getMemSize(); - m_textureMemUsed = 0; prev_lod_max_dim = m_current_lod_max_dim; } #endif @@ -74,10 +71,8 @@ bool KRTexture2D::createGLTexture(int lod_max_dim) { 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_newTextureMemUsed, prev_lod_max_dim)) { + if(!uploadTexture(GL_TEXTURE_2D, lod_max_dim, m_current_lod_max_dim, prev_lod_max_dim)) { GLDEBUG(glDeleteTextures(1, &m_iNewHandle)); - getContext().getTextureManager()->memoryChanged(-m_newTextureMemUsed); - m_newTextureMemUsed = 0; m_iNewHandle = m_iHandle; m_current_lod_max_dim = prev_lod_max_dim; success = false; diff --git a/KREngine/kraken/KRTexture2D.h b/KREngine/kraken/KRTexture2D.h index 87efc8f..139e5d5 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, int prev_lod_max_dim) = 0; + virtual bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, int prev_lod_max_dim) = 0; virtual void bind(GLuint texture_unit); protected: diff --git a/KREngine/kraken/KRTextureCube.cpp b/KREngine/kraken/KRTextureCube.cpp index 710aef0..dcf8e0f 100644 --- a/KREngine/kraken/KRTextureCube.cpp +++ b/KREngine/kraken/KRTextureCube.cpp @@ -68,37 +68,31 @@ bool KRTextureCube::createGLTexture(int lod_max_dim) #endif - - - m_iNewHandle = 0; GLDEBUG(glGenTextures(1, &m_iNewHandle)); - if(m_iNewHandle == 0) { - m_iNewHandle = m_iHandle; - success = false; - } else { - m_current_lod_max_dim = 0; - GLDEBUG(glBindTexture(GL_TEXTURE_CUBE_MAP, m_iNewHandle)); - - bool bMipMaps = false; + assert(m_iNewHandle != 0); + + m_current_lod_max_dim = 0; + GLDEBUG(glBindTexture(GL_TEXTURE_CUBE_MAP, m_iNewHandle)); + + bool bMipMaps = false; - for(int i=0; i<6; i++) { - std::string faceName = getName() + SUFFIXES[i]; - 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_newTextureMemUsed, prev_lod_max_dim); - } - } - - if(bMipMaps) { - GLDEBUG(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)); - } else { - // GLDEBUG(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - GLDEBUG(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)); - GLDEBUG(glGenerateMipmap(GL_TEXTURE_CUBE_MAP)); + for(int i=0; i<6; i++) { + std::string faceName = getName() + SUFFIXES[i]; + 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, prev_lod_max_dim); } } + + if(bMipMaps) { + GLDEBUG(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)); + } else { + // GLDEBUG(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + GLDEBUG(glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)); + GLDEBUG(glGenerateMipmap(GL_TEXTURE_CUBE_MAP)); + } return success; diff --git a/KREngine/kraken/KRTextureManager.cpp b/KREngine/kraken/KRTextureManager.cpp index 5484a9d..b7b8bfa 100644 --- a/KREngine/kraken/KRTextureManager.cpp +++ b/KREngine/kraken/KRTextureManager.cpp @@ -266,7 +266,7 @@ void KRTextureManager::balanceTextureMemory() } // Determine how much memory we need to free up - long memoryDeficit = wantedTextureMem - (getContext().KRENGINE_MAX_TEXTURE_MEM - getMemUsed()); + long memoryDeficit = wantedTextureMem - (getContext().KRENGINE_TARGET_TEXTURE_MEM_MAX - getMemUsed()); // Determine how many mip map levels we need to strip off of inactive textures to free the memory we need @@ -289,10 +289,17 @@ void KRTextureManager::balanceTextureMemory() long inactive_texture_mem_used_target = 0; for(std::set::iterator itr=m_poolTextures_streamer.begin(); itr != m_poolTextures_streamer.end(); itr++) { KRTexture *poolTexture = *itr; - long potentialMemoryDelta = poolTexture->getMemRequiredForSize(maxDimInactive) - poolTexture->getMemSize(); + long mem_required = poolTexture->getMemRequiredForSize(maxDimInactive); + long potentialMemoryDelta = mem_required - poolTexture->getMemSize(); if(potentialMemoryDelta < 0) { - poolTexture->resize(maxDimInactive); - inactive_texture_mem_used_target += poolTexture->getMemRequiredForSize(maxDimInactive); + if(mem_required * 2 + getMemUsed() < KRContext::KRENGINE_MAX_TEXTURE_MEM) { + long mem_free; + m_pContext->getMemoryStats(mem_free); + if(mem_required * 2 < mem_free - 10000000) { + poolTexture->resize(maxDimInactive); + } + } + inactive_texture_mem_used_target += mem_required; } else { inactive_texture_mem_used_target += poolTexture->getMemSize(); } @@ -302,7 +309,7 @@ void KRTextureManager::balanceTextureMemory() long memory_available = 0; long maxDimActive = getContext().KRENGINE_MAX_TEXTURE_DIM; while(memory_available <= 0 && maxDimActive >= getContext().KRENGINE_MIN_TEXTURE_DIM) { - memory_available = getContext().KRENGINE_MAX_TEXTURE_MEM - inactive_texture_mem_used_target; + memory_available = getContext().KRENGINE_TARGET_TEXTURE_MEM_MAX - inactive_texture_mem_used_target; for(std::set::iterator itr=m_activeTextures_streamer.begin(); itr != m_activeTextures_streamer.end() && memory_available > 0; itr++) { KRTexture *activeTexture = *itr; memory_available -= activeTexture->getMemRequiredForSize(maxDimActive); @@ -316,7 +323,14 @@ void KRTextureManager::balanceTextureMemory() // Resize active textures to balance the memory usage and mipmap levels for(std::set::iterator itr=m_activeTextures_streamer.begin(); itr != m_activeTextures_streamer.end() && memory_available > 0; itr++) { KRTexture *activeTexture = *itr; - activeTexture->resize(maxDimActive); + long mem_required = activeTexture->getMemRequiredForSize(maxDimActive); + if(mem_required * 2 + getMemUsed() < KRContext::KRENGINE_MAX_TEXTURE_MEM) { + long mem_free; + m_pContext->getMemoryStats(mem_free); + if(mem_required * 2 < mem_free - 10000000) { + activeTexture->resize(maxDimActive); + } + } } //fprintf(stderr, "Active mipmap size: %i Inactive mapmap size: %i\n", (int)maxDimActive, (int)maxDimInactive); @@ -358,6 +372,7 @@ void KRTextureManager::addMemoryTransferredThisFrame(long memoryTransferred) void KRTextureManager::memoryChanged(long memoryDelta) { m_textureMemUsed += memoryDelta; + //fprintf(stderr, "Texture Memory: %ld / %i\n", (long)m_textureMemUsed, KRContext::KRENGINE_MAX_TEXTURE_MEM); } unordered_map &KRTextureManager::getTextures() diff --git a/KREngine/kraken/KRTextureManager.h b/KREngine/kraken/KRTextureManager.h index 222aac8..b55a473 100644 --- a/KREngine/kraken/KRTextureManager.h +++ b/KREngine/kraken/KRTextureManager.h @@ -101,7 +101,7 @@ private: std::set m_activeTextures_streamer_copy; std::set m_poolTextures_streamer_copy; - long m_textureMemUsed; + std::atomic m_textureMemUsed; void rotateBuffers(); void balanceTextureMemory(); diff --git a/KREngine/kraken/KRTexturePVR.cpp b/KREngine/kraken/KRTexturePVR.cpp index 4765597..6ce9a65 100644 --- a/KREngine/kraken/KRTexturePVR.cpp +++ b/KREngine/kraken/KRTexturePVR.cpp @@ -64,9 +64,11 @@ typedef struct _PVRTexHeader KRTexturePVR::KRTexturePVR(KRContext &context, KRDataBlock *data, std::string name) : KRTexture2D(context, data, name) { #if TARGET_OS_IPHONE - m_pData->lock(); - PVRTexHeader *header = (PVRTexHeader *)m_pData->getStart(); - uint32_t formatFlags = header->flags & PVR_TEXTURE_FLAG_TYPE_MASK; + + PVRTexHeader header; + m_pData->copy(&header, 0, sizeof(PVRTexHeader)); + + uint32_t formatFlags = header.flags & PVR_TEXTURE_FLAG_TYPE_MASK; if (formatFlags == kPVRTextureFlagTypePVRTC_4) { m_internalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; } else if(formatFlags == kPVRTextureFlagTypePVRTC_2) { @@ -75,7 +77,7 @@ KRTexturePVR::KRTexturePVR(KRContext &context, KRDataBlock *data, std::string na assert(false); } - uint32_t pvrTag = header->pvrTag; + uint32_t pvrTag = header.pvrTag; if (gPVRTexIdentifier[0] != ((pvrTag >> 0) & 0xff) || gPVRTexIdentifier[1] != ((pvrTag >> 8) & 0xff) || gPVRTexIdentifier[2] != ((pvrTag >> 16) & 0xff) || @@ -83,12 +85,12 @@ KRTexturePVR::KRTexturePVR(KRContext &context, KRDataBlock *data, std::string na assert(false); } - m_iWidth = header->width; // Note: call __builtin_bswap32 when needed to switch endianness - m_iHeight = header->height; - m_bHasAlpha = header->bitmaskAlpha; + m_iWidth = header.width; // Note: call __builtin_bswap32 when needed to switch endianness + m_iHeight = header.height; + m_bHasAlpha = header.bitmaskAlpha; uint32_t dataStart = sizeof(PVRTexHeader); - uint32_t dataLength = header->dataLength, dataOffset = 0, dataSize = 0; + uint32_t dataLength = header.dataLength, dataOffset = 0, dataSize = 0; uint32_t width = m_iWidth, height = m_iHeight, bpp = 4; uint32_t blockSize = 0, widthBlocks = 0, heightBlocks = 0; @@ -115,11 +117,7 @@ KRTexturePVR::KRTexturePVR(KRContext &context, KRDataBlock *data, std::string na } dataSize = widthBlocks * heightBlocks * ((blockSize * bpp) / 8); - dataBlockStruct newBlock; - newBlock.start = dataStart + dataOffset; - newBlock.length = dataSize; - - m_blocks.push_back(newBlock); + m_blocks.push_back(m_pData->getSubBlock(dataStart + dataOffset, dataSize)); dataOffset += dataSize; @@ -135,13 +133,15 @@ KRTexturePVR::KRTexturePVR(KRContext &context, KRDataBlock *data, std::string na m_max_lod_max_dim = m_iWidth > m_iHeight ? m_iWidth : m_iHeight; m_min_lod_max_dim = width > height ? width : height; - - m_pData->unlock(); #endif } KRTexturePVR::~KRTexturePVR() { - + for(std::list::iterator itr = m_blocks.begin(); itr != m_blocks.end(); itr++) { + KRDataBlock *block = *itr; + delete block; + } + m_blocks.clear(); } long KRTexturePVR::getMemRequiredForSize(int max_dim) @@ -154,10 +154,10 @@ long KRTexturePVR::getMemRequiredForSize(int max_dim) int height = m_iHeight; long memoryRequired = 0; - for(std::list::iterator itr = m_blocks.begin(); itr != m_blocks.end(); itr++) { - dataBlockStruct block = *itr; + for(std::list::iterator itr = m_blocks.begin(); itr != m_blocks.end(); itr++) { + KRDataBlock *block = *itr; if(width <= target_dim && height <= target_dim) { - memoryRequired += block.length; + memoryRequired += block->getSize(); } width = width >> 1; @@ -173,7 +173,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, int prev_lod_max_dim) +bool KRTexturePVR::uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, int prev_lod_max_dim) { int target_dim = lod_max_dim; if(target_dim < m_min_lod_max_dim) target_dim = m_min_lod_max_dim; @@ -196,7 +196,7 @@ bool KRTexturePVR::uploadTexture(GLenum target, int lod_max_dim, int ¤t_lo 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++) { + for(std::list::iterator itr = m_blocks.begin(); itr != m_blocks.end(); itr++) { if(width <= target_dim && height <= target_dim) { if(max_lod_width == 0) { max_lod_width = width; @@ -229,8 +229,8 @@ bool KRTexturePVR::uploadTexture(GLenum target, int lod_max_dim, int ¤t_lo // 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; + for(std::list::iterator itr = m_blocks.begin(); itr != m_blocks.end(); itr++) { + KRDataBlock *block = *itr; if(width <= target_dim && height <= target_dim) { if(width > current_lod_max_dim) { @@ -245,24 +245,23 @@ bool KRTexturePVR::uploadTexture(GLenum target, int lod_max_dim, int ¤t_lo // GLDEBUG(glTexImage2D(target, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL)); GLDEBUG(glCopyTextureLevelsAPPLE(m_iNewHandle, m_iHandle, source_level, 1)); } else { - // glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data); - m_pData->lock(); - GLDEBUG(glCompressedTexSubImage2D(target, destination_level, 0, 0, width, height, m_internalFormat, block.length, (char *)m_pData->getStart() + block.start)); - m_pData->unlock(); -// 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 + block->lock(); + GLDEBUG(glCompressedTexSubImage2D(target, destination_level, 0, 0, width, height, m_internalFormat, (GLsizei)block->getSize(), block->getStart())); + block->unlock(); + + memoryTransferred += block->getSize(); // memoryTransferred does not include throughput of mipmap levels copied through glCopyTextureLevelsAPPLE } #else - m_pData->lock(); + block->lock(); #if GL_EXT_texture_storage - GLDEBUG(glCompressedTexSubImage2D(target, destination_level, 0, 0, width, height, m_internalFormat, block.length, (char *)m_pData->getStart() + block.start)); + GLDEBUG(glCompressedTexSubImage2D(target, destination_level, 0, 0, width, height, m_internalFormat, block->getSize(), block->getStart())); #else - GLDEBUG(glCompressedTexImage2D(target, destination_level, m_internalFormat, width, height, 0, block.length, (char *)m_pData->getStart() + block.start)); + GLDEBUG(glCompressedTexImage2D(target, destination_level, m_internalFormat, width, height, 0, block->getSize(), block->getStart())); #endif - m_pData->unlock(); - memoryTransferred += block.length; // memoryTransferred does not include throughput of mipmap levels copied through glCopyTextureLevelsAPPLE + block->unlock(); + memoryTransferred += block->getSize(); // memoryTransferred does not include throughput of mipmap levels copied through glCopyTextureLevelsAPPLE #endif - memoryRequired += block.length; + memoryRequired += block->getSize(); // // err = glGetError(); // if (err != GL_NO_ERROR) { @@ -288,10 +287,6 @@ bool KRTexturePVR::uploadTexture(GLenum target, int lod_max_dim, int ¤t_lo } } - textureMemUsed += memoryRequired; - getContext().getTextureManager()->memoryChanged(memoryRequired); - getContext().getTextureManager()->addMemoryTransferredThisFrame(memoryTransferred); - return true; } diff --git a/KREngine/kraken/KRTexturePVR.h b/KREngine/kraken/KRTexturePVR.h index 97c6505..974619e 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, int prev_lod_max_dim); + bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, int prev_lod_max_dim); virtual long getMemRequiredForSize(int max_dim); @@ -29,12 +29,7 @@ protected: GLenum m_internalFormat; bool m_bHasAlpha; - struct dataBlockStruct { - uint32_t start; - uint32_t length; - }; - - std::list m_blocks; + std::list m_blocks; }; #endif diff --git a/KREngine/kraken/KRTextureStreamer.mm b/KREngine/kraken/KRTextureStreamer.mm index 26bc2ca..5dc8682 100644 --- a/KREngine/kraken/KRTextureStreamer.mm +++ b/KREngine/kraken/KRTextureStreamer.mm @@ -40,6 +40,8 @@ KRTextureStreamer::~KRTextureStreamer() void KRTextureStreamer::run() { + pthread_setname_np("Kraken - Texture Streamer"); + std::chrono::microseconds sleep_duration( 100 ); [EAGLContext setCurrentContext: gTextureStreamerContext]; diff --git a/KREngine/kraken/KRTextureTGA.cpp b/KREngine/kraken/KRTextureTGA.cpp index b5fd7fa..373385b 100644 --- a/KREngine/kraken/KRTextureTGA.cpp +++ b/KREngine/kraken/KRTextureTGA.cpp @@ -33,6 +33,34 @@ KRTextureTGA::KRTextureTGA(KRContext &context, KRDataBlock *data, std::string na m_max_lod_max_dim = pHeader->width > pHeader->height ? pHeader->width : pHeader->height; m_min_lod_max_dim = m_max_lod_max_dim; // Mipmaps not yet supported for TGA images + switch(pHeader->imagetype) { + case 2: // rgb + switch(pHeader->bitsperpixel) { + case 24: + { + m_imageSize = pHeader->width * pHeader->height * 4; + } + break; + case 32: + { + m_imageSize = pHeader->width * pHeader->height * 4; + } + break; + + default: + { + assert(false); + } + break; + } + break; + default: + { + assert(false); + break; + } + } + data->unlock(); } @@ -41,7 +69,7 @@ KRTextureTGA::~KRTextureTGA() } -bool KRTextureTGA::uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, long &textureMemUsed, int prev_lod_max_dim) +bool KRTextureTGA::uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, int prev_lod_max_dim) { m_pData->lock(); TGA_HEADER *pHeader = (TGA_HEADER *)m_pData->getStart(); @@ -83,10 +111,6 @@ bool KRTextureTGA::uploadTexture(GLenum target, int lod_max_dim, int ¤t_lo m_pData->unlock(); return false; } - int memAllocated = pHeader->width * pHeader->height * 4; - textureMemUsed += memAllocated; - getContext().getTextureManager()->memoryChanged(memAllocated); - getContext().getTextureManager()->addMemoryTransferredThisFrame(memAllocated); current_lod_max_dim = m_max_lod_max_dim; } break; @@ -98,10 +122,6 @@ bool KRTextureTGA::uploadTexture(GLenum target, int lod_max_dim, int ¤t_lo m_pData->unlock(); return false; } - int memAllocated = pHeader->width * pHeader->height * 4; - textureMemUsed += memAllocated; - getContext().getTextureManager()->memoryChanged(memAllocated); - getContext().getTextureManager()->addMemoryTransferredThisFrame(memAllocated); current_lod_max_dim = m_max_lod_max_dim; } break; @@ -121,25 +141,7 @@ bool KRTextureTGA::uploadTexture(GLenum target, int lod_max_dim, int ¤t_lo long KRTextureTGA::getMemRequiredForSize(int max_dim) { - TGA_HEADER *pHeader = (TGA_HEADER *)m_pData->getStart(); - switch(pHeader->imagetype) { - case 2: // rgb - switch(pHeader->bitsperpixel) { - case 24: - { - return pHeader->width * pHeader->height * 4; - } - break; - case 32: - { - return pHeader->width * pHeader->height * 4; - } - break; - } - break; - } - - return 0; + return m_imageSize; } std::string KRTextureTGA::getExtension() diff --git a/KREngine/kraken/KRTextureTGA.h b/KREngine/kraken/KRTextureTGA.h index 1624341..82826d7 100644 --- a/KREngine/kraken/KRTextureTGA.h +++ b/KREngine/kraken/KRTextureTGA.h @@ -18,9 +18,11 @@ public: virtual ~KRTextureTGA(); virtual std::string getExtension(); - bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, long &textureMemUsed, int prev_lod_max_dim); + bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, int prev_lod_max_dim); virtual long getMemRequiredForSize(int max_dim); +private: + long m_imageSize; }; #endif