// メモリの使用状態を表示する void PrintMemoryStatus() { MEMORY_STATUS s; GetMemoryStatus(&s); Print("MEMORY STATUS:\n" " NUM_OF_MEMORY_BLOCKS: %u\n" " SIZE_OF_TOTAL_MEMORY: %u bytes\n", s.MemoryBlocksNum, s.MemorySize); }
void glTextureManager::OnTimer(wxTimerEvent &event) { m_ticks++; // Scrub all the TD's, looking for any completed compression jobs // that have finished // In the interest of not disturbing the GUI, process only one TD per tick if(g_GLOptions.m_bTextureCompression) { for(ChartPathHashTexfactType::iterator itt = m_chart_texfactory_hash.begin(); itt != m_chart_texfactory_hash.end(); ++itt ) { glTexFactory *ptf = itt->second; if(ptf && ptf->OnTimer()) ;//break; } } #if 0 if((m_ticks % 4/*120*/) == 0){ // inventory int mem_total, mem_used; GetMemoryStatus(&mem_total, &mem_used); int map_size = 0; int comp_size = 0; int compcomp_size = 0; for(ChartPathHashTexfactType::iterator itt = m_chart_texfactory_hash.begin(); itt != m_chart_texfactory_hash.end(); ++itt ) { glTexFactory *ptf = itt->second; ptf->AccumulateMemStatistics(map_size, comp_size, compcomp_size); } int m1 = 1024 * 1024; // wxString path = wxFileName(m_ChartPath).GetName(); printf("%6d %6ld Map: %10d Comp:%10d CompComp: %10d \n", mem_used/1024, g_tex_mem_used/m1, map_size, comp_size, compcomp_size);//, path.mb_str().data()); /// qDebug() << "inv" << map_size/m1 << comp_size/m1 << compcomp_size/m1 << g_tex_mem_used/m1 << mem_used/1024; } #endif }
int CFileLoader::Write() { if ( !IsLoaded() ) return ERROR_FILE_NOT_FOUND; if ( !m_data.vStarts.size() || !m_data.vEnemy.size() || !m_data.vLevel.size() ) return ERROR_NOINTERFACE; int err = 0; std::vector<BYTE> file = m_File.vFile; DWORD systemData = 0, levelData = 0, enemyData = 0, occupiedSpace = 0, totalSpace = 0; // first, apply modifications to levels for(int i = 0; i < MAX_LEVELS; ++i) if ( m_vEditors[i]->Changed() ) m_vEditors[i]->Apply(); if ( !GetMemoryStatus(systemData, levelData, enemyData, occupiedSpace, totalSpace) || occupiedSpace >= totalSpace || file.size() < NES_PTR_EOF ) return ERROR_NOT_ENOUGH_MEMORY; const DWORD DELTA_PTR = 0x8010; std::vector<DWORD> vLevels, vEnemies; m_ptr.ptrLevelStarts = NES_PTR_START - DELTA_PTR; CopyMemory(&file[NES_PTR_START], &m_data.vStarts[0], m_data.vStarts.size()); m_ptr.ptrLevels[0] = m_ptr.ptrLevelStarts + m_data.vStarts.size(); m_ptr.ptrLevels[1] = m_ptr.ptrLevels[0] + MAX_LEVELS; // write levels banks DWORD ptr = m_ptr.ptrLevels[1] + MAX_LEVELS; int c = m_data.vLevel.size(); for(int i = 0; i < c; ++i) { vLevels.push_back(ptr); PBYTE pArray = NULL; DWORD dwSize = 0; if ( m_data.vLevel[i]->MakeByteArray(&pArray, &dwSize) && ptr + dwSize + DELTA_PTR < NES_PTR_EOF ) { CopyMemory(&file[ptr + DELTA_PTR], pArray, dwSize); ptr += dwSize; delete[] pArray; } else return ERROR_NOT_ENOUGH_MEMORY; } // write level pointers for(int i = 0; i < MAX_LEVELS; ++i) { file[m_ptr.ptrLevels[1] + DELTA_PTR + i] = HIBYTE(LOWORD(vLevels[m_game.nLevel[i] - 1])); file[m_ptr.ptrLevels[0] + DELTA_PTR + i] = LOBYTE(LOWORD(vLevels[m_game.nLevel[i] - 1])); } // now update place of enemies data // note, that we already checked, that we have enough space to store all data // enemies pointers arrays DWORD dwEnmPtrsSize = MAX_LEVELS * 2 + ( MAX_LEVELS / 10 ) * 4; DWORD eptr = max(ptr, m_ptr.ptrEnemies[0]); if ( eptr + dwEnmPtrsSize + enemyData + DELTA_PTR > NES_PTR_EOF ) // move data backward eptr = NES_PTR_EOF - DELTA_PTR - enemyData - dwEnmPtrsSize; if ( eptr < ptr ) // cant rewrite level data, but it shall be always false return ERROR_NOT_ENOUGH_MEMORY; if ( ptr < eptr ) // fill free space with 'ff' for(DWORD p = ptr + DELTA_PTR; p < eptr + DELTA_PTR; ++p) file[p] = 0xFF; m_ptr.ptrEnemies[0] = eptr; m_ptr.ptrEnemies[1] = m_ptr.ptrEnemies[0] + MAX_LEVELS / 10; m_ptr.ptrEnemies[2] = m_ptr.ptrEnemies[1] + MAX_LEVELS / 10; m_ptr.ptrEnemies[3] = m_ptr.ptrEnemies[2] + MAX_LEVELS / 10; eptr = m_ptr.ptrEnemies[3] + MAX_LEVELS / 10; ptr = eptr + MAX_LEVELS * 2; // now 'eptr' points to start of array ptrs, // and 'ptr' points to data c = m_data.vEnemy.size(); for(int i = 0; i < c; ++i) { vEnemies.push_back(ptr); PBYTE pArray = NULL; DWORD dwSize = 0; if ( m_data.vEnemy[i]->MakeByteArray(&pArray, &dwSize) && ptr + dwSize < NES_PTR_EOF ) { CopyMemory(&file[ptr + DELTA_PTR], pArray, dwSize); delete[] pArray; ptr += dwSize; } else return ERROR_NOT_ENOUGH_MEMORY; } for(; ptr < NES_PTR_EOF - DELTA_PTR; ++ptr) file[ptr + DELTA_PTR] = 0xFF; // write enemies pointers for(int lv = 0; lv < MAX_LEVELS / 10; ++lv) { DWORD levelPtrHi = eptr + 20 * lv, levelPtrLo = eptr + 20 * lv + 10; file[m_ptr.ptrEnemies[0] + lv + DELTA_PTR] = HIBYTE(LOWORD(levelPtrHi)); file[m_ptr.ptrEnemies[1] + lv + DELTA_PTR] = LOBYTE(LOWORD(levelPtrHi)); file[m_ptr.ptrEnemies[2] + lv + DELTA_PTR] = HIBYTE(LOWORD(levelPtrLo)); file[m_ptr.ptrEnemies[3] + lv + DELTA_PTR] = LOBYTE(LOWORD(levelPtrLo)); for(int i = 0; i < 10; ++i) { file[levelPtrHi + DELTA_PTR + i] = HIBYTE(LOWORD(vEnemies[m_game.nEnemy[10 * lv + i] - 1])); file[levelPtrLo + DELTA_PTR + i] = LOBYTE(LOWORD(vEnemies[m_game.nEnemy[10 * lv + i] - 1])); } } // write from copy to a file array m_File.vFile = file; // write main pointers Short(NES_PTR_LEVEL_STARTS, LOWORD(m_ptr.ptrLevelStarts)); Short(NES_PTR_LEVELS1, LOWORD(m_ptr.ptrLevels[0])); Short(NES_PTR_LEVELS2, LOWORD(m_ptr.ptrLevels[1])); Short(NES_PTR_ENEMY1, LOWORD(m_ptr.ptrEnemies[0])); Short(NES_PTR_ENEMY2, LOWORD(m_ptr.ptrEnemies[1])); Short(NES_PTR_ENEMY3, LOWORD(m_ptr.ptrEnemies[2])); Short(NES_PTR_ENEMY4, LOWORD(m_ptr.ptrEnemies[3])); return err; }
bool glTextureManager::ScheduleJob(glTexFactory* client, const wxRect &rect, int level, bool b_throttle_thread, bool b_nolimit, bool b_postZip, bool b_inplace) { wxString chart_path = client->GetChartPath(); if(!b_nolimit) { if(todo_list.GetCount() >= 50){ // remove last job which is least important wxJobListNode *node = todo_list.GetLast(); JobTicket *ticket = node->GetData(); todo_list.DeleteNode(node); delete ticket; } // Avoid adding duplicate jobs, i.e. the same chart_path, and the same rectangle wxJobListNode *node = todo_list.GetFirst(); while(node){ JobTicket *ticket = node->GetData(); if( (ticket->m_ChartPath == chart_path) && (ticket->rect == rect)) { // bump to front todo_list.DeleteNode(node); todo_list.Insert(ticket); ticket->level_min_request = level; return false; } node = node->GetNext(); } // avoid duplicate worker jobs wxJobListNode *tnode = running_list.GetFirst(); while(tnode){ JobTicket *ticket = tnode->GetData(); if(ticket->rect == rect && ticket->m_ChartPath == chart_path) { return false; } tnode = tnode->GetNext(); } } JobTicket *pt = new JobTicket; pt->pFact = client; pt->rect = rect; pt->level_min_request = level; glTextureDescriptor *ptd = client->GetOrCreateTD( pt->rect ); pt->ident = (ptd->tex_name << 16) + level; pt->b_throttle = b_throttle_thread; pt->m_ChartPath = chart_path; pt->level0_bits = NULL; pt->b_abort = false; pt->b_isaborted = false; pt->bpost_zip_compress = b_postZip; pt->binplace = b_inplace; /* do we compress in ram using builtin libraries, or do we upload to the gpu and use the driver to perform compression? we have builtin libraries for DXT1 (squish) and ETC1 (etcpak) FXT1 must use the driver, ETC1 cannot, and DXT1 can use the driver but the results are worse and don't compress well. additionally, if we use the driver we must stay single threaded in this thread (unless we created multiple opengl contexts), but with with our own libraries, we can use multiple threads to take advantage of multiple cores */ if(g_raster_format != GL_COMPRESSED_RGB_FXT1_3DFX) { todo_list.Insert(pt); // push to front as a stack if(bthread_debug){ int mem_used; GetMemoryStatus(0, &mem_used); printf( "Adding job: %08X Job Count: %lu mem_used %d\n", pt->ident, (unsigned long)todo_list.GetCount(), mem_used); } StartTopJob(); } else { // give level 0 buffer to the ticket pt->level0_bits = ptd->map_array[0]; ptd->map_array[0] = NULL; pt->DoJob(); OCPN_CompressionThreadEvent Nevent(wxEVT_OCPN_COMPRESSIONTHREAD, 0); Nevent.type = 0; Nevent.SetTicket(pt); ProcessEventLocally(Nevent); // from here m_ticket is undefined (if deleted in event handler) } return true; }
bool glTextureManager::FactoryCrunch(double factor) { if (m_chart_texfactory_hash.size() == 0) { /* nothing to free */ return false; } int mem_used, mem_start; GetMemoryStatus(0, &mem_used); double hysteresis = 0.90; mem_start = mem_used; ChartPathHashTexfactType::iterator it0; bool bMemCrunch = (mem_used > (double)(g_memCacheLimit) * factor *hysteresis && mem_used > (double)(m_prevMemUsed) * factor *hysteresis) || (m_chart_texfactory_hash.size() > MAX_CACHE_FACTORY); // Need more, so delete the oldest factory if(!bMemCrunch) return false; // Find the oldest unused factory int lru_oldest = 2147483647; glTexFactory *ptf_oldest = NULL; for( it0 = m_chart_texfactory_hash.begin(); it0 != m_chart_texfactory_hash.end(); ++it0 ) { wxString chart_full_path = it0->first; glTexFactory *ptf = it0->second; if(!ptf) continue; // we better have to find one because glTexFactory keep cache texture open // and ocpn will eventually run out of file descriptors if( cc1->GetVP().b_quilt ) // quilted { if( cc1->m_pQuilt && cc1->m_pQuilt->IsComposed() && !cc1->m_pQuilt->IsChartInQuilt( chart_full_path ) ) { int lru = ptf->GetLRUTime(); if(lru < lru_oldest && !ptf->BackgroundCompressionAsJob()){ lru_oldest = lru; ptf_oldest = ptf; } } } else { if( !Current_Ch->GetFullPath().IsSameAs(chart_full_path)) { int lru = ptf->GetLRUTime(); if(lru < lru_oldest && !ptf->BackgroundCompressionAsJob()){ lru_oldest = lru; ptf_oldest = ptf; } } } } // Found one? if(!ptf_oldest) return false; ptf_oldest->FreeSome( g_memCacheLimit * factor * hysteresis); GetMemoryStatus(0, &mem_used); bMemCrunch = (mem_used > (double)(g_memCacheLimit) * factor *hysteresis && mem_used > (double)(m_prevMemUsed) * factor *hysteresis) || (m_chart_texfactory_hash.size() > MAX_CACHE_FACTORY); // Need more memory, so delete the oldest factory if(!bMemCrunch) return false; m_chart_texfactory_hash.erase(ptf_oldest->GetChartPath()); // This chart becoming invalid delete ptf_oldest; // int mem_now; // GetMemoryStatus(0, &mem_now); // printf(">>>>FactoryCrunch was: %d is:%d \n", mem_start, mem_now); return true; }