Asynchronous streaming and memory management improvements in progress.

--HG--
branch : async_streaming
This commit is contained in:
2013-11-16 02:34:18 -08:00
parent cf732a6721
commit 8b29ffab69
23 changed files with 301 additions and 247 deletions

View File

@@ -297,3 +297,31 @@ void KRAnimation::deleteCurves()
}
}
void KRAnimation::_lockData()
{
for(unordered_map<std::string, KRAnimationLayer *>::iterator layer_itr = m_layers.begin(); layer_itr != m_layers.end(); layer_itr++) {
KRAnimationLayer *layer = (*layer_itr).second;
for(std::vector<KRAnimationAttribute *>::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<std::string, KRAnimationLayer *>::iterator layer_itr = m_layers.begin(); layer_itr != m_layers.end(); layer_itr++) {
KRAnimationLayer *layer = (*layer_itr).second;
for(std::vector<KRAnimationAttribute *>::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();
}
}
}
}

View File

@@ -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<std::string, KRAnimationLayer *> m_layers;
bool m_auto_play;

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -38,6 +38,11 @@ KRAnimationManager::KRAnimationManager(KRContext &context) : KRContextObject(con
}
KRAnimationManager::~KRAnimationManager() {
for(std::set<KRAnimation *>::iterator itr = m_activeAnimations.begin(); itr != m_activeAnimations.end(); itr++) {
KRAnimation *animation = *itr;
animation->_unlockData();
}
for(unordered_map<std::string, KRAnimation *>::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();
}
}
}

View File

@@ -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
}

View File

@@ -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;

View File

@@ -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

View File

@@ -34,6 +34,8 @@
#include "KREngine-common.h"
#define KRENGINE_MIN_MMAP 327680000
class KRDataBlock {
public:
KRDataBlock();

View File

@@ -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;

View File

@@ -32,6 +32,8 @@ KRMeshStreamer::~KRMeshStreamer()
void KRMeshStreamer::run()
{
pthread_setname_np("Kraken - Mesh Streamer");
std::chrono::microseconds sleep_duration( 100 );
[EAGLContext setCurrentContext: gMeshStreamerContext];

View File

@@ -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();
}
}

View File

@@ -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<long> m_textureMemUsed;
std::atomic<long> m_newTextureMemUsed;
};

View File

@@ -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;

View File

@@ -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 &current_lod_max_dim, long &textureMemUsed, int prev_lod_max_dim) = 0;
virtual bool uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, int prev_lod_max_dim) = 0;
virtual void bind(GLuint texture_unit);
protected:

View File

@@ -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;

View File

@@ -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<KRTexture *>::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<KRTexture *>::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<KRTexture *>::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<std::string, KRTexture *> &KRTextureManager::getTextures()

View File

@@ -101,7 +101,7 @@ private:
std::set<KRTexture *> m_activeTextures_streamer_copy;
std::set<KRTexture *> m_poolTextures_streamer_copy;
long m_textureMemUsed;
std::atomic<long> m_textureMemUsed;
void rotateBuffers();
void balanceTextureMemory();

View File

@@ -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<KRDataBlock *>::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<dataBlockStruct>::iterator itr = m_blocks.begin(); itr != m_blocks.end(); itr++) {
dataBlockStruct block = *itr;
for(std::list<KRDataBlock *>::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 &current_lod_max_dim, long &textureMemUsed, int prev_lod_max_dim)
bool KRTexturePVR::uploadTexture(GLenum target, int lod_max_dim, int &current_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 &current_lo
int level_count=0;
int max_lod_width=0;
int max_lod_height=0;
for(std::list<dataBlockStruct>::iterator itr = m_blocks.begin(); itr != m_blocks.end(); itr++) {
for(std::list<KRDataBlock *>::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 &current_lo
// Upload texture data
int destination_level=0;
int source_level = 0;
for(std::list<dataBlockStruct>::iterator itr = m_blocks.begin(); itr != m_blocks.end(); itr++) {
dataBlockStruct block = *itr;
for(std::list<KRDataBlock *>::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 &current_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 &current_lo
}
}
textureMemUsed += memoryRequired;
getContext().getTextureManager()->memoryChanged(memoryRequired);
getContext().getTextureManager()->addMemoryTransferredThisFrame(memoryTransferred);
return true;
}

View File

@@ -18,7 +18,7 @@ public:
virtual ~KRTexturePVR();
virtual std::string getExtension();
bool uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, long &textureMemUsed, int prev_lod_max_dim);
bool uploadTexture(GLenum target, int lod_max_dim, int &current_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<dataBlockStruct> m_blocks;
std::list<KRDataBlock *> m_blocks;
};
#endif

View File

@@ -40,6 +40,8 @@ KRTextureStreamer::~KRTextureStreamer()
void KRTextureStreamer::run()
{
pthread_setname_np("Kraken - Texture Streamer");
std::chrono::microseconds sleep_duration( 100 );
[EAGLContext setCurrentContext: gTextureStreamerContext];

View File

@@ -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 &current_lod_max_dim, long &textureMemUsed, int prev_lod_max_dim)
bool KRTextureTGA::uploadTexture(GLenum target, int lod_max_dim, int &current_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 &current_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 &current_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 &current_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()

View File

@@ -18,9 +18,11 @@ public:
virtual ~KRTextureTGA();
virtual std::string getExtension();
bool uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, long &textureMemUsed, int prev_lod_max_dim);
bool uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, int prev_lod_max_dim);
virtual long getMemRequiredForSize(int max_dim);
private:
long m_imageSize;
};
#endif