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:
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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, int prev_lod_max_dim, bool compress = false, bool premultiply_alpha = false) = 0;
|
||||
virtual bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, bool compress = false, bool premultiply_alpha = false) = 0;
|
||||
virtual void bind(GLuint texture_unit);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -153,7 +153,7 @@ long KRTextureKTX::getMemRequiredForSize(int max_dim)
|
||||
return memoryRequired;
|
||||
}
|
||||
|
||||
bool KRTextureKTX::uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, int prev_lod_max_dim, bool compress, bool premultiply_alpha)
|
||||
bool KRTextureKTX::uploadTexture(GLenum target, int lod_max_dim, int ¤t_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 ¤t_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 ¤t_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++;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ public:
|
||||
virtual ~KRTextureKTX();
|
||||
virtual std::string getExtension();
|
||||
|
||||
bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, int prev_lod_max_dim, bool compress = false, bool premultiply_alpha = false);
|
||||
bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, bool compress = false, bool premultiply_alpha = false);
|
||||
|
||||
virtual long getMemRequiredForSize(int max_dim);
|
||||
|
||||
|
||||
@@ -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()) {
|
||||
KRTextureCube *pTexture = new KRTextureCube(getContext(), lowerName);
|
||||
|
||||
m_textures[lowerName] = pTexture;
|
||||
return pTexture;
|
||||
// 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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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, int prev_lod_max_dim, bool compress, bool premultiply_alpha)
|
||||
bool KRTexturePVR::uploadTexture(GLenum target, int lod_max_dim, int ¤t_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 ¤t_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 ¤t_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++;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ public:
|
||||
virtual ~KRTexturePVR();
|
||||
virtual std::string getExtension();
|
||||
|
||||
bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, int prev_lod_max_dim, bool compress = false, bool premultiply_alpha = false);
|
||||
bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, bool compress = false, bool premultiply_alpha = false);
|
||||
|
||||
virtual long getMemRequiredForSize(int max_dim);
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ KRTextureTGA::~KRTextureTGA()
|
||||
|
||||
}
|
||||
|
||||
bool KRTextureTGA::uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, int prev_lod_max_dim, bool compress, bool premultiply_alpha)
|
||||
bool KRTextureTGA::uploadTexture(GLenum target, int lod_max_dim, int ¤t_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));
|
||||
|
||||
@@ -18,7 +18,7 @@ public:
|
||||
virtual ~KRTextureTGA();
|
||||
virtual std::string getExtension();
|
||||
|
||||
bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, int prev_lod_max_dim, bool compress = false, bool premultiply_alpha = false);
|
||||
bool uploadTexture(GLenum target, int lod_max_dim, int ¤t_lod_max_dim, bool compress = false, bool premultiply_alpha = false);
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
virtual KRTexture *compress(bool premultiply_alpha = false);
|
||||
|
||||
Reference in New Issue
Block a user