Remove unused texture code
This commit is contained in:
parent
3374ec66e3
commit
68ceceb6e3
@ -195,19 +195,8 @@ public:
|
||||
//! return open gl texture name
|
||||
virtual u32 getOpenGLTextureName() const = 0;
|
||||
|
||||
virtual u64 getHandle() = 0;
|
||||
|
||||
virtual void unloadHandle() {}
|
||||
|
||||
virtual u32 getTextureSize() const { return 0; }
|
||||
|
||||
virtual void threadedReload(void* ptr, void* param) const {}
|
||||
|
||||
virtual void threadedSubImage(void* ptr) const {}
|
||||
|
||||
virtual void cleanThreadedLoader() {}
|
||||
|
||||
virtual int getThreadedLoadTextureCounter() const { return 0; }
|
||||
protected:
|
||||
|
||||
//! Helper function, helps to get the desired texture creation format from the flags.
|
||||
|
@ -1,120 +0,0 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2017 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#if !(defined(SERVER_ONLY) || defined(USE_GLES2))
|
||||
|
||||
#include "graphics/hq_mipmap_generator.hpp"
|
||||
#include "graphics/stk_tex_manager.hpp"
|
||||
#undef DUMP_MIPMAP
|
||||
#ifdef DUMP_MIPMAP
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
#endif
|
||||
#include <cassert>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <mipmap/img.h>
|
||||
#include <mipmap/imgresize.h>
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
HQMipmapGenerator::HQMipmapGenerator(const io::path& name, uint8_t* data,
|
||||
const core::dimension2d<u32>& size,
|
||||
GLuint texture_name, TexConfig* tc)
|
||||
: video::ITexture(name), m_orig_data(data), m_size(size),
|
||||
m_texture_name(texture_name), m_texture_size(0),
|
||||
m_mipmap_data(NULL), m_tex_config(tc)
|
||||
{
|
||||
assert(m_tex_config != NULL);
|
||||
unsigned width = m_size.Width;
|
||||
unsigned height = m_size.Height;
|
||||
while (true)
|
||||
{
|
||||
width = width < 2 ? 1 : width >> 1;
|
||||
height = height < 2 ? 1 : height >> 1;
|
||||
m_mipmap_sizes.emplace_back(core::dimension2du(width, height),
|
||||
m_texture_size);
|
||||
m_texture_size += width * height * 4;
|
||||
if (width == 1 && height == 1)
|
||||
break;
|
||||
}
|
||||
m_texture_size = unsigned(m_mipmap_sizes.back().second) + 4;
|
||||
m_mipmap_data = malloc(sizeof(imMipmapCascade));
|
||||
} // HQMipmapGenerator
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void HQMipmapGenerator::threadedReload(void* ptr, void* param) const
|
||||
{
|
||||
imReduceOptions options;
|
||||
imReduceSetOptions(&options,
|
||||
m_tex_config->m_normal_map ?
|
||||
IM_REDUCE_FILTER_NORMALMAP: m_tex_config->m_srgb ?
|
||||
IM_REDUCE_FILTER_SRGB : IM_REDUCE_FILTER_LINEAR/*filter*/,
|
||||
2/*hopcount*/, 2.0f/*alpha*/, 1.0f/*amplifynormal*/,
|
||||
0.0f/*normalsustainfactor*/);
|
||||
imMipmapCascade* mm_cascade = (imMipmapCascade*)m_mipmap_data;
|
||||
#ifdef DEBUG
|
||||
int ret = imBuildMipmapCascade(mm_cascade, m_orig_data, m_size.Width,
|
||||
m_size.Height, 1/*layercount*/, 4, m_size.Width * 4, &options, 0);
|
||||
assert(ret == 1);
|
||||
#else
|
||||
imBuildMipmapCascade(mm_cascade, m_orig_data, m_size.Width,
|
||||
m_size.Height, 1/*layercount*/, 4, m_size.Width * 4, &options, 0);
|
||||
#endif
|
||||
for (unsigned int i = 0; i < m_mipmap_sizes.size(); i++)
|
||||
{
|
||||
const unsigned size = m_mipmap_sizes[i].first.getArea() * 4;
|
||||
memcpy((uint8_t*)ptr + m_mipmap_sizes[i].second,
|
||||
mm_cascade->mipmap[i + 1], size);
|
||||
#ifdef DUMP_MIPMAP
|
||||
video::IImage* image = irr_driver->getVideoDriver()
|
||||
->createImageFromData(video::ECF_A8R8G8B8, m_mipmap_sizes[i].first,
|
||||
mm_cascade->mipmap[i + 1], false/*ownForeignMemory*/);
|
||||
irr_driver->getVideoDriver()->writeImageToFile(image, std::string
|
||||
(StringUtils::toString(i) + "_" +
|
||||
StringUtils::getBasename(NamedPath.getPtr())).c_str());
|
||||
image->drop();
|
||||
#endif
|
||||
}
|
||||
} // threadedReload
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void HQMipmapGenerator::threadedSubImage(void* ptr) const
|
||||
{
|
||||
#if !(defined(SERVER_ONLY) || defined(USE_GLES2))
|
||||
glBindTexture(GL_TEXTURE_2D, m_texture_name);
|
||||
for (unsigned int i = 0; i < m_mipmap_sizes.size(); i++)
|
||||
{
|
||||
glTexSubImage2D(GL_TEXTURE_2D, i + 1, 0, 0,
|
||||
m_mipmap_sizes[i].first.Width, m_mipmap_sizes[i].first.Height,
|
||||
GL_BGRA, GL_UNSIGNED_BYTE,
|
||||
(uint8_t*)ptr + m_mipmap_sizes[i].second);
|
||||
}
|
||||
delete this;
|
||||
#endif
|
||||
} // threadedSubImage
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void HQMipmapGenerator::cleanThreadedLoader()
|
||||
{
|
||||
delete[] m_orig_data;
|
||||
imFreeMipmapCascade((imMipmapCascade*)m_mipmap_data);
|
||||
free(m_mipmap_data);
|
||||
} // cleanThreadedLoader
|
||||
|
||||
#endif
|
@ -1,103 +0,0 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2017 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef HEADER_HQ_MIPMAP_GENERATOR_HPP
|
||||
#define HEADER_HQ_MIPMAP_GENERATOR_HPP
|
||||
|
||||
#if !(defined(SERVER_ONLY) || defined(USE_GLES2))
|
||||
|
||||
#include "graphics/gl_headers.hpp"
|
||||
#include "utils/no_copy.hpp"
|
||||
#include "utils/types.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <ITexture.h>
|
||||
|
||||
using namespace irr;
|
||||
struct TexConfig;
|
||||
|
||||
class HQMipmapGenerator : public video::ITexture, NoCopy
|
||||
{
|
||||
private:
|
||||
uint8_t* m_orig_data;
|
||||
|
||||
core::dimension2d<u32> m_size;
|
||||
|
||||
GLuint m_texture_name;
|
||||
|
||||
unsigned int m_texture_size;
|
||||
|
||||
void* m_mipmap_data;
|
||||
|
||||
TexConfig* m_tex_config;
|
||||
|
||||
std::vector<std::pair<core::dimension2d<u32>, size_t> > m_mipmap_sizes;
|
||||
|
||||
public:
|
||||
// ------------------------------------------------------------------------
|
||||
HQMipmapGenerator(const io::path& name, uint8_t* data,
|
||||
const core::dimension2d<u32>& size, GLuint texture_name,
|
||||
TexConfig* tc);
|
||||
// ------------------------------------------------------------------------
|
||||
virtual ~HQMipmapGenerator() {}
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void* lock(video::E_TEXTURE_LOCK_MODE mode =
|
||||
video::ETLM_READ_WRITE, u32 mipmap_level = 0)
|
||||
{ return NULL; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void unlock() {}
|
||||
// ------------------------------------------------------------------------
|
||||
virtual const core::dimension2d<u32>& getOriginalSize() const
|
||||
{ return m_size; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual const core::dimension2d<u32>& getSize() const { return m_size; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual video::E_DRIVER_TYPE getDriverType() const
|
||||
{
|
||||
#if defined(USE_GLES2)
|
||||
return video::EDT_OGLES2;
|
||||
#else
|
||||
return video::EDT_OPENGL;
|
||||
#endif
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
virtual video::ECOLOR_FORMAT getColorFormat() const
|
||||
{ return video::ECF_A8R8G8B8; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual u32 getPitch() const { return 0; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual bool hasMipMaps() const { return false; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void regenerateMipMapLevels(void* mipmap_data = NULL) {}
|
||||
// ------------------------------------------------------------------------
|
||||
virtual u32 getOpenGLTextureName() const { return m_texture_name; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual u64 getHandle() { return 0; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual unsigned int getTextureSize() const { return m_texture_size; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void threadedReload(void* ptr, void* param) const;
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void threadedSubImage(void* ptr) const;
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void cleanThreadedLoader();
|
||||
|
||||
}; // HQMipmapGenerator
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@ -218,8 +218,10 @@ std::shared_ptr<video::IImage> SPTexture::getTextureImage() const
|
||||
for (unsigned int i = 0; i < image->getDimension().Width *
|
||||
image->getDimension().Height; i++)
|
||||
{
|
||||
const bool use_tex_compress = CVS->isTextureCompressionEnabled() &&
|
||||
!m_cache_directory.empty();
|
||||
#ifndef USE_GLES2
|
||||
if (CVS->isTextureCompressionEnabled())
|
||||
if (use_tex_compress)
|
||||
{
|
||||
#endif
|
||||
// to RGBA for libsquish or for gles it's always true
|
||||
@ -229,7 +231,7 @@ std::shared_ptr<video::IImage> SPTexture::getTextureImage() const
|
||||
#ifndef USE_GLES2
|
||||
}
|
||||
#endif
|
||||
if (m_undo_srgb && !CVS->isTextureCompressionEnabled())
|
||||
if (m_undo_srgb && !use_tex_compress)
|
||||
{
|
||||
data[i * 4] = srgbToLinear(data[i * 4] / 255.0f);
|
||||
data[i * 4 + 1] = srgbToLinear(data[i * 4 + 1] / 255.0f);
|
||||
@ -927,8 +929,8 @@ std::vector<std::pair<core::dimension2du, unsigned> >
|
||||
}
|
||||
}
|
||||
// For array textures all textures need to have a same internal format
|
||||
const unsigned tc_flag = squish::kDxt5 | stk_config->m_tc_quality |
|
||||
(m_undo_srgb && CVS->useArrayTextures() ? squish::kToLinear : 0);
|
||||
const unsigned tc_flag = squish::kDxt5 | stk_config->m_tc_quality;
|
||||
// | (m_undo_srgb && CVS->useArrayTextures() ? squish::kToLinear : 0);
|
||||
const unsigned compressed_size = squish::GetStorageRequirements(
|
||||
mipmap_sizes[0].first.Width, mipmap_sizes[0].first.Height,
|
||||
tc_flag);
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "config/hardware_stats.hpp"
|
||||
#include "config/user_config.hpp"
|
||||
#include "graphics/central_settings.hpp"
|
||||
#include "graphics/threaded_tex_loader.hpp"
|
||||
#include "graphics/stk_texture.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
@ -27,95 +26,12 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
STKTexManager::STKTexManager() : m_pbo(0), m_thread_size(0),
|
||||
m_threaded_load_textures_counter(0)
|
||||
{
|
||||
createThreadedTexLoaders();
|
||||
} // STKTexManager
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
STKTexManager::~STKTexManager()
|
||||
{
|
||||
removeTexture(NULL/*texture*/, true/*remove_all*/);
|
||||
destroyThreadedTexLoaders();
|
||||
} // ~STKTexManager
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void STKTexManager::createThreadedTexLoaders()
|
||||
{
|
||||
#if !(defined(SERVER_ONLY) || defined(USE_GLES2))
|
||||
if (CVS->supportsThreadedTextureLoading())
|
||||
{
|
||||
pthread_mutex_init(&m_threaded_load_textures_mutex, NULL);
|
||||
pthread_cond_init(&m_cond_request, NULL);
|
||||
m_thread_size = HardwareStats::getNumProcessors();
|
||||
if (m_thread_size == 0)
|
||||
m_thread_size = 1;
|
||||
m_thread_size = core::clamp(m_thread_size, 1,
|
||||
UserConfigParams::m_hq_mipmap ? m_thread_size : 3);
|
||||
const unsigned max_tex_size =
|
||||
(UserConfigParams::m_high_definition_textures & 0x01) == 0 ?
|
||||
UserConfigParams::m_max_texture_size : 2048;
|
||||
const unsigned each_capacity = max_tex_size * max_tex_size * 4;
|
||||
const unsigned pbo_size = each_capacity * m_thread_size;
|
||||
Log::info("STKTexManager", "%d thread(s) for texture loading,"
|
||||
" each capacity %d MB.", m_thread_size,
|
||||
each_capacity / 1024 / 1024);
|
||||
if (UserConfigParams::m_hq_mipmap)
|
||||
Log::info("STKTexManager", "High quality mipmap enabled.");
|
||||
glGenBuffers(1, &m_pbo);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_pbo);
|
||||
glBufferStorage(GL_PIXEL_UNPACK_BUFFER, pbo_size, NULL,
|
||||
GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT |
|
||||
GL_MAP_COHERENT_BIT);
|
||||
uint8_t* pbo_ptr = (uint8_t*)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER,
|
||||
0, pbo_size, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT |
|
||||
GL_MAP_COHERENT_BIT);
|
||||
size_t offset = 0;
|
||||
for (int i = 0; i < m_thread_size; i++)
|
||||
{
|
||||
m_all_tex_loaders.push_back(new ThreadedTexLoader(each_capacity,
|
||||
offset, pbo_ptr + offset, &m_threaded_load_textures_mutex,
|
||||
&m_cond_request, this));
|
||||
offset += each_capacity;
|
||||
}
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
}
|
||||
#endif
|
||||
} // createThreadedTexLoaders
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void STKTexManager::destroyThreadedTexLoaders()
|
||||
{
|
||||
#if !(defined(SERVER_ONLY) || defined(USE_GLES2))
|
||||
if (CVS->supportsThreadedTextureLoading())
|
||||
{
|
||||
STKTexture* delete_ttl = new STKTexture((uint8_t*)NULL, "delete_ttl",
|
||||
0, false, true);
|
||||
for (int i = 0; i < m_thread_size; i++)
|
||||
addThreadedLoadTexture(delete_ttl);
|
||||
for (int i = 0; i < m_thread_size; i++)
|
||||
{
|
||||
if (!m_all_tex_loaders[i]->waitForReadyToDeleted(2.0f))
|
||||
{
|
||||
Log::info("STKTexManager", "ThreadedTexLoader %d not stopping,"
|
||||
"exiting anyway.", i);
|
||||
}
|
||||
delete m_all_tex_loaders[i];
|
||||
}
|
||||
delete delete_ttl;
|
||||
glDeleteBuffers(1, &m_pbo);
|
||||
pthread_mutex_destroy(&m_threaded_load_textures_mutex);
|
||||
pthread_cond_destroy(&m_cond_request);
|
||||
m_pbo = 0;
|
||||
m_thread_size = 0;
|
||||
m_threaded_load_textures_counter = 0;
|
||||
m_all_tex_loaders.clear();
|
||||
}
|
||||
#endif
|
||||
} // destroyThreadedTexLoaders
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
STKTexture* STKTexManager::findTextureInFileSystem(const std::string& filename,
|
||||
std::string* full_path)
|
||||
@ -185,11 +101,6 @@ video::ITexture* STKTexManager::getTexture(const std::string& path,
|
||||
delete new_texture;
|
||||
return NULL;
|
||||
}
|
||||
if (new_texture->useThreadedLoading())
|
||||
{
|
||||
addThreadedLoadTexture(new_texture);
|
||||
checkThreadedLoadTextures(false/*util_queue_empty*/);
|
||||
}
|
||||
}
|
||||
|
||||
if (create_if_unfound && !no_upload)
|
||||
@ -267,23 +178,6 @@ int STKTexManager::dumpTextureUsage()
|
||||
return size;
|
||||
} // dumpAllTexture
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
video::ITexture* STKTexManager::getUnicolorTexture(const irr::video::SColor &c)
|
||||
{
|
||||
std::string name = StringUtils::toString(c.color) + "unic";
|
||||
auto ret = m_all_textures.find(name);
|
||||
if (ret != m_all_textures.end())
|
||||
return ret->second;
|
||||
|
||||
uint8_t* data = new uint8_t[2 * 2 * 4];
|
||||
memcpy(data, &c.color, sizeof(video::SColor));
|
||||
memcpy(data + 4, &c.color, sizeof(video::SColor));
|
||||
memcpy(data + 8, &c.color, sizeof(video::SColor));
|
||||
memcpy(data + 12, &c.color, sizeof(video::SColor));
|
||||
return addTexture(new STKTexture(data, name, 2));
|
||||
|
||||
} // getUnicolorTexture
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
core::stringw STKTexManager::reloadTexture(const irr::core::stringw& name)
|
||||
{
|
||||
@ -299,10 +193,6 @@ core::stringw STKTexManager::reloadTexture(const irr::core::stringw& name)
|
||||
if (p.second == NULL || !p.second->isMeshTexture())
|
||||
continue;
|
||||
p.second->reload();
|
||||
if (p.second->useThreadedLoading())
|
||||
{
|
||||
addThreadedLoadTexture(p.second);
|
||||
}
|
||||
Log::info("STKTexManager", "%s reloaded",
|
||||
p.second->getName().getPtr());
|
||||
}
|
||||
@ -325,10 +215,6 @@ core::stringw STKTexManager::reloadTexture(const irr::core::stringw& name)
|
||||
if (fname == tex_name || fname == tex_path)
|
||||
{
|
||||
p.second->reload();
|
||||
if (p.second->useThreadedLoading())
|
||||
{
|
||||
addThreadedLoadTexture(p.second);
|
||||
}
|
||||
result += tex_name.c_str();
|
||||
result += L" ";
|
||||
break;
|
||||
@ -341,11 +227,6 @@ core::stringw STKTexManager::reloadTexture(const irr::core::stringw& name)
|
||||
return result + "reloaded.";
|
||||
} // reloadTexture
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void STKTexManager::reset()
|
||||
{
|
||||
} // reset
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sets an error message to be displayed when a texture is not found. This
|
||||
* error message is shown before the "Texture %s not found or invalid"
|
||||
@ -363,78 +244,3 @@ void STKTexManager::setTextureErrorMessage(const std::string &error,
|
||||
else
|
||||
m_texture_error_message = StringUtils::insertValues(error, detail);
|
||||
} // setTextureErrorMessage
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void STKTexManager::checkThreadedLoadTextures(bool util_queue_empty)
|
||||
{
|
||||
#if !(defined(SERVER_ONLY) || defined(USE_GLES2))
|
||||
if (!CVS->supportsThreadedTextureLoading()) return;
|
||||
bool uploaded = false;
|
||||
bool empty_queue = false;
|
||||
if (util_queue_empty)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
pthread_mutex_lock(&m_threaded_load_textures_mutex);
|
||||
empty_queue = m_threaded_load_textures_counter == 0;
|
||||
pthread_mutex_unlock(&m_threaded_load_textures_mutex);
|
||||
if (empty_queue)
|
||||
{
|
||||
for (ThreadedTexLoader* ttl : m_all_tex_loaders)
|
||||
{
|
||||
if (ttl->lastQueueReady())
|
||||
{
|
||||
ttl->lock();
|
||||
ttl->setFinishLoading();
|
||||
uploaded = true;
|
||||
ttl->unlock(false/*finish_it*/);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
checkThreadedLoadTextures(false/*util_queue_empty*/);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (empty_queue && !uploaded)
|
||||
return;
|
||||
uploaded = false;
|
||||
for (ThreadedTexLoader* ttl : m_all_tex_loaders)
|
||||
{
|
||||
ttl->lock();
|
||||
if (ttl->finishedLoading())
|
||||
{
|
||||
if (!uploaded)
|
||||
{
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_pbo);
|
||||
uploaded = true;
|
||||
}
|
||||
ttl->handleCompletedTextures();
|
||||
}
|
||||
else
|
||||
{
|
||||
ttl->unlock(false/*finish_it*/);
|
||||
}
|
||||
}
|
||||
if (uploaded)
|
||||
{
|
||||
GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
GLenum reason = glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, 0);
|
||||
if (reason != GL_ALREADY_SIGNALED)
|
||||
{
|
||||
do
|
||||
{
|
||||
reason = glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT,
|
||||
1000000);
|
||||
}
|
||||
while (reason == GL_TIMEOUT_EXPIRED);
|
||||
}
|
||||
glDeleteSync(sync);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
for (ThreadedTexLoader* ttl : m_all_tex_loaders)
|
||||
ttl->unlock(true/*finish_it*/);
|
||||
}
|
||||
#endif
|
||||
} // checkThreadedLoadTextures
|
||||
|
@ -69,37 +69,12 @@ private:
|
||||
* This is used to specify details like: "while loading kart '...'" */
|
||||
std::string m_texture_error_message;
|
||||
|
||||
std::vector<ThreadedTexLoader*> m_all_tex_loaders;
|
||||
|
||||
GLuint m_pbo;
|
||||
|
||||
int m_thread_size;
|
||||
|
||||
class SmallestTexture
|
||||
{
|
||||
public:
|
||||
inline bool operator()(const irr::video::ITexture* a,
|
||||
const irr::video::ITexture* b) const
|
||||
{
|
||||
return a->getTextureSize() > b->getTextureSize();
|
||||
}
|
||||
};
|
||||
std::priority_queue<irr::video::ITexture*,
|
||||
std::vector<irr::video::ITexture*>, SmallestTexture>
|
||||
m_threaded_load_textures;
|
||||
|
||||
int m_threaded_load_textures_counter;
|
||||
|
||||
pthread_mutex_t m_threaded_load_textures_mutex;
|
||||
|
||||
pthread_cond_t m_cond_request;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
STKTexture* findTextureInFileSystem(const std::string& filename,
|
||||
std::string* full_path);
|
||||
public:
|
||||
// ------------------------------------------------------------------------
|
||||
STKTexManager();
|
||||
STKTexManager() {}
|
||||
// ------------------------------------------------------------------------
|
||||
~STKTexManager();
|
||||
// ------------------------------------------------------------------------
|
||||
@ -108,8 +83,6 @@ public:
|
||||
bool no_upload = false,
|
||||
bool create_if_unfound = true);
|
||||
// ------------------------------------------------------------------------
|
||||
irr::video::ITexture* getUnicolorTexture(const irr::video::SColor &c);
|
||||
// ------------------------------------------------------------------------
|
||||
irr::video::ITexture* addTexture(STKTexture* texture);
|
||||
// ------------------------------------------------------------------------
|
||||
void removeTexture(STKTexture* texture, bool remove_all = false);
|
||||
@ -120,8 +93,6 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
irr::core::stringw reloadTexture(const irr::core::stringw& name);
|
||||
// ------------------------------------------------------------------------
|
||||
void reset();
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the currently defined texture error message, which is used
|
||||
* by event_handler.cpp to print additional info about irrlicht
|
||||
* internal errors or warnings. If no error message is currently
|
||||
@ -174,35 +145,6 @@ public:
|
||||
return getTexture(filename, std::string(error_message),
|
||||
std::string(detail));
|
||||
} // getTexture
|
||||
// ------------------------------------------------------------------------
|
||||
void checkThreadedLoadTextures(bool util_queue_empty);
|
||||
// ------------------------------------------------------------------------
|
||||
irr::video::ITexture* getThreadedLoadTexture()
|
||||
{ return m_threaded_load_textures.top(); }
|
||||
// ------------------------------------------------------------------------
|
||||
void setThreadedLoadTextureCounter(int val)
|
||||
{
|
||||
m_threaded_load_textures_counter += val;
|
||||
assert(m_threaded_load_textures_counter >= 0);
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
void addThreadedLoadTexture(irr::video::ITexture* t)
|
||||
{
|
||||
pthread_mutex_lock(&m_threaded_load_textures_mutex);
|
||||
m_threaded_load_textures.push(t);
|
||||
setThreadedLoadTextureCounter(t->getThreadedLoadTextureCounter());
|
||||
pthread_cond_signal(&m_cond_request);
|
||||
pthread_mutex_unlock(&m_threaded_load_textures_mutex);
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
void removeThreadedLoadTexture() { m_threaded_load_textures.pop(); }
|
||||
// ------------------------------------------------------------------------
|
||||
bool isThreadedLoadTexturesEmpty()
|
||||
{ return m_threaded_load_textures.empty(); }
|
||||
// ------------------------------------------------------------------------
|
||||
void createThreadedTexLoaders();
|
||||
// ------------------------------------------------------------------------
|
||||
void destroyThreadedTexLoaders();
|
||||
|
||||
}; // STKTexManager
|
||||
|
||||
|
@ -18,35 +18,22 @@
|
||||
#include "graphics/stk_texture.hpp"
|
||||
#include "config/user_config.hpp"
|
||||
#include "graphics/central_settings.hpp"
|
||||
#include "graphics/hq_mipmap_generator.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "graphics/material.hpp"
|
||||
#include "graphics/material_manager.hpp"
|
||||
#include "graphics/stk_tex_manager.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "modes/profile_world.hpp"
|
||||
#include "utils/log.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
|
||||
#if !defined(USE_GLES2)
|
||||
static const uint8_t CACHE_VERSION = 2;
|
||||
#endif
|
||||
// ----------------------------------------------------------------------------
|
||||
STKTexture::STKTexture(const std::string& path, TexConfig* tc, bool no_upload)
|
||||
: video::ITexture(path.c_str()), m_texture_handle(0),
|
||||
m_single_channel(false), m_tex_config(NULL), m_material(NULL),
|
||||
m_texture_name(0), m_texture_size(0), m_texture_image(NULL),
|
||||
m_file(NULL), m_img_loader(NULL)
|
||||
: video::ITexture(path.c_str()), m_single_channel(false),
|
||||
m_tex_config(NULL), m_texture_name(0), m_texture_size(0),
|
||||
m_texture_image(NULL)
|
||||
{
|
||||
if (tc != NULL)
|
||||
{
|
||||
m_tex_config = (TexConfig*)malloc(sizeof(TexConfig));
|
||||
memcpy(m_tex_config, tc, sizeof(TexConfig));
|
||||
m_single_channel = m_tex_config->m_colorization_mask;
|
||||
if (m_tex_config->m_set_material)
|
||||
m_material = material_manager->getMaterialFor(this);
|
||||
}
|
||||
#ifndef SERVER_ONLY
|
||||
if (m_tex_config)
|
||||
@ -66,25 +53,22 @@ STKTexture::STKTexture(const std::string& path, TexConfig* tc, bool no_upload)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
STKTexture::STKTexture(uint8_t* data, const std::string& name, unsigned int size,
|
||||
bool single_channel, bool delete_ttl)
|
||||
: video::ITexture(name.c_str()), m_texture_handle(0),
|
||||
m_single_channel(single_channel), m_tex_config(NULL),
|
||||
m_material(NULL), m_texture_name(0), m_texture_size(0),
|
||||
m_texture_image(NULL), m_file(NULL), m_img_loader(NULL)
|
||||
bool single_channel)
|
||||
: video::ITexture(name.c_str()), m_single_channel(single_channel),
|
||||
m_tex_config(NULL), m_texture_name(0), m_texture_size(0),
|
||||
m_texture_image(NULL)
|
||||
{
|
||||
m_size.Width = size;
|
||||
m_size.Height = size;
|
||||
m_orig_size = m_size;
|
||||
if (!delete_ttl)
|
||||
reload(false/*no_upload*/, data);
|
||||
reload(false/*no_upload*/, data);
|
||||
} // STKTexture
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
STKTexture::STKTexture(video::IImage* img, const std::string& name)
|
||||
: video::ITexture(name.c_str()), m_texture_handle(0),
|
||||
m_single_channel(false), m_tex_config(NULL), m_material(NULL),
|
||||
m_texture_name(0), m_texture_size(0), m_texture_image(NULL),
|
||||
m_file(NULL), m_img_loader(NULL)
|
||||
: video::ITexture(name.c_str()), m_single_channel(false),
|
||||
m_tex_config(NULL), m_texture_name(0), m_texture_size(0),
|
||||
m_texture_image(NULL)
|
||||
{
|
||||
reload(false/*no_upload*/, NULL/*preload_data*/, img);
|
||||
} // STKTexture
|
||||
@ -93,7 +77,6 @@ STKTexture::STKTexture(video::IImage* img, const std::string& name)
|
||||
STKTexture::~STKTexture()
|
||||
{
|
||||
#ifndef SERVER_ONLY
|
||||
unloadHandle();
|
||||
if (m_texture_name != 0)
|
||||
{
|
||||
glDeleteTextures(1, &m_texture_name);
|
||||
@ -122,112 +105,34 @@ void STKTexture::reload(bool no_upload, uint8_t* preload_data,
|
||||
}
|
||||
#ifndef SERVER_ONLY
|
||||
|
||||
std::string compressed_texture;
|
||||
#if !defined(USE_GLES2)
|
||||
if (!no_upload && isMeshTexture() && CVS->isTextureCompressionEnabled())
|
||||
{
|
||||
std::string orig_file = NamedPath.getPtr();
|
||||
|
||||
std::string basename = StringUtils::getBasename(orig_file);
|
||||
std::string container_id;
|
||||
if (file_manager->searchTextureContainerId(container_id, basename))
|
||||
{
|
||||
std::string cache_subdir = "hd/";
|
||||
if ((UserConfigParams::m_high_definition_textures & 0x01) == 0x01)
|
||||
{
|
||||
cache_subdir = "hd/";
|
||||
}
|
||||
else
|
||||
{
|
||||
cache_subdir = StringUtils::insertValues("resized_%i/",
|
||||
(int)UserConfigParams::m_max_texture_size);
|
||||
}
|
||||
|
||||
std::string cache_dir = file_manager->getCachedTexturesDir() +
|
||||
cache_subdir + container_id;
|
||||
compressed_texture = cache_dir + "/" + basename + ".stktz";
|
||||
|
||||
if ((!file_manager->fileExists(compressed_texture) ||
|
||||
file_manager->fileIsNewer(compressed_texture, orig_file)) &&
|
||||
loadCompressedTexture(compressed_texture))
|
||||
{
|
||||
Log::debug("STKTexture", "Compressed %s for texture %s",
|
||||
compressed_texture.c_str(), orig_file.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
file_manager->checkAndCreateDirectoryP(cache_dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::warn("STKTexture", "Cannot find container_id for texture %s",
|
||||
orig_file.c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
video::IImage* orig_img = NULL;
|
||||
uint8_t* data = preload_data;
|
||||
if (data == NULL)
|
||||
{
|
||||
if (preload_img)
|
||||
orig_img = preload_img;
|
||||
else
|
||||
orig_img = preload_img ? preload_img :
|
||||
irr_driver->getVideoDriver()->createImageFromFile(NamedPath);
|
||||
if (orig_img == NULL)
|
||||
{
|
||||
m_file = irr_driver->getDevice()->getFileSystem()
|
||||
->createAndOpenFile(NamedPath);
|
||||
if (m_file == NULL)
|
||||
return;
|
||||
irr_driver->getVideoDriver()->createImageFromFile(m_file,
|
||||
&m_img_loader);
|
||||
if (m_img_loader == NULL)
|
||||
return;
|
||||
m_file->seek(0);
|
||||
m_orig_size = m_img_loader->getImageSize(m_file);
|
||||
if ((!m_material || m_material->getAlphaMask().empty()) &&
|
||||
useThreadedLoading() && !no_upload)
|
||||
{
|
||||
if (m_orig_size.Width == 0 || m_orig_size.Height == 0)
|
||||
{
|
||||
m_file->drop();
|
||||
m_file = NULL;
|
||||
m_img_loader = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
orig_img = m_img_loader->loadImage(m_file);
|
||||
m_file->drop();
|
||||
m_file = NULL;
|
||||
if (orig_img == NULL || orig_img->getDimension().Width == 0 ||
|
||||
orig_img->getDimension().Height == 0)
|
||||
{
|
||||
if (orig_img)
|
||||
orig_img->drop();
|
||||
return;
|
||||
}
|
||||
m_img_loader = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (orig_img->getDimension().Width == 0 ||
|
||||
orig_img->getDimension().Height == 0)
|
||||
{
|
||||
orig_img->drop();
|
||||
return;
|
||||
}
|
||||
orig_img = resizeImage(orig_img, &m_orig_size, &m_size);
|
||||
applyMask(orig_img);
|
||||
data = orig_img ? (uint8_t*)orig_img->lock() : NULL;
|
||||
if (m_single_channel && !useThreadedLoading())
|
||||
{
|
||||
data = singleChannelConversion(data);
|
||||
orig_img->unlock();
|
||||
orig_img->drop();
|
||||
orig_img = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned int w = m_size.Width;
|
||||
const unsigned int h = m_size.Height;
|
||||
unsigned int format = m_single_channel ? GL_RED : GL_BGRA;
|
||||
unsigned int internal_format = m_single_channel ? GL_R8 : isSrgb() ?
|
||||
GL_SRGB8_ALPHA8 : GL_RGBA8;
|
||||
unsigned int internal_format = m_single_channel ? GL_R8 : isSrgb() ?
|
||||
GL_SRGB8_ALPHA8 : GL_RGBA8;
|
||||
|
||||
// GLES 2.0 specs doesn't allow GL_RGBA8 internal format
|
||||
// GLES 2.0 specs doesn't allow GL_RGBA8 internal format
|
||||
#if defined(USE_GLES2)
|
||||
if (!CVS->isGLSL())
|
||||
{
|
||||
@ -235,17 +140,7 @@ void STKTexture::reload(bool no_upload, uint8_t* preload_data,
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(USE_GLES2)
|
||||
if (isMeshTexture() && CVS->isTextureCompressionEnabled())
|
||||
{
|
||||
internal_format = m_single_channel ? GL_COMPRESSED_RED_RGTC1 :
|
||||
isSrgb() ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT :
|
||||
GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!useThreadedLoading())
|
||||
formatConversion(data, &format, w, h);
|
||||
formatConversion(data, &format, w, h);
|
||||
|
||||
if (!no_upload)
|
||||
{
|
||||
@ -264,35 +159,17 @@ void STKTexture::reload(bool no_upload, uint8_t* preload_data,
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_ONE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED);
|
||||
}
|
||||
if (useThreadedLoading())
|
||||
{
|
||||
int levels = 1;
|
||||
int width = w;
|
||||
int height = h;
|
||||
while (true)
|
||||
{
|
||||
width = width < 2 ? 1 : width >> 1;
|
||||
height = height < 2 ? 1 : height >> 1;
|
||||
levels++;
|
||||
if (width == 1 && height == 1)
|
||||
break;
|
||||
}
|
||||
glTexStorage2D(GL_TEXTURE_2D, levels, internal_format, w, h);
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, w, h, 0, format,
|
||||
GL_UNSIGNED_BYTE, data);
|
||||
}
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, w, h, 0, format,
|
||||
GL_UNSIGNED_BYTE, data);
|
||||
}
|
||||
else if (!useThreadedLoading())
|
||||
else
|
||||
{
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, format,
|
||||
GL_UNSIGNED_BYTE, data);
|
||||
}
|
||||
if (orig_img)
|
||||
orig_img->unlock();
|
||||
if (!useThreadedLoading() && hasMipMaps())
|
||||
if (hasMipMaps())
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
@ -304,8 +181,6 @@ void STKTexture::reload(bool no_upload, uint8_t* preload_data,
|
||||
else
|
||||
delete[] data;
|
||||
|
||||
if (!compressed_texture.empty())
|
||||
saveCompressedTexture(compressed_texture);
|
||||
if (!no_upload)
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
@ -398,201 +273,6 @@ video::IImage* STKTexture::resizeImage(video::IImage* orig_img,
|
||||
return image;
|
||||
} // resizeImage
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void STKTexture::applyMask(video::IImage* orig_img)
|
||||
{
|
||||
#ifndef SERVER_ONLY
|
||||
if (m_material && !m_material->getAlphaMask().empty())
|
||||
{
|
||||
video::IImage* converted_mask = irr_driver->getVideoDriver()
|
||||
->createImageFromFile(m_material->getAlphaMask().c_str());
|
||||
if (converted_mask == NULL)
|
||||
{
|
||||
Log::warn("STKTexture", "Applying mask failed for '%s'!",
|
||||
m_material->getAlphaMask().c_str());
|
||||
return;
|
||||
}
|
||||
converted_mask = resizeImage(converted_mask);
|
||||
if (converted_mask->lock())
|
||||
{
|
||||
const core::dimension2du& dim = orig_img->getDimension();
|
||||
for (unsigned int x = 0; x < dim.Width; x++)
|
||||
{
|
||||
for (unsigned int y = 0; y < dim.Height; y++)
|
||||
{
|
||||
video::SColor col = orig_img->getPixel(x, y);
|
||||
video::SColor alpha = converted_mask->getPixel(x, y);
|
||||
col.setAlpha(alpha.getRed());
|
||||
orig_img->setPixel(x, y, col, false);
|
||||
} // for y
|
||||
} // for x
|
||||
}
|
||||
converted_mask->unlock();
|
||||
converted_mask->drop();
|
||||
}
|
||||
#endif // !SERVER_ONLY
|
||||
} // applyMask
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** 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 STKTexture::loadCompressedTexture(const std::string& file_name)
|
||||
{
|
||||
#if !(defined(SERVER_ONLY) || defined(USE_GLES2))
|
||||
std::ifstream ifs(file_name.c_str(), std::ios::in | std::ios::binary);
|
||||
if (!ifs.is_open())
|
||||
return false;
|
||||
|
||||
int internal_format;
|
||||
uint8_t cache_verison;
|
||||
ifs.read((char*)&cache_verison, sizeof(uint8_t));
|
||||
if (cache_verison != CACHE_VERSION)
|
||||
{
|
||||
Log::debug("STKTexture", "%s version %d is not supported!",
|
||||
file_name.c_str(), cache_verison);
|
||||
ifs.close();
|
||||
std::remove(file_name.c_str());
|
||||
return false;
|
||||
}
|
||||
ifs.read((char*)&internal_format, sizeof(int));
|
||||
ifs.read((char*)&m_size.Width, sizeof(unsigned int));
|
||||
ifs.read((char*)&m_size.Height, sizeof(unsigned int));
|
||||
ifs.read((char*)&m_orig_size.Width, sizeof(unsigned int));
|
||||
ifs.read((char*)&m_orig_size.Height, sizeof(unsigned int));
|
||||
ifs.read((char*)&m_texture_size, sizeof(unsigned int));
|
||||
|
||||
if (ifs.fail() || m_texture_size == 0)
|
||||
return false;
|
||||
|
||||
std::vector<char> compressed;
|
||||
compressed.resize(m_texture_size);
|
||||
ifs.read(compressed.data(), m_texture_size);
|
||||
if (!ifs.fail())
|
||||
{
|
||||
// No on the fly reload is supported for compressed texture
|
||||
assert(m_texture_name == 0);
|
||||
glGenTextures(1, &m_texture_name);
|
||||
glBindTexture(GL_TEXTURE_2D, m_texture_name);
|
||||
if (internal_format == GL_COMPRESSED_RED_RGTC1)
|
||||
{
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ONE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_ONE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_ONE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED);
|
||||
}
|
||||
glCompressedTexImage2D(GL_TEXTURE_2D, 0, internal_format,
|
||||
m_size.Width, m_size.Height, 0, m_texture_size, compressed.data());
|
||||
unsigned width = m_size.Width;
|
||||
unsigned height = m_size.Height;
|
||||
std::vector<std::pair<unsigned, unsigned> > mipmap_sizes;
|
||||
while (true)
|
||||
{
|
||||
width = width < 2 ? 1 : width >> 1;
|
||||
height = height < 2 ? 1 : height >> 1;
|
||||
mipmap_sizes.emplace_back(width, height);
|
||||
if (width == 1 && height == 1)
|
||||
break;
|
||||
}
|
||||
for (unsigned i = 0; i < mipmap_sizes.size(); i++)
|
||||
{
|
||||
unsigned cur_mipmap_size = 0;
|
||||
ifs.read((char*)&cur_mipmap_size, sizeof(unsigned int));
|
||||
ifs.read(compressed.data(), cur_mipmap_size);
|
||||
if (cur_mipmap_size == 0 || ifs.fail())
|
||||
{
|
||||
ifs.close();
|
||||
std::remove(file_name.c_str());
|
||||
return false;
|
||||
}
|
||||
glCompressedTexImage2D(GL_TEXTURE_2D, i + 1, internal_format,
|
||||
mipmap_sizes[i].first, mipmap_sizes[i].second, 0,
|
||||
cur_mipmap_size, compressed.data());
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
return true;
|
||||
}
|
||||
ifs.close();
|
||||
std::remove(file_name.c_str());
|
||||
#endif
|
||||
return false;
|
||||
} // loadCompressedTexture
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** 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>
|
||||
* <version><internal-format><w><h><orig_w><orig_h><size><data> <br>
|
||||
* The first element is the version of cache, next six elements are
|
||||
* integers and the last one is stored on \c size bytes.
|
||||
* \see loadCompressedTexture
|
||||
*/
|
||||
void STKTexture::saveCompressedTexture(const std::string& compressed_tex)
|
||||
{
|
||||
#if !(defined(SERVER_ONLY) || defined(USE_GLES2))
|
||||
int internal_format;
|
||||
int compression_successful = 0;
|
||||
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT,
|
||||
(GLint *)&internal_format);
|
||||
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH,
|
||||
(GLint *)&m_size.Width);
|
||||
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT,
|
||||
(GLint *)&m_size.Height);
|
||||
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED,
|
||||
(GLint *)&compression_successful);
|
||||
if (compression_successful == 0) return;
|
||||
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
|
||||
GL_TEXTURE_COMPRESSED_IMAGE_SIZE, (GLint *)&m_texture_size);
|
||||
if (m_texture_size == 0) return;
|
||||
|
||||
std::vector<char> compressed;
|
||||
compressed.resize(m_texture_size);
|
||||
glGetCompressedTexImage(GL_TEXTURE_2D, 0, compressed.data());
|
||||
std::ofstream ofs(compressed_tex.c_str(),
|
||||
std::ios::out | std::ios::binary);
|
||||
if (ofs.is_open())
|
||||
{
|
||||
ofs.write((char*)&CACHE_VERSION, sizeof(uint8_t));
|
||||
ofs.write((char*)&internal_format, sizeof(int));
|
||||
ofs.write((char*)&m_size.Width, sizeof(unsigned int));
|
||||
ofs.write((char*)&m_size.Height, sizeof(unsigned int));
|
||||
ofs.write((char*)&m_orig_size.Width, sizeof(unsigned int));
|
||||
ofs.write((char*)&m_orig_size.Height, sizeof(unsigned int));
|
||||
ofs.write((char*)&m_texture_size, sizeof(unsigned int));
|
||||
ofs.write(compressed.data(), m_texture_size);
|
||||
unsigned width = m_size.Width;
|
||||
unsigned height = m_size.Height;
|
||||
std::vector<std::pair<unsigned, unsigned> > mipmap_sizes;
|
||||
while (true)
|
||||
{
|
||||
width = width < 2 ? 1 : width >> 1;
|
||||
height = height < 2 ? 1 : height >> 1;
|
||||
mipmap_sizes.emplace_back(width, height);
|
||||
if (width == 1 && height == 1)
|
||||
break;
|
||||
}
|
||||
for (unsigned i = 0; i < mipmap_sizes.size(); i++)
|
||||
{
|
||||
GLint cur_mipmap_size = 0;
|
||||
glGetTexLevelParameteriv(GL_TEXTURE_2D, i + 1,
|
||||
GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &cur_mipmap_size);
|
||||
if (cur_mipmap_size == 0)
|
||||
{
|
||||
ofs.close();
|
||||
std::remove(compressed_tex.c_str());
|
||||
}
|
||||
glGetCompressedTexImage(GL_TEXTURE_2D, i + 1, compressed.data());
|
||||
ofs.write((char*)&cur_mipmap_size, sizeof(unsigned int));
|
||||
ofs.write(compressed.data(), cur_mipmap_size);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} // saveCompressedTexture
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool STKTexture::hasMipMaps() const
|
||||
{
|
||||
@ -623,97 +303,6 @@ void* STKTexture::lock(video::E_TEXTURE_LOCK_MODE mode, u32 mipmap_level)
|
||||
return NULL;
|
||||
} // lock
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
u64 STKTexture::getHandle()
|
||||
{
|
||||
return m_texture_handle;
|
||||
} // getHandle
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void STKTexture::unloadHandle()
|
||||
{
|
||||
} // unloadHandle
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool STKTexture::useThreadedLoading() const
|
||||
{
|
||||
#ifdef SERVER_ONLY
|
||||
return false;
|
||||
#else
|
||||
return CVS->supportsThreadedTextureLoading() &&
|
||||
!CVS->isTextureCompressionEnabled() && isMeshTexture() &&
|
||||
m_img_loader && m_img_loader->supportThreadedLoading();
|
||||
#endif
|
||||
} // useThreadedLoading
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void STKTexture::threadedReload(void* ptr, void* param) const
|
||||
{
|
||||
#if !(defined(SERVER_ONLY) || defined(USE_GLES2))
|
||||
video::IImage* orig_img =
|
||||
m_img_loader->loadImage(m_file, true/*skip_checking*/);
|
||||
orig_img = resizeImage(orig_img);
|
||||
uint8_t* data = (uint8_t*)orig_img->lock();
|
||||
if (m_single_channel)
|
||||
{
|
||||
data = singleChannelConversion(data);
|
||||
orig_img->unlock();
|
||||
orig_img->drop();
|
||||
orig_img = NULL;
|
||||
}
|
||||
formatConversion(data, NULL, m_size.Width, m_size.Height);
|
||||
memcpy(ptr, data, m_texture_size);
|
||||
|
||||
if (orig_img)
|
||||
{
|
||||
orig_img->unlock();
|
||||
orig_img->setDeleteMemory(false);
|
||||
orig_img->drop();
|
||||
}
|
||||
if (useHQMipmap())
|
||||
{
|
||||
HQMipmapGenerator* hqmg = new HQMipmapGenerator(NamedPath, data,
|
||||
m_size, m_texture_name, m_tex_config);
|
||||
((STKTexManager*)(param))->addThreadedLoadTexture(hqmg);
|
||||
}
|
||||
else
|
||||
delete[] data;
|
||||
#endif
|
||||
} // threadedReload
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void STKTexture::threadedSubImage(void* ptr) const
|
||||
{
|
||||
#if !(defined(SERVER_ONLY) || defined(USE_GLES2))
|
||||
glBindTexture(GL_TEXTURE_2D, m_texture_name);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_size.Width, m_size.Height,
|
||||
m_single_channel ? GL_RED : GL_BGRA, GL_UNSIGNED_BYTE, ptr);
|
||||
if (useHQMipmap())
|
||||
return;
|
||||
if (hasMipMaps())
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
|
||||
#endif
|
||||
} // threadedSubImage
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void STKTexture::cleanThreadedLoader()
|
||||
{
|
||||
#if !(defined(SERVER_ONLY) || defined(USE_GLES2))
|
||||
assert(m_file);
|
||||
m_file->drop();
|
||||
m_file = NULL;
|
||||
m_img_loader = NULL;
|
||||
#endif
|
||||
} // cleanThreadedLoader
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool STKTexture::useHQMipmap() const
|
||||
{
|
||||
return !m_single_channel && UserConfigParams::m_hq_mipmap &&
|
||||
m_size.Width > 1 && m_size.Height > 1;
|
||||
} // useHQMipmap
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool STKTexture::isSrgb() const
|
||||
{
|
||||
|
@ -24,64 +24,33 @@
|
||||
#include <string>
|
||||
#include <ITexture.h>
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace io { class IReadFile; }
|
||||
namespace video { class IImageLoader; }
|
||||
}
|
||||
|
||||
using namespace irr;
|
||||
|
||||
struct TexConfig;
|
||||
class Material;
|
||||
|
||||
class STKTexture : public video::ITexture, NoCopy
|
||||
{
|
||||
private:
|
||||
core::dimension2d<u32> m_size, m_orig_size;
|
||||
|
||||
uint64_t m_texture_handle;
|
||||
|
||||
bool m_single_channel;
|
||||
|
||||
TexConfig* m_tex_config;
|
||||
|
||||
Material* m_material;
|
||||
|
||||
GLuint m_texture_name;
|
||||
|
||||
unsigned int m_texture_size;
|
||||
|
||||
video::IImage* m_texture_image;
|
||||
|
||||
io::IReadFile* m_file;
|
||||
|
||||
video::IImageLoader* m_img_loader;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
video::IImage* resizeImage(video::IImage* orig_img,
|
||||
core::dimension2du* orig_size = NULL,
|
||||
core::dimension2du* final_size = NULL) const;
|
||||
// ------------------------------------------------------------------------
|
||||
void applyMask(video::IImage* orig_img);
|
||||
// ------------------------------------------------------------------------
|
||||
bool loadCompressedTexture(const std::string& file_name);
|
||||
// ------------------------------------------------------------------------
|
||||
void saveCompressedTexture(const std::string& file_name);
|
||||
// ------------------------------------------------------------------------
|
||||
void formatConversion(uint8_t* data, unsigned int* format, unsigned int w,
|
||||
unsigned int h) const;
|
||||
// ------------------------------------------------------------------------
|
||||
uint8_t* singleChannelConversion(uint8_t* data) const
|
||||
{
|
||||
uint8_t* sc = new uint8_t[m_size.Width * m_size.Height];
|
||||
for (unsigned int i = 0; i < m_size.Width * m_size.Height; i++)
|
||||
sc[i] = data[4 * i + 3];
|
||||
return sc;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
bool useHQMipmap() const;
|
||||
// ------------------------------------------------------------------------
|
||||
bool isSrgb() const;
|
||||
// ------------------------------------------------------------------------
|
||||
bool isPremulAlpha() const;
|
||||
@ -91,7 +60,7 @@ public:
|
||||
STKTexture(const std::string& path, TexConfig* tc, bool no_upload = false);
|
||||
// ------------------------------------------------------------------------
|
||||
STKTexture(uint8_t* data, const std::string& name, unsigned int size,
|
||||
bool single_channel = false, bool delete_ttl = false);
|
||||
bool single_channel = false);
|
||||
// ------------------------------------------------------------------------
|
||||
STKTexture(video::IImage* img, const std::string& name);
|
||||
// ------------------------------------------------------------------------
|
||||
@ -131,10 +100,6 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
virtual u32 getOpenGLTextureName() const { return m_texture_name; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual u64 getHandle();
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void unloadHandle();
|
||||
// ------------------------------------------------------------------------
|
||||
virtual unsigned int getTextureSize() const { return m_texture_size; }
|
||||
// ------------------------------------------------------------------------
|
||||
void reload(bool no_upload = false, uint8_t* preload_data = NULL,
|
||||
@ -142,19 +107,6 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
video::IImage* getTextureImage() { return m_texture_image; }
|
||||
// ------------------------------------------------------------------------
|
||||
bool useThreadedLoading() const;
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void threadedReload(void* ptr, void* param) const;
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void threadedSubImage(void* ptr) const;
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void cleanThreadedLoader();
|
||||
// ------------------------------------------------------------------------
|
||||
virtual int getThreadedLoadTextureCounter() const
|
||||
{
|
||||
return useHQMipmap() ? 2 : 1;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
bool isMeshTexture() const;
|
||||
|
||||
}; // STKTexture
|
||||
|
@ -1,100 +0,0 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2017 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#if !(defined(SERVER_ONLY) || defined(USE_GLES2))
|
||||
|
||||
#include "graphics/threaded_tex_loader.hpp"
|
||||
#include "graphics/stk_tex_manager.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
#include "utils/vs.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <ITexture.h>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void* ThreadedTexLoader::startRoutine(void *obj)
|
||||
{
|
||||
ThreadedTexLoader* ttl = (ThreadedTexLoader*)obj;
|
||||
VS::setThreadName((std::string("ThrTexLoader") +
|
||||
StringUtils::toString(ttl->m_pbo_offset / 1024 / 1024)).c_str());
|
||||
while (true)
|
||||
{
|
||||
pthread_mutex_lock(&ttl->m_mutex);
|
||||
bool finished = ttl->finishedLoading();
|
||||
pthread_mutex_unlock(&ttl->m_mutex);
|
||||
if (finished)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
pthread_mutex_lock(ttl->m_texture_queue_mutex);
|
||||
bool waiting = ttl->m_stktm->isThreadedLoadTexturesEmpty();
|
||||
ttl->m_last_queue_ready.setAtomic(!ttl->m_completed_textures.empty() &&
|
||||
waiting);
|
||||
while (waiting)
|
||||
{
|
||||
pthread_cond_wait(ttl->m_cond_request, ttl->m_texture_queue_mutex);
|
||||
waiting = ttl->m_stktm->isThreadedLoadTexturesEmpty();
|
||||
}
|
||||
irr::video::ITexture* target_tex =
|
||||
ttl->m_stktm->getThreadedLoadTexture();
|
||||
if (strcmp(target_tex->getName().getPtr(), "delete_ttl") == 0)
|
||||
{
|
||||
ttl->m_stktm->removeThreadedLoadTexture();
|
||||
ttl->m_stktm->setThreadedLoadTextureCounter(-1);
|
||||
pthread_mutex_unlock(ttl->m_texture_queue_mutex);
|
||||
ttl->setCanBeDeleted();
|
||||
return NULL;
|
||||
}
|
||||
assert(target_tex->getTextureSize() <= ttl->m_tex_capacity);
|
||||
if (target_tex->getTextureSize() + ttl->m_tex_size_loaded >
|
||||
ttl->m_tex_capacity)
|
||||
{
|
||||
pthread_mutex_lock(&ttl->m_mutex);
|
||||
ttl->setFinishLoading();
|
||||
pthread_mutex_unlock(&ttl->m_mutex);
|
||||
pthread_mutex_unlock(ttl->m_texture_queue_mutex);
|
||||
continue;
|
||||
}
|
||||
ttl->m_stktm->removeThreadedLoadTexture();
|
||||
pthread_mutex_unlock(ttl->m_texture_queue_mutex);
|
||||
target_tex->threadedReload(ttl->m_pbo_ptr + ttl->m_tex_size_loaded,
|
||||
ttl->m_stktm);
|
||||
target_tex->cleanThreadedLoader();
|
||||
ttl->m_tex_size_loaded += target_tex->getTextureSize();
|
||||
ttl->m_completed_textures.push_back(target_tex);
|
||||
pthread_mutex_lock(ttl->m_texture_queue_mutex);
|
||||
ttl->m_stktm->setThreadedLoadTextureCounter(-1);
|
||||
pthread_mutex_unlock(ttl->m_texture_queue_mutex);
|
||||
}
|
||||
return NULL;
|
||||
} // startRoutine
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void ThreadedTexLoader::handleCompletedTextures()
|
||||
{
|
||||
assert(m_locked);
|
||||
size_t offset = m_pbo_offset;
|
||||
for (irr::video::ITexture* tex : m_completed_textures)
|
||||
{
|
||||
size_t cur_offset = tex->getTextureSize();
|
||||
tex->threadedSubImage((void*)offset);
|
||||
offset += cur_offset;
|
||||
}
|
||||
m_completed_textures.clear();
|
||||
} // handleCompletedTextures
|
||||
|
||||
#endif
|
@ -1,118 +0,0 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2017 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef HEADER_THREADED_TEX_LOADER_HPP
|
||||
#define HEADER_THREADED_TEX_LOADER_HPP
|
||||
|
||||
#if !(defined(SERVER_ONLY) || defined(USE_GLES2))
|
||||
|
||||
#include "utils/can_be_deleted.hpp"
|
||||
#include "utils/no_copy.hpp"
|
||||
#include "utils/synchronised.hpp"
|
||||
#include "utils/types.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace video { class ITexture; }
|
||||
}
|
||||
class STKTexManager;
|
||||
|
||||
class ThreadedTexLoader : public NoCopy, public CanBeDeleted
|
||||
{
|
||||
private:
|
||||
const unsigned m_tex_capacity;
|
||||
|
||||
const size_t m_pbo_offset;
|
||||
|
||||
uint8_t* m_pbo_ptr;
|
||||
|
||||
pthread_mutex_t m_mutex;
|
||||
|
||||
pthread_mutex_t* m_texture_queue_mutex;
|
||||
|
||||
pthread_cond_t* m_cond_request;
|
||||
|
||||
STKTexManager* m_stktm;
|
||||
|
||||
unsigned m_tex_size_loaded;
|
||||
|
||||
pthread_t m_thread;
|
||||
|
||||
bool m_finished_loading, m_locked;
|
||||
|
||||
Synchronised<bool> m_last_queue_ready;
|
||||
|
||||
std::vector<irr::video::ITexture*> m_completed_textures;
|
||||
|
||||
public:
|
||||
// ------------------------------------------------------------------------
|
||||
static void* startRoutine(void *obj);
|
||||
// ------------------------------------------------------------------------
|
||||
ThreadedTexLoader(unsigned capacity, size_t offset, uint8_t* pbo_ptr,
|
||||
pthread_mutex_t* mutex, pthread_cond_t* cond,
|
||||
STKTexManager* stktm)
|
||||
: m_tex_capacity(capacity), m_pbo_offset(offset),
|
||||
m_pbo_ptr(pbo_ptr), m_texture_queue_mutex(mutex),
|
||||
m_cond_request(cond), m_stktm(stktm),
|
||||
m_tex_size_loaded(0), m_finished_loading(false),
|
||||
m_locked(false), m_last_queue_ready(false)
|
||||
{
|
||||
pthread_mutex_init(&m_mutex, NULL);
|
||||
pthread_create(&m_thread, NULL, &startRoutine, this);
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
~ThreadedTexLoader()
|
||||
{
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
pthread_join(m_thread, NULL);
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
bool finishedLoading() const { return m_finished_loading; }
|
||||
// ------------------------------------------------------------------------
|
||||
void setFinishLoading()
|
||||
{
|
||||
m_last_queue_ready.setAtomic(false);
|
||||
m_finished_loading = true;
|
||||
m_tex_size_loaded = 0;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
bool lastQueueReady() const { return m_last_queue_ready.getAtomic(); }
|
||||
// ------------------------------------------------------------------------
|
||||
void handleCompletedTextures();
|
||||
// ------------------------------------------------------------------------
|
||||
void lock()
|
||||
{
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
m_locked = true;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
void unlock(bool finish_it)
|
||||
{
|
||||
if (!m_locked) return;
|
||||
m_locked = false;
|
||||
if (finish_it)
|
||||
m_finished_loading = false;
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
}
|
||||
|
||||
}; // ThreadedTexLoader
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@ -23,7 +23,6 @@
|
||||
#include "config/user_config.hpp"
|
||||
#include "graphics/central_settings.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "graphics/stk_tex_manager.hpp"
|
||||
#include "guiengine/screen.hpp"
|
||||
#include "guiengine/widgets/button_widget.hpp"
|
||||
#include "guiengine/widgets/check_box_widget.hpp"
|
||||
@ -649,8 +648,6 @@ void OptionsScreenVideo::tearDown()
|
||||
else if (m_prev_img_quality != getImageQuality())
|
||||
{
|
||||
irr_driver->setMaxTextureSize();
|
||||
STKTexManager::getInstance()->destroyThreadedTexLoaders();
|
||||
STKTexManager::getInstance()->createThreadedTexLoaders();
|
||||
}
|
||||
Screen::tearDown();
|
||||
// save changes when leaving screen
|
||||
|
Loading…
Reference in New Issue
Block a user