Corrected bug that allowed incomplete cube map textures to attempt to load, resulting in gl errors

Implemented procedural loading of textures with new streamer algorithm
Fixed thread safety issues in streamer (double-buffered old level tracking variables)
Texture streamer now only processes once per frame

--HG--
branch : nfb
This commit is contained in:
2014-04-14 00:47:29 -07:00
parent 462d0ec6e7
commit ee35c5540e
14 changed files with 92 additions and 53 deletions

View File

@@ -55,7 +55,7 @@ void KRLODSet::updateLODVisibility(const KRViewport &viewport)
} else if(m_activeLODGroup == NULL) {
m_activeLODGroup = new_active_lod_group;
} else if(new_active_lod_group != m_activeLODGroup) {
if(/*true || */new_active_lod_group->getStreamLevel(true, viewport) >= kraken_stream_level::STREAM_LEVEL_IN_LQ) { // FINDME, HACK! Disabled due to performance issues.
if(true || new_active_lod_group->getStreamLevel(true, viewport) >= kraken_stream_level::STREAM_LEVEL_IN_LQ) { // FINDME, HACK! Disabled due to performance issues.
// fprintf(stderr, "LOD %s -> %s\n", m_activeLODGroup->getName().c_str(), new_active_lod_group->getName().c_str());
m_activeLODGroup = new_active_lod_group;
} else {

View File

@@ -14,6 +14,8 @@
KRTexture::KRTexture(KRContext &context, std::string name) : KRResource(context, name)
{
m_current_lod_max_dim = 0;
m_new_lod_max_dim = 0;
m_iHandle = 0;
m_iNewHandle = 0;
m_textureMemUsed = 0;
@@ -45,6 +47,8 @@ void KRTexture::releaseHandles() {
m_iHandle = 0;
m_textureMemUsed = 0;
}
m_current_lod_max_dim = 0;
m_new_lod_max_dim = 0;
m_handle_lock.clear();
@@ -71,7 +75,7 @@ void KRTexture::resize(int max_dim)
int target_dim = max_dim;
if(target_dim < m_min_lod_max_dim) target_dim = m_min_lod_max_dim;
if(m_current_lod_max_dim != target_dim || (m_iHandle == 0 && m_iNewHandle == 0)) {
if(m_new_lod_max_dim != target_dim || (m_iHandle == 0 && m_iNewHandle == 0)) {
assert(m_newTextureMemUsed == 0);
m_newTextureMemUsed = getMemRequiredForSize(target_dim);
@@ -175,6 +179,10 @@ int KRTexture::getCurrentLodMaxDim() {
return m_current_lod_max_dim;
}
int KRTexture::getNewLodMaxDim() {
return m_new_lod_max_dim;
}
int KRTexture::getMaxMipMap() {
return m_max_lod_max_dim;
}
@@ -207,6 +215,7 @@ void KRTexture::_swapHandles()
m_textureMemUsed = (long)m_newTextureMemUsed;
m_newTextureMemUsed = 0;
m_iHandle = m_iNewHandle;
m_current_lod_max_dim = m_new_lod_max_dim;
}
m_handle_lock.clear();
}

View File

@@ -80,6 +80,7 @@ public:
virtual KRTexture *compress(bool premultiply_alpha = false);
int getCurrentLodMaxDim();
int getNewLodMaxDim(); // For use by streamer only
int getMaxMipMap();
int getMinMipMap();
bool hasMipmaps();
@@ -100,6 +101,7 @@ protected:
std::atomic_flag m_handle_lock;
int m_current_lod_max_dim;
int m_new_lod_max_dim;
uint32_t m_max_lod_max_dim;
uint32_t m_min_lod_max_dim;

View File

@@ -34,7 +34,6 @@
#include "KRTextureManager.h"
KRTexture2D::KRTexture2D(KRContext &context, KRDataBlock *data, std::string name) : KRTexture(context, name) {
m_current_lod_max_dim = 0;
m_pData = data;
}
@@ -48,16 +47,11 @@ bool KRTexture2D::createGLTexture(int lod_max_dim) {
}
bool success = true;
int prev_lod_max_dim = 0;
#if GL_APPLE_copy_texture_levels && GL_EXT_texture_storage
int prev_lod_max_dim = m_new_lod_max_dim;
if(m_iHandle != 0) {
prev_lod_max_dim = m_current_lod_max_dim;
}
#endif
m_iNewHandle = 0;
m_current_lod_max_dim = 0;
m_new_lod_max_dim = 0;
GLDEBUG(glGenTextures(1, &m_iNewHandle));
if(m_iNewHandle == 0) {
@@ -71,10 +65,10 @@ 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, prev_lod_max_dim)) {
if(!uploadTexture(GL_TEXTURE_2D, lod_max_dim, m_new_lod_max_dim)) {
GLDEBUG(glDeleteTextures(1, &m_iNewHandle));
m_iNewHandle = m_iHandle;
m_current_lod_max_dim = prev_lod_max_dim;
m_new_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, int prev_lod_max_dim, bool compress = false, bool premultiply_alpha = false) = 0;
virtual bool uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, bool compress = false, bool premultiply_alpha = false) = 0;
virtual void bind(GLuint texture_unit);
protected:

View File

@@ -46,6 +46,8 @@ KRTextureCube::KRTextureCube(KRContext &context, std::string name) : KRTexture(c
if(m_textures[i]) {
if(m_textures[i]->getMaxMipMap() < m_max_lod_max_dim) m_max_lod_max_dim = m_textures[i]->getMaxMipMap();
if(m_textures[i]->getMinMipMap() > m_min_lod_max_dim) m_min_lod_max_dim = m_textures[i]->getMinMipMap();
} else {
assert(false);
}
}
}
@@ -59,21 +61,12 @@ bool KRTextureCube::createGLTexture(int lod_max_dim)
assert(m_iNewHandle == m_iHandle); // Only allow one resize per frame
bool success = true;
int prev_lod_max_dim = 0;
#if GL_APPLE_copy_texture_levels && GL_EXT_texture_storage
if(m_iHandle != 0) {
prev_lod_max_dim = m_current_lod_max_dim;
}
#endif
m_iNewHandle = 0;
GLDEBUG(glGenTextures(1, &m_iNewHandle));
assert(m_iNewHandle != 0);
m_current_lod_max_dim = 0;
m_new_lod_max_dim = 0;
GLDEBUG(glBindTexture(GL_TEXTURE_CUBE_MAP, m_iNewHandle));
bool bMipMaps = false;
@@ -82,7 +75,7 @@ bool KRTextureCube::createGLTexture(int lod_max_dim)
std::string faceName = getName() + SUFFIXES[i];
if(m_textures[i]) {
if(m_textures[i]->hasMipmaps()) bMipMaps = true;
m_textures[i]->uploadTexture(TARGETS[i], lod_max_dim, m_current_lod_max_dim, prev_lod_max_dim);
m_textures[i]->uploadTexture(TARGETS[i], lod_max_dim, m_new_lod_max_dim);
}
}
@@ -112,7 +105,7 @@ long KRTextureCube::getMemRequiredForSize(int max_dim)
return memoryRequired;
}
/*
void KRTextureCube::resetPoolExpiry(float lodCoverage, texture_usage_t textureUsage)
{
KRTexture::resetPoolExpiry(lodCoverage, textureUsage);
@@ -122,6 +115,7 @@ void KRTextureCube::resetPoolExpiry(float lodCoverage, texture_usage_t textureUs
}
}
}
*/
void KRTextureCube::bind(GLuint texture_unit)
{

View File

@@ -46,7 +46,7 @@ public:
virtual void bind(GLuint texture_unit);
virtual long getMemRequiredForSize(int max_dim);
virtual void resetPoolExpiry(float lodCoverage, texture_usage_t textureUsage);
// virtual void resetPoolExpiry(float lodCoverage, texture_usage_t textureUsage);
private:
virtual bool createGLTexture(int lod_max_dim);

View File

@@ -153,7 +153,7 @@ long KRTextureKTX::getMemRequiredForSize(int max_dim)
return memoryRequired;
}
bool KRTextureKTX::uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, int prev_lod_max_dim, bool compress, bool premultiply_alpha)
bool KRTextureKTX::uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, bool compress, bool premultiply_alpha)
{
int target_dim = lod_max_dim;
if(target_dim < m_min_lod_max_dim) target_dim = m_min_lod_max_dim;
@@ -220,7 +220,7 @@ bool KRTextureKTX::uploadTexture(GLenum target, int lod_max_dim, int &current_lo
current_lod_max_dim = height;
}
#if GL_APPLE_copy_texture_levels && GL_EXT_texture_storage
if(target == GL_TEXTURE_2D && width <= prev_lod_max_dim && height <= prev_lod_max_dim) {
if(target == GL_TEXTURE_2D && width <= m_current_lod_max_dim && height <= m_current_lod_max_dim) {
//GLDEBUG(glCompressedTexImage2D(target, i, (GLenum)m_header.glInternalFormat, width, height, 0, block.length, NULL)); // Allocate, but don't copy
// GLDEBUG(glTexImage2D(target, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL));
GLDEBUG(glCopyTextureLevelsAPPLE(m_iNewHandle, m_iHandle, source_level, 1));
@@ -253,7 +253,7 @@ bool KRTextureKTX::uploadTexture(GLenum target, int lod_max_dim, int &current_lo
destination_level++;
}
if(width <= prev_lod_max_dim && height <= prev_lod_max_dim) {
if(width <= m_current_lod_max_dim && height <= m_current_lod_max_dim) {
source_level++;
}

View File

@@ -19,7 +19,7 @@ public:
virtual ~KRTextureKTX();
virtual std::string getExtension();
bool uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, int prev_lod_max_dim, bool compress = false, bool premultiply_alpha = false);
bool uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, bool compress = false, bool premultiply_alpha = false);
virtual long getMemRequiredForSize(int max_dim);

View File

@@ -145,10 +145,42 @@ KRTexture *KRTextureManager::getTextureCube(const char *szName) {
unordered_map<std::string, KRTexture *>::iterator itr = m_textures.find(lowerName);
if(itr == m_textures.end()) {
// Defer resolving the texture cube until its referenced textures are ready
const GLenum TARGETS[6] = {
GL_TEXTURE_CUBE_MAP_POSITIVE_X,
GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
};
const char *SUFFIXES[6] = {
"_positive_x",
"_negative_x",
"_positive_y",
"_negative_y",
"_positive_z",
"_negative_z"
};
bool found_all = true;
for(int i=0; i<6; i++) {
std::string faceName = lowerName + SUFFIXES[i];
KRTexture *faceTexture = dynamic_cast<KRTexture2D *>(getContext().getTextureManager()->getTexture(faceName));
if(faceTexture == NULL) {
found_all = false;
}
}
if(found_all) {
KRTextureCube *pTexture = new KRTextureCube(getContext(), lowerName);
m_textures[lowerName] = pTexture;
return pTexture;
} else {
return NULL;
}
} else {
return (*itr).second;
}
@@ -251,7 +283,7 @@ void KRTextureManager::doStreaming()
{
// TODO - Implement proper double-buffering to reduce copy operations
m_streamerFenceMutex.lock();
m_activeTextures_streamer = m_activeTextures_streamer_copy;
m_activeTextures_streamer = std::move(m_activeTextures_streamer_copy);
m_streamerFenceMutex.unlock();
balanceTextureMemory();
@@ -277,15 +309,8 @@ void KRTextureManager::balanceTextureMemory()
// ---------------
/*
// TODO - Would this be faster with int's for weights?
std::vector<std::pair<float, KRTexture *> > sortedTextures;
for(auto itr=m_activeTextures_streamer.begin(); itr != m_activeTextures_streamer.end(); itr++) {
KRTexture *texture = *itr;
float priority = texture->getStreamPriority();
sortedTextures.push_back(std::pair<float, KRTexture *>(priority, texture));
}
*/
//long MAX_STREAM_TIME = 66;
//long startTime = getContext().getAbsoluteTimeMilliseconds();
std::sort(m_activeTextures_streamer.begin(), m_activeTextures_streamer.end(), std::greater<std::pair<float, KRTexture *>>());
@@ -298,12 +323,14 @@ void KRTextureManager::balanceTextureMemory()
long minLodMem = texture->getMemRequiredForSize(min_mip_level);
memoryRemaining -= minLodMem;
if(memoryRemainingThisFrame > minLodMem && texture->getCurrentLodMaxDim() < min_mip_level) {
if(memoryRemainingThisFrame > minLodMem && texture->getNewLodMaxDim() < min_mip_level) {
memoryRemainingThisFrame -= minLodMem;
texture->resize(min_mip_level);
}
}
//long minMipTime = getContext().getAbsoluteTimeMilliseconds() - startTime;
std::vector<int> mipPercents = {75, 75, 50, 50, 50};
int mip_drop = -1;
auto mip_itr = mipPercents.begin();
@@ -329,13 +356,26 @@ void KRTextureManager::balanceTextureMemory()
memoryRemainingThisMip -= additionalMemRequired;
memoryRemaining -= additionalMemRequired;
if(memoryRemainingThisMip > 0 && memoryRemainingThisFrame > targetMem) {
if(texture->getCurrentLodMaxDim() != target_mip_level) {
int current_mip_level = texture->getNewLodMaxDim();
if(current_mip_level == (target_mip_level >> 1) || target_mip_level < current_mip_level) {
memoryRemainingThisFrame -= targetMem;
texture->resize(target_mip_level);
}
} else if(current_mip_level == (target_mip_level >> 2)) {
memoryRemainingThisFrame -= texture->getMemRequiredForSize(target_mip_level >> 1);
texture->resize(target_mip_level >> 1);
} else if(current_mip_level < (target_mip_level >> 2)) {
memoryRemainingThisFrame -= texture->getMemRequiredForSize(target_mip_level >> 2);
texture->resize(target_mip_level >> 2);
}
}
//if(getContext().getAbsoluteTimeMilliseconds() - startTime > MAX_STREAM_TIME) {
// return; // Bail out early if we spend too long
//}
}
//long streamerTime = getContext().getAbsoluteTimeMilliseconds() - startTime;
//fprintf(stderr, "%i / %i\n", (int)minMipTime, (int)streamerTime);
}

View File

@@ -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, int prev_lod_max_dim, bool compress, bool premultiply_alpha)
bool KRTexturePVR::uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, bool compress, bool premultiply_alpha)
{
int target_dim = lod_max_dim;
if(target_dim < m_min_lod_max_dim) target_dim = m_min_lod_max_dim;
@@ -240,7 +240,7 @@ bool KRTexturePVR::uploadTexture(GLenum target, int lod_max_dim, int &current_lo
current_lod_max_dim = height;
}
#if GL_APPLE_copy_texture_levels && GL_EXT_texture_storage
if(target == GL_TEXTURE_2D && width <= prev_lod_max_dim && height <= prev_lod_max_dim) {
if(target == GL_TEXTURE_2D && width <= m_current_lod_max_dim && height <= m_current_lod_max_dim) {
//GLDEBUG(glCompressedTexImage2D(target, i, m_internalFormat, width, height, 0, block.length, NULL)); // Allocate, but don't copy
// GLDEBUG(glTexImage2D(target, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL));
GLDEBUG(glCopyTextureLevelsAPPLE(m_iNewHandle, m_iHandle, source_level, 1));
@@ -273,7 +273,7 @@ bool KRTexturePVR::uploadTexture(GLenum target, int lod_max_dim, int &current_lo
destination_level++;
}
if(width <= prev_lod_max_dim && height <= prev_lod_max_dim) {
if(width <= m_current_lod_max_dim && height <= m_current_lod_max_dim) {
source_level++;
}

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, int prev_lod_max_dim, bool compress = false, bool premultiply_alpha = false);
bool uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, bool compress = false, bool premultiply_alpha = false);
virtual long getMemRequiredForSize(int max_dim);

View File

@@ -71,7 +71,7 @@ KRTextureTGA::~KRTextureTGA()
}
bool KRTextureTGA::uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, int prev_lod_max_dim, bool compress, bool premultiply_alpha)
bool KRTextureTGA::uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, bool compress, bool premultiply_alpha)
{
m_pData->lock();
TGA_HEADER *pHeader = (TGA_HEADER *)m_pData->getStart();
@@ -298,7 +298,7 @@ KRTexture *KRTextureTGA::compress(bool premultiply_alpha)
GLDEBUG(glBindTexture(GL_TEXTURE_2D, compressed_handle));
int current_max_dim = 0;
if(!uploadTexture(GL_TEXTURE_2D, m_max_lod_max_dim, current_max_dim, 0, true, premultiply_alpha)) {
if(!uploadTexture(GL_TEXTURE_2D, m_max_lod_max_dim, current_max_dim, true, premultiply_alpha)) {
assert(false); // Failed to upload the texture
}
GLDEBUG(glGenerateMipmap(GL_TEXTURE_2D));

View File

@@ -18,7 +18,7 @@ public:
virtual ~KRTextureTGA();
virtual std::string getExtension();
bool uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, int prev_lod_max_dim, bool compress = false, bool premultiply_alpha = false);
bool uploadTexture(GLenum target, int lod_max_dim, int &current_lod_max_dim, bool compress = false, bool premultiply_alpha = false);
#if !TARGET_OS_IPHONE
virtual KRTexture *compress(bool premultiply_alpha = false);