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) {
965 todo_list.splice(todo_list.begin(), todo_list, node);
966 ticket->level_min_request = level;
972 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
974 if (ticket->m_rect == rect && ticket->m_ChartPath == chart_path) {
983 pt->level_min_request = level;
985 pt->ident = (ptd->tex_name << 16) + level;
986 pt->b_throttle = b_throttle_thread;
987 pt->m_ChartPath = chart_path;
989 pt->level0_bits = NULL;
991 pt->b_isaborted =
false;
992 pt->bpost_zip_compress = b_postZip;
993 pt->binplace = b_inplace;
1007 todo_list.insert(todo_list.begin(), pt);
1008 if (bthread_debug) {
1011 printf(
"Adding job: %08X Job Count: %lu mem_used %d\n", pt->ident,
1012 (
unsigned long)todo_list.size(), mem_used);
1018 pt->level0_bits = ptd->map_array[0];
1019 ptd->map_array[0] = NULL;
1025 Nevent.SetTicket(pt);
1026 ProcessEventLocally(Nevent);
1032bool glTextureManager::StartTopJob() {
1033 auto node = todo_list.begin();
1034 if (node == todo_list.end())
return false;
1039 if (GetRunningJobCount() >= wxMax(m_max_jobs - ticket->b_throttle, 1))
1041 auto found = std::find(todo_list.begin(), todo_list.end(), ticket);
1042 if (found != todo_list.end()) todo_list.erase(found);
1046 if (ptd->comp_array[0]) {
1048 return StartTopJob();
1051 if (ptd->map_array[0]) {
1052 if (ticket->level_min_request == 0) {
1054 ticket->level0_bits = ptd->map_array[0];
1055 ptd->map_array[0] = NULL;
1058 int size = TextureTileSize(0,
false);
1059 ticket->level0_bits = (
unsigned char *)malloc(size);
1060 memcpy(ticket->level0_bits, ptd->map_array[0], size);
1064 running_list.push_back(ticket);
1065 DoThreadJob(ticket);
1070bool glTextureManager::DoThreadJob(
JobTicket *pticket) {
1072 printf(
" Starting job: %08X Jobs running: %d Jobs left: %lu\n",
1073 pticket->ident, GetRunningJobCount(),
1074 (
unsigned long)todo_list.size());
1079 pticket->pthread = t;
1086bool glTextureManager::AsJob(wxString
const &chart_path)
const {
1087 if (chart_path.Len()) {
1088 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
1090 if (ticket->m_ChartPath.IsSameAs(chart_path)) {
1098void glTextureManager::PurgeJobList(wxString chart_path) {
1099 if (chart_path.Len()) {
1101 auto &list = todo_list;
1102 auto removed_begin =
1103 std::remove_if(list.begin(), list.end(), [chart_path](
JobTicket *t) {
1104 bool is_chart_match = t->m_ChartPath == chart_path;
1105 if (is_chart_match) delete t;
1106 return is_chart_match;
1108 list.erase(removed_begin, list.end());
1111 std::cout <<
"Pool: Purge, todo count: " << list.size() <<
"\n";
1113 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
1119 for (
auto node = running_list.begin(); node != running_list.end(); ++node) {
1121 ticket->b_abort =
true;
1126void glTextureManager::ClearJobList() {
1127 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
1134void glTextureManager::ClearAllRasterTextures() {
1136 ChartPathHashTexfactType::iterator itt;
1137 for (itt = m_chart_texfactory_hash.begin();
1138 itt != m_chart_texfactory_hash.end(); ++itt) {
1143 m_chart_texfactory_hash.clear();
1145 if (g_tex_mem_used != 0)
1146 wxLogMessage(
"Texture memory use calculation error\n");
1149bool glTextureManager::PurgeChartTextures(
ChartBase *pc,
bool b_purge_factory) {
1151 ChartPathHashTexfactType::iterator ittf =
1152 m_chart_texfactory_hash.find(pc->GetHashKey());
1155 if (ittf != m_chart_texfactory_hash.end()) {
1159 if (b_purge_factory) {
1160 m_chart_texfactory_hash.erase(ittf);
1167 m_chart_texfactory_hash.erase(ittf);
1174bool glTextureManager::TextureCrunch(
double factor) {
1175 double hysteresis = 0.90;
1179 (double)(g_GLOptions.m_iTextureMemorySize * 1024 * 1024) * factor;
1180 if (!bGLMemCrunch)
return false;
1182 ChartPathHashTexfactType::iterator it0;
1183 for (it0 = m_chart_texfactory_hash.begin();
1184 it0 != m_chart_texfactory_hash.end(); ++it0) {
1187 wxString chart_full_path = ptf->GetChartPath();
1189 bGLMemCrunch = g_tex_mem_used >
1190 (double)(g_GLOptions.m_iTextureMemorySize * 1024 * 1024) *
1191 factor * hysteresis;
1192 if (!bGLMemCrunch)
break;
1195 for (
unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
1198 if (cc->GetVP().b_quilt)
1200 if (cc->m_pQuilt && cc->m_pQuilt->IsComposed() &&
1201 !cc->m_pQuilt->IsChartInQuilt(chart_full_path)) {
1202 ptf->DeleteSomeTextures(g_GLOptions.m_iTextureMemorySize * 1024 *
1203 1024 * factor * hysteresis);
1207 if (!cc->m_singleChart->GetFullPath().IsSameAs(chart_full_path)) {
1208 ptf->DeleteSomeTextures(g_GLOptions.m_iTextureMemorySize * 1024 *
1209 1024 * factor * hysteresis);
1219#define MAX_CACHE_FACTORY 50
1220bool glTextureManager::FactoryCrunch(
double factor) {
1221 if (m_chart_texfactory_hash.size() == 0) {
1228 double hysteresis = 0.90;
1229 ChartPathHashTexfactType::iterator it0;
1233 ((mem_used > (double)(g_memCacheLimit)*factor * hysteresis &&
1234 mem_used > (double)(m_prevMemUsed)*factor * hysteresis) ||
1235 (m_chart_texfactory_hash.size() > MAX_CACHE_FACTORY)));
1237 if (!bMemCrunch)
return false;
1241 int lru_oldest = 2147483647;
1244 for (it0 = m_chart_texfactory_hash.begin();
1245 it0 != m_chart_texfactory_hash.end(); ++it0) {
1248 wxString chart_full_path = ptf->GetChartPath();
1254 for (
unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
1257 if (cc->GetVP().b_quilt)
1259 if (cc->m_pQuilt && cc->m_pQuilt->IsComposed() &&
1260 !cc->m_pQuilt->IsChartInQuilt(chart_full_path)) {
1261 int lru = ptf->GetLRUTime();
1262 if (lru < lru_oldest && !ptf->BackgroundCompressionAsJob()) {
1268 if (!cc->m_singleChart->GetFullPath().IsSameAs(chart_full_path)) {
1269 int lru = ptf->GetLRUTime();
1270 if (lru < lru_oldest && !ptf->BackgroundCompressionAsJob()) {
1281 if (!ptf_oldest)
return false;
1283 ptf_oldest->FreeSome(g_memCacheLimit * factor * hysteresis);
1287 bMemCrunch = (g_memCacheLimit &&
1288 ((mem_used > (double)(g_memCacheLimit)*factor * hysteresis &&
1289 mem_used > (double)(m_prevMemUsed)*factor * hysteresis) ||
1290 (m_chart_texfactory_hash.size() > MAX_CACHE_FACTORY)));
1292 if (!bMemCrunch)
return false;
1296 m_chart_texfactory_hash.erase(
1297 ptf_oldest->GetHashKey());
1304void glTextureManager::BuildCompressedCache() {
1305 idx_sorted_by_distance.Clear();
1313 for (
int i = 0; i <
ChartData->GetChartTableEntries(); i++) {
1316 ChartTypeEnum chart_type = (ChartTypeEnum)cte.GetChartType();
1317 if (chart_type == CHART_TYPE_PLUGIN) {
1318 if (cte.GetChartFamily() != CHART_FAMILY_RASTER)
continue;
1320 if (chart_type != CHART_TYPE_KAP)
continue;
1323 wxString CompressedCacheFilePath =
1324 CompressedCachePath(
ChartData->GetDBChartFileName(i));
1325 wxFileName fn(CompressedCacheFilePath);
1329 idx_sorted_by_distance.Add(i);
1334 if (count == 0)
return;
1336 wxLogMessage(wxString::Format(
"BuildCompressedCache() count = %d", count));
1340 if (GetRunningJobCount()) {
1341 wxLogMessage(
"Starting compressor pool drain");
1342 wxDateTime now = wxDateTime::Now();
1343 time_t stall = now.GetTicks();
1344#define THREAD_WAIT_SECONDS 5
1345 time_t end = stall + THREAD_WAIT_SECONDS;
1348 while (stall < end) {
1349 wxDateTime later = wxDateTime::Now();
1350 stall = later.GetTicks();
1353 msg.Printf(
"Time: %d Job Count: %d", n_comploop, GetRunningJobCount());
1355 if (!GetRunningJobCount())
break;
1361 fmsg.Printf(
"Finished compressor pool drain..Time: %d Job Count: %d",
1362 n_comploop, GetRunningJobCount());
1365 ClearAllRasterTextures();
1372 ArrayOfCompressTargets ct_array;
1373 for (
unsigned int j = 0; j < idx_sorted_by_distance.GetCount(); j++) {
1374 int i = idx_sorted_by_distance[j];
1377 double distance = chart_dist(i);
1379 wxString filename = cte.GetFullSystemPath();
1382 pct->distance = distance;
1383 pct->chart_path = filename;
1389 long style = wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME |
1390 wxPD_REMAINING_TIME | wxPD_CAN_ABORT;
1400 "longgggggggggggggggggggggggggggggggggggggggggggg\ngggggggggggggggggg"
1401 "gggggggggggggggggggggggggg top line ";
1404 for (
int i = 0; i < m_max_jobs + 1; i++)
1407 m_progDialog =
new wxGenericProgressDialog();
1410 int fontSize = qFont->GetPointSize();
1412 wxSize csz = gFrame->GetClientSize();
1413 if (csz.x < 500 || csz.y < 500)
1415 10, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
1419 wxFONTWEIGHT_NORMAL);
1421 m_progDialog->SetFont(*sFont);
1426 sdc.GetTextExtent(
"[WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW]", &width, &height, NULL,
1428 if (width > (csz.x / 2)) m_bcompact =
true;
1430 m_progDialog->Create(_(
"OpenCPN Compressed Cache Update"), msg0, count + 1,
1434 m_progDialog->Hide();
1435 wxSize sz = m_progDialog->GetSize();
1436 sz.x = csz.x * 9 / 10;
1437 m_progDialog->SetSize(sz);
1439 m_progDialog->Layout();
1440 wxSize sza = m_progDialog->GetSize();
1442 m_progDialog->Centre();
1443 m_progDialog->Show();
1444 m_progDialog->Raise();
1450 for (m_jcnt = 0; m_jcnt < ct_array.GetCount(); m_jcnt++) {
1451 wxString filename = ct_array[m_jcnt].chart_path;
1452 wxString CompressedCacheFilePath = CompressedCachePath(filename);
1453 double distance = ct_array[m_jcnt].distance;
1463 if (pBSBChart == 0)
continue;
1467 m_progMsg.Printf(_(
"Distance from Ownship: %4.0f NMi"), distance);
1469 m_progMsg.Prepend(
"Preparing RNC Cache...\n");
1478 int size_X = pBSBChart->GetSize_X();
1479 int size_Y = pBSBChart->GetSize_Y();
1481 int tex_dim = g_GLOptions.m_iTextureDimension;
1483 int nx_tex = ceil((
float)size_X / tex_dim);
1484 int ny_tex = ceil((
float)size_Y / tex_dim);
1488 rect.width = tex_dim;
1489 rect.height = tex_dim;
1490 for (
int y = 0; y < ny_tex; y++) {
1492 for (
int x = 0; x < nx_tex; x++) {
1494 if (!tex_fact->IsLevelInCache(level, rect, global_color_scheme)) {
1498 rect.x += rect.width;
1500 rect.y += rect.height;
1510 if (!m_progDialog->Update(m_jcnt)) {
1521 ScheduleJob(tex_fact, wxRect(), 0,
false,
true,
true,
false);
1524 int cnt = GetJobCount() - GetRunningJobCount();
1537 while (GetRunningJobCount()) {
1545 delete m_progDialog;
1546 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.