/************************************************************************ * Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This software is provided as-is, without any express or implied * * warranty. In no event will the authors be held liable for any * * damages arising from the use of this software. * * * * Permission is granted to anyone to use this software for any purpose, * * including commercial applications, and to alter it and redistribute * * it freely, subject to the following restrictions: * * * * 1. The origin of this software must not be misrepresented; you must * * not claim that you wrote the original software. If you use this * * software in a product, an acknowledgment in the product documentation * * would be appreciated but is not required. * * * * 2. Altered source versions must be plainly marked as such, and must * * not be misrepresented as being the original software. * * * * 3. This notice may not be removed or altered from any source * * distribution. * ************************************************************************/ #include #include #include #include "gl_texturecache.h" #include "log.h" namespace OpenGL { template TextureCache::TextureCache(const char* with_name) : m_name(with_name) { instance_id = instance_count++; clearMagic = 0; has_cached_query = false; last_query_result = 0; minClearElements = 50; } template TextureCache::TextureCache() { instance_id = instance_count++; std::ostringstream stream; stream << "TextureCache_" << instance_count; m_name = stream.str(); has_cached_query = false; clearMagic = 0; minClearElements = 50; } template TextureCache::~TextureCache() { unsigned int ts = cached.size(); clearAll(); INFO << m_name << " exited - " << ts << " textures recycled" << std::endl; m_name.clear(); instance_count--; } template void TextureCache::clearAll() { typename std::map::iterator i = cached.begin(); while (i != cached.end()) { GLuint tid = (i->second->texId); glDeleteTextures(1, &tid); delete i->second; i++; } cached.clear(); } template void TextureCache::status() { std::cout << "* " << m_name << " status: " << cached.size() << " textures total" << std::endl << "position = game_id : usage_count" << std::endl; printStats(); } template void TextureCache::sink() { typename std::map::iterator i = cached.begin(); while (i != cached.end()) { if (i->second->refCount <= 1) i->second->refCount = 0; else if (i->second->refCount < _max_4) i->second->refCount = i->second->refCount >> 1; else if (i->second->refCount < _max_2) { INFO << m_name << " texture id " << int(i->first) << " -- half-count reached" << std::endl; i->second->refCount = i->second->refCount >> 2; } else { WARN << m_name << " texture id " << int(i->first) << " -- going critical" << std::endl; i->second->refCount = i->second->refCount >> 3; } i++; } } template void TextureCache::clear() { if (clearMagic == 0) return; if (cached.size() < minClearElements) return; typename std::map::iterator i = cached.begin(); uint32_t numCleared = 0; while (i != cached.end()) { if (i->second->refCount < clearMagic) { //INFO <<"## " << m_name << " clearing: " << int(i->first) << " count: " << i->second->refCount << std::endl; GLuint tid = (i->second->texId); glDeleteTextures(1, &tid); delete i->second; cached.erase(i++); numCleared++; } else { ++i; } } INFO << m_name << " " << numCleared << " textures recycled" << std::endl; } template void TextureCache::clearStats() { typename std::map::iterator i = cached.begin(); while (i != cached.end()) { i->second->refCount = 0; i++; } } template void TextureCache::printStats() { typename std::map::iterator i = cached.begin(); size_t c = 1; size_t c_active = 0; while (i != cached.end()) { if (i->second->refCount > 0) { std::cout << c << " = " << uint32_t(i->first) << " : " << i->second->refCount << std::endl; c_active++; } i++; c++; } std::cout << c_active << " different textures used" << std::endl; } template GLuint TextureCache::getTextureWithId(key_type id) { if (matchingCachedQuery(id)) { last_query_result->refCount++; return last_query_result->texId; } typename std::map::iterator i = cached.find(id); if (i == cached.end()) { ERROR << m_name << " failed to find texture " << int(id) << std::endl; return 0; } else { cacheQuery(id, i->second); i->second->refCount++; } /* * if (i->second->isAnimated) { AnimControl->lookup(i->second) * } */ return i->second->texId; } template bool TextureCache::hasTexture(key_type id) { if (matchingCachedQuery(id)) return true; // last_query_result; typename std::map::iterator i = cached.find(id); if (i == cached.end()) return false; cacheQuery(id, i->second); return true; } template void TextureCache::setToAlpha(key_type id) { typename std::map::iterator i = cached.find(id); if (i == cached.end()) { ERROR << m_name << " texture not found when trying to set alpha" << std::endl; return; } i->second->hasAlpha = true; } template void TextureCache::setToAnimated(key_type id) { typename std::map::iterator i = cached.find(id); if (i == cached.end()) { ERROR << m_name << " texture not found when trying to set animation" << std::endl; return; } i->second->isAnimated = true; } template void TextureCache::addTexture(key_type id, GLuint texId) { /* std::map::iterator i = cached.find(id); if (i == cached.end()) return;*/ texTuple* tt = new texTuple(); tt->texId = texId; tt->refCount = 1; tt->hasAlpha = false; tt->isAnimated = false; cached[id] = tt; INFO << m_name << " GL texture " << texId << " added for key: " << int(id) << std::endl; } template void TextureCache::cacheQuery(key_type id, texTuple *pos) { has_cached_query = true; last_query_id = id; last_query_result = pos; } template bool TextureCache::matchingCachedQuery(key_type id) { return ((has_cached_query) && (id == last_query_id)); } template void TextureCache::setClearMagic(uint32_t removeLesser) { clearMagic = removeLesser; } template void TextureCache::setMinClearElements(uint32_t minElements) { minClearElements = minElements; } template unsigned int TextureCache::instance_count = 0; std::numeric_limits _countInfo; template const uint32_t TextureCache::_max_4 = _countInfo.max() / 4; template const uint32_t TextureCache::_max_2 = _countInfo.max() / 2; template class TextureCache; template class TextureCache; template class TextureCache; template class TextureCache; }