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; }
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; }
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(); } }