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 *>;
89extern arrayofCanvasPtr g_canvasArray;
93static bool bthread_debug;
95wxString CompressedCachePath(wxString path) {
97 int colon = path.find(
':', 0);
98 if (colon != wxNOT_FOUND) path.Remove(colon, 1);
102 wxChar separator = wxFileName::GetPathSeparator();
103 for (
unsigned int pos = 0; pos < path.size(); pos = path.find(separator, pos))
104 path.replace(pos, 1,
"!");
108 wxCharBuffer buf = path.ToUTF8();
109 unsigned char sha1_out[20];
110 sha1((
unsigned char *)buf.data(), strlen(buf.data()), sha1_out);
113 for (
unsigned int i = 0; i < 20; i++) {
115 s.Printf(
"%02X", sha1_out[i]);
124OCPN_CompressProgressEvent::OCPN_CompressProgressEvent(wxEventType commandType,
int id)
125:wxEvent(id, commandType)
129OCPN_CompressProgressEvent::~OCPN_CompressProgressEvent()
133wxEvent* OCPN_CompressProgressEvent::Clone()
const
135 OCPN_CompressProgressEvent *newevent=
new OCPN_CompressProgressEvent(*
this);
136 newevent->m_string=this->m_string;
137 newevent->count=this->count;
138 newevent->thread=this->thread;
143static double chart_dist(
int index) {
149 if (cte.GetBBox().Contains(
gLat,
gLon))
154 clon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
155 d = DistGreatCircle(cte.GetLatMax(), clon,
gLat,
gLon);
156 t = DistGreatCircle(cte.GetLatMin(), clon,
gLat,
gLon);
159 clat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
160 t = DistGreatCircle(clat, cte.GetLonMin(),
gLat,
gLon);
162 t = DistGreatCircle(clat, cte.GetLonMax(),
gLat,
gLon);
168WX_DEFINE_SORTED_ARRAY_INT(
int, MySortedArrayInt);
169int CompareInts(
int n1,
int n2) {
170 double d1 = chart_dist(n1);
171 double d2 = chart_dist(n2);
172 return (
int)(d1 - d2);
175static MySortedArrayInt idx_sorted_by_distance(CompareInts);
186JobTicket::JobTicket() {
187 for (
int i = 0; i < 10; i++) {
188 compcomp_size_array[i] = 0;
189 comp_bits_array[i] = NULL;
190 compcomp_bits_array[i] = NULL;
200void FlattenColorsForCompression(
unsigned char *data,
int dim,
bool swap_colors=
true)
205 for(
int i = 0; i<dim*dim; i++) {
207 unsigned char t = data[off + 0];
208 data[off + 0] = data[off + 2] & 0xfc;
209 data[off + 1] &= 0xf8;
210 data[off + 2] = t & 0xfc;
214 for(
int i = 0; i<dim*dim; i++) {
216 data[off + 0] &= 0xfc;
217 data[off + 1] &= 0xf8;
218 data[off + 2] &= 0xfc;
224static void CompressDataETC(
const unsigned char *data,
int dim,
int size,
225 unsigned char *tex_data,
volatile bool &b_abort) {
226 wxASSERT(dim * dim == 2 * size || (dim < 4 && size == 8));
227 uint64_t *tex_data64 = (uint64_t *)tex_data;
229 int mbrow = wxMin(4, dim), mbcol = wxMin(4, dim);
230 uint8_t
block[48] = {};
231 for (
int row = 0; row < dim; row += 4) {
232 for (
int col = 0; col < dim; col += 4) {
233 for (
int brow = 0; brow < mbrow; brow++)
234 for (
int bcol = 0; bcol < mbcol; bcol++)
235 memcpy(
block + (bcol * 4 + brow) * 3,
236 data + ((row + brow) * dim + col + bcol) * 3, 3);
238 extern uint64_t ProcessRGB(
const uint8_t *src);
239 *tex_data64++ = ProcessRGB(
block);
245static bool CompressUsingGPU(
const unsigned char *data,
int dim,
int size,
246 unsigned char *tex_data,
int level,
bool inplace) {
247#ifndef USE_ANDROID_GLES2
251 glGenTextures(1, &comp_tex);
252 glBindTexture(GL_TEXTURE_2D, comp_tex);
253 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
254 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
258 glTexImage2D(GL_TEXTURE_2D, level,
g_raster_format, dim, dim, 0, GL_RGB,
259 GL_UNSIGNED_BYTE, data);
262 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_ARB,
265 if (compressed == GL_TRUE) {
267 GLint compressedSize;
268 glGetTexLevelParameteriv(GL_TEXTURE_2D, level,
269 GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &compressedSize);
271 if (compressedSize != size)
return false;
274 glGetCompressedTexImage(GL_TEXTURE_2D, level, tex_data);
277 if (!inplace) glDeleteTextures(1, &comp_tex);
286 wxString &chart_path) {
289 ptd->map_array[0] = 0;
294 (
unsigned char *)calloc(ncrect.width * ncrect.height * 4, 1);
302 unsigned char *t_buf =
303 (
unsigned char *)malloc(ncrect.width * ncrect.height * 4);
304 pBSBChart->GetChartBits(ncrect, t_buf, 1);
307 ptd->map_array[0] = t_buf;
310 (
unsigned char *)calloc(ncrect.width * ncrect.height * 4, 1);
316 wxString chart_path,
int level) {
319 if (ptd->map_array[level])
return;
323 for (first_level = level; first_level; first_level--)
324 if (ptd->map_array[first_level - 1])
break;
328 GetLevel0Map(ptd, rect, chart_path);
332 int dim = g_GLOptions.m_iTextureDimension;
333 for (
int i = 0; i <= level; i++) {
334 if (i >= first_level) {
335 ptd->map_array[i] = (
unsigned char *)malloc(dim * dim * 3);
336 MipMap_24(2 * dim, 2 * dim, ptd->map_array[i - 1], ptd->map_array[i]);
342int TextureDim(
int level) {
343 int dim = g_GLOptions.m_iTextureDimension;
344 for (
int i = 0; i < level; i++) dim /= 2;
348int TextureTileSize(
int level,
bool compressed) {
354 for (
int i = 0; i < level; i++) {
356 if (size < 8) size = 8;
359 size = g_uncompressed_tile_size;
360 for (
int i = 0; i < level; i++) size /= 4;
366bool JobTicket::DoJob() {
367 if (!m_rect.IsEmpty())
return DoJob(m_rect);
371 if (!pchart)
return false;
374 if (!pBSBChart)
return false;
376 int size_X = pBSBChart->GetSize_X();
377 int size_Y = pBSBChart->GetSize_Y();
379 int dim = g_GLOptions.m_iTextureDimension;
381 int nx_tex = ceil((
float)size_X / dim);
382 int ny_tex = ceil((
float)size_Y / dim);
388 for (
int y = 0; y < ny_tex; y++) {
389 if (pthread && pthread->m_pMessageTarget) {
392 Nevent.nstat_max = ny_tex;
394 Nevent.SetTicket(
this);
395 pthread->m_pMessageTarget->AddPendingEvent(Nevent);
399 for (
int x = 0; x < nx_tex; x++) {
400 if (!DoJob(rect))
return false;
402 pFact->UpdateCacheAllLevels(rect, global_color_scheme,
403 compcomp_bits_array, compcomp_size_array);
406 free(comp_bits_array[i]), comp_bits_array[i] = 0;
407 free(compcomp_bits_array[i]), compcomp_bits_array[i] = 0;
410 rect.x += rect.width;
412 rect.y += rect.height;
424 void Start() { clock_gettime(CLOCK_REALTIME, &tp); }
428 clock_gettime(CLOCK_REALTIME, &tp_end);
429 return (tp_end.tv_sec - tp.tv_sec) * 1.e3 + (tp_end.tv_nsec - tp.tv_nsec) / 1.e6;
439static void throttle_func(
void *data) {
440 if (!wxThread::IsMain()) {
442 if (sww->Time() > 1) {
449static wxMutex s_mutexProtectingChartBitRead;
451bool JobTicket::DoJob(
const wxRect &rect) {
452 unsigned char *bit_array[10];
453 for (
int i = 0; i < 10; i++) bit_array[i] = 0;
457 bit_array[0] = level0_bits;
468 wxMutexLocker lock(s_mutexProtectingChartBitRead);
470 index =
ChartData->FinddbIndex(m_ChartPath);
471 pchart =
ChartData->OpenChartFromDBAndLock(index, FULL_INIT);
473 if (pchart &&
ChartData->IsChartLocked(index)) {
477 (
unsigned char *)malloc(ncrect.width * ncrect.height * 4);
478 pBSBChart->GetChartBits(ncrect, bit_array[0], 1);
488 if (!bit_array[0])
return false;
491 dim = g_GLOptions.m_iTextureDimension;
494 size_t nmalloc = wxMax(dim * dim * 3, 4 * 4 * 3);
495 bit_array[i] = (
unsigned char *)malloc(nmalloc);
496 MipMap_24(2 * dim, 2 * dim, bit_array[i - 1], bit_array[i]);
500 int texture_level = 0;
502 int dim = TextureDim(level);
503 int size = TextureTileSize(level,
true);
504 unsigned char *tex_data = (
unsigned char *)malloc(size);
507 int flags = squish::kDxt1 | squish::kColourRangeFit;
509 if (g_GLOptions.m_bTextureCompressionCaching) {
513 flags = squish::kDxt1 | squish::kColourClusterFit;
517 squish::CompressImageRGBpow2_Flatten_Throttle_Abort(
518 bit_array[level], dim, dim, tex_data, flags,
true,
519 b_throttle ? throttle_func : 0, &sww, b_abort);
522 CompressDataETC(bit_array[level], dim, size, tex_data, b_abort);
524 if (!CompressUsingGPU(bit_array[level], dim, size, tex_data,
525 texture_level, binplace)) {
530 if (binplace) g_tex_mem_used += size;
534 comp_bits_array[level] = tex_data;
551 if (b_throttle) wxThread::Sleep(1);
553 if (b_abort)
return false;
555 if (bpost_zip_compress) {
556 int max_compressed_size = LZ4_COMPRESSBOUND(g_tile_size);
559 if (b_abort)
return false;
561 unsigned char *compressed_data =
562 (
unsigned char *)malloc(max_compressed_size);
563 int csize = TextureTileSize(level,
true);
565 char *src = (
char *)comp_bits_array[level];
566 int compressed_size =
567 LZ4_compressHC2(src, (
char *)compressed_data, csize, 4);
572 (
unsigned char *)realloc(compressed_data, compressed_size);
573 compcomp_bits_array[level] = compressed_data;
574 compcomp_size_array[level] = compressed_size;
597 SE_Exception(
unsigned int n) : nSE(n) {}
599 unsigned int getSeNumber() {
return nSE; }
602void my_translate(
unsigned int code, _EXCEPTION_POINTERS *ep) {
603 throw SE_Exception();
607OCPN_CompressionThreadEvent::OCPN_CompressionThreadEvent(
608 wxEventType commandType,
int id)
609 : wxEvent(id, commandType) {
613OCPN_CompressionThreadEvent::~OCPN_CompressionThreadEvent() {}
615wxEvent *OCPN_CompressionThreadEvent::Clone()
const {
618 newevent->m_ticket = this->m_ticket;
619 newevent->type = this->type;
620 newevent->nstat = this->nstat;
621 newevent->nstat_max = this->nstat_max;
653CompressionPoolThread::CompressionPoolThread(
JobTicket *ticket,
654 wxEvtHandler *message_target) {
655 m_pMessageTarget = message_target;
661void *CompressionPoolThread::Entry() {
663 _set_se_translator(my_translate);
673 SetPriority(WXTHREAD_MIN_PRIORITY);
675 if (!m_ticket->DoJob()) m_ticket->b_isaborted =
true;
677 if (m_pMessageTarget) {
679 Nevent.SetTicket(m_ticket);
681 m_pMessageTarget->QueueEvent(Nevent.Clone());
689 catch (SE_Exception e) {
690 if (m_pMessageTarget) {
692 m_ticket->b_isaborted =
true;
693 Nevent.SetTicket(m_ticket);
695 m_pMessageTarget->QueueEvent(Nevent.Clone());
706glTextureManager::glTextureManager() {
709 int nCPU = wxMax(1, wxThread::GetCPUCount());
710 if (g_nCPUCount > 0) nCPU = g_nCPUCount;
717 m_max_jobs = wxMax(nCPU / 2, 1);
721 if (bthread_debug) printf(
" nCPU: %d m_max_jobs :%d\n", nCPU, m_max_jobs);
725 for (
int i = 0; i < m_max_jobs; i++) progList.push_back(
new ProgressInfoItem);
730 wxEVT_OCPN_COMPRESSIONTHREAD,
731 (wxObjectEventFunction)(wxEventFunction)&glTextureManager::OnEvtThread);
738 m_timer.Connect(wxEVT_TIMER, wxTimerEventHandler(glTextureManager::OnTimer),
743glTextureManager::~glTextureManager() {
746 for (
int i = 0; i < m_max_jobs; i++) {
747 auto it = progList.begin();
752 for (
auto hash : m_chart_texfactory_hash) {
755 m_chart_texfactory_hash.clear();
758#define NBAR_LENGTH 40
763 if (event.type == 1) {
771 for (
auto tnode = progList.begin(); tnode != progList.end(); tnode++) {
773 if (item->file_path == ticket->m_ChartPath) {
781 for (
auto tnode = progList.begin(); tnode != progList.end(); tnode++) {
783 if (item->file_path.IsEmpty()) {
785 item->file_path = ticket->m_ChartPath;
794 int bar_length = NBAR_LENGTH;
795 if (m_bcompact) bar_length = 20;
798 wxString
block = wxString::Format(
"%c", 0x2588);
800 if (event.nstat_max != 0)
801 cutoff = ((
event.nstat + 1) / (
float)
event.nstat_max) * bar_length;
802 for (
int i = 0; i < bar_length; i++) {
812 msgy.Printf(
" [%3d/%3d] ", event.nstat + 1, event.nstat_max);
815 wxFileName fn(ticket->m_ChartPath);
816 msgx += fn.GetFullName();
819 msgx.Printf(
"\n %3d/%3d", event.nstat + 1, event.nstat_max);
826 for (
auto tnode = progList.begin(); tnode != progList.end(); tnode++) {
828 msg += item->msgx +
"\n";
831 if (m_skipout) m_progMsg =
"Skipping, please wait...\n\n";
833 if (!m_progDialog->Update(m_jcnt, m_progMsg + msg, &m_skip)) m_skip =
true;
834 if (m_skip) m_skipout =
true;
838 if (ticket->b_isaborted || ticket->b_abort) {
840 free(ticket->comp_bits_array[i]);
841 free(ticket->compcomp_bits_array[i]);
846 " Abort job: %08X Jobs running: %d Job count: %lu "
848 ticket->ident, GetRunningJobCount(), (
unsigned long)todo_list.size());
849 }
else if (!ticket->b_inCompressAll) {
854 ptd->comp_array[i] = ticket->comp_bits_array[i];
856 if (ticket->bpost_zip_compress) {
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(), (
unsigned long)todo_list.size());
878 if (ticket->b_inCompressAll) {
880 ChartData->OpenChartFromDB(ticket->m_ChartPath, FULL_INIT);
882 delete ticket->pFact;
885 for (
auto tnode = progList.begin(); tnode != progList.end(); ++tnode) {
887 if (item->file_path == ticket->m_ChartPath) item->file_path =
"";
891 auto found = std::find(running_list.begin(), running_list.end(), ticket);
892 if (found != running_list.end()) running_list.erase(found);
899void glTextureManager::OnTimer(wxTimerEvent &event) {
905 if (g_GLOptions.m_bTextureCompression) {
906 for (ChartPathHashTexfactType::iterator itt =
907 m_chart_texfactory_hash.begin();
908 itt != m_chart_texfactory_hash.end(); ++itt) {
910 if (ptf && ptf->OnTimer()) {
917 if((m_ticks % 4) == 0){
920 int mem_total, mem_used;
925 int compcomp_size = 0;
927 for(ChartPathHashTexfactType::iterator itt = m_chart_texfactory_hash.begin();
928 itt != m_chart_texfactory_hash.end(); ++itt ) {
931 ptf->AccumulateMemStatistics(map_size, comp_size, compcomp_size);
934 int m1 = 1024 * 1024;
936 printf(
"%6d %6ld Map: %10d Comp:%10d CompComp: %10d \n", mem_used/1024, g_tex_mem_used/m1, map_size, comp_size, compcomp_size);
943bool glTextureManager::ScheduleJob(
glTexFactory *client,
const wxRect &rect,
944 int level,
bool b_throttle_thread,
945 bool b_nolimit,
bool b_postZip,
947 wxString chart_path = client->GetChartPath();
949 if (todo_list.size() >= 50) {
951 auto node = todo_list.rbegin();
953 auto found = std::find(todo_list.begin(), todo_list.end(), ticket);
954 todo_list.erase(found);
960 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
962 if ((ticket->m_ChartPath == chart_path) && (ticket->m_rect == rect)) {
964 auto found = std::find(todo_list.begin(), todo_list.end(), ticket);
965 if (found != todo_list.end()) todo_list.erase(found);
966 todo_list.insert(todo_list.begin(), ticket);
967 ticket->level_min_request = level;
973 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
975 if (ticket->m_rect == rect && ticket->m_ChartPath == chart_path) {
984 pt->level_min_request = level;
986 pt->ident = (ptd->tex_name << 16) + level;
987 pt->b_throttle = b_throttle_thread;
988 pt->m_ChartPath = chart_path;
990 pt->level0_bits = NULL;
992 pt->b_isaborted =
false;
993 pt->bpost_zip_compress = b_postZip;
994 pt->binplace = b_inplace;
1008 todo_list.insert(todo_list.begin(), pt);
1009 if (bthread_debug) {
1012 printf(
"Adding job: %08X Job Count: %lu mem_used %d\n", pt->ident,
1013 (
unsigned long)todo_list.size(), mem_used);
1019 pt->level0_bits = ptd->map_array[0];
1020 ptd->map_array[0] = NULL;
1026 Nevent.SetTicket(pt);
1027 ProcessEventLocally(Nevent);
1033bool glTextureManager::StartTopJob() {
1034 auto node = todo_list.begin();
1035 if (node == todo_list.end())
return false;
1040 if (GetRunningJobCount() >= wxMax(m_max_jobs - ticket->b_throttle, 1))
1042 auto found = std::find(todo_list.begin(), todo_list.end(), ticket);
1043 if (found != todo_list.end()) todo_list.erase(found);
1047 if (ptd->comp_array[0]) {
1049 return StartTopJob();
1052 if (ptd->map_array[0]) {
1053 if (ticket->level_min_request == 0) {
1055 ticket->level0_bits = ptd->map_array[0];
1056 ptd->map_array[0] = NULL;
1059 int size = TextureTileSize(0,
false);
1060 ticket->level0_bits = (
unsigned char *)malloc(size);
1061 memcpy(ticket->level0_bits, ptd->map_array[0], size);
1065 running_list.push_back(ticket);
1066 DoThreadJob(ticket);
1071bool glTextureManager::DoThreadJob(
JobTicket *pticket) {
1073 printf(
" Starting job: %08X Jobs running: %d Jobs left: %lu\n",
1074 pticket->ident, GetRunningJobCount(),
1075 (
unsigned long)todo_list.size());
1080 pticket->pthread = t;
1087bool glTextureManager::AsJob(wxString
const &chart_path)
const {
1088 if (chart_path.Len()) {
1089 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
1091 if (ticket->m_ChartPath.IsSameAs(chart_path)) {
1099void glTextureManager::PurgeJobList(wxString chart_path) {
1100 if (chart_path.Len()) {
1102 auto &list = todo_list;
1103 auto removed_begin =
1104 std::remove_if(list.begin(), list.end(), [chart_path](
JobTicket *t) {
1105 bool is_chart_match = t->m_ChartPath == chart_path;
1106 if (is_chart_match) delete t;
1107 return is_chart_match;
1109 list.erase(removed_begin, list.end());
1112 std::cout <<
"Pool: Purge, todo count: " << list.size() <<
"\n";
1114 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
1120 for (
auto node = running_list.begin(); node != running_list.end(); ++node) {
1122 ticket->b_abort =
true;
1127void glTextureManager::ClearJobList() {
1128 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
1135void glTextureManager::ClearAllRasterTextures() {
1137 ChartPathHashTexfactType::iterator itt;
1138 for (itt = m_chart_texfactory_hash.begin();
1139 itt != m_chart_texfactory_hash.end(); ++itt) {
1144 m_chart_texfactory_hash.clear();
1146 if (g_tex_mem_used != 0)
1147 wxLogMessage(
"Texture memory use calculation error\n");
1150bool glTextureManager::PurgeChartTextures(
ChartBase *pc,
bool b_purge_factory) {
1152 ChartPathHashTexfactType::iterator ittf =
1153 m_chart_texfactory_hash.find(pc->GetHashKey());
1156 if (ittf != m_chart_texfactory_hash.end()) {
1160 if (b_purge_factory) {
1161 m_chart_texfactory_hash.erase(ittf);
1168 m_chart_texfactory_hash.erase(ittf);
1175bool glTextureManager::TextureCrunch(
double factor) {
1176 double hysteresis = 0.90;
1180 (double)(g_GLOptions.m_iTextureMemorySize * 1024 * 1024) * factor;
1181 if (!bGLMemCrunch)
return false;
1183 ChartPathHashTexfactType::iterator it0;
1184 for (it0 = m_chart_texfactory_hash.begin();
1185 it0 != m_chart_texfactory_hash.end(); ++it0) {
1188 wxString chart_full_path = ptf->GetChartPath();
1190 bGLMemCrunch = g_tex_mem_used >
1191 (double)(g_GLOptions.m_iTextureMemorySize * 1024 * 1024) *
1192 factor * hysteresis;
1193 if (!bGLMemCrunch)
break;
1196 for (
unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
1199 if (cc->GetVP().b_quilt)
1201 if (cc->m_pQuilt && cc->m_pQuilt->IsComposed() &&
1202 !cc->m_pQuilt->IsChartInQuilt(chart_full_path)) {
1203 ptf->DeleteSomeTextures(g_GLOptions.m_iTextureMemorySize * 1024 *
1204 1024 * factor * hysteresis);
1208 if (!cc->m_singleChart->GetFullPath().IsSameAs(chart_full_path)) {
1209 ptf->DeleteSomeTextures(g_GLOptions.m_iTextureMemorySize * 1024 *
1210 1024 * factor * hysteresis);
1220#define MAX_CACHE_FACTORY 50
1221bool glTextureManager::FactoryCrunch(
double factor) {
1222 if (m_chart_texfactory_hash.size() == 0) {
1229 double hysteresis = 0.90;
1230 ChartPathHashTexfactType::iterator it0;
1234 ((mem_used > (double)(g_memCacheLimit)*factor * hysteresis &&
1235 mem_used > (double)(m_prevMemUsed)*factor * hysteresis) ||
1236 (m_chart_texfactory_hash.size() > MAX_CACHE_FACTORY)));
1238 if (!bMemCrunch)
return false;
1242 int lru_oldest = 2147483647;
1245 for (it0 = m_chart_texfactory_hash.begin();
1246 it0 != m_chart_texfactory_hash.end(); ++it0) {
1249 wxString chart_full_path = ptf->GetChartPath();
1255 for (
unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
1258 if (cc->GetVP().b_quilt)
1260 if (cc->m_pQuilt && cc->m_pQuilt->IsComposed() &&
1261 !cc->m_pQuilt->IsChartInQuilt(chart_full_path)) {
1262 int lru = ptf->GetLRUTime();
1263 if (lru < lru_oldest && !ptf->BackgroundCompressionAsJob()) {
1269 if (!cc->m_singleChart->GetFullPath().IsSameAs(chart_full_path)) {
1270 int lru = ptf->GetLRUTime();
1271 if (lru < lru_oldest && !ptf->BackgroundCompressionAsJob()) {
1282 if (!ptf_oldest)
return false;
1284 ptf_oldest->FreeSome(g_memCacheLimit * factor * hysteresis);
1288 bMemCrunch = (g_memCacheLimit &&
1289 ((mem_used > (double)(g_memCacheLimit)*factor * hysteresis &&
1290 mem_used > (double)(m_prevMemUsed)*factor * hysteresis) ||
1291 (m_chart_texfactory_hash.size() > MAX_CACHE_FACTORY)));
1293 if (!bMemCrunch)
return false;
1297 m_chart_texfactory_hash.erase(
1298 ptf_oldest->GetHashKey());
1305void glTextureManager::BuildCompressedCache() {
1306 idx_sorted_by_distance.Clear();
1314 for (
int i = 0; i <
ChartData->GetChartTableEntries(); i++) {
1317 ChartTypeEnum chart_type = (ChartTypeEnum)cte.GetChartType();
1318 if (chart_type == CHART_TYPE_PLUGIN) {
1319 if (cte.GetChartFamily() != CHART_FAMILY_RASTER)
continue;
1321 if (chart_type != CHART_TYPE_KAP)
continue;
1324 wxString CompressedCacheFilePath =
1325 CompressedCachePath(
ChartData->GetDBChartFileName(i));
1326 wxFileName fn(CompressedCacheFilePath);
1330 idx_sorted_by_distance.Add(i);
1335 if (count == 0)
return;
1337 wxLogMessage(wxString::Format(
"BuildCompressedCache() count = %d", count));
1341 if (GetRunningJobCount()) {
1342 wxLogMessage(
"Starting compressor pool drain");
1343 wxDateTime now = wxDateTime::Now();
1344 time_t stall = now.GetTicks();
1345#define THREAD_WAIT_SECONDS 5
1346 time_t end = stall + THREAD_WAIT_SECONDS;
1349 while (stall < end) {
1350 wxDateTime later = wxDateTime::Now();
1351 stall = later.GetTicks();
1354 msg.Printf(
"Time: %d Job Count: %d", n_comploop, GetRunningJobCount());
1356 if (!GetRunningJobCount())
break;
1362 fmsg.Printf(
"Finished compressor pool drain..Time: %d Job Count: %d",
1363 n_comploop, GetRunningJobCount());
1366 ClearAllRasterTextures();
1373 ArrayOfCompressTargets ct_array;
1374 for (
unsigned int j = 0; j < idx_sorted_by_distance.GetCount(); j++) {
1375 int i = idx_sorted_by_distance[j];
1378 double distance = chart_dist(i);
1380 wxString filename = cte.GetFullSystemPath();
1383 pct->distance = distance;
1384 pct->chart_path = filename;
1390 long style = wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME |
1391 wxPD_REMAINING_TIME | wxPD_CAN_ABORT;
1401 "longgggggggggggggggggggggggggggggggggggggggggggg\ngggggggggggggggggg"
1402 "gggggggggggggggggggggggggg top line ";
1405 for (
int i = 0; i < m_max_jobs + 1; i++)
1408 m_progDialog =
new wxGenericProgressDialog();
1411 int fontSize = qFont->GetPointSize();
1413 wxSize csz = gFrame->GetClientSize();
1414 if (csz.x < 500 || csz.y < 500)
1416 10, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
1420 wxFONTWEIGHT_NORMAL);
1422 m_progDialog->SetFont(*sFont);
1427 sdc.GetTextExtent(
"[WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW]", &width, &height, NULL,
1429 if (width > (csz.x / 2)) m_bcompact =
true;
1431 m_progDialog->Create(_(
"OpenCPN Compressed Cache Update"), msg0, count + 1,
1435 m_progDialog->Hide();
1436 wxSize sz = m_progDialog->GetSize();
1437 sz.x = csz.x * 9 / 10;
1438 m_progDialog->SetSize(sz);
1440 m_progDialog->Layout();
1441 wxSize sza = m_progDialog->GetSize();
1443 m_progDialog->Centre();
1444 m_progDialog->Show();
1445 m_progDialog->Raise();
1451 for (m_jcnt = 0; m_jcnt < ct_array.GetCount(); m_jcnt++) {
1452 wxString filename = ct_array[m_jcnt].chart_path;
1453 wxString CompressedCacheFilePath = CompressedCachePath(filename);
1454 double distance = ct_array[m_jcnt].distance;
1464 if (pBSBChart == 0)
continue;
1468 m_progMsg.Printf(_(
"Distance from Ownship: %4.0f NMi"), distance);
1470 m_progMsg.Prepend(
"Preparing RNC Cache...\n");
1479 int size_X = pBSBChart->GetSize_X();
1480 int size_Y = pBSBChart->GetSize_Y();
1482 int tex_dim = g_GLOptions.m_iTextureDimension;
1484 int nx_tex = ceil((
float)size_X / tex_dim);
1485 int ny_tex = ceil((
float)size_Y / tex_dim);
1489 rect.width = tex_dim;
1490 rect.height = tex_dim;
1491 for (
int y = 0; y < ny_tex; y++) {
1493 for (
int x = 0; x < nx_tex; x++) {
1495 if (!tex_fact->IsLevelInCache(level, rect, global_color_scheme)) {
1499 rect.x += rect.width;
1501 rect.y += rect.height;
1511 if (!m_progDialog->Update(m_jcnt)) {
1522 ScheduleJob(tex_fact, wxRect(), 0,
false,
true,
true,
false);
1525 int cnt = GetJobCount() - GetRunningJobCount();
1538 while (GetRunningJobCount()) {
1546 delete m_progDialog;
1547 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.