478 lines
14 KiB
C++
478 lines
14 KiB
C++
/**
|
|
@file JCResManager.cpp
|
|
@brief
|
|
@author James
|
|
@version 1.0
|
|
@date 2016_5_12
|
|
*/
|
|
|
|
#include "JCResManager.h"
|
|
#include "JCResource.h"
|
|
#include "../util/Log.h"
|
|
#include <stdlib.h>
|
|
#include <string>
|
|
#include <sstream>
|
|
#include <iostream>
|
|
namespace laya
|
|
{
|
|
JCResManager::JCResManager(int p_nFreeSize,bool bUseMap)
|
|
{
|
|
m_nGlobalID = 0;
|
|
m_nCurTick = rand()%SLEEPINGAGE; //给一个随机值。避免所有的manager同时清理。
|
|
m_nNextCleanTick = m_nCurTick+SLEEPINGAGE;
|
|
m_nCurSize = 0;
|
|
m_nFreeSize = p_nFreeSize;
|
|
m_nMaxSize = 1*m_nFreeSize;//本来是可以有一个阀值的
|
|
m_bUseSetResLock = false;
|
|
m_bReleasing = false;
|
|
m_nID = 0;
|
|
m_pUpdatingSzRes = NULL;
|
|
m_bChkThread = false;
|
|
m_pLastTouchedRes=NULL;
|
|
m_nFreedCount = 0;
|
|
m_bUseMap = bUseMap;
|
|
}
|
|
|
|
JCResManager::~JCResManager(){
|
|
m_bReleasing=true;
|
|
destroyAll();
|
|
}
|
|
|
|
void JCResManager::setFreeSize( unsigned int p_nFreeSize )
|
|
{
|
|
m_nFreeSize = p_nFreeSize;
|
|
m_nMaxSize = 1 * m_nFreeSize;//本来是可以有一个阀值的
|
|
}
|
|
|
|
void JCResManager::setFreeSize( unsigned int p_nFreeSize, unsigned int p_nMaxSize ){
|
|
m_nFreeSize = p_nFreeSize;
|
|
m_nMaxSize = p_nMaxSize;
|
|
}
|
|
|
|
//注意,为了效率不要频繁调用
|
|
//如果需要创建,则改名成 getRes
|
|
JCResManager::ResType JCResManager::find(const std::string& p_key ){
|
|
ResMap::iterator it = m_AllRes.find(p_key);
|
|
if(it==m_AllRes.end()){
|
|
return NULL;
|
|
//TODO 需要在这里创建新的么。
|
|
//TYPE pnew = createNew(p_key);
|
|
//m_AllRes[p_key]=pnew;
|
|
//return pnew;
|
|
}else{
|
|
//如果已经释放了,需要出发恢复流程?
|
|
return (*it).second;
|
|
}
|
|
}
|
|
//这个只有一个res资源,只能处理活动列表的问题,不能根据map来查找。
|
|
void JCResManager::add(JCResManager::ResType pRes){
|
|
if( m_bChkThread){
|
|
if( m_WorkThread!=std::this_thread::get_id()){
|
|
LOGE("JCResManager[%d] have been operated by other threads.", m_nID);
|
|
throw -22;
|
|
}
|
|
}
|
|
//为了省事,用一个lock,由于add不太频繁,所以应该问题不大
|
|
std::unique_lock<std::recursive_mutex> _lock(m_Lock);
|
|
if( pRes->isActive()){
|
|
LOGE("Resources have been added!\n");
|
|
return;
|
|
}
|
|
pRes->m_pResManager = this;
|
|
pRes->m_nTouch=m_nCurTick;
|
|
m_ActiveRes.push_back(pRes);
|
|
m_pLastTouchedRes = pRes;
|
|
updateSz(pRes);
|
|
}
|
|
|
|
bool JCResManager::freeRes(JCResManager::ResType pRes, bool bDel ){
|
|
if( m_bChkThread){
|
|
if( m_WorkThread!=std::this_thread::get_id()){
|
|
LOGE("JCResManager[%d] have been operated by other threads.", m_nID);
|
|
throw -22;
|
|
}
|
|
}
|
|
if( !pRes->isActive())
|
|
return false;
|
|
std::unique_lock<std::recursive_mutex> _lock(m_Lock);
|
|
m_ActiveRes.delNode(pRes);
|
|
m_nCurSize-=pRes->m_nUsedMem;
|
|
pRes->m_nResSize = 0;
|
|
pRes->m_nUsedMem = 0;
|
|
pRes->freeRes(!bDel);
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
从map中删除。如果 bDel为true,则同时删除对象。
|
|
返回值:
|
|
true 找到这个资源了
|
|
false 没有这个资源
|
|
*/
|
|
bool JCResManager::delRes( const std::string& p_key, bool bDel ){
|
|
//避免删除某个资源的时候,又调回来了。
|
|
if (m_bReleasing)
|
|
return true;
|
|
if( m_bChkThread){
|
|
if( m_WorkThread!=std::this_thread::get_id()){
|
|
LOGE("JCResManager[%d] have been operated by other threads", m_nID);
|
|
throw -22;
|
|
}
|
|
}
|
|
ResMap::iterator it = m_AllRes.find(p_key);
|
|
if(it!=m_AllRes.end()){
|
|
(*it).second->m_nResSize = 0;
|
|
freeRes( (*it).second, true );
|
|
if(bDel){
|
|
//DelFun df;
|
|
delete ((*it).second);
|
|
}
|
|
m_AllRes.erase(it);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool JCResManager::delRes(int p_key, bool bDel) {
|
|
//避免删除某个资源的时候,又调回来了。
|
|
if (m_bReleasing)
|
|
return true;
|
|
if (m_bChkThread) {
|
|
if (m_WorkThread != std::this_thread::get_id()) {
|
|
LOGE("JCResManager[%d] have been operated by other threads", m_nID);
|
|
throw - 22;
|
|
}
|
|
}
|
|
if ((size_t)p_key < m_AllResVector.size())
|
|
{
|
|
ResType pRes = m_AllResVector[p_key];
|
|
if (pRes == NULL) return false;
|
|
pRes->m_nResSize = 0;
|
|
freeRes(pRes, true);
|
|
if (bDel) {
|
|
//DelFun df;
|
|
delete pRes;
|
|
}
|
|
m_AllResVector[p_key] = NULL;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//每帧都会调用的。
|
|
//由于resManager不会太多,所以可以每帧都调用,不用用请求列表的方式。
|
|
void JCResManager::tick(){
|
|
m_nCurTick++;
|
|
if( m_nCurTick>=m_nNextCleanTick){
|
|
if( m_nCurSize>m_nFreeSize )
|
|
freeRes( (m_nCurSize-m_nFreeSize)*2 );
|
|
m_nNextCleanTick+=SLEEPINGAGE;
|
|
}
|
|
}
|
|
|
|
//删除所有的,这个不会有回调
|
|
void JCResManager::destroyAll(bool bDelObj){
|
|
m_bReleasing=true;
|
|
freeAll();
|
|
if (m_bUseMap)
|
|
{
|
|
if (bDelObj) {
|
|
ResMap::iterator it = m_AllRes.begin();
|
|
while (it != m_AllRes.end()) {
|
|
delete (*it).second;
|
|
it++;
|
|
}
|
|
}
|
|
m_AllRes.clear();
|
|
}
|
|
else
|
|
{
|
|
if (bDelObj) {
|
|
for (size_t i = 0; i < m_AllResVector.size(); i++)
|
|
{
|
|
ResType pRes = m_AllResVector[i];
|
|
if (pRes)
|
|
{
|
|
delete pRes;
|
|
}
|
|
}
|
|
}
|
|
m_AllResVector.clear();
|
|
}
|
|
m_nCurSize = 0;
|
|
m_bReleasing=false;
|
|
m_nGlobalID = 0;
|
|
}
|
|
|
|
//释放所有的。会有回调
|
|
void JCResManager::freeAll(){
|
|
std::unique_lock<std::recursive_mutex> _lock(m_Lock);
|
|
if( m_ActiveRes.size()<=0)
|
|
return ;
|
|
ListNode* pHead = m_ActiveRes.getHead();
|
|
ListNode* pCurNode = pHead->_Next;
|
|
while( pCurNode!=pHead){//越往后越新
|
|
JCResource* pRes = (JCResource*)pCurNode;
|
|
pRes->m_nResSize=0; //阻止freeRes里面再调用freeRes
|
|
pRes->freeRes(!m_bReleasing);
|
|
pRes->setState(JCResource::freed);
|
|
ListNode* pNext = pCurNode->_Next;
|
|
m_ActiveRes.delNode(pCurNode);
|
|
pCurNode=pNext;
|
|
}
|
|
m_pLastTouchedRes = NULL;
|
|
m_nCurSize=0;
|
|
}
|
|
|
|
//返回实际释放的大小
|
|
int JCResManager::freeRes(int p_nSize ){
|
|
if( m_bChkThread){
|
|
if( m_WorkThread!=std::this_thread::get_id()){
|
|
LOGE("JCResManager[%d] have been operated by other threads.", m_nID);
|
|
throw -22;
|
|
}
|
|
}
|
|
//TODO 这个应该有线程的问题
|
|
m_nFreedCount++;
|
|
std::unique_lock<std::recursive_mutex> _lock(m_Lock);
|
|
if( m_ActiveRes.size()<=0)
|
|
return 0;
|
|
int oldnum = m_ActiveRes.size();
|
|
int nFreeSize=0;
|
|
//int nLastSize = m_nCurSize;
|
|
//int nTargetSz = m_nCurSize-p_nSize;
|
|
ListNode* pHead = m_ActiveRes.getHead();
|
|
ListNode* pCurNode = pHead->_Next;
|
|
//int nid=GetCurrentThreadId();
|
|
while( pCurNode!=pHead){//越往后越新
|
|
JCResource* pRes = (JCResource*)pCurNode;
|
|
//先屏蔽了,因为在ios会出现资源管理恢复导致的黑屏闪烁一下问题
|
|
//if (pRes->mnResSize <= 0)
|
|
//{
|
|
// pCurNode = pCurNode->_Next;
|
|
// continue;
|
|
//}
|
|
if( pRes == m_pUpdatingSzRes){
|
|
if(pCurNode->_Next==pHead)
|
|
break;
|
|
else{
|
|
LOGE("被保护资源不在最后一个?");
|
|
throw -1;
|
|
}
|
|
}
|
|
nFreeSize+=pRes->m_nUsedMem;
|
|
if(pRes->m_nUsedMem==0){
|
|
//可能是目前的资源还没有加载完成,例如图片还没与解码完成。
|
|
}
|
|
pRes->m_nUsedMem = 0;
|
|
pRes->m_nResSize = 0;
|
|
pRes->freeRes(true);
|
|
if (pRes == m_pLastTouchedRes)
|
|
m_pLastTouchedRes = NULL;
|
|
pRes->setState(JCResource::freed);
|
|
|
|
ListNode* pNext = pCurNode->_Next;
|
|
m_ActiveRes.delNode(pCurNode);
|
|
pCurNode=pNext;
|
|
//if( m_nCurSize<=nTargetSz )
|
|
// break;
|
|
if(nFreeSize>=p_nSize){
|
|
break;
|
|
}
|
|
}
|
|
m_nCurSize-=nFreeSize;
|
|
LOGI("freeRes(%d):Total:%d,left:%d,clearedMem:%d\n", m_nID, oldnum, m_ActiveRes.size(),nFreeSize);
|
|
return nFreeSize;
|
|
//return (nLastSize-m_nCurSize);
|
|
}
|
|
|
|
/*
|
|
加到map中。
|
|
加到活动列表中。
|
|
*/
|
|
void JCResManager::setItem(JCResManager::ResType pRes, const char* name){
|
|
if( m_bUseSetResLock ) m_setResLock.lock();
|
|
if(pRes->m_pResManager==NULL){
|
|
pRes->m_pResManager=this;
|
|
}
|
|
if(name)
|
|
m_AllRes[name]=pRes;
|
|
if( pRes->getResSize()>0){
|
|
m_pUpdatingSzRes = pRes; //防止被删除。
|
|
touchRes(pRes);
|
|
updateSz(pRes);
|
|
m_pUpdatingSzRes = NULL;
|
|
}
|
|
if( m_bUseSetResLock ) m_setResLock.unlock();
|
|
}
|
|
|
|
void JCResManager::setItem(JCResManager::ResType pRes, int nID) {
|
|
if (m_bUseSetResLock) m_setResLock.lock();
|
|
if (pRes->m_pResManager == NULL) {
|
|
pRes->m_pResManager = this;
|
|
}
|
|
//放入vector
|
|
int nSize = (int)m_AllResVector.size();
|
|
if (nID == nSize)
|
|
{
|
|
m_AllResVector.push_back(pRes);
|
|
}
|
|
else if (nID < nSize)
|
|
{
|
|
if (m_AllResVector[nID] == NULL)
|
|
{
|
|
m_AllResVector[nID] = pRes;
|
|
}
|
|
else
|
|
{
|
|
LOGE("JCResManager::addToAllRes error m_vRes[%d] != NULL", nID);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int nOldSize = m_AllResVector.size();
|
|
m_AllResVector.resize(nID + 1);
|
|
m_AllResVector[nID] = pRes;
|
|
}
|
|
if (pRes->getResSize() > 0) {
|
|
m_pUpdatingSzRes = pRes; //防止被删除。
|
|
touchRes(pRes);
|
|
updateSz(pRes);
|
|
m_pUpdatingSzRes = NULL;
|
|
}
|
|
if (m_bUseSetResLock) m_setResLock.unlock();
|
|
}
|
|
void JCResManager::addToAllRes(JCResManager::ResType pRes, const char* name){
|
|
if( m_bUseSetResLock ) m_setResLock.lock();
|
|
if(name)
|
|
m_AllRes[name]=pRes;
|
|
if( m_bUseSetResLock ) m_setResLock.unlock();
|
|
}
|
|
void JCResManager::addToAllRes(ResType pRes, int nID)
|
|
{
|
|
if (m_bUseSetResLock) m_setResLock.lock();
|
|
int nSize = (int)m_AllResVector.size();
|
|
if (nID == nSize)
|
|
{
|
|
m_AllResVector.push_back(pRes);
|
|
}
|
|
else if (nID < nSize)
|
|
{
|
|
if (m_AllResVector[nID] == NULL)
|
|
{
|
|
m_AllResVector[nID] = pRes;
|
|
}
|
|
else
|
|
{
|
|
LOGE("JCResManager::addToAllRes error m_vRes[%d] != NULL", nID);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int nOldSize = m_AllResVector.size();
|
|
m_AllResVector.resize(nID + 1);
|
|
m_AllResVector[nID] = pRes;
|
|
}
|
|
if (m_bUseSetResLock) m_setResLock.unlock();
|
|
}
|
|
void JCResManager::touchRes( JCResManager::ResType pRes, bool restoreRes ){
|
|
if( m_bChkThread){
|
|
if( m_WorkThread!=std::this_thread::get_id()){
|
|
LOGE("JCResManager[%d] have been operated by other threads.", m_nID);
|
|
throw -22;
|
|
}
|
|
}
|
|
pRes->m_nTouch = m_nCurTick;
|
|
if(m_pLastTouchedRes==pRes){
|
|
if( restoreRes && pRes->getState()==JCResource::freed ){
|
|
pRes->restoreRes();
|
|
}
|
|
return;
|
|
}
|
|
m_pLastTouchedRes = pRes;
|
|
|
|
if( m_bUseSetResLock ) m_setResLock.lock();
|
|
m_ActiveRes.delNode(pRes);
|
|
m_ActiveRes.push_back(pRes);
|
|
if (!pRes->isActive())
|
|
add(pRes);
|
|
//问题:如果资源还没准备好怎么办
|
|
if( restoreRes && pRes->getState()==JCResource::freed ){
|
|
pRes->restoreRes();
|
|
}
|
|
if( m_bUseSetResLock ) m_setResLock.unlock();
|
|
}
|
|
|
|
void JCResManager::updateRes(JCResManager::ResType pRes ){
|
|
if( m_bUseSetResLock ) m_setResLock.lock();
|
|
if( pRes->m_nResSize==0){
|
|
//freeRes(pRes,m_bReleasing); 这个太容易引起混乱。例如freeRes->setResSize(0)->updateRes()->freeRes()...
|
|
}else{
|
|
m_pUpdatingSzRes = pRes;
|
|
touchRes(pRes); //先把这个资源放到最后。
|
|
updateSz(pRes); //然后在清理资源。这样就会满足本资源是保护资源,并且在队列的最后,就能不被删除了。
|
|
m_pUpdatingSzRes = NULL;
|
|
}
|
|
if( m_bUseSetResLock ) m_setResLock.unlock();
|
|
}
|
|
|
|
void JCResManager::updateSz(ResType pRes){
|
|
int size = pRes->m_nResSize;// resSize();
|
|
int ds = size - pRes->m_nUsedMem;
|
|
m_nCurSize += ds;
|
|
pRes->m_nUsedMem = size;
|
|
pRes->m_nTouch = m_nCurTick; //类似touch,如果是restore了,这个会保证自己不会被轻易释放
|
|
//如果ds<=0表示正在清理,这时候不要再freeRes了
|
|
if( ds>0 && m_nMaxSize>0 && m_nCurSize>m_nMaxSize ){
|
|
freeRes(m_nMaxSize/3);
|
|
}
|
|
}
|
|
|
|
void JCResManager::InitWorkThread(){
|
|
m_WorkThread = std::this_thread::get_id();
|
|
}
|
|
|
|
bool JCResManager::chkMemSize(){
|
|
std::unique_lock<std::recursive_mutex> _lock(m_Lock);
|
|
if( m_ActiveRes.size()<=0)
|
|
return m_nCurSize==0;
|
|
ListNode* pHead = m_ActiveRes.getHead();
|
|
ListNode* pCurNode = pHead->_Next;
|
|
int nMemSize=0;
|
|
while( pCurNode!=pHead){//越往后越新
|
|
JCResource* pRes = (JCResource*)pCurNode;
|
|
nMemSize += pRes->m_nResSize;
|
|
ListNode* pNext = pCurNode->_Next;
|
|
pCurNode=pNext;
|
|
}
|
|
return m_nCurSize==nMemSize;
|
|
}
|
|
int JCResManager::getGlobalID()
|
|
{
|
|
m_setResLock.lock();
|
|
int nID = m_nGlobalID++;
|
|
m_setResLock.unlock();
|
|
return nID;
|
|
}
|
|
void JCResManager::printfActiveTextureInfo()
|
|
{
|
|
LOGI("JCResManager::printfActiveTextureInfo currentSize=%d", m_nCurSize );
|
|
/*
|
|
listNode* pHead = m_ActiveRes.getHead();
|
|
listNode* pCurNode = pHead->_Next;
|
|
int nMemSize = 0;
|
|
while (pCurNode != pHead)
|
|
{
|
|
LayaTexture* pRes = (LayaTexture*)pCurNode;
|
|
LOGI("JCResManager printfInfo id=%d gpuID=%d type=%d width=%d height=%d textureWidth=%d textureHeight=%d size=%d", pRes->getTextureID(),pRes->m_pGpuTexture, pRes->m_nType,pRes->getWidth(),pRes->getHeight(), pRes->getTextureWidth(), pRes->getTextureHeight(), pRes->getTextureWidth() * pRes->getTextureHeight() * 4 );
|
|
listNode* pNext = pCurNode->_Next;
|
|
pCurNode = pNext;
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
//-----------------------------END FILE--------------------------------
|