27 #include <wx/wxprec.h>
28 #include <wx/progdlg.h>
30 #include <wx/thread.h>
32 #if defined(__OCPN__ANDROID__)
33 #include <GLES2/gl2.h>
34 #elif defined(__WXQT__) || defined(__WXGTK__)
40 #include "glTexCache.h"
41 #include "glTextureDescriptor.h"
44 #include "glChartCanvas.h"
46 #include "chartbase.h"
49 #include "OCPNPlatform.h"
51 #include "mipmap/mipmap.h"
53 #include "ocpn_frame.h"
54 #include "model/own_ship.h"
56 #ifndef GL_ETC1_RGB8_OES
57 #define GL_ETC1_RGB8_OES 0x8D64
64 #include <wx/listimpl.cpp>
65 WX_DEFINE_LIST(JobList);
66 WX_DEFINE_LIST(ProgressInfoList);
68 WX_DEFINE_ARRAY_PTR(
ChartCanvas *, arrayofCanvasPtr);
70 extern int g_mipmap_max_level;
71 extern GLuint g_raster_format;
72 extern int g_memCacheLimit;
75 extern long g_tex_mem_used;
76 extern int g_tile_size;
77 extern int g_uncompressed_tile_size;
78 extern int g_nCPUCount;
80 extern bool b_inCompressAllCharts;
82 extern arrayofCanvasPtr g_canvasArray;
85 extern ColorScheme global_color_scheme;
87 extern bool GetMemoryStatus(
int *mem_total,
int *mem_used);
90 bool g_throttle_squish;
96 wxString CompressedCachePath(wxString path) {
97 #if defined(__WXMSW__)
98 int colon = path.find(
':', 0);
99 if (colon != wxNOT_FOUND) path.Remove(colon, 1);
103 wxChar separator = wxFileName::GetPathSeparator();
104 for (
unsigned int pos = 0; pos < path.size(); pos = path.find(separator, pos))
105 path.replace(pos, 1, _T(
"!"));
109 wxCharBuffer buf = path.ToUTF8();
110 unsigned char sha1_out[20];
111 sha1((
unsigned char *)buf.data(), strlen(buf.data()), sha1_out);
114 for (
unsigned int i = 0; i < 20; i++) {
116 s.Printf(_T(
"%02X"), sha1_out[i]);
121 _T(
"raster_texture_cache") + separator + sha1;
124 int g_mipmap_max_level = 4;
127 OCPN_CompressProgressEvent::OCPN_CompressProgressEvent(wxEventType commandType,
int id)
128 :wxEvent(id, commandType)
132 OCPN_CompressProgressEvent::~OCPN_CompressProgressEvent()
136 wxEvent* OCPN_CompressProgressEvent::Clone()
const
138 OCPN_CompressProgressEvent *newevent=
new OCPN_CompressProgressEvent(*
this);
139 newevent->m_string=this->m_string;
140 newevent->count=this->count;
141 newevent->thread=this->thread;
146 static double chart_dist(
int index) {
152 if (cte.GetBBox().Contains(gLat, gLon))
157 clon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
158 d = DistGreatCircle(cte.GetLatMax(), clon, gLat, gLon);
159 t = DistGreatCircle(cte.GetLatMin(), clon, gLat, gLon);
162 clat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
163 t = DistGreatCircle(clat, cte.GetLonMin(), gLat, gLon);
165 t = DistGreatCircle(clat, cte.GetLonMax(), gLat, gLon);
171 WX_DEFINE_SORTED_ARRAY_INT(
int, MySortedArrayInt);
172 int CompareInts(
int n1,
int n2) {
173 double d1 = chart_dist(n1);
174 double d2 = chart_dist(n2);
175 return (
int)(d1 - d2);
178 static MySortedArrayInt idx_sorted_by_distance(CompareInts);
186 #include <wx/arrimpl.cpp>
191 JobTicket::JobTicket() {
192 for (
int i = 0; i < 10; i++) {
193 compcomp_size_array[i] = 0;
194 comp_bits_array[i] = NULL;
195 compcomp_bits_array[i] = NULL;
205 void FlattenColorsForCompression(
unsigned char *data,
int dim,
bool swap_colors=
true)
210 for(
int i = 0; i<dim*dim; i++) {
212 unsigned char t = data[off + 0];
213 data[off + 0] = data[off + 2] & 0xfc;
214 data[off + 1] &= 0xf8;
215 data[off + 2] = t & 0xfc;
219 for(
int i = 0; i<dim*dim; i++) {
221 data[off + 0] &= 0xfc;
222 data[off + 1] &= 0xf8;
223 data[off + 2] &= 0xfc;
229 static void CompressDataETC(
const unsigned char *data,
int dim,
int size,
230 unsigned char *tex_data,
volatile bool &b_abort) {
231 wxASSERT(dim * dim == 2 * size || (dim < 4 && size == 8));
232 uint64_t *tex_data64 = (uint64_t *)tex_data;
234 int mbrow = wxMin(4, dim), mbcol = wxMin(4, dim);
235 uint8_t
block[48] = {};
236 for (
int row = 0; row < dim; row += 4) {
237 for (
int col = 0; col < dim; col += 4) {
238 for (
int brow = 0; brow < mbrow; brow++)
239 for (
int bcol = 0; bcol < mbcol; bcol++)
240 memcpy(
block + (bcol * 4 + brow) * 3,
241 data + ((row + brow) * dim + col + bcol) * 3, 3);
243 extern uint64_t ProcessRGB(
const uint8_t *src);
244 *tex_data64++ = ProcessRGB(
block);
250 static bool CompressUsingGPU(
const unsigned char *data,
int dim,
int size,
251 unsigned char *tex_data,
int level,
bool inplace) {
252 #ifndef USE_ANDROID_GLES2
256 glGenTextures(1, &comp_tex);
257 glBindTexture(GL_TEXTURE_2D, comp_tex);
258 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
259 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
263 glTexImage2D(GL_TEXTURE_2D, level, g_raster_format, dim, dim, 0, GL_RGB,
264 GL_UNSIGNED_BYTE, data);
267 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_ARB,
270 if (compressed == GL_TRUE) {
272 GLint compressedSize;
273 glGetTexLevelParameteriv(GL_TEXTURE_2D, level,
274 GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &compressedSize);
276 if (compressedSize != size)
return false;
279 glGetCompressedTexImage(GL_TEXTURE_2D, level, tex_data);
282 if (!inplace) glDeleteTextures(1, &comp_tex);
291 wxString &chart_path) {
294 ptd->map_array[0] = 0;
296 ChartBase *pChart = ChartData->OpenChartFromDB(chart_path, FULL_INIT);
299 (
unsigned char *)calloc(ncrect.width * ncrect.height * 4, 1);
307 unsigned char *t_buf =
308 (
unsigned char *)malloc(ncrect.width * ncrect.height * 4);
309 pBSBChart->GetChartBits(ncrect, t_buf, 1);
312 ptd->map_array[0] = t_buf;
315 (
unsigned char *)calloc(ncrect.width * ncrect.height * 4, 1);
321 wxString chart_path,
int level) {
324 if (ptd->map_array[level])
return;
328 for (first_level = level; first_level; first_level--)
329 if (ptd->map_array[first_level - 1])
break;
333 GetLevel0Map(ptd, rect, chart_path);
337 int dim = g_GLOptions.m_iTextureDimension;
338 for (
int i = 0; i <= level; i++) {
339 if (i >= first_level) {
340 ptd->map_array[i] = (
unsigned char *)malloc(dim * dim * 3);
341 MipMap_24(2 * dim, 2 * dim, ptd->map_array[i - 1], ptd->map_array[i]);
347 int TextureDim(
int level) {
348 int dim = g_GLOptions.m_iTextureDimension;
349 for (
int i = 0; i < level; i++) dim /= 2;
353 int TextureTileSize(
int level,
bool compressed) {
354 if (level == g_mipmap_max_level + 1)
return 0;
359 for (
int i = 0; i < level; i++) {
361 if (size < 8) size = 8;
364 size = g_uncompressed_tile_size;
365 for (
int i = 0; i < level; i++) size /= 4;
371 bool JobTicket::DoJob() {
372 if (!m_rect.IsEmpty())
return DoJob(m_rect);
375 ChartBase *pchart = ChartData->OpenChartFromDB(m_ChartPath, FULL_INIT);
376 if (!pchart)
return false;
379 if (!pBSBChart)
return false;
381 int size_X = pBSBChart->GetSize_X();
382 int size_Y = pBSBChart->GetSize_Y();
384 int dim = g_GLOptions.m_iTextureDimension;
386 int nx_tex = ceil((
float)size_X / dim);
387 int ny_tex = ceil((
float)size_Y / dim);
393 for (
int y = 0; y < ny_tex; y++) {
394 if (pthread && pthread->m_pMessageTarget) {
397 Nevent.nstat_max = ny_tex;
399 Nevent.SetTicket(
this);
400 pthread->m_pMessageTarget->AddPendingEvent(Nevent);
404 for (
int x = 0; x < nx_tex; x++) {
405 if (!DoJob(rect))
return false;
407 pFact->UpdateCacheAllLevels(rect, global_color_scheme,
408 compcomp_bits_array, compcomp_size_array);
410 for (
int i = 0; i < g_mipmap_max_level + 1; i++) {
411 free(comp_bits_array[i]), comp_bits_array[i] = 0;
412 free(compcomp_bits_array[i]), compcomp_bits_array[i] = 0;
415 rect.x += rect.width;
417 rect.y += rect.height;
429 void Start() { clock_gettime(CLOCK_REALTIME, &tp); }
433 clock_gettime(CLOCK_REALTIME, &tp_end);
434 return (tp_end.tv_sec - tp.tv_sec) * 1.e3 + (tp_end.tv_nsec - tp.tv_nsec) / 1.e6;
444 static void throttle_func(
void *data) {
445 if (!wxThread::IsMain()) {
447 if (sww->Time() > 1) {
454 static wxMutex s_mutexProtectingChartBitRead;
456 bool JobTicket::DoJob(
const wxRect &rect) {
457 unsigned char *bit_array[10];
458 for (
int i = 0; i < 10; i++) bit_array[i] = 0;
462 bit_array[0] = level0_bits;
473 wxMutexLocker lock(s_mutexProtectingChartBitRead);
475 index = ChartData->FinddbIndex(m_ChartPath);
476 pchart = ChartData->OpenChartFromDBAndLock(index, FULL_INIT);
478 if (pchart && ChartData->IsChartLocked(index)) {
482 (
unsigned char *)malloc(ncrect.width * ncrect.height * 4);
483 pBSBChart->GetChartBits(ncrect, bit_array[0], 1);
485 ChartData->UnLockCacheChart(index);
493 if (!bit_array[0])
return false;
496 dim = g_GLOptions.m_iTextureDimension;
498 for (
int i = 1; i < g_mipmap_max_level + 1; i++) {
499 size_t nmalloc = wxMax(dim * dim * 3, 4 * 4 * 3);
500 bit_array[i] = (
unsigned char *)malloc(nmalloc);
501 MipMap_24(2 * dim, 2 * dim, bit_array[i - 1], bit_array[i]);
505 int texture_level = 0;
506 for (
int level = level_min_request; level < g_mipmap_max_level + 1; level++) {
507 int dim = TextureDim(level);
508 int size = TextureTileSize(level,
true);
509 unsigned char *tex_data = (
unsigned char *)malloc(size);
510 if (g_raster_format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT) {
512 int flags = squish::kDxt1 | squish::kColourRangeFit;
514 if (g_GLOptions.m_bTextureCompressionCaching) {
518 flags = squish::kDxt1 | squish::kColourClusterFit;
522 squish::CompressImageRGBpow2_Flatten_Throttle_Abort(
523 bit_array[level], dim, dim, tex_data, flags,
true,
524 b_throttle ? throttle_func : 0, &sww, b_abort);
526 }
else if (g_raster_format == GL_ETC1_RGB8_OES)
527 CompressDataETC(bit_array[level], dim, size, tex_data, b_abort);
528 else if (g_raster_format == GL_COMPRESSED_RGB_FXT1_3DFX) {
529 if (!CompressUsingGPU(bit_array[level], dim, size, tex_data,
530 texture_level, binplace)) {
535 if (binplace) g_tex_mem_used += size;
539 comp_bits_array[level] = tex_data;
542 for (
int i = 0; i < g_mipmap_max_level + 1; i++) {
551 for (
int i = 0; i < g_mipmap_max_level + 1; i++) {
556 if (b_throttle) wxThread::Sleep(1);
558 if (b_abort)
return false;
560 if (bpost_zip_compress) {
561 int max_compressed_size = LZ4_COMPRESSBOUND(g_tile_size);
562 for (
int level = level_min_request; level < g_mipmap_max_level + 1;
564 if (b_abort)
return false;
566 unsigned char *compressed_data =
567 (
unsigned char *)malloc(max_compressed_size);
568 int csize = TextureTileSize(level,
true);
570 char *src = (
char *)comp_bits_array[level];
571 int compressed_size =
572 LZ4_compressHC2(src, (
char *)compressed_data, csize, 4);
577 (
unsigned char *)realloc(compressed_data, compressed_size);
578 compcomp_bits_array[level] = compressed_data;
579 compcomp_size_array[level] = compressed_size;
602 SE_Exception(
unsigned int n) : nSE(n) {}
604 unsigned int getSeNumber() {
return nSE; }
607 void my_translate(
unsigned int code, _EXCEPTION_POINTERS *ep) {
608 throw SE_Exception();
612 OCPN_CompressionThreadEvent::OCPN_CompressionThreadEvent(
613 wxEventType commandType,
int id)
614 : wxEvent(id, commandType) {
618 OCPN_CompressionThreadEvent::~OCPN_CompressionThreadEvent() {}
620 wxEvent *OCPN_CompressionThreadEvent::Clone()
const {
623 newevent->m_ticket = this->m_ticket;
624 newevent->type = this->type;
625 newevent->nstat = this->nstat;
626 newevent->nstat_max = this->nstat_max;
658 CompressionPoolThread::CompressionPoolThread(
JobTicket *ticket,
659 wxEvtHandler *message_target) {
660 m_pMessageTarget = message_target;
666 void *CompressionPoolThread::Entry() {
668 _set_se_translator(my_translate);
678 SetPriority(WXTHREAD_MIN_PRIORITY);
680 if (!m_ticket->DoJob()) m_ticket->b_isaborted =
true;
682 if (m_pMessageTarget) {
684 Nevent.SetTicket(m_ticket);
686 m_pMessageTarget->QueueEvent(Nevent.Clone());
694 catch (SE_Exception e) {
695 if (m_pMessageTarget) {
697 m_ticket->b_isaborted =
true;
698 Nevent.SetTicket(m_ticket);
700 m_pMessageTarget->QueueEvent(Nevent.Clone());
711 glTextureManager::glTextureManager() {
714 int nCPU = wxMax(1, wxThread::GetCPUCount());
715 if (g_nCPUCount > 0) nCPU = g_nCPUCount;
721 m_max_jobs = wxMax(nCPU, 1);
724 if (bthread_debug) printf(
" nCPU: %d m_max_jobs :%d\n", nCPU, m_max_jobs);
733 wxEVT_OCPN_COMPRESSIONTHREAD,
734 (wxObjectEventFunction)(wxEventFunction)&glTextureManager::OnEvtThread);
741 m_timer.Connect(wxEVT_TIMER, wxTimerEventHandler(glTextureManager::OnTimer),
746 glTextureManager::~glTextureManager() {
749 for (
int i = 0; i < m_max_jobs; i++) {
753 for(
auto hash : m_chart_texfactory_hash) {
756 m_chart_texfactory_hash.clear();
759 #define NBAR_LENGTH 40
764 if (event.type == 1) {
772 wxProgressInfoListNode *tnode = progList.GetFirst();
774 item = tnode->GetData();
775 if (item->file_path == ticket->m_ChartPath) {
779 tnode = tnode->GetNext();
784 tnode = progList.GetFirst();
786 item = tnode->GetData();
787 if (item->file_path.IsEmpty()) {
789 item->file_path = ticket->m_ChartPath;
792 tnode = tnode->GetNext();
799 int bar_length = NBAR_LENGTH;
800 if (m_bcompact) bar_length = 20;
803 wxString
block = wxString::Format(_T(
"%c"), 0x2588);
805 if (event.nstat_max != 0)
806 cutoff = ((
event.nstat + 1) / (
float)
event.nstat_max) * bar_length;
807 for (
int i = 0; i < bar_length; i++) {
817 msgy.Printf(_T(
" [%3d/%3d] "), event.nstat + 1, event.nstat_max);
820 wxFileName fn(ticket->m_ChartPath);
821 msgx += fn.GetFullName();
824 msgx.Printf(_T(
"\n %3d/%3d"), event.nstat + 1, event.nstat_max);
831 tnode = progList.GetFirst();
833 item = tnode->GetData();
834 msg += item->msgx + _T(
"\n");
835 tnode = tnode->GetNext();
838 if (m_skipout) m_progMsg = _T(
"Skipping, please wait...\n\n");
840 if (!m_progDialog->Update(m_jcnt, m_progMsg + msg, &m_skip)) m_skip =
true;
841 if (m_skip) m_skipout =
true;
845 if (ticket->b_isaborted || ticket->b_abort) {
846 for (
int i = 0; i < g_mipmap_max_level + 1; i++) {
847 free(ticket->comp_bits_array[i]);
848 free(ticket->compcomp_bits_array[i]);
853 " Abort job: %08X Jobs running: %d Job count: %lu "
855 ticket->ident, GetRunningJobCount(),
856 (
unsigned long)todo_list.GetCount());
857 }
else if (!ticket->b_inCompressAll) {
861 for (
int i = 0; i < g_mipmap_max_level + 1; i++)
862 ptd->comp_array[i] = ticket->comp_bits_array[i];
864 if (ticket->bpost_zip_compress) {
865 for (
int i = 0; i < g_mipmap_max_level + 1; i++) {
866 ptd->compcomp_array[i] = ticket->compcomp_bits_array[i];
867 ptd->compcomp_size[i] = ticket->compcomp_size_array[i];
874 gFrame->InvalidateAllGL();
875 ptd->compdata_ticks = 10;
880 " Finished job: %08X Jobs running: %d Job count: %lu "
882 ticket->ident, GetRunningJobCount(),
883 (
unsigned long)todo_list.GetCount());
887 if (ticket->b_inCompressAll) {
889 ChartData->OpenChartFromDB(ticket->m_ChartPath, FULL_INIT);
890 ChartData->DeleteCacheChart(pchart);
891 delete ticket->pFact;
894 wxProgressInfoListNode *tnode = progList.GetFirst();
897 if (item->file_path == ticket->m_ChartPath) item->file_path = _T(
"");
898 tnode = tnode->GetNext();
901 if (g_raster_format != GL_COMPRESSED_RGB_FXT1_3DFX) {
902 running_list.DeleteObject(ticket);
909 void glTextureManager::OnTimer(wxTimerEvent &event) {
915 if (g_GLOptions.m_bTextureCompression) {
916 for (ChartPathHashTexfactType::iterator itt =
917 m_chart_texfactory_hash.begin();
918 itt != m_chart_texfactory_hash.end(); ++itt) {
920 if (ptf && ptf->OnTimer()) {
927 if((m_ticks % 4) == 0){
930 int mem_total, mem_used;
931 GetMemoryStatus(&mem_total, &mem_used);
935 int compcomp_size = 0;
937 for(ChartPathHashTexfactType::iterator itt = m_chart_texfactory_hash.begin();
938 itt != m_chart_texfactory_hash.end(); ++itt ) {
941 ptf->AccumulateMemStatistics(map_size, comp_size, compcomp_size);
944 int m1 = 1024 * 1024;
946 printf(
"%6d %6ld Map: %10d Comp:%10d CompComp: %10d \n", mem_used/1024, g_tex_mem_used/m1, map_size, comp_size, compcomp_size);
953 bool glTextureManager::ScheduleJob(
glTexFactory *client,
const wxRect &rect,
954 int level,
bool b_throttle_thread,
955 bool b_nolimit,
bool b_postZip,
957 wxString chart_path = client->GetChartPath();
959 if (todo_list.GetCount() >= 50) {
961 wxJobListNode *node = todo_list.GetLast();
963 todo_list.DeleteNode(node);
969 wxJobListNode *node = todo_list.GetFirst();
972 if ((ticket->m_ChartPath == chart_path) && (ticket->m_rect == rect)) {
974 todo_list.DeleteNode(node);
975 todo_list.Insert(ticket);
976 ticket->level_min_request = level;
980 node = node->GetNext();
984 wxJobListNode *tnode = running_list.GetFirst();
987 if (ticket->m_rect == rect && ticket->m_ChartPath == chart_path) {
990 tnode = tnode->GetNext();
997 pt->level_min_request = level;
999 pt->ident = (ptd->tex_name << 16) + level;
1000 pt->b_throttle = b_throttle_thread;
1001 pt->m_ChartPath = chart_path;
1003 pt->level0_bits = NULL;
1004 pt->b_abort =
false;
1005 pt->b_isaborted =
false;
1006 pt->bpost_zip_compress = b_postZip;
1007 pt->binplace = b_inplace;
1008 pt->b_inCompressAll = b_inCompressAllCharts;
1020 if (g_raster_format != GL_COMPRESSED_RGB_FXT1_3DFX) {
1021 todo_list.Insert(pt);
1022 if (bthread_debug) {
1024 GetMemoryStatus(0, &mem_used);
1025 printf(
"Adding job: %08X Job Count: %lu mem_used %d\n", pt->ident,
1026 (
unsigned long)todo_list.GetCount(), mem_used);
1032 pt->level0_bits = ptd->map_array[0];
1033 ptd->map_array[0] = NULL;
1039 Nevent.SetTicket(pt);
1040 ProcessEventLocally(Nevent);
1046 bool glTextureManager::StartTopJob() {
1047 wxJobListNode *node = todo_list.GetFirst();
1048 if (!node)
return false;
1053 if (GetRunningJobCount() >= wxMax(m_max_jobs - ticket->b_throttle, 1))
1056 todo_list.DeleteNode(node);
1060 if (ptd->comp_array[0]) {
1062 return StartTopJob();
1065 if (ptd->map_array[0]) {
1066 if (ticket->level_min_request == 0) {
1068 ticket->level0_bits = ptd->map_array[0];
1069 ptd->map_array[0] = NULL;
1072 int size = TextureTileSize(0,
false);
1073 ticket->level0_bits = (
unsigned char *)malloc(size);
1074 memcpy(ticket->level0_bits, ptd->map_array[0], size);
1078 running_list.Append(ticket);
1079 DoThreadJob(ticket);
1084 bool glTextureManager::DoThreadJob(
JobTicket *pticket) {
1086 printf(
" Starting job: %08X Jobs running: %d Jobs left: %lu\n",
1087 pticket->ident, GetRunningJobCount(),
1088 (
unsigned long)todo_list.GetCount());
1093 pticket->pthread = t;
1100 bool glTextureManager::AsJob(wxString
const &chart_path)
const {
1101 if (chart_path.Len()) {
1102 wxJobListNode *tnode = running_list.GetFirst();
1105 if (ticket->m_ChartPath.IsSameAs(chart_path)) {
1108 tnode = tnode->GetNext();
1114 void glTextureManager::PurgeJobList(wxString chart_path) {
1115 if (chart_path.Len()) {
1117 wxJobListNode *next, *tnode = todo_list.GetFirst();
1120 next = tnode->GetNext();
1121 if (ticket->m_ChartPath.IsSameAs(chart_path)) {
1123 printf(
"Pool: Purge pending job for purged chart\n");
1124 todo_list.DeleteNode(tnode);
1130 wxJobListNode *node = running_list.GetFirst();
1133 if (ticket->m_ChartPath.IsSameAs(chart_path)) {
1134 ticket->b_abort =
true;
1136 node = node->GetNext();
1140 printf(
"Pool: Purge, todo count: %lu\n",
1141 (
long unsigned)todo_list.GetCount());
1143 wxJobListNode *node = todo_list.GetFirst();
1147 node = node->GetNext();
1151 node = running_list.GetFirst();
1154 ticket->b_abort =
true;
1155 node = node->GetNext();
1160 void glTextureManager::ClearJobList() {
1161 wxJobListNode *node = todo_list.GetFirst();
1165 node = node->GetNext();
1170 void glTextureManager::ClearAllRasterTextures(
void) {
1172 ChartPathHashTexfactType::iterator itt;
1173 for (itt = m_chart_texfactory_hash.begin();
1174 itt != m_chart_texfactory_hash.end(); ++itt) {
1179 m_chart_texfactory_hash.clear();
1181 if (g_tex_mem_used != 0)
1182 wxLogMessage(_T(
"Texture memory use calculation error\n"));
1185 bool glTextureManager::PurgeChartTextures(
ChartBase *pc,
bool b_purge_factory) {
1187 ChartPathHashTexfactType::iterator ittf =
1188 m_chart_texfactory_hash.find(pc->GetHashKey());
1191 if (ittf != m_chart_texfactory_hash.end()) {
1195 if (b_purge_factory) {
1196 m_chart_texfactory_hash.erase(ittf);
1203 m_chart_texfactory_hash.erase(ittf);
1210 bool glTextureManager::TextureCrunch(
double factor) {
1211 double hysteresis = 0.90;
1215 (double)(g_GLOptions.m_iTextureMemorySize * 1024 * 1024) * factor;
1216 if (!bGLMemCrunch)
return false;
1218 ChartPathHashTexfactType::iterator it0;
1219 for (it0 = m_chart_texfactory_hash.begin();
1220 it0 != m_chart_texfactory_hash.end(); ++it0) {
1223 wxString chart_full_path = ptf->GetChartPath();
1225 bGLMemCrunch = g_tex_mem_used >
1226 (double)(g_GLOptions.m_iTextureMemorySize * 1024 * 1024) *
1227 factor * hysteresis;
1228 if (!bGLMemCrunch)
break;
1231 for (
unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
1234 if (cc->GetVP().b_quilt)
1236 if (cc->m_pQuilt && cc->m_pQuilt->IsComposed() &&
1237 !cc->m_pQuilt->IsChartInQuilt(chart_full_path)) {
1238 ptf->DeleteSomeTextures(g_GLOptions.m_iTextureMemorySize * 1024 *
1239 1024 * factor * hysteresis);
1243 if (!cc->m_singleChart->GetFullPath().IsSameAs(chart_full_path)) {
1244 ptf->DeleteSomeTextures(g_GLOptions.m_iTextureMemorySize * 1024 *
1245 1024 * factor * hysteresis);
1255 #define MAX_CACHE_FACTORY 50
1256 bool glTextureManager::FactoryCrunch(
double factor) {
1257 if (m_chart_texfactory_hash.size() == 0) {
1263 GetMemoryStatus(0, &mem_used);
1264 double hysteresis = 0.90;
1265 ChartPathHashTexfactType::iterator it0;
1269 ((mem_used > (double)(g_memCacheLimit)*factor * hysteresis &&
1270 mem_used > (double)(m_prevMemUsed)*factor * hysteresis) ||
1271 (m_chart_texfactory_hash.size() > MAX_CACHE_FACTORY)));
1273 if (!bMemCrunch)
return false;
1277 int lru_oldest = 2147483647;
1280 for (it0 = m_chart_texfactory_hash.begin();
1281 it0 != m_chart_texfactory_hash.end(); ++it0) {
1284 wxString chart_full_path = ptf->GetChartPath();
1290 for (
unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
1293 if (cc->GetVP().b_quilt)
1295 if (cc->m_pQuilt && cc->m_pQuilt->IsComposed() &&
1296 !cc->m_pQuilt->IsChartInQuilt(chart_full_path)) {
1297 int lru = ptf->GetLRUTime();
1298 if (lru < lru_oldest && !ptf->BackgroundCompressionAsJob()) {
1304 if (!cc->m_singleChart->GetFullPath().IsSameAs(chart_full_path)) {
1305 int lru = ptf->GetLRUTime();
1306 if (lru < lru_oldest && !ptf->BackgroundCompressionAsJob()) {
1317 if (!ptf_oldest)
return false;
1319 ptf_oldest->FreeSome(g_memCacheLimit * factor * hysteresis);
1321 GetMemoryStatus(0, &mem_used);
1323 bMemCrunch = (g_memCacheLimit &&
1324 ((mem_used > (double)(g_memCacheLimit)*factor * hysteresis &&
1325 mem_used > (double)(m_prevMemUsed)*factor * hysteresis) ||
1326 (m_chart_texfactory_hash.size() > MAX_CACHE_FACTORY)));
1328 if (!bMemCrunch)
return false;
1332 m_chart_texfactory_hash.erase(
1333 ptf_oldest->GetHashKey());
1340 void glTextureManager::BuildCompressedCache() {
1341 idx_sorted_by_distance.Clear();
1349 for (
int i = 0; i < ChartData->GetChartTableEntries(); i++) {
1352 ChartTypeEnum chart_type = (ChartTypeEnum)cte.GetChartType();
1353 if (chart_type == CHART_TYPE_PLUGIN) {
1354 if (cte.GetChartFamily() != CHART_FAMILY_RASTER)
continue;
1356 if (chart_type != CHART_TYPE_KAP)
continue;
1359 wxString CompressedCacheFilePath =
1360 CompressedCachePath(ChartData->GetDBChartFileName(i));
1361 wxFileName fn(CompressedCacheFilePath);
1365 idx_sorted_by_distance.Add(i);
1370 if (count == 0)
return;
1373 wxString::Format(_T(
"BuildCompressedCache() count = %d"), count));
1377 if (GetRunningJobCount()) {
1378 wxLogMessage(_T(
"Starting compressor pool drain"));
1379 wxDateTime now = wxDateTime::Now();
1380 time_t stall = now.GetTicks();
1381 #define THREAD_WAIT_SECONDS 5
1382 time_t end = stall + THREAD_WAIT_SECONDS;
1385 while (stall < end) {
1386 wxDateTime later = wxDateTime::Now();
1387 stall = later.GetTicks();
1390 msg.Printf(_T(
"Time: %d Job Count: %d"), n_comploop,
1391 GetRunningJobCount());
1393 if (!GetRunningJobCount())
break;
1399 fmsg.Printf(_T(
"Finished compressor pool drain..Time: %d Job Count: %d"),
1400 n_comploop, GetRunningJobCount());
1403 ClearAllRasterTextures();
1404 b_inCompressAllCharts =
true;
1410 ArrayOfCompressTargets ct_array;
1411 for (
unsigned int j = 0; j < idx_sorted_by_distance.GetCount(); j++) {
1412 int i = idx_sorted_by_distance[j];
1415 double distance = chart_dist(i);
1417 wxString filename = cte.GetFullSystemPath();
1420 pct->distance = distance;
1421 pct->chart_path = filename;
1427 long style = wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME |
1428 wxPD_REMAINING_TIME | wxPD_CAN_ABORT;
1438 _T("longgggggggggggggggggggggggggggggggggggggggggggg\ngggggggggggggggggg")
1439 _T("gggggggggggggggggggggggggg top line ");
1442 for (
int i = 0; i < m_max_jobs + 1; i++)
1445 m_progDialog =
new wxGenericProgressDialog();
1447 wxFont *qFont = GetOCPNScaledFont(_(
"Dialog"));
1448 int fontSize = qFont->GetPointSize();
1450 wxSize csz = gFrame->GetClientSize();
1451 if (csz.x < 500 || csz.y < 500)
1452 sFont = FontMgr::Get().FindOrCreateFont(
1453 10, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
1455 sFont = FontMgr::Get().FindOrCreateFont(fontSize, wxFONTFAMILY_TELETYPE,
1457 wxFONTWEIGHT_NORMAL);
1459 m_progDialog->SetFont(*sFont);
1464 sdc.GetTextExtent(_T(
"[WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW]"), &width, &height,
1466 if (width > (csz.x / 2)) m_bcompact =
true;
1468 m_progDialog->Create(_(
"OpenCPN Compressed Cache Update"), msg0, count + 1,
1472 m_progDialog->Hide();
1473 wxSize sz = m_progDialog->GetSize();
1474 sz.x = csz.x * 9 / 10;
1475 m_progDialog->SetSize(sz);
1477 m_progDialog->Layout();
1478 wxSize sza = m_progDialog->GetSize();
1480 m_progDialog->Centre();
1481 m_progDialog->Show();
1482 m_progDialog->Raise();
1488 for (m_jcnt = 0; m_jcnt < ct_array.GetCount(); m_jcnt++) {
1489 wxString filename = ct_array[m_jcnt].chart_path;
1490 wxString CompressedCacheFilePath = CompressedCachePath(filename);
1491 double distance = ct_array[m_jcnt].distance;
1493 ChartBase *pchart = ChartData->OpenChartFromDBAndLock(filename, FULL_INIT);
1498 g_glTextureManager->PurgeChartTextures(pchart,
true);
1501 if (pBSBChart == 0)
continue;
1505 m_progMsg.Printf(_(
"Distance from Ownship: %4.0f NMi"), distance);
1507 m_progMsg.Prepend(_T(
"Preparing RNC Cache...\n"));
1510 g_glTextureManager->PurgeJobList();
1511 ChartData->DeleteCacheChart(pchart);
1516 int size_X = pBSBChart->GetSize_X();
1517 int size_Y = pBSBChart->GetSize_Y();
1519 int tex_dim = g_GLOptions.m_iTextureDimension;
1521 int nx_tex = ceil((
float)size_X / tex_dim);
1522 int ny_tex = ceil((
float)size_Y / tex_dim);
1526 rect.width = tex_dim;
1527 rect.height = tex_dim;
1528 for (
int y = 0; y < ny_tex; y++) {
1530 for (
int x = 0; x < nx_tex; x++) {
1531 for (
int level = 0; level < g_mipmap_max_level + 1; level++) {
1532 if (!tex_fact->IsLevelInCache(level, rect, global_color_scheme)) {
1536 rect.x += rect.width;
1538 rect.y += rect.height;
1542 ChartData->DeleteCacheChart(pchart);
1548 if (!m_progDialog->Update(m_jcnt)) {
1559 ScheduleJob(tex_fact, wxRect(), 0,
false,
true,
true,
false);
1562 int cnt = GetJobCount() - GetRunningJobCount();
1568 g_glTextureManager->PurgeJobList();
1569 ChartData->DeleteCacheChart(pchart);
1575 while (GetRunningJobCount()) {
1580 b_inCompressAllCharts =
false;
1583 delete m_progDialog;
1584 m_progDialog =
nullptr;
General purpose GUI support.
Runtime representation of a plugin block.