29#include <wx/progdlg.h>
33#if defined(__ANDROID__)
35#elif defined(__WXQT__) || defined(__WXGTK__)
39#include <wx/datetime.h>
41#include <wx/filename.h>
45#include <wx/progdlg.h>
46#include <wx/stopwatch.h>
51#include <wx/listimpl.cpp>
52#include <wx/arrimpl.cpp>
54#include "mipmap/mipmap.h"
80#ifndef GL_ETC1_RGB8_OES
81#define GL_ETC1_RGB8_OES 0x8D64
84using JobList = std::list<JobTicket *>;
88extern arrayofCanvasPtr g_canvasArray;
92static bool bthread_debug;
94wxString CompressedCachePath(wxString path) {
96 int colon = path.find(
':', 0);
97 if (colon != wxNOT_FOUND) path.Remove(colon, 1);
101 wxChar separator = wxFileName::GetPathSeparator();
102 for (
unsigned int pos = 0; pos < path.size(); pos = path.find(separator, pos))
103 path.replace(pos, 1,
"!");
107 wxCharBuffer buf = path.ToUTF8();
108 unsigned char sha1_out[20];
109 sha1((
unsigned char *)buf.data(), strlen(buf.data()), sha1_out);
112 for (
unsigned int i = 0; i < 20; i++) {
114 s.Printf(
"%02X", sha1_out[i]);
123OCPN_CompressProgressEvent::OCPN_CompressProgressEvent(wxEventType commandType,
int id)
124:wxEvent(id, commandType)
128OCPN_CompressProgressEvent::~OCPN_CompressProgressEvent()
132wxEvent* OCPN_CompressProgressEvent::Clone()
const
134 OCPN_CompressProgressEvent *newevent=
new OCPN_CompressProgressEvent(*
this);
135 newevent->m_string=this->m_string;
136 newevent->count=this->count;
137 newevent->thread=this->thread;
142static double chart_dist(
int index) {
148 if (cte.GetBBox().Contains(
gLat,
gLon))
153 clon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
154 d = DistGreatCircle(cte.GetLatMax(), clon,
gLat,
gLon);
155 t = DistGreatCircle(cte.GetLatMin(), clon,
gLat,
gLon);
158 clat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
159 t = DistGreatCircle(clat, cte.GetLonMin(),
gLat,
gLon);
161 t = DistGreatCircle(clat, cte.GetLonMax(),
gLat,
gLon);
167WX_DEFINE_SORTED_ARRAY_INT(
int, MySortedArrayInt);
168int CompareInts(
int n1,
int n2) {
169 double d1 = chart_dist(n1);
170 double d2 = chart_dist(n2);
171 return (
int)(d1 - d2);
174static MySortedArrayInt idx_sorted_by_distance(CompareInts);
185JobTicket::JobTicket() {
186 for (
int i = 0; i < 10; i++) {
187 compcomp_size_array[i] = 0;
188 comp_bits_array[i] = NULL;
189 compcomp_bits_array[i] = NULL;
199void FlattenColorsForCompression(
unsigned char *data,
int dim,
bool swap_colors=
true)
204 for(
int i = 0; i<dim*dim; i++) {
206 unsigned char t = data[off + 0];
207 data[off + 0] = data[off + 2] & 0xfc;
208 data[off + 1] &= 0xf8;
209 data[off + 2] = t & 0xfc;
213 for(
int i = 0; i<dim*dim; i++) {
215 data[off + 0] &= 0xfc;
216 data[off + 1] &= 0xf8;
217 data[off + 2] &= 0xfc;
223static void CompressDataETC(
const unsigned char *data,
int dim,
int size,
224 unsigned char *tex_data,
volatile bool &b_abort) {
225 wxASSERT(dim * dim == 2 * size || (dim < 4 && size == 8));
226 uint64_t *tex_data64 = (uint64_t *)tex_data;
228 int mbrow = wxMin(4, dim), mbcol = wxMin(4, dim);
229 uint8_t
block[48] = {};
230 for (
int row = 0; row < dim; row += 4) {
231 for (
int col = 0; col < dim; col += 4) {
232 for (
int brow = 0; brow < mbrow; brow++)
233 for (
int bcol = 0; bcol < mbcol; bcol++)
234 memcpy(
block + (bcol * 4 + brow) * 3,
235 data + ((row + brow) * dim + col + bcol) * 3, 3);
237 extern uint64_t ProcessRGB(
const uint8_t *src);
238 *tex_data64++ = ProcessRGB(
block);
244static bool CompressUsingGPU(
const unsigned char *data,
int dim,
int size,
245 unsigned char *tex_data,
int level,
bool inplace) {
246#ifndef USE_ANDROID_GLES2
250 glGenTextures(1, &comp_tex);
251 glBindTexture(GL_TEXTURE_2D, comp_tex);
252 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
253 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
257 glTexImage2D(GL_TEXTURE_2D, level,
g_raster_format, dim, dim, 0, GL_RGB,
258 GL_UNSIGNED_BYTE, data);
261 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_ARB,
264 if (compressed == GL_TRUE) {
266 GLint compressedSize;
267 glGetTexLevelParameteriv(GL_TEXTURE_2D, level,
268 GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &compressedSize);
270 if (compressedSize != size)
return false;
273 glGetCompressedTexImage(GL_TEXTURE_2D, level, tex_data);
276 if (!inplace) glDeleteTextures(1, &comp_tex);
285 wxString &chart_path) {
288 ptd->map_array[0] = 0;
293 (
unsigned char *)calloc(ncrect.width * ncrect.height * 4, 1);
301 unsigned char *t_buf =
302 (
unsigned char *)malloc(ncrect.width * ncrect.height * 4);
303 pBSBChart->GetChartBits(ncrect, t_buf, 1);
306 ptd->map_array[0] = t_buf;
309 (
unsigned char *)calloc(ncrect.width * ncrect.height * 4, 1);
315 wxString chart_path,
int level) {
318 if (ptd->map_array[level])
return;
322 for (first_level = level; first_level; first_level--)
323 if (ptd->map_array[first_level - 1])
break;
327 GetLevel0Map(ptd, rect, chart_path);
331 int dim = g_GLOptions.m_iTextureDimension;
332 for (
int i = 0; i <= level; i++) {
333 if (i >= first_level) {
334 ptd->map_array[i] = (
unsigned char *)malloc(dim * dim * 3);
335 MipMap_24(2 * dim, 2 * dim, ptd->map_array[i - 1], ptd->map_array[i]);
341int TextureDim(
int level) {
342 int dim = g_GLOptions.m_iTextureDimension;
343 for (
int i = 0; i < level; i++) dim /= 2;
347int TextureTileSize(
int level,
bool compressed) {
353 for (
int i = 0; i < level; i++) {
355 if (size < 8) size = 8;
358 size = g_uncompressed_tile_size;
359 for (
int i = 0; i < level; i++) size /= 4;
365bool JobTicket::DoJob() {
366 if (!m_rect.IsEmpty())
return DoJob(m_rect);
370 if (!pchart)
return false;
373 if (!pBSBChart)
return false;
375 int size_X = pBSBChart->GetSize_X();
376 int size_Y = pBSBChart->GetSize_Y();
378 int dim = g_GLOptions.m_iTextureDimension;
380 int nx_tex = ceil((
float)size_X / dim);
381 int ny_tex = ceil((
float)size_Y / dim);
387 for (
int y = 0; y < ny_tex; y++) {
388 if (pthread && pthread->m_pMessageTarget) {
391 Nevent.nstat_max = ny_tex;
393 Nevent.SetTicket(
this);
394 pthread->m_pMessageTarget->AddPendingEvent(Nevent);
398 for (
int x = 0; x < nx_tex; x++) {
399 if (!DoJob(rect))
return false;
401 pFact->UpdateCacheAllLevels(rect, global_color_scheme,
402 compcomp_bits_array, compcomp_size_array);
405 free(comp_bits_array[i]), comp_bits_array[i] = 0;
406 free(compcomp_bits_array[i]), compcomp_bits_array[i] = 0;
409 rect.x += rect.width;
411 rect.y += rect.height;
423 void Start() { clock_gettime(CLOCK_REALTIME, &tp); }
427 clock_gettime(CLOCK_REALTIME, &tp_end);
428 return (tp_end.tv_sec - tp.tv_sec) * 1.e3 + (tp_end.tv_nsec - tp.tv_nsec) / 1.e6;
438static void throttle_func(
void *data) {
439 if (!wxThread::IsMain()) {
441 if (sww->Time() > 1) {
448static wxMutex s_mutexProtectingChartBitRead;
450bool JobTicket::DoJob(
const wxRect &rect) {
451 unsigned char *bit_array[10];
452 for (
int i = 0; i < 10; i++) bit_array[i] = 0;
456 bit_array[0] = level0_bits;
467 wxMutexLocker lock(s_mutexProtectingChartBitRead);
469 index =
ChartData->FinddbIndex(m_ChartPath);
470 pchart =
ChartData->OpenChartFromDBAndLock(index, FULL_INIT);
472 if (pchart &&
ChartData->IsChartLocked(index)) {
476 (
unsigned char *)malloc(ncrect.width * ncrect.height * 4);
477 pBSBChart->GetChartBits(ncrect, bit_array[0], 1);
487 if (!bit_array[0])
return false;
490 dim = g_GLOptions.m_iTextureDimension;
493 size_t nmalloc = wxMax(dim * dim * 3, 4 * 4 * 3);
494 bit_array[i] = (
unsigned char *)malloc(nmalloc);
495 MipMap_24(2 * dim, 2 * dim, bit_array[i - 1], bit_array[i]);
499 int texture_level = 0;
501 int dim = TextureDim(level);
502 int size = TextureTileSize(level,
true);
503 unsigned char *tex_data = (
unsigned char *)malloc(size);
506 int flags = squish::kDxt1 | squish::kColourRangeFit;
508 if (g_GLOptions.m_bTextureCompressionCaching) {
512 flags = squish::kDxt1 | squish::kColourClusterFit;
516 squish::CompressImageRGBpow2_Flatten_Throttle_Abort(
517 bit_array[level], dim, dim, tex_data, flags,
true,
518 b_throttle ? throttle_func : 0, &sww, b_abort);
521 CompressDataETC(bit_array[level], dim, size, tex_data, b_abort);
523 if (!CompressUsingGPU(bit_array[level], dim, size, tex_data,
524 texture_level, binplace)) {
529 if (binplace) g_tex_mem_used += size;
533 comp_bits_array[level] = tex_data;
550 if (b_throttle) wxThread::Sleep(1);
552 if (b_abort)
return false;
554 if (bpost_zip_compress) {
555 int max_compressed_size = LZ4_COMPRESSBOUND(g_tile_size);
558 if (b_abort)
return false;
560 unsigned char *compressed_data =
561 (
unsigned char *)malloc(max_compressed_size);
562 int csize = TextureTileSize(level,
true);
564 char *src = (
char *)comp_bits_array[level];
565 int compressed_size =
566 LZ4_compressHC2(src, (
char *)compressed_data, csize, 4);
571 (
unsigned char *)realloc(compressed_data, compressed_size);
572 compcomp_bits_array[level] = compressed_data;
573 compcomp_size_array[level] = compressed_size;
596 SE_Exception(
unsigned int n) : nSE(n) {}
598 unsigned int getSeNumber() {
return nSE; }
601void my_translate(
unsigned int code, _EXCEPTION_POINTERS *ep) {
602 throw SE_Exception();
606OCPN_CompressionThreadEvent::OCPN_CompressionThreadEvent(
607 wxEventType commandType,
int id)
608 : wxEvent(id, commandType) {
612OCPN_CompressionThreadEvent::~OCPN_CompressionThreadEvent() {}
614wxEvent *OCPN_CompressionThreadEvent::Clone()
const {
617 newevent->m_ticket = this->m_ticket;
618 newevent->type = this->type;
619 newevent->nstat = this->nstat;
620 newevent->nstat_max = this->nstat_max;
652CompressionPoolThread::CompressionPoolThread(
JobTicket *ticket,
653 wxEvtHandler *message_target) {
654 m_pMessageTarget = message_target;
660void *CompressionPoolThread::Entry() {
662 _set_se_translator(my_translate);
672 SetPriority(WXTHREAD_MIN_PRIORITY);
674 if (!m_ticket->DoJob()) m_ticket->b_isaborted =
true;
676 if (m_pMessageTarget) {
678 Nevent.SetTicket(m_ticket);
680 m_pMessageTarget->QueueEvent(Nevent.Clone());
688 catch (SE_Exception e) {
689 if (m_pMessageTarget) {
691 m_ticket->b_isaborted =
true;
692 Nevent.SetTicket(m_ticket);
694 m_pMessageTarget->QueueEvent(Nevent.Clone());
705glTextureManager::glTextureManager() {
708 int nCPU = wxMax(1, wxThread::GetCPUCount());
709 if (g_nCPUCount > 0) nCPU = g_nCPUCount;
715 m_max_jobs = wxMax(nCPU, 1);
718 if (bthread_debug) printf(
" nCPU: %d m_max_jobs :%d\n", nCPU, m_max_jobs);
722 for (
int i = 0; i < m_max_jobs; i++) progList.push_back(
new ProgressInfoItem);
727 wxEVT_OCPN_COMPRESSIONTHREAD,
728 (wxObjectEventFunction)(wxEventFunction)&glTextureManager::OnEvtThread);
735 m_timer.Connect(wxEVT_TIMER, wxTimerEventHandler(glTextureManager::OnTimer),
740glTextureManager::~glTextureManager() {
743 for (
int i = 0; i < m_max_jobs; i++) {
744 auto it = progList.begin();
749 for (
auto hash : m_chart_texfactory_hash) {
752 m_chart_texfactory_hash.clear();
755#define NBAR_LENGTH 40
760 if (event.type == 1) {
768 for (
auto tnode = progList.begin(); tnode != progList.end(); tnode++) {
770 if (item->file_path == ticket->m_ChartPath) {
778 for (
auto tnode = progList.begin(); tnode != progList.end(); tnode++) {
780 if (item->file_path.IsEmpty()) {
782 item->file_path = ticket->m_ChartPath;
791 int bar_length = NBAR_LENGTH;
792 if (m_bcompact) bar_length = 20;
795 wxString
block = wxString::Format(
"%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(
" [%3d/%3d] ", event.nstat + 1, event.nstat_max);
812 wxFileName fn(ticket->m_ChartPath);
813 msgx += fn.GetFullName();
816 msgx.Printf(
"\n %3d/%3d", event.nstat + 1, event.nstat_max);
823 for (
auto tnode = progList.begin(); tnode != progList.end(); tnode++) {
825 msg += item->msgx +
"\n";
828 if (m_skipout) m_progMsg =
"Skipping, please wait...\n\n";
830 if (!m_progDialog->Update(m_jcnt, m_progMsg + msg, &m_skip)) m_skip =
true;
831 if (m_skip) m_skipout =
true;
835 if (ticket->b_isaborted || ticket->b_abort) {
837 free(ticket->comp_bits_array[i]);
838 free(ticket->compcomp_bits_array[i]);
843 " Abort job: %08X Jobs running: %d Job count: %lu "
845 ticket->ident, GetRunningJobCount(), (
unsigned long)todo_list.size());
846 }
else if (!ticket->b_inCompressAll) {
851 ptd->comp_array[i] = ticket->comp_bits_array[i];
853 if (ticket->bpost_zip_compress) {
855 ptd->compcomp_array[i] = ticket->compcomp_bits_array[i];
856 ptd->compcomp_size[i] = ticket->compcomp_size_array[i];
863 gFrame->InvalidateAllGL();
864 ptd->compdata_ticks = 10;
869 " Finished job: %08X Jobs running: %d Job count: %lu "
871 ticket->ident, GetRunningJobCount(), (
unsigned long)todo_list.size());
875 if (ticket->b_inCompressAll) {
877 ChartData->OpenChartFromDB(ticket->m_ChartPath, FULL_INIT);
879 delete ticket->pFact;
882 for (
auto tnode = progList.begin(); tnode != progList.end(); ++tnode) {
884 if (item->file_path == ticket->m_ChartPath) item->file_path =
"";
888 auto found = std::find(running_list.begin(), running_list.end(), ticket);
889 if (found != running_list.end()) running_list.erase(found);
896void glTextureManager::OnTimer(wxTimerEvent &event) {
902 if (g_GLOptions.m_bTextureCompression) {
903 for (ChartPathHashTexfactType::iterator itt =
904 m_chart_texfactory_hash.begin();
905 itt != m_chart_texfactory_hash.end(); ++itt) {
907 if (ptf && ptf->OnTimer()) {
914 if((m_ticks % 4) == 0){
917 int mem_total, mem_used;
922 int compcomp_size = 0;
924 for(ChartPathHashTexfactType::iterator itt = m_chart_texfactory_hash.begin();
925 itt != m_chart_texfactory_hash.end(); ++itt ) {
928 ptf->AccumulateMemStatistics(map_size, comp_size, compcomp_size);
931 int m1 = 1024 * 1024;
933 printf(
"%6d %6ld Map: %10d Comp:%10d CompComp: %10d \n", mem_used/1024, g_tex_mem_used/m1, map_size, comp_size, compcomp_size);
940bool glTextureManager::ScheduleJob(
glTexFactory *client,
const wxRect &rect,
941 int level,
bool b_throttle_thread,
942 bool b_nolimit,
bool b_postZip,
944 wxString chart_path = client->GetChartPath();
946 if (todo_list.size() >= 50) {
948 auto node = todo_list.rbegin();
950 auto found = std::find(todo_list.begin(), todo_list.end(), ticket);
951 todo_list.erase(found);
957 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
959 if ((ticket->m_ChartPath == chart_path) && (ticket->m_rect == rect)) {
961 auto found = std::find(todo_list.begin(), todo_list.end(), ticket);
962 if (found != todo_list.end()) todo_list.erase(found);
963 todo_list.insert(todo_list.begin(), ticket);
964 ticket->level_min_request = level;
970 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
972 if (ticket->m_rect == rect && ticket->m_ChartPath == chart_path) {
981 pt->level_min_request = level;
983 pt->ident = (ptd->tex_name << 16) + level;
984 pt->b_throttle = b_throttle_thread;
985 pt->m_ChartPath = chart_path;
987 pt->level0_bits = NULL;
989 pt->b_isaborted =
false;
990 pt->bpost_zip_compress = b_postZip;
991 pt->binplace = b_inplace;
1005 todo_list.insert(todo_list.begin(), pt);
1006 if (bthread_debug) {
1009 printf(
"Adding job: %08X Job Count: %lu mem_used %d\n", pt->ident,
1010 (
unsigned long)todo_list.size(), mem_used);
1016 pt->level0_bits = ptd->map_array[0];
1017 ptd->map_array[0] = NULL;
1023 Nevent.SetTicket(pt);
1024 ProcessEventLocally(Nevent);
1030bool glTextureManager::StartTopJob() {
1031 auto node = todo_list.begin();
1032 if (node == todo_list.end())
return false;
1037 if (GetRunningJobCount() >= wxMax(m_max_jobs - ticket->b_throttle, 1))
1039 auto found = std::find(todo_list.begin(), todo_list.end(), ticket);
1040 if (found != todo_list.end()) todo_list.erase(found);
1044 if (ptd->comp_array[0]) {
1046 return StartTopJob();
1049 if (ptd->map_array[0]) {
1050 if (ticket->level_min_request == 0) {
1052 ticket->level0_bits = ptd->map_array[0];
1053 ptd->map_array[0] = NULL;
1056 int size = TextureTileSize(0,
false);
1057 ticket->level0_bits = (
unsigned char *)malloc(size);
1058 memcpy(ticket->level0_bits, ptd->map_array[0], size);
1062 running_list.push_back(ticket);
1063 DoThreadJob(ticket);
1068bool glTextureManager::DoThreadJob(
JobTicket *pticket) {
1070 printf(
" Starting job: %08X Jobs running: %d Jobs left: %lu\n",
1071 pticket->ident, GetRunningJobCount(),
1072 (
unsigned long)todo_list.size());
1077 pticket->pthread = t;
1084bool glTextureManager::AsJob(wxString
const &chart_path)
const {
1085 if (chart_path.Len()) {
1086 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
1088 if (ticket->m_ChartPath.IsSameAs(chart_path)) {
1096void glTextureManager::PurgeJobList(wxString chart_path) {
1097 if (chart_path.Len()) {
1099 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
1101 if (ticket->m_ChartPath.IsSameAs(chart_path)) {
1103 printf(
"Pool: Purge pending job for purged chart\n");
1104 auto found = std::find(todo_list.begin(), todo_list.end(), ticket);
1105 if (found != todo_list.end()) todo_list.erase(found);
1110 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
1112 if (ticket->m_ChartPath.IsSameAs(chart_path)) {
1113 ticket->b_abort =
true;
1118 printf(
"Pool: Purge, todo count: %lu\n",
1119 (
long unsigned)todo_list.size());
1121 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
1127 for (
auto node = running_list.begin(); node != running_list.end(); ++node) {
1129 ticket->b_abort =
true;
1134void glTextureManager::ClearJobList() {
1135 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
1142void glTextureManager::ClearAllRasterTextures() {
1144 ChartPathHashTexfactType::iterator itt;
1145 for (itt = m_chart_texfactory_hash.begin();
1146 itt != m_chart_texfactory_hash.end(); ++itt) {
1151 m_chart_texfactory_hash.clear();
1153 if (g_tex_mem_used != 0)
1154 wxLogMessage(
"Texture memory use calculation error\n");
1157bool glTextureManager::PurgeChartTextures(
ChartBase *pc,
bool b_purge_factory) {
1159 ChartPathHashTexfactType::iterator ittf =
1160 m_chart_texfactory_hash.find(pc->GetHashKey());
1163 if (ittf != m_chart_texfactory_hash.end()) {
1167 if (b_purge_factory) {
1168 m_chart_texfactory_hash.erase(ittf);
1175 m_chart_texfactory_hash.erase(ittf);
1182bool glTextureManager::TextureCrunch(
double factor) {
1183 double hysteresis = 0.90;
1187 (double)(g_GLOptions.m_iTextureMemorySize * 1024 * 1024) * factor;
1188 if (!bGLMemCrunch)
return false;
1190 ChartPathHashTexfactType::iterator it0;
1191 for (it0 = m_chart_texfactory_hash.begin();
1192 it0 != m_chart_texfactory_hash.end(); ++it0) {
1195 wxString chart_full_path = ptf->GetChartPath();
1197 bGLMemCrunch = g_tex_mem_used >
1198 (double)(g_GLOptions.m_iTextureMemorySize * 1024 * 1024) *
1199 factor * hysteresis;
1200 if (!bGLMemCrunch)
break;
1203 for (
unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
1206 if (cc->GetVP().b_quilt)
1208 if (cc->m_pQuilt && cc->m_pQuilt->IsComposed() &&
1209 !cc->m_pQuilt->IsChartInQuilt(chart_full_path)) {
1210 ptf->DeleteSomeTextures(g_GLOptions.m_iTextureMemorySize * 1024 *
1211 1024 * factor * hysteresis);
1215 if (!cc->m_singleChart->GetFullPath().IsSameAs(chart_full_path)) {
1216 ptf->DeleteSomeTextures(g_GLOptions.m_iTextureMemorySize * 1024 *
1217 1024 * factor * hysteresis);
1227#define MAX_CACHE_FACTORY 50
1228bool glTextureManager::FactoryCrunch(
double factor) {
1229 if (m_chart_texfactory_hash.size() == 0) {
1236 double hysteresis = 0.90;
1237 ChartPathHashTexfactType::iterator it0;
1241 ((mem_used > (double)(g_memCacheLimit)*factor * hysteresis &&
1242 mem_used > (double)(m_prevMemUsed)*factor * hysteresis) ||
1243 (m_chart_texfactory_hash.size() > MAX_CACHE_FACTORY)));
1245 if (!bMemCrunch)
return false;
1249 int lru_oldest = 2147483647;
1252 for (it0 = m_chart_texfactory_hash.begin();
1253 it0 != m_chart_texfactory_hash.end(); ++it0) {
1256 wxString chart_full_path = ptf->GetChartPath();
1262 for (
unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
1265 if (cc->GetVP().b_quilt)
1267 if (cc->m_pQuilt && cc->m_pQuilt->IsComposed() &&
1268 !cc->m_pQuilt->IsChartInQuilt(chart_full_path)) {
1269 int lru = ptf->GetLRUTime();
1270 if (lru < lru_oldest && !ptf->BackgroundCompressionAsJob()) {
1276 if (!cc->m_singleChart->GetFullPath().IsSameAs(chart_full_path)) {
1277 int lru = ptf->GetLRUTime();
1278 if (lru < lru_oldest && !ptf->BackgroundCompressionAsJob()) {
1289 if (!ptf_oldest)
return false;
1291 ptf_oldest->FreeSome(g_memCacheLimit * factor * hysteresis);
1295 bMemCrunch = (g_memCacheLimit &&
1296 ((mem_used > (double)(g_memCacheLimit)*factor * hysteresis &&
1297 mem_used > (double)(m_prevMemUsed)*factor * hysteresis) ||
1298 (m_chart_texfactory_hash.size() > MAX_CACHE_FACTORY)));
1300 if (!bMemCrunch)
return false;
1304 m_chart_texfactory_hash.erase(
1305 ptf_oldest->GetHashKey());
1312void glTextureManager::BuildCompressedCache() {
1313 idx_sorted_by_distance.Clear();
1321 for (
int i = 0; i <
ChartData->GetChartTableEntries(); i++) {
1324 ChartTypeEnum chart_type = (ChartTypeEnum)cte.GetChartType();
1325 if (chart_type == CHART_TYPE_PLUGIN) {
1326 if (cte.GetChartFamily() != CHART_FAMILY_RASTER)
continue;
1328 if (chart_type != CHART_TYPE_KAP)
continue;
1331 wxString CompressedCacheFilePath =
1332 CompressedCachePath(
ChartData->GetDBChartFileName(i));
1333 wxFileName fn(CompressedCacheFilePath);
1337 idx_sorted_by_distance.Add(i);
1342 if (count == 0)
return;
1344 wxLogMessage(wxString::Format(
"BuildCompressedCache() count = %d", count));
1348 if (GetRunningJobCount()) {
1349 wxLogMessage(
"Starting compressor pool drain");
1350 wxDateTime now = wxDateTime::Now();
1351 time_t stall = now.GetTicks();
1352#define THREAD_WAIT_SECONDS 5
1353 time_t end = stall + THREAD_WAIT_SECONDS;
1356 while (stall < end) {
1357 wxDateTime later = wxDateTime::Now();
1358 stall = later.GetTicks();
1361 msg.Printf(
"Time: %d Job Count: %d", n_comploop, GetRunningJobCount());
1363 if (!GetRunningJobCount())
break;
1369 fmsg.Printf(
"Finished compressor pool drain..Time: %d Job Count: %d",
1370 n_comploop, GetRunningJobCount());
1373 ClearAllRasterTextures();
1380 ArrayOfCompressTargets ct_array;
1381 for (
unsigned int j = 0; j < idx_sorted_by_distance.GetCount(); j++) {
1382 int i = idx_sorted_by_distance[j];
1385 double distance = chart_dist(i);
1387 wxString filename = cte.GetFullSystemPath();
1390 pct->distance = distance;
1391 pct->chart_path = filename;
1397 long style = wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME |
1398 wxPD_REMAINING_TIME | wxPD_CAN_ABORT;
1408 "longgggggggggggggggggggggggggggggggggggggggggggg\ngggggggggggggggggg"
1409 "gggggggggggggggggggggggggg top line ";
1412 for (
int i = 0; i < m_max_jobs + 1; i++)
1415 m_progDialog =
new wxGenericProgressDialog();
1418 int fontSize = qFont->GetPointSize();
1420 wxSize csz = gFrame->GetClientSize();
1421 if (csz.x < 500 || csz.y < 500)
1423 10, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
1427 wxFONTWEIGHT_NORMAL);
1429 m_progDialog->SetFont(*sFont);
1434 sdc.GetTextExtent(
"[WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW]", &width, &height, NULL,
1436 if (width > (csz.x / 2)) m_bcompact =
true;
1438 m_progDialog->Create(_(
"OpenCPN Compressed Cache Update"), msg0, count + 1,
1442 m_progDialog->Hide();
1443 wxSize sz = m_progDialog->GetSize();
1444 sz.x = csz.x * 9 / 10;
1445 m_progDialog->SetSize(sz);
1447 m_progDialog->Layout();
1448 wxSize sza = m_progDialog->GetSize();
1450 m_progDialog->Centre();
1451 m_progDialog->Show();
1452 m_progDialog->Raise();
1458 for (m_jcnt = 0; m_jcnt < ct_array.GetCount(); m_jcnt++) {
1459 wxString filename = ct_array[m_jcnt].chart_path;
1460 wxString CompressedCacheFilePath = CompressedCachePath(filename);
1461 double distance = ct_array[m_jcnt].distance;
1471 if (pBSBChart == 0)
continue;
1475 m_progMsg.Printf(_(
"Distance from Ownship: %4.0f NMi"), distance);
1477 m_progMsg.Prepend(
"Preparing RNC Cache...\n");
1486 int size_X = pBSBChart->GetSize_X();
1487 int size_Y = pBSBChart->GetSize_Y();
1489 int tex_dim = g_GLOptions.m_iTextureDimension;
1491 int nx_tex = ceil((
float)size_X / tex_dim);
1492 int ny_tex = ceil((
float)size_Y / tex_dim);
1496 rect.width = tex_dim;
1497 rect.height = tex_dim;
1498 for (
int y = 0; y < ny_tex; y++) {
1500 for (
int x = 0; x < nx_tex; x++) {
1502 if (!tex_fact->IsLevelInCache(level, rect, global_color_scheme)) {
1506 rect.x += rect.width;
1508 rect.y += rect.height;
1518 if (!m_progDialog->Update(m_jcnt)) {
1529 ScheduleJob(tex_fact, wxRect(), 0,
false,
true,
true,
false);
1532 int cnt = GetJobCount() - GetRunningJobCount();
1545 while (GetRunningJobCount()) {
1553 delete m_progDialog;
1554 m_progDialog =
nullptr;
General chart base definitions.
ChartDB * ChartData
Global instance.
Charts database management
Generic Chart canvas base.
Base class for BSB (Maptech/NOS) format nautical charts.
Base class for all chart types.
ChartCanvas - Main chart display and interaction component.
wxFont * FindOrCreateFont(int point_size, wxFontFamily family, wxFontStyle style, wxFontWeight weight, bool underline=false, const wxString &facename=wxEmptyString, wxFontEncoding encoding=wxFONTENCODING_DEFAULT)
Creates or finds a matching font in the font cache.
Global variables stored in configuration file.
GLuint g_raster_format
Global instance.
OpenGL chart rendering canvas.
glTextureManager * g_glTextureManager
Global instance.
OpenGL texture container.
glTextureManager * g_glTextureManager
Global instance.
GLuint g_raster_format
Global instance.
int g_mipmap_max_level
Global instance.
wxFont * GetOCPNScaledFont(wxString item, int default_size)
Retrieves a font from FontMgr, optionally scaled for physical readability.
General purpose GUI support.
bool b_inCompressAllCharts
Flag to control adaptive UI scaling.
int g_mipmap_max_level
Global instance.
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
double gLat
Vessel's current latitude in decimal degrees.
double gLon
Vessel's current longitude in decimal degrees.
Position, course, speed, etc.
Represents an entry in the chart table, containing information about a single chart.
Runtime representation of a plugin block.
Geographic projection and coordinate transformations.