From cf732a6721e2b3443cb8b14fdb0bb6e753f448f6 Mon Sep 17 00:00:00 2001 From: Kearwood Gilbert Date: Wed, 13 Nov 2013 23:52:17 -0800 Subject: [PATCH] Asynchronous streaming and memory management improvements in progress. --HG-- branch : async_streaming --- KREngine/kraken/KRContext.cpp | 12 ++++++++++- KREngine/kraken/KRContext.h | 4 ++++ KREngine/kraken/KREngine-common.h | 1 + KREngine/kraken/KRMeshStreamer.mm | 4 ++++ KREngine/kraken/KRTexture.cpp | 11 +++++----- KREngine/kraken/KRTextureManager.cpp | 31 +++++++++++++++++++++------- KREngine/kraken/KRTextureManager.h | 11 ++++++++++ KREngine/kraken/KRTextureStreamer.h | 4 ++++ KREngine/kraken/KRTextureStreamer.mm | 20 +++++++++++++++--- 9 files changed, 82 insertions(+), 16 deletions(-) diff --git a/KREngine/kraken/KRContext.cpp b/KREngine/kraken/KRContext.cpp index 6c1145d..ffa113a 100644 --- a/KREngine/kraken/KRContext.cpp +++ b/KREngine/kraken/KRContext.cpp @@ -27,6 +27,7 @@ const char *KRContext::extension_names[KRENGINE_NUM_EXTENSIONS] = { }; KRContext::KRContext() { + m_streamingEnabled = false; mach_timebase_info(&m_timebase_info); m_bDetectedExtensions = false; @@ -43,7 +44,7 @@ KRContext::KRContext() { m_pAnimationCurveManager = new KRAnimationCurveManager(*this); m_pSoundManager = new KRAudioManager(*this); m_pUnknownManager = new KRUnknownManager(*this); - + m_streamingEnabled = true; } KRContext::~KRContext() { @@ -271,3 +272,12 @@ long KRContext::getAbsoluteTimeMilliseconds() return (long)(mach_absolute_time() / 1000 * m_timebase_info.numer / m_timebase_info.denom); // Division done first to avoid potential overflow } +bool KRContext::getStreamingEnabled() +{ + return m_streamingEnabled; +} + +void KRContext::setStreamingEnabled(bool enable) +{ + m_streamingEnabled = enable; +} diff --git a/KREngine/kraken/KRContext.h b/KREngine/kraken/KRContext.h index 47a0b34..824afbd 100644 --- a/KREngine/kraken/KRContext.h +++ b/KREngine/kraken/KRContext.h @@ -73,6 +73,8 @@ public: long getAbsoluteTimeMilliseconds(); std::vector getResources(); + bool getStreamingEnabled(); + void setStreamingEnabled(bool enable); private: KRBundleManager *m_pBundleManager; @@ -93,6 +95,8 @@ private: float m_absolute_time; mach_timebase_info_data_t m_timebase_info; + + std::atomic m_streamingEnabled; }; #endif diff --git a/KREngine/kraken/KREngine-common.h b/KREngine/kraken/KREngine-common.h index fbde9bc..1edc1af 100644 --- a/KREngine/kraken/KREngine-common.h +++ b/KREngine/kraken/KREngine-common.h @@ -14,6 +14,7 @@ float const PI = 3.141592653589793f; float const D2R = PI * 2 / 360; + #include #include #include diff --git a/KREngine/kraken/KRMeshStreamer.mm b/KREngine/kraken/KRMeshStreamer.mm index b2aa5de..ec30a22 100644 --- a/KREngine/kraken/KRMeshStreamer.mm +++ b/KREngine/kraken/KRMeshStreamer.mm @@ -9,6 +9,7 @@ #include "KRMeshStreamer.h" #include "KREngine-common.h" +#include "KRContext.h" #include @@ -36,6 +37,9 @@ void KRMeshStreamer::run() while(!m_stop) { + if(m_context.getStreamingEnabled()) { + + } std::this_thread::sleep_for( sleep_duration ); } } diff --git a/KREngine/kraken/KRTexture.cpp b/KREngine/kraken/KRTexture.cpp index 5c0830c..1588ff1 100644 --- a/KREngine/kraken/KRTexture.cpp +++ b/KREngine/kraken/KRTexture.cpp @@ -52,19 +52,20 @@ long KRTexture::getReferencedMemSize() { void KRTexture::resize(int max_dim) { - assert(m_iHandle == m_iNewHandle); // Only allow one resize() per frame + 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(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; @@ -74,13 +75,13 @@ void KRTexture::resize(int max_dim) // 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); } } - } +// } } } diff --git a/KREngine/kraken/KRTextureManager.cpp b/KREngine/kraken/KRTextureManager.cpp index 605e48e..5484a9d 100644 --- a/KREngine/kraken/KRTextureManager.cpp +++ b/KREngine/kraken/KRTextureManager.cpp @@ -215,13 +215,20 @@ long KRTextureManager::getMemActive() { void KRTextureManager::startFrame(float deltaTime) { + m_streamer.startStreamer(); _clearGLState(); for(std::set::iterator itr=m_activeTextures.begin(); itr != m_activeTextures.end(); itr++) { KRTexture *activeTexture = *itr; activeTexture->_swapHandles(); } + + // TODO - Implement proper double-buffering to reduce copy operations + m_streamerFenceMutex.lock(); + m_activeTextures_streamer_copy = m_activeTextures; + m_poolTextures_streamer_copy = m_poolTextures; + m_streamerFenceMutex.unlock(); + m_memoryTransferredThisFrame = 0; - balanceTextureMemory(); rotateBuffers(); } @@ -234,15 +241,25 @@ void KRTextureManager::endFrame(float deltaTime) } } +void KRTextureManager::doStreaming() +{ + // TODO - Implement proper double-buffering to reduce copy operations + m_streamerFenceMutex.lock(); + m_activeTextures_streamer = m_activeTextures_streamer_copy; + m_poolTextures_streamer = m_poolTextures_streamer_copy; + m_streamerFenceMutex.unlock(); + + balanceTextureMemory(); +} + void KRTextureManager::balanceTextureMemory() { - return; // Balance texture memory by reducing and increasing the maximum mip-map level of both active and inactive textures // Favour performance over maximum texture resolution when memory is insufficient for textures at full resolution. // Determine the additional amount of memory required in order to resize all active textures to the maximum size long wantedTextureMem = 0; - for(std::set::iterator itr=m_activeTextures.begin(); itr != m_activeTextures.end(); itr++) { + for(std::set::iterator itr=m_activeTextures_streamer.begin(); itr != m_activeTextures_streamer.end(); itr++) { KRTexture *activeTexture = *itr; wantedTextureMem = activeTexture->getMemRequiredForSize(getContext().KRENGINE_MAX_TEXTURE_DIM) - activeTexture->getMemSize(); @@ -259,7 +276,7 @@ void KRTextureManager::balanceTextureMemory() maxDimInactive = maxDimInactive >> 1; potentialMemorySaving = 0; - for(std::set::iterator itr=m_poolTextures.begin(); itr != m_poolTextures.end(); itr++) { + 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(); if(potentialMemoryDelta < 0) { @@ -270,7 +287,7 @@ void KRTextureManager::balanceTextureMemory() // Strip off mipmap levels of inactive textures to free up memory long inactive_texture_mem_used_target = 0; - for(std::set::iterator itr=m_poolTextures.begin(); itr != m_poolTextures.end(); itr++) { + 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(); if(potentialMemoryDelta < 0) { @@ -286,7 +303,7 @@ void KRTextureManager::balanceTextureMemory() 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; - for(std::set::iterator itr=m_activeTextures.begin(); itr != m_activeTextures.end() && memory_available > 0; itr++) { + 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); } @@ -297,7 +314,7 @@ void KRTextureManager::balanceTextureMemory() } // Resize active textures to balance the memory usage and mipmap levels - for(std::set::iterator itr=m_activeTextures.begin(); itr != m_activeTextures.end() && memory_available > 0; itr++) { + for(std::set::iterator itr=m_activeTextures_streamer.begin(); itr != m_activeTextures_streamer.end() && memory_available > 0; itr++) { KRTexture *activeTexture = *itr; activeTexture->resize(maxDimActive); } diff --git a/KREngine/kraken/KRTextureManager.h b/KREngine/kraken/KRTextureManager.h index 02af498..222aac8 100644 --- a/KREngine/kraken/KRTextureManager.h +++ b/KREngine/kraken/KRTextureManager.h @@ -78,6 +78,8 @@ public: void _clearGLState(); void setMaxAnisotropy(float max_anisotropy); + void doStreaming(); + private: int m_iActiveTexture; @@ -89,15 +91,24 @@ private: GLuint m_wrapModeS[KRENGINE_MAX_TEXTURE_UNITS]; GLuint m_wrapModeT[KRENGINE_MAX_TEXTURE_UNITS]; float m_maxAnisotropy[KRENGINE_MAX_TEXTURE_UNITS]; + + std::set m_activeTextures; std::set m_poolTextures; + std::set m_activeTextures_streamer; + std::set m_poolTextures_streamer; + std::set m_activeTextures_streamer_copy; + std::set m_poolTextures_streamer_copy; + long m_textureMemUsed; void rotateBuffers(); void balanceTextureMemory(); KRTextureStreamer m_streamer; + + std::mutex m_streamerFenceMutex; }; #endif diff --git a/KREngine/kraken/KRTextureStreamer.h b/KREngine/kraken/KRTextureStreamer.h index b370871..22dbdb0 100644 --- a/KREngine/kraken/KRTextureStreamer.h +++ b/KREngine/kraken/KRTextureStreamer.h @@ -45,13 +45,17 @@ public: KRTextureStreamer(KRContext &context); ~KRTextureStreamer(); + void startStreamer(); + private: KRContext &m_context; std::thread m_thread; std::atomic m_stop; + std::atomic m_running; void run(); + }; #endif /* defined(KRTEXTURESTREAMER_H) */ diff --git a/KREngine/kraken/KRTextureStreamer.mm b/KREngine/kraken/KRTextureStreamer.mm index 004b2d9..26bc2ca 100644 --- a/KREngine/kraken/KRTextureStreamer.mm +++ b/KREngine/kraken/KRTextureStreamer.mm @@ -9,16 +9,25 @@ #include "KREngine-common.h" #include "KRTextureStreamer.h" +#include "KRContext.h" #include -EAGLContext *gTextureStreamerContext; +EAGLContext *gTextureStreamerContext = nil; KRTextureStreamer::KRTextureStreamer(KRContext &context) : m_context(context) { - gTextureStreamerContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 sharegroup: [EAGLContext currentContext].sharegroup]; + m_running = false; m_stop = false; - m_thread = std::thread(&KRTextureStreamer::run, this); +} + +void KRTextureStreamer::startStreamer() +{ + if(!m_running) { + m_running = true; + gTextureStreamerContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 sharegroup: [EAGLContext currentContext].sharegroup]; + m_thread = std::thread(&KRTextureStreamer::run, this); + } } KRTextureStreamer::~KRTextureStreamer() @@ -36,6 +45,11 @@ void KRTextureStreamer::run() while(!m_stop) { + if(m_context.getStreamingEnabled()) { + m_context.getTextureManager()->doStreaming(); + } std::this_thread::sleep_for( sleep_duration ); } + + m_running = false; }