28#include <wx/progdlg.h>
32#if defined(__OCPN__ANDROID__)
34#elif defined(__WXQT__) || defined(__WXGTK__)
40#include "glTexCache.h"
41#include "glTextureDescriptor.h"
44#include "glChartCanvas.h"
49#include "OCPNPlatform.h"
51#include "mipmap/mipmap.h"
53#include "ocpn_frame.h"
56#ifndef GL_ETC1_RGB8_OES
57#define GL_ETC1_RGB8_OES 0x8D64
64#include <wx/listimpl.cpp>
65WX_DEFINE_LIST(JobList);
66WX_DEFINE_LIST(ProgressInfoList);
68WX_DEFINE_ARRAY_PTR(
ChartCanvas *, arrayofCanvasPtr);
70extern int g_mipmap_max_level;
71extern GLuint g_raster_format;
72extern int g_memCacheLimit;
75extern long g_tex_mem_used;
76extern int g_tile_size;
77extern int g_uncompressed_tile_size;
78extern int g_nCPUCount;
80extern bool b_inCompressAllCharts;
82extern arrayofCanvasPtr g_canvasArray;
85extern ColorScheme global_color_scheme;
87extern bool GetMemoryStatus(
int *mem_total,
int *mem_used);
90bool g_throttle_squish;
96wxString CompressedCachePath(wxString path) {
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]);
120 return g_Platform->GetPrivateDataDir() + separator +
121 _T(
"raster_texture_cache") + separator + sha1;
124int g_mipmap_max_level = 4;
127OCPN_CompressProgressEvent::OCPN_CompressProgressEvent(wxEventType commandType,
int id)
128:wxEvent(id, commandType)
132OCPN_CompressProgressEvent::~OCPN_CompressProgressEvent()
136wxEvent* 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;
146static 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);
171WX_DEFINE_SORTED_ARRAY_INT(
int, MySortedArrayInt);
172int CompareInts(
int n1,
int n2) {
173 double d1 = chart_dist(n1);
174 double d2 = chart_dist(n2);
175 return (
int)(d1 - d2);
178static MySortedArrayInt idx_sorted_by_distance(CompareInts);
186#include <wx/arrimpl.cpp>
191JobTicket::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;
205void 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;
229static 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);
250static 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]);
347int TextureDim(
int level) {
348 int dim = g_GLOptions.m_iTextureDimension;
349 for (
int i = 0; i < level; i++) dim /= 2;
353int 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;
371bool 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;
444static void throttle_func(
void *data) {
445 if (!wxThread::IsMain()) {
447 if (sww->Time() > 1) {
454static wxMutex s_mutexProtectingChartBitRead;
456bool 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; }
607void my_translate(
unsigned int code, _EXCEPTION_POINTERS *ep) {
608 throw SE_Exception();
612OCPN_CompressionThreadEvent::OCPN_CompressionThreadEvent(
613 wxEventType commandType,
int id)
614 : wxEvent(id, commandType) {
618OCPN_CompressionThreadEvent::~OCPN_CompressionThreadEvent() {}
620wxEvent *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;
658CompressionPoolThread::CompressionPoolThread(
JobTicket *ticket,
659 wxEvtHandler *message_target) {
660 m_pMessageTarget = message_target;
666void *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());
711glTextureManager::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),
746glTextureManager::~glTextureManager() {
751#define NBAR_LENGTH 40
756 if (event.type == 1) {
764 wxProgressInfoListNode *tnode = progList.GetFirst();
766 item = tnode->GetData();
767 if (item->file_path == ticket->m_ChartPath) {
771 tnode = tnode->GetNext();
776 tnode = progList.GetFirst();
778 item = tnode->GetData();
779 if (item->file_path.IsEmpty()) {
781 item->file_path = ticket->m_ChartPath;
784 tnode = tnode->GetNext();
791 int bar_length = NBAR_LENGTH;
792 if (m_bcompact) bar_length = 20;
795 wxString
block = wxString::Format(_T(
"%c"), 0x2588);
797 if (event.nstat_max != 0)
798 cutoff = ((
event.nstat + 1) / (
float)
event.nstat_max) * bar_length;
799 for (
int i = 0; i < bar_length; i++) {
809 msgy.Printf(_T(
" [%3d/%3d] "), event.nstat + 1, event.nstat_max);
812 wxFileName fn(ticket->m_ChartPath);
813 msgx += fn.GetFullName();
816 msgx.Printf(_T(
"\n %3d/%3d"), event.nstat + 1, event.nstat_max);
823 tnode = progList.GetFirst();
825 item = tnode->GetData();
826 msg += item->msgx + _T(
"\n");
827 tnode = tnode->GetNext();
830 if (m_skipout) m_progMsg = _T(
"Skipping, please wait...\n\n");
832 if (!m_progDialog->Update(m_jcnt, m_progMsg + msg, &m_skip)) m_skip =
true;
833 if (m_skip) m_skipout =
true;
837 if (ticket->b_isaborted || ticket->b_abort) {
838 for (
int i = 0; i < g_mipmap_max_level + 1; i++) {
839 free(ticket->comp_bits_array[i]);
840 free(ticket->compcomp_bits_array[i]);
845 " Abort job: %08X Jobs running: %d Job count: %lu "
847 ticket->ident, GetRunningJobCount(),
848 (
unsigned long)todo_list.GetCount());
849 }
else if (!ticket->b_inCompressAll) {
853 for (
int i = 0; i < g_mipmap_max_level + 1; i++)
854 ptd->comp_array[i] = ticket->comp_bits_array[i];
856 if (ticket->bpost_zip_compress) {
857 for (
int i = 0; i < g_mipmap_max_level + 1; i++) {
858 ptd->compcomp_array[i] = ticket->compcomp_bits_array[i];
859 ptd->compcomp_size[i] = ticket->compcomp_size_array[i];
866 gFrame->InvalidateAllGL();
867 ptd->compdata_ticks = 10;
872 " Finished job: %08X Jobs running: %d Job count: %lu "
874 ticket->ident, GetRunningJobCount(),
875 (
unsigned long)todo_list.GetCount());
879 if (ticket->b_inCompressAll) {
881 ChartData->OpenChartFromDB(ticket->m_ChartPath, FULL_INIT);
882 ChartData->DeleteCacheChart(pchart);
883 delete ticket->pFact;
886 wxProgressInfoListNode *tnode = progList.GetFirst();
889 if (item->file_path == ticket->m_ChartPath) item->file_path = _T(
"");
890 tnode = tnode->GetNext();
893 if (g_raster_format != GL_COMPRESSED_RGB_FXT1_3DFX) {
894 running_list.DeleteObject(ticket);
901void glTextureManager::OnTimer(wxTimerEvent &event) {
907 if (g_GLOptions.m_bTextureCompression) {
908 for (ChartPathHashTexfactType::iterator itt =
909 m_chart_texfactory_hash.begin();
910 itt != m_chart_texfactory_hash.end(); ++itt) {
912 if (ptf && ptf->OnTimer()) {
919 if((m_ticks % 4) == 0){
922 int mem_total, mem_used;
923 GetMemoryStatus(&mem_total, &mem_used);
927 int compcomp_size = 0;
929 for(ChartPathHashTexfactType::iterator itt = m_chart_texfactory_hash.begin();
930 itt != m_chart_texfactory_hash.end(); ++itt ) {
933 ptf->AccumulateMemStatistics(map_size, comp_size, compcomp_size);
936 int m1 = 1024 * 1024;
938 printf(
"%6d %6ld Map: %10d Comp:%10d CompComp: %10d \n", mem_used/1024, g_tex_mem_used/m1, map_size, comp_size, compcomp_size);
945bool glTextureManager::ScheduleJob(
glTexFactory *client,
const wxRect &rect,
946 int level,
bool b_throttle_thread,
947 bool b_nolimit,
bool b_postZip,
949 wxString chart_path = client->GetChartPath();
951 if (todo_list.GetCount() >= 50) {
953 wxJobListNode *node = todo_list.GetLast();
955 todo_list.DeleteNode(node);
961 wxJobListNode *node = todo_list.GetFirst();
964 if ((ticket->m_ChartPath == chart_path) && (ticket->m_rect == rect)) {
966 todo_list.DeleteNode(node);
967 todo_list.Insert(ticket);
968 ticket->level_min_request = level;
972 node = node->GetNext();
976 wxJobListNode *tnode = running_list.GetFirst();
979 if (ticket->m_rect == rect && ticket->m_ChartPath == chart_path) {
982 tnode = tnode->GetNext();
989 pt->level_min_request = level;
991 pt->ident = (ptd->tex_name << 16) + level;
992 pt->b_throttle = b_throttle_thread;
993 pt->m_ChartPath = chart_path;
995 pt->level0_bits = NULL;
997 pt->b_isaborted =
false;
998 pt->bpost_zip_compress = b_postZip;
999 pt->binplace = b_inplace;
1000 pt->b_inCompressAll = b_inCompressAllCharts;
1012 if (g_raster_format != GL_COMPRESSED_RGB_FXT1_3DFX) {
1013 todo_list.Insert(pt);
1014 if (bthread_debug) {
1016 GetMemoryStatus(0, &mem_used);
1017 printf(
"Adding job: %08X Job Count: %lu mem_used %d\n", pt->ident,
1018 (
unsigned long)todo_list.GetCount(), mem_used);
1024 pt->level0_bits = ptd->map_array[0];
1025 ptd->map_array[0] = NULL;
1031 Nevent.SetTicket(pt);
1032 ProcessEventLocally(Nevent);
1038bool glTextureManager::StartTopJob() {
1039 wxJobListNode *node = todo_list.GetFirst();
1040 if (!node)
return false;
1045 if (GetRunningJobCount() >= wxMax(m_max_jobs - ticket->b_throttle, 1))
1048 todo_list.DeleteNode(node);
1052 if (ptd->comp_array[0]) {
1054 return StartTopJob();
1057 if (ptd->map_array[0]) {
1058 if (ticket->level_min_request == 0) {
1060 ticket->level0_bits = ptd->map_array[0];
1061 ptd->map_array[0] = NULL;
1064 int size = TextureTileSize(0,
false);
1065 ticket->level0_bits = (
unsigned char *)malloc(size);
1066 memcpy(ticket->level0_bits, ptd->map_array[0], size);
1070 running_list.Append(ticket);
1071 DoThreadJob(ticket);
1076bool glTextureManager::DoThreadJob(
JobTicket *pticket) {
1078 printf(
" Starting job: %08X Jobs running: %d Jobs left: %lu\n",
1079 pticket->ident, GetRunningJobCount(),
1080 (
unsigned long)todo_list.GetCount());
1085 pticket->pthread = t;
1092bool glTextureManager::AsJob(wxString
const &chart_path)
const {
1093 if (chart_path.Len()) {
1094 wxJobListNode *tnode = running_list.GetFirst();
1097 if (ticket->m_ChartPath.IsSameAs(chart_path)) {
1100 tnode = tnode->GetNext();
1106void glTextureManager::PurgeJobList(wxString chart_path) {
1107 if (chart_path.Len()) {
1109 wxJobListNode *next, *tnode = todo_list.GetFirst();
1112 next = tnode->GetNext();
1113 if (ticket->m_ChartPath.IsSameAs(chart_path)) {
1115 printf(
"Pool: Purge pending job for purged chart\n");
1116 todo_list.DeleteNode(tnode);
1122 wxJobListNode *node = running_list.GetFirst();
1125 if (ticket->m_ChartPath.IsSameAs(chart_path)) {
1126 ticket->b_abort =
true;
1128 node = node->GetNext();
1132 printf(
"Pool: Purge, todo count: %lu\n",
1133 (
long unsigned)todo_list.GetCount());
1135 wxJobListNode *node = todo_list.GetFirst();
1139 node = node->GetNext();
1143 node = running_list.GetFirst();
1146 ticket->b_abort =
true;
1147 node = node->GetNext();
1152void glTextureManager::ClearJobList() {
1153 wxJobListNode *node = todo_list.GetFirst();
1157 node = node->GetNext();
1162void glTextureManager::ClearAllRasterTextures(
void) {
1164 ChartPathHashTexfactType::iterator itt;
1165 for (itt = m_chart_texfactory_hash.begin();
1166 itt != m_chart_texfactory_hash.end(); ++itt) {
1171 m_chart_texfactory_hash.clear();
1173 if (g_tex_mem_used != 0)
1174 wxLogMessage(_T(
"Texture memory use calculation error\n"));
1177bool glTextureManager::PurgeChartTextures(
ChartBase *pc,
bool b_purge_factory) {
1179 ChartPathHashTexfactType::iterator ittf =
1180 m_chart_texfactory_hash.find(pc->GetHashKey());
1183 if (ittf != m_chart_texfactory_hash.end()) {
1187 if (b_purge_factory) {
1188 m_chart_texfactory_hash.erase(ittf);
1195 m_chart_texfactory_hash.erase(ittf);
1202bool glTextureManager::TextureCrunch(
double factor) {
1203 double hysteresis = 0.90;
1207 (double)(g_GLOptions.m_iTextureMemorySize * 1024 * 1024) * factor;
1208 if (!bGLMemCrunch)
return false;
1210 ChartPathHashTexfactType::iterator it0;
1211 for (it0 = m_chart_texfactory_hash.begin();
1212 it0 != m_chart_texfactory_hash.end(); ++it0) {
1215 wxString chart_full_path = ptf->GetChartPath();
1217 bGLMemCrunch = g_tex_mem_used >
1218 (double)(g_GLOptions.m_iTextureMemorySize * 1024 * 1024) *
1219 factor * hysteresis;
1220 if (!bGLMemCrunch)
break;
1223 for (
unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
1226 if (cc->GetVP().b_quilt)
1228 if (cc->m_pQuilt && cc->m_pQuilt->IsComposed() &&
1229 !cc->m_pQuilt->IsChartInQuilt(chart_full_path)) {
1230 ptf->DeleteSomeTextures(g_GLOptions.m_iTextureMemorySize * 1024 *
1231 1024 * factor * hysteresis);
1235 if (!cc->m_singleChart->GetFullPath().IsSameAs(chart_full_path)) {
1236 ptf->DeleteSomeTextures(g_GLOptions.m_iTextureMemorySize * 1024 *
1237 1024 * factor * hysteresis);
1247#define MAX_CACHE_FACTORY 50
1248bool glTextureManager::FactoryCrunch(
double factor) {
1249 if (m_chart_texfactory_hash.size() == 0) {
1255 GetMemoryStatus(0, &mem_used);
1256 double hysteresis = 0.90;
1257 ChartPathHashTexfactType::iterator it0;
1261 ((mem_used > (double)(g_memCacheLimit)*factor * hysteresis &&
1262 mem_used > (double)(m_prevMemUsed)*factor * hysteresis) ||
1263 (m_chart_texfactory_hash.size() > MAX_CACHE_FACTORY)));
1265 if (!bMemCrunch)
return false;
1269 int lru_oldest = 2147483647;
1272 for (it0 = m_chart_texfactory_hash.begin();
1273 it0 != m_chart_texfactory_hash.end(); ++it0) {
1276 wxString chart_full_path = ptf->GetChartPath();
1282 for (
unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
1285 if (cc->GetVP().b_quilt)
1287 if (cc->m_pQuilt && cc->m_pQuilt->IsComposed() &&
1288 !cc->m_pQuilt->IsChartInQuilt(chart_full_path)) {
1289 int lru = ptf->GetLRUTime();
1290 if (lru < lru_oldest && !ptf->BackgroundCompressionAsJob()) {
1296 if (!cc->m_singleChart->GetFullPath().IsSameAs(chart_full_path)) {
1297 int lru = ptf->GetLRUTime();
1298 if (lru < lru_oldest && !ptf->BackgroundCompressionAsJob()) {
1309 if (!ptf_oldest)
return false;
1311 ptf_oldest->FreeSome(g_memCacheLimit * factor * hysteresis);
1313 GetMemoryStatus(0, &mem_used);
1315 bMemCrunch = (g_memCacheLimit &&
1316 ((mem_used > (double)(g_memCacheLimit)*factor * hysteresis &&
1317 mem_used > (double)(m_prevMemUsed)*factor * hysteresis) ||
1318 (m_chart_texfactory_hash.size() > MAX_CACHE_FACTORY)));
1320 if (!bMemCrunch)
return false;
1324 m_chart_texfactory_hash.erase(
1325 ptf_oldest->GetHashKey());
1332void glTextureManager::BuildCompressedCache() {
1333 idx_sorted_by_distance.Clear();
1341 for (
int i = 0; i < ChartData->GetChartTableEntries(); i++) {
1344 ChartTypeEnum chart_type = (ChartTypeEnum)cte.GetChartType();
1345 if (chart_type == CHART_TYPE_PLUGIN) {
1346 if (cte.GetChartFamily() != CHART_FAMILY_RASTER)
continue;
1348 if (chart_type != CHART_TYPE_KAP)
continue;
1351 wxString CompressedCacheFilePath =
1352 CompressedCachePath(ChartData->GetDBChartFileName(i));
1353 wxFileName fn(CompressedCacheFilePath);
1357 idx_sorted_by_distance.Add(i);
1362 if (count == 0)
return;
1365 wxString::Format(_T(
"BuildCompressedCache() count = %d"), count));
1369 if (GetRunningJobCount()) {
1370 wxLogMessage(_T(
"Starting compressor pool drain"));
1371 wxDateTime now = wxDateTime::Now();
1372 time_t stall = now.GetTicks();
1373#define THREAD_WAIT_SECONDS 5
1374 time_t end = stall + THREAD_WAIT_SECONDS;
1377 while (stall < end) {
1378 wxDateTime later = wxDateTime::Now();
1379 stall = later.GetTicks();
1382 msg.Printf(_T(
"Time: %d Job Count: %d"), n_comploop,
1383 GetRunningJobCount());
1385 if (!GetRunningJobCount())
break;
1391 fmsg.Printf(_T(
"Finished compressor pool drain..Time: %d Job Count: %d"),
1392 n_comploop, GetRunningJobCount());
1395 ClearAllRasterTextures();
1396 b_inCompressAllCharts =
true;
1402 ArrayOfCompressTargets ct_array;
1403 for (
unsigned int j = 0; j < idx_sorted_by_distance.GetCount(); j++) {
1404 int i = idx_sorted_by_distance[j];
1407 double distance = chart_dist(i);
1409 wxString filename = cte.GetFullSystemPath();
1412 pct->distance = distance;
1413 pct->chart_path = filename;
1419 long style = wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME |
1420 wxPD_REMAINING_TIME | wxPD_CAN_ABORT;
1430 _T("longgggggggggggggggggggggggggggggggggggggggggggg\ngggggggggggggggggg")
1431 _T("gggggggggggggggggggggggggg top line ");
1434 for (
int i = 0; i < m_max_jobs + 1; i++)
1437 m_progDialog =
new wxGenericProgressDialog();
1439 wxFont *qFont = GetOCPNScaledFont(_(
"Dialog"));
1440 int fontSize = qFont->GetPointSize();
1442 wxSize csz = gFrame->GetClientSize();
1443 if (csz.x < 500 || csz.y < 500)
1444 sFont = FontMgr::Get().FindOrCreateFont(
1445 10, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
1447 sFont = FontMgr::Get().FindOrCreateFont(fontSize, wxFONTFAMILY_TELETYPE,
1449 wxFONTWEIGHT_NORMAL);
1451 m_progDialog->SetFont(*sFont);
1456 sdc.GetTextExtent(_T(
"[WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW]"), &width, &height,
1458 if (width > (csz.x / 2)) m_bcompact =
true;
1460 m_progDialog->Create(_(
"OpenCPN Compressed Cache Update"), msg0, count + 1,
1464 m_progDialog->Hide();
1465 wxSize sz = m_progDialog->GetSize();
1466 sz.x = csz.x * 9 / 10;
1467 m_progDialog->SetSize(sz);
1469 m_progDialog->Layout();
1470 wxSize sza = m_progDialog->GetSize();
1472 m_progDialog->Centre();
1473 m_progDialog->Show();
1474 m_progDialog->Raise();
1480 for (m_jcnt = 0; m_jcnt < ct_array.GetCount(); m_jcnt++) {
1481 wxString filename = ct_array[m_jcnt].chart_path;
1482 wxString CompressedCacheFilePath = CompressedCachePath(filename);
1483 double distance = ct_array[m_jcnt].distance;
1485 ChartBase *pchart = ChartData->OpenChartFromDBAndLock(filename, FULL_INIT);
1490 g_glTextureManager->PurgeChartTextures(pchart,
true);
1493 if (pBSBChart == 0)
continue;
1497 m_progMsg.Printf(_(
"Distance from Ownship: %4.0f NMi"), distance);
1499 m_progMsg.Prepend(_T(
"Preparing RNC Cache...\n"));
1502 g_glTextureManager->PurgeJobList();
1503 ChartData->DeleteCacheChart(pchart);
1508 int size_X = pBSBChart->GetSize_X();
1509 int size_Y = pBSBChart->GetSize_Y();
1511 int tex_dim = g_GLOptions.m_iTextureDimension;
1513 int nx_tex = ceil((
float)size_X / tex_dim);
1514 int ny_tex = ceil((
float)size_Y / tex_dim);
1518 rect.width = tex_dim;
1519 rect.height = tex_dim;
1520 for (
int y = 0; y < ny_tex; y++) {
1522 for (
int x = 0; x < nx_tex; x++) {
1523 for (
int level = 0; level < g_mipmap_max_level + 1; level++) {
1524 if (!tex_fact->IsLevelInCache(level, rect, global_color_scheme)) {
1528 rect.x += rect.width;
1530 rect.y += rect.height;
1534 ChartData->DeleteCacheChart(pchart);
1540 if (!m_progDialog->Update(m_jcnt)) {
1551 ScheduleJob(tex_fact, wxRect(), 0,
false,
true,
true,
false);
1554 int cnt = GetJobCount() - GetRunningJobCount();
1560 g_glTextureManager->PurgeJobList();
1561 ChartData->DeleteCacheChart(pchart);
1567 while (GetRunningJobCount()) {
1572 b_inCompressAllCharts =
false;
1575 delete m_progDialog;
1576 m_progDialog =
nullptr;
Runtime representation of a plugin block.