30#include <wx/progdlg.h>
34#if defined(__ANDROID__)
36#elif defined(__WXQT__) || defined(__WXGTK__)
40#include <wx/datetime.h>
42#include <wx/filename.h>
46#include <wx/progdlg.h>
47#include <wx/stopwatch.h>
52#include <wx/listimpl.cpp>
53#include <wx/arrimpl.cpp>
55#include "mipmap/mipmap.h"
81#ifndef GL_ETC1_RGB8_OES
82#define GL_ETC1_RGB8_OES 0x8D64
85using JobList = std::list<JobTicket *>;
91static bool bthread_debug;
93wxString CompressedCachePath(wxString path) {
95 int colon = path.find(
':', 0);
96 if (colon != wxNOT_FOUND) path.Remove(colon, 1);
100 wxChar separator = wxFileName::GetPathSeparator();
101 for (
unsigned int pos = 0; pos < path.size(); pos = path.find(separator, pos))
102 path.replace(pos, 1,
"!");
106 wxCharBuffer buf = path.ToUTF8();
107 unsigned char sha1_out[20];
108 sha1((
unsigned char *)buf.data(), strlen(buf.data()), sha1_out);
111 for (
unsigned int i = 0; i < 20; i++) {
113 s.Printf(
"%02X", sha1_out[i]);
122OCPN_CompressProgressEvent::OCPN_CompressProgressEvent(wxEventType commandType,
int id)
123:wxEvent(id, commandType)
127OCPN_CompressProgressEvent::~OCPN_CompressProgressEvent()
131wxEvent* OCPN_CompressProgressEvent::Clone()
const
133 OCPN_CompressProgressEvent *newevent=
new OCPN_CompressProgressEvent(*
this);
134 newevent->m_string=this->m_string;
135 newevent->count=this->count;
136 newevent->thread=this->thread;
141static double chart_dist(
int index) {
147 if (cte.GetBBox().Contains(
gLat,
gLon))
152 clon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
153 d = DistGreatCircle(cte.GetLatMax(), clon,
gLat,
gLon);
154 t = DistGreatCircle(cte.GetLatMin(), clon,
gLat,
gLon);
157 clat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
158 t = DistGreatCircle(clat, cte.GetLonMin(),
gLat,
gLon);
160 t = DistGreatCircle(clat, cte.GetLonMax(),
gLat,
gLon);
166WX_DEFINE_SORTED_ARRAY_INT(
int, MySortedArrayInt);
167int CompareInts(
int n1,
int n2) {
168 double d1 = chart_dist(n1);
169 double d2 = chart_dist(n2);
170 return (
int)(d1 - d2);
173static MySortedArrayInt idx_sorted_by_distance(CompareInts);
184JobTicket::JobTicket() {
185 for (
int i = 0; i < 10; i++) {
186 compcomp_size_array[i] = 0;
187 comp_bits_array[i] = NULL;
188 compcomp_bits_array[i] = NULL;
198void FlattenColorsForCompression(
unsigned char *data,
int dim,
bool swap_colors=
true)
203 for(
int i = 0; i<dim*dim; i++) {
205 unsigned char t = data[off + 0];
206 data[off + 0] = data[off + 2] & 0xfc;
207 data[off + 1] &= 0xf8;
208 data[off + 2] = t & 0xfc;
212 for(
int i = 0; i<dim*dim; i++) {
214 data[off + 0] &= 0xfc;
215 data[off + 1] &= 0xf8;
216 data[off + 2] &= 0xfc;
222static void CompressDataETC(
const unsigned char *data,
int dim,
int size,
223 unsigned char *tex_data,
volatile bool &b_abort) {
224 wxASSERT(dim * dim == 2 * size || (dim < 4 && size == 8));
225 uint64_t *tex_data64 = (uint64_t *)tex_data;
227 int mbrow = wxMin(4, dim), mbcol = wxMin(4, dim);
228 uint8_t
block[48] = {};
229 for (
int row = 0; row < dim; row += 4) {
230 for (
int col = 0; col < dim; col += 4) {
231 for (
int brow = 0; brow < mbrow; brow++)
232 for (
int bcol = 0; bcol < mbcol; bcol++)
233 memcpy(
block + (bcol * 4 + brow) * 3,
234 data + ((row + brow) * dim + col + bcol) * 3, 3);
236 extern uint64_t ProcessRGB(
const uint8_t *src);
237 *tex_data64++ = ProcessRGB(
block);
243static bool CompressUsingGPU(
const unsigned char *data,
int dim,
int size,
244 unsigned char *tex_data,
int level,
bool inplace) {
245#ifndef USE_ANDROID_GLES2
249 glGenTextures(1, &comp_tex);
250 glBindTexture(GL_TEXTURE_2D, comp_tex);
251 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
252 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
256 glTexImage2D(GL_TEXTURE_2D, level,
g_raster_format, dim, dim, 0, GL_RGB,
257 GL_UNSIGNED_BYTE, data);
260 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_ARB,
263 if (compressed == GL_TRUE) {
265 GLint compressedSize;
266 glGetTexLevelParameteriv(GL_TEXTURE_2D, level,
267 GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &compressedSize);
269 if (compressedSize != size)
return false;
272 glGetCompressedTexImage(GL_TEXTURE_2D, level, tex_data);
275 if (!inplace) glDeleteTextures(1, &comp_tex);
284 wxString &chart_path) {
287 ptd->map_array[0] = 0;
292 (
unsigned char *)calloc(ncrect.width * ncrect.height * 4, 1);
300 unsigned char *t_buf =
301 (
unsigned char *)malloc(ncrect.width * ncrect.height * 4);
302 pBSBChart->GetChartBits(ncrect, t_buf, 1);
305 ptd->map_array[0] = t_buf;
308 (
unsigned char *)calloc(ncrect.width * ncrect.height * 4, 1);
314 wxString chart_path,
int level) {
317 if (ptd->map_array[level])
return;
321 for (first_level = level; first_level; first_level--)
322 if (ptd->map_array[first_level - 1])
break;
326 GetLevel0Map(ptd, rect, chart_path);
330 int dim = g_GLOptions.m_iTextureDimension;
331 for (
int i = 0; i <= level; i++) {
332 if (i >= first_level) {
333 ptd->map_array[i] = (
unsigned char *)malloc(dim * dim * 3);
334 MipMap_24(2 * dim, 2 * dim, ptd->map_array[i - 1], ptd->map_array[i]);
340int TextureDim(
int level) {
341 int dim = g_GLOptions.m_iTextureDimension;
342 for (
int i = 0; i < level; i++) dim /= 2;
346int TextureTileSize(
int level,
bool compressed) {
352 for (
int i = 0; i < level; i++) {
354 if (size < 8) size = 8;
357 size = g_uncompressed_tile_size;
358 for (
int i = 0; i < level; i++) size /= 4;
364bool JobTicket::DoJob() {
365 if (!m_rect.IsEmpty())
return DoJob(m_rect);
369 if (!pchart)
return false;
372 if (!pBSBChart)
return false;
374 int size_X = pBSBChart->GetSize_X();
375 int size_Y = pBSBChart->GetSize_Y();
377 int dim = g_GLOptions.m_iTextureDimension;
379 int nx_tex = ceil((
float)size_X / dim);
380 int ny_tex = ceil((
float)size_Y / dim);
386 for (
int y = 0; y < ny_tex; y++) {
387 if (pthread && pthread->m_pMessageTarget) {
390 Nevent.nstat_max = ny_tex;
392 Nevent.SetTicket(
this);
393 pthread->m_pMessageTarget->AddPendingEvent(Nevent);
397 for (
int x = 0; x < nx_tex; x++) {
398 if (!DoJob(rect))
return false;
400 pFact->UpdateCacheAllLevels(rect, global_color_scheme,
401 compcomp_bits_array, compcomp_size_array);
404 free(comp_bits_array[i]), comp_bits_array[i] = 0;
405 free(compcomp_bits_array[i]), compcomp_bits_array[i] = 0;
408 rect.x += rect.width;
410 rect.y += rect.height;
422 void Start() { clock_gettime(CLOCK_REALTIME, &tp); }
426 clock_gettime(CLOCK_REALTIME, &tp_end);
427 return (tp_end.tv_sec - tp.tv_sec) * 1.e3 + (tp_end.tv_nsec - tp.tv_nsec) / 1.e6;
437static void throttle_func(
void *data) {
438 if (!wxThread::IsMain()) {
440 if (sww->Time() > 1) {
447static wxMutex s_mutexProtectingChartBitRead;
449bool JobTicket::DoJob(
const wxRect &rect) {
450 unsigned char *bit_array[10];
451 for (
int i = 0; i < 10; i++) bit_array[i] = 0;
455 bit_array[0] = level0_bits;
466 wxMutexLocker lock(s_mutexProtectingChartBitRead);
468 index =
ChartData->FinddbIndex(m_ChartPath);
469 pchart =
ChartData->OpenChartFromDBAndLock(index, FULL_INIT);
471 if (pchart &&
ChartData->IsChartLocked(index)) {
475 (
unsigned char *)malloc(ncrect.width * ncrect.height * 4);
476 pBSBChart->GetChartBits(ncrect, bit_array[0], 1);
486 if (!bit_array[0])
return false;
489 dim = g_GLOptions.m_iTextureDimension;
492 size_t nmalloc = wxMax(dim * dim * 3, 4 * 4 * 3);
493 bit_array[i] = (
unsigned char *)malloc(nmalloc);
494 MipMap_24(2 * dim, 2 * dim, bit_array[i - 1], bit_array[i]);
498 int texture_level = 0;
500 int dim = TextureDim(level);
501 int size = TextureTileSize(level,
true);
502 unsigned char *tex_data = (
unsigned char *)malloc(size);
505 int flags = squish::kDxt1 | squish::kColourRangeFit;
507 if (g_GLOptions.m_bTextureCompressionCaching) {
511 flags = squish::kDxt1 | squish::kColourClusterFit;
515 squish::CompressImageRGBpow2_Flatten_Throttle_Abort(
516 bit_array[level], dim, dim, tex_data, flags,
true,
517 b_throttle ? throttle_func : 0, &sww, b_abort);
520 CompressDataETC(bit_array[level], dim, size, tex_data, b_abort);
522 if (!CompressUsingGPU(bit_array[level], dim, size, tex_data,
523 texture_level, binplace)) {
528 if (binplace) g_tex_mem_used += size;
532 comp_bits_array[level] = tex_data;
549 if (b_throttle) wxThread::Sleep(1);
551 if (b_abort)
return false;
553 if (bpost_zip_compress) {
554 int max_compressed_size = LZ4_COMPRESSBOUND(g_tile_size);
557 if (b_abort)
return false;
559 unsigned char *compressed_data =
560 (
unsigned char *)malloc(max_compressed_size);
561 int csize = TextureTileSize(level,
true);
563 char *src = (
char *)comp_bits_array[level];
564 int compressed_size =
565 LZ4_compressHC2(src, (
char *)compressed_data, csize, 4);
570 (
unsigned char *)realloc(compressed_data, compressed_size);
571 compcomp_bits_array[level] = compressed_data;
572 compcomp_size_array[level] = compressed_size;
595 SE_Exception(
unsigned int n) : nSE(n) {}
597 unsigned int getSeNumber() {
return nSE; }
600void my_translate(
unsigned int code, _EXCEPTION_POINTERS *ep) {
601 throw SE_Exception();
605OCPN_CompressionThreadEvent::OCPN_CompressionThreadEvent(
606 wxEventType commandType,
int id)
607 : wxEvent(id, commandType) {
611OCPN_CompressionThreadEvent::~OCPN_CompressionThreadEvent() {}
613wxEvent *OCPN_CompressionThreadEvent::Clone()
const {
616 newevent->m_ticket = this->m_ticket;
617 newevent->type = this->type;
618 newevent->nstat = this->nstat;
619 newevent->nstat_max = this->nstat_max;
651CompressionPoolThread::CompressionPoolThread(
JobTicket *ticket,
652 wxEvtHandler *message_target) {
653 m_pMessageTarget = message_target;
659void *CompressionPoolThread::Entry() {
661 _set_se_translator(my_translate);
671 SetPriority(WXTHREAD_MIN_PRIORITY);
673 if (!m_ticket->DoJob()) m_ticket->b_isaborted =
true;
675 if (m_pMessageTarget) {
677 Nevent.SetTicket(m_ticket);
679 m_pMessageTarget->QueueEvent(Nevent.Clone());
687 catch (SE_Exception e) {
688 if (m_pMessageTarget) {
690 m_ticket->b_isaborted =
true;
691 Nevent.SetTicket(m_ticket);
693 m_pMessageTarget->QueueEvent(Nevent.Clone());
704glTextureManager::glTextureManager() {
707 int nCPU = wxMax(1, wxThread::GetCPUCount());
708 if (g_nCPUCount > 0) nCPU = g_nCPUCount;
715 m_max_jobs = wxMax(nCPU / 2, 1);
719 if (bthread_debug) printf(
" nCPU: %d m_max_jobs :%d\n", nCPU, m_max_jobs);
723 for (
int i = 0; i < m_max_jobs; i++) progList.push_back(
new ProgressInfoItem);
728 wxEVT_OCPN_COMPRESSIONTHREAD,
729 (wxObjectEventFunction)(wxEventFunction)&glTextureManager::OnEvtThread);
736 m_timer.Connect(wxEVT_TIMER, wxTimerEventHandler(glTextureManager::OnTimer),
741glTextureManager::~glTextureManager() {
744 for (
int i = 0; i < m_max_jobs; i++) {
745 auto it = progList.begin();
750 for (
auto hash : m_chart_texfactory_hash) {
753 m_chart_texfactory_hash.clear();
756#define NBAR_LENGTH 40
761 if (event.type == 1) {
769 for (
auto tnode = progList.begin(); tnode != progList.end(); tnode++) {
771 if (item->file_path == ticket->m_ChartPath) {
779 for (
auto tnode = progList.begin(); tnode != progList.end(); tnode++) {
781 if (item->file_path.IsEmpty()) {
783 item->file_path = ticket->m_ChartPath;
792 int bar_length = NBAR_LENGTH;
793 if (m_bcompact) bar_length = 20;
796 wxString
block = wxString::Format(
"%c", 0x2588);
798 if (event.nstat_max != 0)
799 cutoff = ((
event.nstat + 1) / (
float)
event.nstat_max) * bar_length;
800 for (
int i = 0; i < bar_length; i++) {
810 msgy.Printf(
" [%3d/%3d] ", event.nstat + 1, event.nstat_max);
813 wxFileName fn(ticket->m_ChartPath);
814 msgx += fn.GetFullName();
817 msgx.Printf(
"\n %3d/%3d", event.nstat + 1, event.nstat_max);
824 for (
auto tnode = progList.begin(); tnode != progList.end(); tnode++) {
826 msg += item->msgx +
"\n";
829 if (m_skipout) m_progMsg =
"Skipping, please wait...\n\n";
831 if (!m_progDialog->Update(m_jcnt, m_progMsg + msg, &m_skip)) m_skip =
true;
832 if (m_skip) m_skipout =
true;
836 if (ticket->b_isaborted || ticket->b_abort) {
838 free(ticket->comp_bits_array[i]);
839 free(ticket->compcomp_bits_array[i]);
844 " Abort job: %08X Jobs running: %d Job count: %lu "
846 ticket->ident, GetRunningJobCount(), (
unsigned long)todo_list.size());
847 }
else if (!ticket->b_inCompressAll) {
852 ptd->comp_array[i] = ticket->comp_bits_array[i];
854 if (ticket->bpost_zip_compress) {
856 ptd->compcomp_array[i] = ticket->compcomp_bits_array[i];
857 ptd->compcomp_size[i] = ticket->compcomp_size_array[i];
864 top_frame::Get()->InvalidateAllGL();
865 ptd->compdata_ticks = 10;
870 " Finished job: %08X Jobs running: %d Job count: %lu "
872 ticket->ident, GetRunningJobCount(), (
unsigned long)todo_list.size());
876 if (ticket->b_inCompressAll) {
878 ChartData->OpenChartFromDB(ticket->m_ChartPath, FULL_INIT);
880 delete ticket->pFact;
883 for (
auto tnode = progList.begin(); tnode != progList.end(); ++tnode) {
885 if (item->file_path == ticket->m_ChartPath) item->file_path =
"";
889 auto found = std::find(running_list.begin(), running_list.end(), ticket);
890 if (found != running_list.end()) running_list.erase(found);
897void glTextureManager::OnTimer(wxTimerEvent &event) {
903 if (g_GLOptions.m_bTextureCompression) {
904 for (ChartPathHashTexfactType::iterator itt =
905 m_chart_texfactory_hash.begin();
906 itt != m_chart_texfactory_hash.end(); ++itt) {
908 if (ptf && ptf->OnTimer()) {
915 if((m_ticks % 4) == 0){
918 int mem_total, mem_used;
923 int compcomp_size = 0;
925 for(ChartPathHashTexfactType::iterator itt = m_chart_texfactory_hash.begin();
926 itt != m_chart_texfactory_hash.end(); ++itt ) {
929 ptf->AccumulateMemStatistics(map_size, comp_size, compcomp_size);
932 int m1 = 1024 * 1024;
934 printf(
"%6d %6ld Map: %10d Comp:%10d CompComp: %10d \n", mem_used/1024, g_tex_mem_used/m1, map_size, comp_size, compcomp_size);
941bool glTextureManager::ScheduleJob(
glTexFactory *client,
const wxRect &rect,
942 int level,
bool b_throttle_thread,
943 bool b_nolimit,
bool b_postZip,
945 wxString chart_path = client->GetChartPath();
947 if (todo_list.size() >= 50) {
949 auto node = todo_list.rbegin();
951 auto found = std::find(todo_list.begin(), todo_list.end(), ticket);
952 todo_list.erase(found);
958 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
960 if (ticket->m_ChartPath == chart_path && ticket->m_rect == rect) {
963 todo_list.splice(todo_list.begin(), todo_list, node);
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 auto &list = todo_list;
1100 auto removed_begin =
1101 std::remove_if(list.begin(), list.end(), [chart_path](
JobTicket *t) {
1102 bool is_chart_match = t->m_ChartPath == chart_path;
1103 if (is_chart_match) delete t;
1104 return is_chart_match;
1106 list.erase(removed_begin, list.end());
1109 std::cout <<
"Pool: Purge, todo count: " << list.size() <<
"\n";
1111 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
1117 for (
auto node = running_list.begin(); node != running_list.end(); ++node) {
1119 ticket->b_abort =
true;
1124void glTextureManager::ClearJobList() {
1125 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
1132void glTextureManager::ClearAllRasterTextures() {
1134 ChartPathHashTexfactType::iterator itt;
1135 for (itt = m_chart_texfactory_hash.begin();
1136 itt != m_chart_texfactory_hash.end(); ++itt) {
1141 m_chart_texfactory_hash.clear();
1143 if (g_tex_mem_used != 0)
1144 wxLogMessage(
"Texture memory use calculation error\n");
1147bool glTextureManager::PurgeChartTextures(
ChartBase *pc,
bool b_purge_factory) {
1149 ChartPathHashTexfactType::iterator ittf =
1150 m_chart_texfactory_hash.find(pc->GetHashKey());
1153 if (ittf != m_chart_texfactory_hash.end()) {
1157 if (b_purge_factory) {
1158 m_chart_texfactory_hash.erase(ittf);
1165 m_chart_texfactory_hash.erase(ittf);
1172bool glTextureManager::TextureCrunch(
double factor) {
1173 double hysteresis = 0.90;
1177 (double)(g_GLOptions.m_iTextureMemorySize * 1024 * 1024) * factor;
1178 if (!bGLMemCrunch)
return false;
1180 ChartPathHashTexfactType::iterator it0;
1181 for (it0 = m_chart_texfactory_hash.begin();
1182 it0 != m_chart_texfactory_hash.end(); ++it0) {
1185 wxString chart_full_path = ptf->GetChartPath();
1187 bGLMemCrunch = g_tex_mem_used >
1188 (double)(g_GLOptions.m_iTextureMemorySize * 1024 * 1024) *
1189 factor * hysteresis;
1190 if (!bGLMemCrunch)
break;
1193 for (
unsigned int i = 0; i <
g_canvasArray.GetCount(); i++) {
1196 if (cc->GetVP().b_quilt)
1198 if (cc->m_pQuilt && cc->m_pQuilt->IsComposed() &&
1199 !cc->m_pQuilt->IsChartInQuilt(chart_full_path)) {
1200 ptf->DeleteSomeTextures(g_GLOptions.m_iTextureMemorySize * 1024 *
1201 1024 * factor * hysteresis);
1205 if (!cc->m_singleChart->GetFullPath().IsSameAs(chart_full_path)) {
1206 ptf->DeleteSomeTextures(g_GLOptions.m_iTextureMemorySize * 1024 *
1207 1024 * factor * hysteresis);
1217#define MAX_CACHE_FACTORY 50
1218bool glTextureManager::FactoryCrunch(
double factor) {
1219 if (m_chart_texfactory_hash.size() == 0) {
1226 double hysteresis = 0.90;
1227 ChartPathHashTexfactType::iterator it0;
1231 ((mem_used > (double)(g_memCacheLimit)*factor * hysteresis &&
1232 mem_used > (double)(m_prevMemUsed)*factor * hysteresis) ||
1233 (m_chart_texfactory_hash.size() > MAX_CACHE_FACTORY)));
1235 if (!bMemCrunch)
return false;
1239 int lru_oldest = 2147483647;
1242 for (it0 = m_chart_texfactory_hash.begin();
1243 it0 != m_chart_texfactory_hash.end(); ++it0) {
1246 wxString chart_full_path = ptf->GetChartPath();
1252 for (
unsigned int i = 0; i <
g_canvasArray.GetCount(); i++) {
1255 if (cc->GetVP().b_quilt)
1257 if (cc->m_pQuilt && cc->m_pQuilt->IsComposed() &&
1258 !cc->m_pQuilt->IsChartInQuilt(chart_full_path)) {
1259 int lru = ptf->GetLRUTime();
1260 if (lru < lru_oldest && !ptf->BackgroundCompressionAsJob()) {
1266 if (!cc->m_singleChart->GetFullPath().IsSameAs(chart_full_path)) {
1267 int lru = ptf->GetLRUTime();
1268 if (lru < lru_oldest && !ptf->BackgroundCompressionAsJob()) {
1279 if (!ptf_oldest)
return false;
1281 ptf_oldest->FreeSome(g_memCacheLimit * factor * hysteresis);
1285 bMemCrunch = (g_memCacheLimit &&
1286 ((mem_used > (double)(g_memCacheLimit)*factor * hysteresis &&
1287 mem_used > (double)(m_prevMemUsed)*factor * hysteresis) ||
1288 (m_chart_texfactory_hash.size() > MAX_CACHE_FACTORY)));
1290 if (!bMemCrunch)
return false;
1294 m_chart_texfactory_hash.erase(
1295 ptf_oldest->GetHashKey());
1302void glTextureManager::BuildCompressedCache() {
1303 idx_sorted_by_distance.Clear();
1311 for (
int i = 0; i <
ChartData->GetChartTableEntries(); i++) {
1314 ChartTypeEnum chart_type = (ChartTypeEnum)cte.GetChartType();
1315 if (chart_type == CHART_TYPE_PLUGIN) {
1316 if (cte.GetChartFamily() != CHART_FAMILY_RASTER)
continue;
1318 if (chart_type != CHART_TYPE_KAP)
continue;
1321 wxString CompressedCacheFilePath =
1322 CompressedCachePath(
ChartData->GetDBChartFileName(i));
1323 wxFileName fn(CompressedCacheFilePath);
1327 idx_sorted_by_distance.Add(i);
1332 if (count == 0)
return;
1334 wxLogMessage(wxString::Format(
"BuildCompressedCache() count = %d", count));
1338 if (GetRunningJobCount()) {
1339 wxLogMessage(
"Starting compressor pool drain");
1340 wxDateTime now = wxDateTime::Now();
1341 time_t stall = now.GetTicks();
1342#define THREAD_WAIT_SECONDS 5
1343 time_t end = stall + THREAD_WAIT_SECONDS;
1346 while (stall < end) {
1347 wxDateTime later = wxDateTime::Now();
1348 stall = later.GetTicks();
1351 msg.Printf(
"Time: %d Job Count: %d", n_comploop, GetRunningJobCount());
1353 if (!GetRunningJobCount())
break;
1359 fmsg.Printf(
"Finished compressor pool drain..Time: %d Job Count: %d",
1360 n_comploop, GetRunningJobCount());
1363 ClearAllRasterTextures();
1370 ArrayOfCompressTargets ct_array;
1371 for (
unsigned int j = 0; j < idx_sorted_by_distance.GetCount(); j++) {
1372 int i = idx_sorted_by_distance[j];
1375 double distance = chart_dist(i);
1377 wxString filename = cte.GetFullSystemPath();
1380 pct->distance = distance;
1381 pct->chart_path = filename;
1387 long style = wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME |
1388 wxPD_REMAINING_TIME | wxPD_CAN_ABORT;
1398 "longgggggggggggggggggggggggggggggggggggggggggggg\ngggggggggggggggggg"
1399 "gggggggggggggggggggggggggg top line ";
1402 for (
int i = 0; i < m_max_jobs + 1; i++)
1405 m_progDialog =
new wxGenericProgressDialog();
1408 int fontSize = qFont->GetPointSize();
1410 wxSize csz = wxTheApp->GetTopWindow()->GetClientSize();
1411 if (csz.x < 500 || csz.y < 500)
1413 10, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
1417 wxFONTWEIGHT_NORMAL);
1419 m_progDialog->SetFont(*sFont);
1424 sdc.GetTextExtent(
"[WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW]", &width, &height, NULL,
1426 if (width > (csz.x / 2)) m_bcompact =
true;
1428 m_progDialog->Create(_(
"OpenCPN Compressed Cache Update"), msg0, count + 1,
1432 m_progDialog->Hide();
1433 wxSize sz = m_progDialog->GetSize();
1434 sz.x = csz.x * 9 / 10;
1435 m_progDialog->SetSize(sz);
1437 m_progDialog->Layout();
1438 wxSize sza = m_progDialog->GetSize();
1440 m_progDialog->Centre();
1441 m_progDialog->Show();
1442 m_progDialog->Raise();
1448 for (m_jcnt = 0; m_jcnt < ct_array.GetCount(); m_jcnt++) {
1449 wxString filename = ct_array[m_jcnt].chart_path;
1450 wxString CompressedCacheFilePath = CompressedCachePath(filename);
1451 double distance = ct_array[m_jcnt].distance;
1461 if (pBSBChart == 0)
continue;
1465 m_progMsg.Printf(_(
"Distance from Ownship: %4.0f NMi"), distance);
1467 m_progMsg.Prepend(
"Preparing RNC Cache...\n");
1476 int size_X = pBSBChart->GetSize_X();
1477 int size_Y = pBSBChart->GetSize_Y();
1479 int tex_dim = g_GLOptions.m_iTextureDimension;
1481 int nx_tex = ceil((
float)size_X / tex_dim);
1482 int ny_tex = ceil((
float)size_Y / tex_dim);
1486 rect.width = tex_dim;
1487 rect.height = tex_dim;
1488 for (
int y = 0; y < ny_tex; y++) {
1490 for (
int x = 0; x < nx_tex; x++) {
1492 if (!tex_fact->IsLevelInCache(level, rect, global_color_scheme)) {
1496 rect.x += rect.width;
1498 rect.y += rect.height;
1508 if (!m_progDialog->Update(m_jcnt)) {
1519 ScheduleJob(tex_fact, wxRect(), 0,
false,
true,
true,
false);
1522 int cnt = GetJobCount() - GetRunningJobCount();
1535 while (GetRunningJobCount()) {
1543 delete m_progDialog;
1544 m_progDialog =
nullptr;
General chart base definitions.
ChartDB * ChartData
Global instance.
Charts database management
arrayofCanvasPtr g_canvasArray
Global instance.
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.
Abstract gFrame/MyFrame interface.
Geographic projection and coordinate transformations.