Extend caching abilities to compressed textures. Also, improve the structure of cache directories to fit new needs.

This commit is contained in:
Guillaume P 2014-05-08 18:04:22 +02:00
parent ab824f0ac3
commit af91b8b4ae
6 changed files with 160 additions and 18 deletions

View File

@ -68,6 +68,8 @@ PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;
PFNGLGETUNIFORMBLOCKINDEXPROC glGetUniformBlockIndex; PFNGLGETUNIFORMBLOCKINDEXPROC glGetUniformBlockIndex;
PFNGLUNIFORMBLOCKBINDINGPROC glUniformBlockBinding; PFNGLUNIFORMBLOCKBINDINGPROC glUniformBlockBinding;
PFNGLBLENDCOLORPROC glBlendColor; PFNGLBLENDCOLORPROC glBlendColor;
PFNGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D;
PFNGLGETCOMPRESSEDTEXIMAGEPROC glGetCompressedTexImage;
#endif #endif
static bool is_gl_init = false; static bool is_gl_init = false;
@ -215,6 +217,8 @@ void initGL()
glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)IRR_OGL_LOAD_EXTENSION("glGetUniformBlockIndex"); glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)IRR_OGL_LOAD_EXTENSION("glGetUniformBlockIndex");
glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)IRR_OGL_LOAD_EXTENSION("glUniformBlockBinding"); glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)IRR_OGL_LOAD_EXTENSION("glUniformBlockBinding");
glBlendColor = (PFNGLBLENDCOLORPROC)IRR_OGL_LOAD_EXTENSION("glBlendColor"); glBlendColor = (PFNGLBLENDCOLORPROC)IRR_OGL_LOAD_EXTENSION("glBlendColor");
glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)IRR_OGL_LOAD_EXTENSION("glCompressedTexImage2D");
glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)IRR_OGL_LOAD_EXTENSION("glGetCompressedTexImage");
#ifdef DEBUG #ifdef DEBUG
glDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC)IRR_OGL_LOAD_EXTENSION("glDebugMessageCallbackARB"); glDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC)IRR_OGL_LOAD_EXTENSION("glDebugMessageCallbackARB");
#endif #endif
@ -303,17 +307,32 @@ GLuint getDepthTexture(irr::video::ITexture *tex)
} }
std::set<irr::video::ITexture *> AlreadyTransformedTexture; std::set<irr::video::ITexture *> AlreadyTransformedTexture;
void compressTexture(irr::video::ITexture *tex, bool srgb) void compressTexture(irr::video::ITexture *tex, bool srgb)
{ {
if (AlreadyTransformedTexture.find(tex) != AlreadyTransformedTexture.end()) if (AlreadyTransformedTexture.find(tex) != AlreadyTransformedTexture.end())
return; return;
AlreadyTransformedTexture.insert(tex); AlreadyTransformedTexture.insert(tex);
glBindTexture(GL_TEXTURE_2D, getTextureGLuint(tex));
std::string cached_file;
if (UserConfigParams::m_texture_compression)
{
// Try to retrieve the compressed texture in cache
std::string tex_name = irr_driver->getTextureName(tex);
if (!tex_name.empty()) {
cached_file = file_manager->getTextureCacheLocation(tex_name) + ".gltz";
if (!file_manager->fileIsNewer(tex_name, cached_file)) {
if (loadCompressedTexture(cached_file))
return;
}
}
}
size_t w = tex->getSize().Width, h = tex->getSize().Height; size_t w = tex->getSize().Width, h = tex->getSize().Height;
char *data = new char[w * h * 4]; char *data = new char[w * h * 4];
memcpy(data, tex->lock(), w * h * 4); memcpy(data, tex->lock(), w * h * 4);
tex->unlock(); tex->unlock();
glBindTexture(GL_TEXTURE_2D, getTextureGLuint(tex));
unsigned internalFormat, Format; unsigned internalFormat, Format;
if (tex->hasAlpha()) if (tex->hasAlpha())
Format = GL_BGRA; Format = GL_BGRA;
@ -337,6 +356,84 @@ void compressTexture(irr::video::ITexture *tex, bool srgb)
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, w, h, 0, Format, GL_UNSIGNED_BYTE, (GLvoid *)data); glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, w, h, 0, Format, GL_UNSIGNED_BYTE, (GLvoid *)data);
glGenerateMipmap(GL_TEXTURE_2D); glGenerateMipmap(GL_TEXTURE_2D);
delete[] data; delete[] data;
if (UserConfigParams::m_texture_compression && !cached_file.empty())
{
// Save the compressed texture in the cache for later use.
saveCompressedTexture(cached_file);
}
}
//-----------------------------------------------------------------------------
/** Try to load a compressed texture from the given file name.
* Data in the specified file need to have a specific format. See the
* saveCompressedTexture() function for a description of the format.
* \return true if the loading succeeded, false otherwise.
* \see saveCompressedTexture
*/
bool loadCompressedTexture(const std::string& compressed_tex)
{
std::ifstream ifs(compressed_tex, std::ios::in | std::ios::binary);
if (!ifs.is_open())
return false;
int internal_format;
int w, h;
int size = -1;
ifs.read((char*)&internal_format, sizeof(int));
ifs.read((char*)&w, sizeof(int));
ifs.read((char*)&h, sizeof(int));
ifs.read((char*)&size, sizeof(int));
if (ifs.fail() || size == -1)
return false;
char *data = new char[size];
ifs.read(data, size);
if (!ifs.fail())
{
glCompressedTexImage2D(GL_TEXTURE_2D, 0, internal_format,
w, h, 0, size, (GLvoid*)data);
glGenerateMipmap(GL_TEXTURE_2D);
delete[] data;
ifs.close();
return true;
}
delete[] data;
return false;
}
//-----------------------------------------------------------------------------
/** Try to save the last texture sent to glTexImage2D in a file of the given
* file name. This function should only be used for textures sent to
* glTexImage2D with a compressed internal format as argument.<br>
* \note The following format is used to save the compressed texture:<br>
* <internal-format><width><height><size><data> <br>
* The first four elements are integers and the last one is stored
* on \c size bytes.
* \see loadCompressedTexture
*/
void saveCompressedTexture(const std::string& compressed_tex)
{
int internal_format, width, height, size;
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, (GLint *)&internal_format);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, (GLint *)&width);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, (GLint *)&height);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, (GLint *)&size);
char *data = new char[size];
glGetCompressedTexImage(GL_TEXTURE_2D, 0, (GLvoid*)data);
std::ofstream ofs(compressed_tex, std::ios::out | std::ios::binary);
if (ofs.is_open())
{
ofs.write((char*)&internal_format, sizeof(int));
ofs.write((char*)&width, sizeof(int));
ofs.write((char*)&height, sizeof(int));
ofs.write((char*)&size, sizeof(int));
ofs.write(data, size);
ofs.close();
}
delete[] data;
} }
void setTexture(unsigned TextureUnit, GLuint TextureId, GLenum MagFilter, GLenum MinFilter, bool allowAF) void setTexture(unsigned TextureUnit, GLuint TextureId, GLenum MagFilter, GLenum MinFilter, bool allowAF)

View File

@ -85,6 +85,8 @@ extern PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;
extern PFNGLGETUNIFORMBLOCKINDEXPROC glGetUniformBlockIndex; extern PFNGLGETUNIFORMBLOCKINDEXPROC glGetUniformBlockIndex;
extern PFNGLUNIFORMBLOCKBINDINGPROC glUniformBlockBinding; extern PFNGLUNIFORMBLOCKBINDINGPROC glUniformBlockBinding;
extern PFNGLBLENDCOLORPROC glBlendColor; extern PFNGLBLENDCOLORPROC glBlendColor;
extern PFNGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D;
extern PFNGLGETCOMPRESSEDTEXIMAGEPROC glGetCompressedTexImage;
#ifdef DEBUG #ifdef DEBUG
extern PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB; extern PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB;
#endif #endif
@ -160,6 +162,8 @@ GLint LoadProgram(Types ... args)
GLuint getTextureGLuint(irr::video::ITexture *tex); GLuint getTextureGLuint(irr::video::ITexture *tex);
GLuint getDepthTexture(irr::video::ITexture *tex); GLuint getDepthTexture(irr::video::ITexture *tex);
void compressTexture(irr::video::ITexture *tex, bool srgb); void compressTexture(irr::video::ITexture *tex, bool srgb);
bool loadCompressedTexture(const std::string& compressed_tex);
void saveCompressedTexture(const std::string& compressed_tex);
void blitFBO(GLuint Src, GLuint Dst, size_t width, size_t height); void blitFBO(GLuint Src, GLuint Dst, size_t width, size_t height);
void draw2DImage(const irr::video::ITexture* texture, const irr::core::rect<s32>& destRect, void draw2DImage(const irr::video::ITexture* texture, const irr::core::rect<s32>& destRect,

View File

@ -1245,7 +1245,8 @@ void IrrDriver::unsetTextureErrorMessage()
* version for each of them and save them in the cache. Smaller textures are * version for each of them and save them in the cache. Smaller textures are
* generated only if they do not already exist or if their original version * generated only if they do not already exist or if their original version
* is newer than the cached one. * is newer than the cached one.
* \param dir Directory from where textures will be retrieve. * \param dir Directory from where textures will be retrieved.
* Must end with '/'.
* \return Directory where smaller textures were cached. * \return Directory where smaller textures were cached.
*/ */
std::string IrrDriver::generateSmallerTextures(const std::string& dir) std::string IrrDriver::generateSmallerTextures(const std::string& dir)
@ -1263,7 +1264,7 @@ std::string IrrDriver::generateSmallerTextures(const std::string& dir)
} }
} // for it in files } // for it in files
return file_manager->getCachedTexturesDir(); return file_manager->getTextureCacheLocation(dir);
} // generateSmallerTextures } // generateSmallerTextures
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -1272,21 +1273,11 @@ std::string IrrDriver::generateSmallerTextures(const std::string& dir)
* exist or if the original version is newer than the cached one. * exist or if the original version is newer than the cached one.
* \param filename File name of the original texture. * \param filename File name of the original texture.
* \return File name of the cached texture. * \return File name of the cached texture.
*
* \todo Regenerate the texture if the original version is newer than the
* cached one.
*/ */
std::string IrrDriver::getSmallerTexture(const std::string& filename) std::string IrrDriver::getSmallerTexture(const std::string& filename)
{ {
// Retrieve the filename of the cached texture // Retrieve the filename of the cached texture
std::string file = StringUtils::getBasename(filename); std::string cached_file = file_manager->getTextureCacheLocation(filename);
std::string parent_dir = StringUtils::getPath(filename);
if (StringUtils::hasSuffix(parent_dir, "/"))
parent_dir = parent_dir.substr(0, parent_dir.size() - 1);
parent_dir = StringUtils::getBasename(parent_dir);
std::string cached_file = file_manager->getCachedTexturesDir() + parent_dir + "/";
file_manager->checkAndCreateDirectoryP(cached_file);
cached_file += file;
// If the cached texture does not exist, we generate it. // If the cached texture does not exist, we generate it.
if (!file_manager->fileExists(cached_file) || if (!file_manager->fileExists(cached_file) ||
@ -1428,9 +1419,26 @@ video::ITexture *IrrDriver::getTexture(const std::string &filename,
Log::error("irr_driver", "Texture '%s' not found.", filename.c_str()); Log::error("irr_driver", "Texture '%s' not found.", filename.c_str());
} }
m_texturesFileName[out] = filename;
return out; return out;
} // getTexture } // getTexture
// ----------------------------------------------------------------------------
/** Get the texture file name using a texture pointer.
* \param tex Pointer on the texture for which we want to find the file name.
* \return Filename of the texture if found, or an empty string otherwise.
*/
std::string IrrDriver::getTextureName(video::ITexture* tex)
{
std::map<video::ITexture*, std::string>::iterator it;
it = m_texturesFileName.find(tex);
if (it != m_texturesFileName.end())
return it->second;
else
return "";
} // getTextureName
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Appends a pointer to each texture used in this mesh to the vector. /** Appends a pointer to each texture used in this mesh to the vector.
* \param mesh The mesh from which the textures are being determined. * \param mesh The mesh from which the textures are being determined.

View File

@ -133,6 +133,8 @@ private:
float greenSHCoeff[9]; float greenSHCoeff[9];
float redSHCoeff[9]; float redSHCoeff[9];
/** Keep a trace of the origin file name of a texture. */
std::map<video::ITexture*, std::string> m_texturesFileName;
/** Flag to indicate if a resolution change is pending (which will be /** Flag to indicate if a resolution change is pending (which will be
* acted upon in the next update). None means no change, yes means * acted upon in the next update). None means no change, yes means
@ -311,6 +313,7 @@ public:
bool is_premul=false, bool is_premul=false,
bool is_prediv=false, bool is_prediv=false,
bool complain_if_not_found=true); bool complain_if_not_found=true);
std::string getTextureName(video::ITexture* tex);
void grabAllTextures(const scene::IMesh *mesh); void grabAllTextures(const scene::IMesh *mesh);
void dropAllTextures(const scene::IMesh *mesh); void dropAllTextures(const scene::IMesh *mesh);
scene::IMesh *createQuadMesh(const video::SMaterial *material=NULL, scene::IMesh *createQuadMesh(const video::SMaterial *material=NULL,

View File

@ -868,13 +868,13 @@ void FileManager::checkAndCreateScreenshotDir()
void FileManager::checkAndCreateCachedTexturesDir() void FileManager::checkAndCreateCachedTexturesDir()
{ {
#if defined(WIN32) || defined(__CYGWIN__) #if defined(WIN32) || defined(__CYGWIN__)
m_cached_textures_dir = m_user_config_dir + "resized-textures/"; m_cached_textures_dir = m_user_config_dir + "cached-textures/";
#elif defined(__APPLE__) #elif defined(__APPLE__)
m_cached_textures_dir = getenv("HOME"); m_cached_textures_dir = getenv("HOME");
m_cached_textures_dir += "/Library/Application Support/SuperTuxKart/ResizedTextures/"; m_cached_textures_dir += "/Library/Application Support/SuperTuxKart/CachedTextures/";
#else #else
m_cached_textures_dir = checkAndCreateLinuxDir("XDG_CACHE_HOME", "supertuxkart", ".cache/", "."); m_cached_textures_dir = checkAndCreateLinuxDir("XDG_CACHE_HOME", "supertuxkart", ".cache/", ".");
m_cached_textures_dir += "resized-textures/"; m_cached_textures_dir += "cached-textures/";
#endif #endif
if (!checkAndCreateDirectory(m_cached_textures_dir)) if (!checkAndCreateDirectory(m_cached_textures_dir))
@ -1010,6 +1010,35 @@ void FileManager::redirectOutput()
Log::openOutputFiles(logoutfile); Log::openOutputFiles(logoutfile);
} // redirectOutput } // redirectOutput
//-----------------------------------------------------------------------------
/** Returns the theoretical location of the cached version of a texture
* depending of the current config. (This function also works for directories:
* in this case the returned directory will be the cache location for all
* textures that you will find in the specified directory. The specified
* directory must end with '/')
* \note The returned location is where the cached data should be read or
* written but the file itseft does not necessarity exist. However, the
* directory structure is automatically created if it does not exist.
*/
std::string FileManager::getTextureCacheLocation(const std::string& filename)
{
std::string file = StringUtils::getBasename(filename);
std::string parent_dir = StringUtils::getPath(filename);
if (StringUtils::hasSuffix(parent_dir, "/"))
parent_dir = parent_dir.substr(0, parent_dir.size() - 1);
parent_dir = StringUtils::getBasename(parent_dir);
std::string cache_subdir = UserConfigParams::m_high_definition_textures
? "hd/"
: "resized/";
std::string cached_file =
getCachedTexturesDir() + cache_subdir + parent_dir + "/";
checkAndCreateDirectoryP(cached_file);
cached_file += file;
return cached_file;
} // getTextureCacheLocation
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Returns the directory for addon files. */ /** Returns the directory for addon files. */
const std::string &FileManager::getAddonsDir() const const std::string &FileManager::getAddonsDir() const

View File

@ -116,6 +116,7 @@ public:
std::string getScreenshotDir() const; std::string getScreenshotDir() const;
std::string getCachedTexturesDir() const; std::string getCachedTexturesDir() const;
std::string getGPDir() const; std::string getGPDir() const;
std::string getTextureCacheLocation(const std::string& filename);
bool checkAndCreateDirectoryP(const std::string &path); bool checkAndCreateDirectoryP(const std::string &path);
const std::string &getAddonsDir() const; const std::string &getAddonsDir() const;
std::string getAddonsFile(const std::string &name); std::string getAddonsFile(const std::string &name);