Asynchronous streaming and memory management improvements in progress.
--HG-- branch : async_streaming
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -73,6 +73,8 @@ public:
|
||||
long getAbsoluteTimeMilliseconds();
|
||||
|
||||
std::vector<KRResource *> 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<bool> m_streamingEnabled;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
float const PI = 3.141592653589793f;
|
||||
float const D2R = PI * 2 / 360;
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "KRMeshStreamer.h"
|
||||
|
||||
#include "KREngine-common.h"
|
||||
#include "KRContext.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
@@ -36,6 +37,9 @@ void KRMeshStreamer::run()
|
||||
|
||||
while(!m_stop)
|
||||
{
|
||||
if(m_context.getStreamingEnabled()) {
|
||||
|
||||
}
|
||||
std::this_thread::sleep_for( sleep_duration );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -215,13 +215,20 @@ long KRTextureManager::getMemActive() {
|
||||
|
||||
void KRTextureManager::startFrame(float deltaTime)
|
||||
{
|
||||
m_streamer.startStreamer();
|
||||
_clearGLState();
|
||||
for(std::set<KRTexture *>::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<KRTexture *>::iterator itr=m_activeTextures.begin(); itr != m_activeTextures.end(); itr++) {
|
||||
for(std::set<KRTexture *>::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<KRTexture *>::iterator itr=m_poolTextures.begin(); itr != m_poolTextures.end(); itr++) {
|
||||
for(std::set<KRTexture *>::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<KRTexture *>::iterator itr=m_poolTextures.begin(); itr != m_poolTextures.end(); itr++) {
|
||||
for(std::set<KRTexture *>::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<KRTexture *>::iterator itr=m_activeTextures.begin(); itr != m_activeTextures.end() && memory_available > 0; itr++) {
|
||||
for(std::set<KRTexture *>::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<KRTexture *>::iterator itr=m_activeTextures.begin(); itr != m_activeTextures.end() && memory_available > 0; itr++) {
|
||||
for(std::set<KRTexture *>::iterator itr=m_activeTextures_streamer.begin(); itr != m_activeTextures_streamer.end() && memory_available > 0; itr++) {
|
||||
KRTexture *activeTexture = *itr;
|
||||
activeTexture->resize(maxDimActive);
|
||||
}
|
||||
|
||||
@@ -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<KRTexture *> m_activeTextures;
|
||||
std::set<KRTexture *> m_poolTextures;
|
||||
|
||||
std::set<KRTexture *> m_activeTextures_streamer;
|
||||
std::set<KRTexture *> m_poolTextures_streamer;
|
||||
std::set<KRTexture *> m_activeTextures_streamer_copy;
|
||||
std::set<KRTexture *> m_poolTextures_streamer_copy;
|
||||
|
||||
long m_textureMemUsed;
|
||||
|
||||
void rotateBuffers();
|
||||
void balanceTextureMemory();
|
||||
|
||||
KRTextureStreamer m_streamer;
|
||||
|
||||
std::mutex m_streamerFenceMutex;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -45,13 +45,17 @@ public:
|
||||
KRTextureStreamer(KRContext &context);
|
||||
~KRTextureStreamer();
|
||||
|
||||
void startStreamer();
|
||||
|
||||
private:
|
||||
KRContext &m_context;
|
||||
|
||||
std::thread m_thread;
|
||||
std::atomic<bool> m_stop;
|
||||
std::atomic<bool> m_running;
|
||||
|
||||
void run();
|
||||
|
||||
};
|
||||
|
||||
#endif /* defined(KRTEXTURESTREAMER_H) */
|
||||
|
||||
@@ -9,16 +9,25 @@
|
||||
#include "KREngine-common.h"
|
||||
|
||||
#include "KRTextureStreamer.h"
|
||||
#include "KRContext.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user