void glTextureManager::OnEvtThread( OCPN_CompressionThreadEvent & event ) { JobTicket *ticket = event.GetTicket(); if(ticket->b_isaborted || ticket->b_abort){ for(int i=0 ; i < g_mipmap_max_level+1 ; i++) { free(ticket->comp_bits_array[i]); free( ticket->compcomp_bits_array[i] ); } if(bthread_debug) printf( " Abort job: %08X Jobs running: %d Job count: %lu \n", ticket->ident, GetRunningJobCount(), (unsigned long)todo_list.GetCount()); } else if(!b_inCompressAllCharts) { // Normal completion from here glTextureDescriptor *ptd = ticket->pFact->GetpTD( ticket->rect ); if(ptd) { for(int i=0 ; i < g_mipmap_max_level+1 ; i++) ptd->comp_array[i] = ticket->comp_bits_array[i]; if(ticket->bpost_zip_compress){ for(int i=0 ; i < g_mipmap_max_level+1 ; i++){ ptd->compcomp_array[i] = ticket->compcomp_bits_array[i]; ptd->compcomp_size[i] = ticket->compcomp_size_array[i]; } } // We need to force a refresh to replace the uncompressed texture // This frees video memory and is also really required if we had // gone up a mipmap level extern ChartCanvas *cc1; if(cc1) { glChartCanvas::Invalidate(); // ensure we refresh cc1->Refresh(); } ptd->compdata_ticks = 10; } if(bthread_debug) printf( " Finished job: %08X Jobs running: %d Job count: %lu \n", ticket->ident, GetRunningJobCount(), (unsigned long)todo_list.GetCount()); } // Free all possible memory if(b_inCompressAllCharts) { // if compressing all write cache here ChartBase *pchart = ChartData->OpenChartFromDB(ticket->m_ChartPath, FULL_INIT ); ChartData->DeleteCacheChart(pchart); delete ticket->pFact; } delete ticket; if(g_raster_format != GL_COMPRESSED_RGB_FXT1_3DFX) { running_list.DeleteObject(ticket); StartTopJob(); } }
bool glTextureManager::StartTopJob() { wxJobListNode *node = todo_list.GetFirst(); if(!node) return false; JobTicket *ticket = node->GetData(); // Is it possible to start another job? if(GetRunningJobCount() >= wxMax(m_max_jobs - ticket->b_throttle, 1)) return false; todo_list.DeleteNode(node); glTextureDescriptor *ptd = ticket->pFact->GetpTD( ticket->rect ); // don't need the job if we already have the compressed data if(ptd->comp_array[0]) { delete ticket; return StartTopJob(); } if(ptd->map_array[0]) { if(ticket->level_min_request == 0) { // give level 0 buffer to the ticket ticket->level0_bits = ptd->map_array[0]; ptd->map_array[0] = NULL; } else { // would be nicer to use reference counters int size = TextureTileSize(0, false); ticket->level0_bits = (unsigned char*)malloc(size); memcpy(ticket->level0_bits, ptd->map_array[0], size); } } running_list.Append(ticket); DoThreadJob(ticket); return true; }
void glTextureManager::OnEvtThread( OCPN_CompressionThreadEvent & event ) { JobTicket *ticket = event.GetTicket(); if(event.type ==1){ if(m_progDialog){ // Look for a matching entry... bool bfound = false; ProgressInfoItem *item; wxProgressInfoListNode *tnode = progList.GetFirst(); while(tnode){ item = tnode->GetData(); if(item->file_path == ticket->m_ChartPath){ bfound = true; break; } tnode = tnode->GetNext(); } if(bfound){ wxString msgx; if(1){ int bar_length = NBAR_LENGTH; if(m_bcompact) bar_length = 20; msgx += _T("\n["); wxString block = wxString::Format(_T("%c"), 0x2589); float cutoff = ((event.nstat+1) / (float)event.nstat_max) * bar_length; for(int i=0 ; i < bar_length ; i++){ if(i <= cutoff) msgx += block; else msgx += _T("-"); } msgx += _T("]"); if(!m_bcompact){ wxString msgy; msgy.Printf(_T(" [%3d/%3d] "), event.nstat+1, event.nstat_max); msgx += msgy; wxFileName fn(ticket->m_ChartPath); msgx += fn.GetFullName(); } } else msgx.Printf(_T("\n %3d/%3d"), event.nstat+1, event.nstat_max); item->msgx = msgx; } // look for an empty slot else{ bool bfound_empty = false; tnode = progList.GetFirst(); while(tnode){ item = tnode->GetData(); if(item->file_path.IsEmpty()){ bfound_empty = true; break; } tnode = tnode->GetNext(); } if(bfound_empty){ item->file_path = ticket->m_ChartPath; wxString msgx; msgx.Printf(_T("\n [%3d/%3d]"), event.nstat+1, event.nstat_max); item->msgx = msgx; } } // Ready to compose wxString msg; tnode = progList.GetFirst(); while(tnode){ item = tnode->GetData(); msg += item->msgx + _T("\n"); tnode = tnode->GetNext(); } if(m_skipout) m_progMsg = _T("Skipping, please wait...\n\n"); m_progDialog->Update(m_jcnt, m_progMsg + msg, &m_skip ); if(m_skip) m_skipout = true; return; } } if(ticket->b_isaborted || ticket->b_abort){ for(int i=0 ; i < g_mipmap_max_level+1 ; i++) { free(ticket->comp_bits_array[i]); free( ticket->compcomp_bits_array[i] ); } if(bthread_debug) printf( " Abort job: %08X Jobs running: %d Job count: %lu \n", ticket->ident, GetRunningJobCount(), (unsigned long)todo_list.GetCount()); } else if(!b_inCompressAllCharts) { // Normal completion from here glTextureDescriptor *ptd = ticket->pFact->GetpTD( ticket->rect ); if(ptd) { for(int i=0 ; i < g_mipmap_max_level+1 ; i++) ptd->comp_array[i] = ticket->comp_bits_array[i]; if(ticket->bpost_zip_compress){ for(int i=0 ; i < g_mipmap_max_level+1 ; i++){ ptd->compcomp_array[i] = ticket->compcomp_bits_array[i]; ptd->compcomp_size[i] = ticket->compcomp_size_array[i]; } } // We need to force a refresh to replace the uncompressed texture // This frees video memory and is also really required if we had // gone up a mipmap level extern ChartCanvas *cc1; if(cc1) { glChartCanvas::Invalidate(); // ensure we refresh cc1->Refresh(); } ptd->compdata_ticks = 10; } if(bthread_debug) printf( " Finished job: %08X Jobs running: %d Job count: %lu \n", ticket->ident, GetRunningJobCount(), (unsigned long)todo_list.GetCount()); } // Free all possible memory if(b_inCompressAllCharts) { // if compressing all write cache here ChartBase *pchart = ChartData->OpenChartFromDB(ticket->m_ChartPath, FULL_INIT ); ChartData->DeleteCacheChart(pchart); delete ticket->pFact; } wxProgressInfoListNode *tnode = progList.GetFirst(); while(tnode){ ProgressInfoItem *item = tnode->GetData(); if(item->file_path == ticket->m_ChartPath) item->file_path = _T(""); tnode = tnode->GetNext(); } delete ticket; if(g_raster_format != GL_COMPRESSED_RGB_FXT1_3DFX) { running_list.DeleteObject(ticket); StartTopJob(); } }
void glTextureManager::BuildCompressedCache() { idx_sorted_by_distance.Clear(); // Building the cache may take a long time.... // Be a little smarter. // Build a sorted array of chart database indices, sorted on distance from the ownship currently. // This way, a user may build a few charts textures for immediate use, then "skip" out on the rest until later. int count = 0; for(int i = 0; i<ChartData->GetChartTableEntries(); i++) { /* skip if not kap */ const ChartTableEntry &cte = ChartData->GetChartTableEntry(i); ChartTypeEnum chart_type = (ChartTypeEnum)cte.GetChartType(); if(chart_type != CHART_TYPE_KAP) continue; wxString CompressedCacheFilePath = CompressedCachePath(ChartData->GetDBChartFileName(i)); wxFileName fn(CompressedCacheFilePath); // if(fn.FileExists()) /* skip if file exists */ // continue; idx_sorted_by_distance.Add(i); count++; } if(count == 0) return; wxLogMessage(wxString::Format(_T("BuildCompressedCache() count = %d"), count )); b_inCompressAllCharts = true; PurgeJobList(); ClearAllRasterTextures(); // Build another array of sorted compression targets. // We need to do this, as the chart table will not be invariant // after the compression threads start, so our index array will be invalid. ArrayOfCompressTargets ct_array; for(unsigned int j = 0; j<idx_sorted_by_distance.GetCount(); j++) { int i = idx_sorted_by_distance.Item(j); const ChartTableEntry &cte = ChartData->GetChartTableEntry(i); double distance = chart_dist(i); wxString filename(cte.GetpFullPath(), wxConvUTF8); compress_target *pct = new compress_target; pct->distance = distance; pct->chart_path = filename; ct_array.Add(pct); } // create progress dialog long style = wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | wxPD_CAN_SKIP; wxString msg0; msg0 = _T(" \n \n "); #ifdef __WXQT__ msg0 = _T("Very longgggggggggggggggggggggggggggggggggggggggggggg\ngggggggggggggggggggggggggggggggggggggggggggg top line "); #endif for(int i=0 ; i < m_max_jobs+1 ; i++) msg0 += _T("\n "); m_progDialog = new wxGenericProgressDialog(); wxFont *qFont = GetOCPNScaledFont(_("Dialog")); int fontSize = qFont->GetPointSize(); wxFont *sFont; wxSize csz = cc1->GetClientSize(); if(csz.x < 500 || csz.y < 500) sFont = FontMgr::Get().FindOrCreateFont( 10, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL); else sFont = FontMgr::Get().FindOrCreateFont( fontSize, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL); m_progDialog->SetFont( *sFont ); // Should we use "compact" screen layout? wxScreenDC sdc; int height, width; sdc.GetTextExtent(_T("[WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW]"), &width, &height, NULL, NULL, sFont); if(width > (csz.x / 2)) m_bcompact = true; m_progDialog->Create(_("OpenCPN Compressed Cache Update"), msg0, count+1, NULL, style ); // Make sure the dialog is big enough to be readable m_progDialog->Hide(); wxSize sz = m_progDialog->GetSize(); sz.x = csz.x * 9 / 10; m_progDialog->SetSize( sz ); m_progDialog->Layout(); wxSize sza = m_progDialog->GetSize(); wxSize pprog_size = sz; m_progDialog->Centre(); m_progDialog->Show(); m_progDialog->Raise(); m_skipout = false; m_skip = false; for( m_jcnt = 0; m_jcnt<ct_array.GetCount(); m_jcnt++) { wxString filename = ct_array.Item(m_jcnt).chart_path; wxString CompressedCacheFilePath = CompressedCachePath(filename); double distance = ct_array.Item(m_jcnt).distance; ChartBase *pchart = ChartData->OpenChartFromDBAndLock( filename, FULL_INIT ); if(!pchart) /* probably a corrupt chart */ continue; // bad things if more than one texfactory for a chart g_glTextureManager->PurgeChartTextures( pchart, true ); ChartBaseBSB *pBSBChart = dynamic_cast<ChartBaseBSB*>( pchart ); if(pBSBChart) { glTexFactory *tex_fact = new glTexFactory(pchart, g_raster_format); m_progMsg.Printf( _("Distance from Ownship: %4.0f NMi\n"), distance); m_progMsg.Prepend(_T("Preparing RNC Cache...\n")); if(m_skipout) { g_glTextureManager->PurgeJobList(); ChartData->DeleteCacheChart(pchart); delete tex_fact; break; } int size_X = pBSBChart->GetSize_X(); int size_Y = pBSBChart->GetSize_Y(); int tex_dim = g_GLOptions.m_iTextureDimension; int nx_tex = ceil( (float)size_X / tex_dim ); int ny_tex = ceil( (float)size_Y / tex_dim ); int nt = ny_tex * nx_tex; wxRect rect; rect.y = 0; rect.width = tex_dim; rect.height = tex_dim; for( int y = 0; y < ny_tex; y++ ) { rect.x = 0; for( int x = 0; x < nx_tex; x++ ) { for(int level = 0; level < g_mipmap_max_level + 1; level++ ) if(!tex_fact->IsLevelInCache( level, rect, global_color_scheme )){ goto schedule; } rect.x += rect.width; } rect.y += rect.height; } // Free all possible memory ChartData->DeleteCacheChart(pchart); delete tex_fact; continue; schedule: ScheduleJob(tex_fact, wxRect(), 0, false, true, true, false); while(!m_skip) { ::wxYield(); int cnt = GetJobCount() - GetRunningJobCount(); if(!cnt) break; wxThread::Sleep(1); } if(m_skipout) { g_glTextureManager->PurgeJobList(); ChartData->DeleteCacheChart(pchart); delete tex_fact; break; } } } while(GetRunningJobCount()) { wxThread::Sleep(1); ::wxYield(); } b_inCompressAllCharts = false; delete m_progDialog; m_progDialog = NULL; }
bool glTextureManager::DoThreadJob(JobTicket* pticket) { if(bthread_debug) printf( " Starting job: %08X Jobs running: %d Jobs left: %lu\n", pticket->ident, GetRunningJobCount(), (unsigned long)todo_list.GetCount()); /// qDebug() << "Starting job" << GetRunningJobCount() << (unsigned long)todo_list.GetCount() << g_tex_mem_used; CompressionPoolThread *t = new CompressionPoolThread( pticket, this); pticket->pthread = t; t->Run(); return true; }