tahoma2d/toonz/sources/tnzext/ttexturesstorage.cpp

235 lines
8.1 KiB
C++
Raw Normal View History

2016-04-14 19:51:50 +12:00
#include <memory>
2016-03-19 06:57:51 +13:00
// TnzCore includes
#include "tgl.h"
// TnzExt includes
#include "ext/meshtexturizer.h"
// tcg includes
#include "tcg/tcg_list.h"
// Qt includes
#include <QString>
#include <QCache>
#include <QMutex>
#include <QMutexLocker>
#include "ext/ttexturesstorage.h"
//***************************************************************************************
// Local namespace - structures
//***************************************************************************************
struct TexturesContainer {
2016-06-15 18:43:10 +12:00
MeshTexturizer
m_texturizer; //!< The mesh texturizer - actual textures container
tcg::list<QString> m_keys; //!< Keys in the storage
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
TexturesContainer() {}
2016-03-19 06:57:51 +13:00
private:
2016-06-15 18:43:10 +12:00
TexturesContainer(const TexturesContainer &);
TexturesContainer &operator=(const TexturesContainer &);
2016-03-19 06:57:51 +13:00
};
//***************************************************************************************
// Local namespace - variables
//***************************************************************************************
2016-06-15 18:43:10 +12:00
namespace {
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
QMutex l_mutex(QMutex::Recursive); // A mutex is needed to synchronize access
// to the following objects
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
std::map<int, TexturesContainer *>
l_texturesContainers; // Texture Containers by display lists space id
QCache<QString, DrawableTextureDataP> l_objects(500 * 1024); // 500 MB cache
// for now - NOTE:
// MUST be
// allocated
// before the
// following
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
} // namespace
2016-03-19 06:57:51 +13:00
//***************************************************************************************
// Local namespace - global functions
//***************************************************************************************
2016-06-15 18:43:10 +12:00
namespace {
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
inline QString textureString(int dlSpaceId, const std::string &texId) {
return QString::number(dlSpaceId) + "_" + QString::fromStdString(texId);
2016-03-19 06:57:51 +13:00
}
//-------------------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
inline void deleteTexturesContainer(
const std::pair<int, TexturesContainer *> &pair) {
delete pair.second;
2016-03-19 06:57:51 +13:00
}
}
//***************************************************************************************
// DrawableTextureData implementation
//***************************************************************************************
2016-06-15 18:43:10 +12:00
DrawableTextureData::~DrawableTextureData() {
QMutexLocker locker(&l_mutex);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
TexturesContainer *texContainer = l_texturesContainers[m_dlSpaceId];
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (m_dlSpaceId >= 0) {
// Load the container's display lists space (remember current OpenGL
// context, too)
TGLDisplayListsProxy *proxy =
TGLDisplayListsManager::instance()->dlProxy(m_dlSpaceId);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
TGlContext currentContext = tglGetCurrentContext();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Unbind the textures
{
QMutexLocker locker(proxy->mutex());
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
proxy->makeCurrent();
texContainer->m_texturizer.unbindTexture(m_texId);
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Restore OpenGL context - equivalent to tglDoneCurrent if currentContext
// == TGlContext()
tglMakeCurrent(currentContext);
} else
// Temporary - use current OpenGL context directly
texContainer->m_texturizer.unbindTexture(m_texId);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
texContainer->m_keys.erase(m_objIdx);
2016-03-19 06:57:51 +13:00
}
//***************************************************************************************
// TTexturesStorage implementation
//***************************************************************************************
2016-06-15 18:43:10 +12:00
TTexturesStorage::TTexturesStorage() {
// This singleton is dependent on TGLDisplayListsManager
TGLDisplayListsManager::instance()->addObserver(this);
2016-03-19 06:57:51 +13:00
}
//-------------------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
TTexturesStorage::~TTexturesStorage() {
l_objects.clear();
std::for_each(l_texturesContainers.begin(), l_texturesContainers.end(),
deleteTexturesContainer);
2016-03-19 06:57:51 +13:00
}
//-------------------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
TTexturesStorage *TTexturesStorage::instance() {
static TTexturesStorage theInstance;
return &theInstance;
2016-03-19 06:57:51 +13:00
}
//-------------------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
DrawableTextureDataP TTexturesStorage::loadTexture(const std::string &textureId,
const TRaster32P &ras,
const TRectD &geometry) {
// Try to retrieve the proxy associated to current OpenGL context
TGlContext currentContext = tglGetCurrentContext();
int dlSpaceId =
TGLDisplayListsManager::instance()->displayListsSpaceId(currentContext);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
QString texString(::textureString(dlSpaceId, textureId));
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Deal with containers
QMutexLocker locker(&l_mutex);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// If necessary, allocate a textures container
std::map<int, TexturesContainer *>::iterator it =
l_texturesContainers.find(dlSpaceId);
if (it == l_texturesContainers.end())
it = l_texturesContainers
.insert(std::make_pair(dlSpaceId, new TexturesContainer))
.first;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
MeshTexturizer &texturizer = it->second->m_texturizer;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
DrawableTextureDataP dataPtr = std::make_shared<DrawableTextureData>();
DrawableTextureData *data = dataPtr.get();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
data->m_dlSpaceId = dlSpaceId;
data->m_texId = texturizer.bindTexture(ras, geometry);
data->m_objIdx = it->second->m_keys.push_back(texString);
data->m_textureData = texturizer.getTextureData(data->m_texId);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
l_objects.insert(texString, new DrawableTextureDataP(dataPtr),
(ras->getLx() * ras->getLy() * ras->getPixelSize()) >> 10);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (dlSpaceId < 0) {
// obj is a temporary. It was pushed in the cache to make space for it -
// however, it must not be
// stored. Remove it now.
l_objects.remove(texString);
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
return dataPtr;
2016-03-19 06:57:51 +13:00
}
//-------------------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void TTexturesStorage::unloadTexture(const std::string &textureId) {
QMutexLocker locker(&l_mutex);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Remove the specified texture from ALL the display lists spaces
std::map<int, TexturesContainer *>::iterator it,
iEnd(l_texturesContainers.end());
for (it = l_texturesContainers.begin(); it != iEnd; ++it)
l_objects.remove(::textureString(it->first, textureId));
2016-03-19 06:57:51 +13:00
}
//-----------------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void TTexturesStorage::onDisplayListDestroyed(int dlSpaceId) {
QMutexLocker locker(&l_mutex);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Remove the textures container associated with dlSpaceId
std::map<int, TexturesContainer *>::iterator it =
l_texturesContainers.find(dlSpaceId);
if (it == l_texturesContainers.end()) return;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
tcg::list<QString>::iterator st, sEnd(it->second->m_keys.end());
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
for (st = it->second->m_keys.begin(); st != sEnd;) // Note that the increment
// is performed BEFORE the
// texture is removed.
l_objects.remove(*st++); // This is because texture removal may destroy the
// key being addressed,
// whose iterator would then be invalidated.
delete it->second;
l_texturesContainers.erase(it);
2016-03-19 06:57:51 +13:00
}
//-------------------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
DrawableTextureDataP TTexturesStorage::getTextureData(
const std::string &textureId) {
// Get current display lists space
TGlContext currentContext = tglGetCurrentContext();
int dlSpaceId =
TGLDisplayListsManager::instance()->displayListsSpaceId(currentContext);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// If there is no known associated display lists space, the texture cannot be
// stored.
if (dlSpaceId < 0) return DrawableTextureDataP();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
QMutexLocker locker(&l_mutex);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Search the texture object
QString texString(::textureString(dlSpaceId, textureId));
if (!l_objects.contains(texString)) return DrawableTextureDataP();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
return *l_objects.object(texString);
2016-03-19 06:57:51 +13:00
}