Extend caching abilities to compressed textures. Also, improve the structure of cache directories to fit new needs.
This commit is contained in:
parent
ab824f0ac3
commit
af91b8b4ae
@ -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)
|
||||||
|
@ -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,
|
||||||
|
@ -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.
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user