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"
59#include "model/own_ship.h"
73#include "ocpn_frame.h"
74#include "OCPNPlatform.h"
79#ifndef GL_ETC1_RGB8_OES
80#define GL_ETC1_RGB8_OES 0x8D64
83using JobList = std::list<JobTicket *>;
85WX_DEFINE_ARRAY_PTR(
ChartCanvas *, arrayofCanvasPtr);
89extern arrayofCanvasPtr g_canvasArray;
92extern bool GetMemoryStatus(
int *mem_total,
int *mem_used);
96static bool bthread_debug;
98wxString CompressedCachePath(wxString path) {
100 int colon = path.find(
':', 0);
101 if (colon != wxNOT_FOUND) path.Remove(colon, 1);
105 wxChar separator = wxFileName::GetPathSeparator();
106 for (
unsigned int pos = 0; pos < path.size(); pos = path.find(separator, pos))
107 path.replace(pos, 1,
"!");
111 wxCharBuffer buf = path.ToUTF8();
112 unsigned char sha1_out[20];
113 sha1((
unsigned char *)buf.data(), strlen(buf.data()), sha1_out);
116 for (
unsigned int i = 0; i < 20; i++) {
118 s.Printf(
"%02X", sha1_out[i]);
127OCPN_CompressProgressEvent::OCPN_CompressProgressEvent(wxEventType commandType,
int id)
128:wxEvent(id, commandType)
132OCPN_CompressProgressEvent::~OCPN_CompressProgressEvent()
136wxEvent* OCPN_CompressProgressEvent::Clone()
const
138 OCPN_CompressProgressEvent *newevent=
new OCPN_CompressProgressEvent(*
this);
139 newevent->m_string=this->m_string;
140 newevent->count=this->count;
141 newevent->thread=this->thread;
146static double chart_dist(
int index) {
152 if (cte.GetBBox().Contains(gLat, gLon))
157 clon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
158 d = DistGreatCircle(cte.GetLatMax(), clon, gLat, gLon);
159 t = DistGreatCircle(cte.GetLatMin(), clon, gLat, gLon);
162 clat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
163 t = DistGreatCircle(clat, cte.GetLonMin(), gLat, gLon);
165 t = DistGreatCircle(clat, cte.GetLonMax(), gLat, gLon);
171WX_DEFINE_SORTED_ARRAY_INT(
int, MySortedArrayInt);
172int CompareInts(
int n1,
int n2) {
173 double d1 = chart_dist(n1);
174 double d2 = chart_dist(n2);
175 return (
int)(d1 - d2);
178static MySortedArrayInt idx_sorted_by_distance(CompareInts);
189JobTicket::JobTicket() {
190 for (
int i = 0; i < 10; i++) {
191 compcomp_size_array[i] = 0;
192 comp_bits_array[i] = NULL;
193 compcomp_bits_array[i] = NULL;
203void FlattenColorsForCompression(
unsigned char *data,
int dim,
bool swap_colors=
true)
208 for(
int i = 0; i<dim*dim; i++) {
210 unsigned char t = data[off + 0];
211 data[off + 0] = data[off + 2] & 0xfc;
212 data[off + 1] &= 0xf8;
213 data[off + 2] = t & 0xfc;
217 for(
int i = 0; i<dim*dim; i++) {
219 data[off + 0] &= 0xfc;
220 data[off + 1] &= 0xf8;
221 data[off + 2] &= 0xfc;
227static void CompressDataETC(
const unsigned char *data,
int dim,
int size,
228 unsigned char *tex_data,
volatile bool &b_abort) {
229 wxASSERT(dim * dim == 2 * size || (dim < 4 && size == 8));
230 uint64_t *tex_data64 = (uint64_t *)tex_data;
232 int mbrow = wxMin(4, dim), mbcol = wxMin(4, dim);
233 uint8_t
block[48] = {};
234 for (
int row = 0; row < dim; row += 4) {
235 for (
int col = 0; col < dim; col += 4) {
236 for (
int brow = 0; brow < mbrow; brow++)
237 for (
int bcol = 0; bcol < mbcol; bcol++)
238 memcpy(
block + (bcol * 4 + brow) * 3,
239 data + ((row + brow) * dim + col + bcol) * 3, 3);
241 extern uint64_t ProcessRGB(
const uint8_t *src);
242 *tex_data64++ = ProcessRGB(
block);
248static bool CompressUsingGPU(
const unsigned char *data,
int dim,
int size,
249 unsigned char *tex_data,
int level,
bool inplace) {
250#ifndef USE_ANDROID_GLES2
254 glGenTextures(1, &comp_tex);
255 glBindTexture(GL_TEXTURE_2D, comp_tex);
256 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
257 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
261 glTexImage2D(GL_TEXTURE_2D, level,
g_raster_format, dim, dim, 0, GL_RGB,
262 GL_UNSIGNED_BYTE, data);
265 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_ARB,
268 if (compressed == GL_TRUE) {
270 GLint compressedSize;
271 glGetTexLevelParameteriv(GL_TEXTURE_2D, level,
272 GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &compressedSize);
274 if (compressedSize != size)
return false;
277 glGetCompressedTexImage(GL_TEXTURE_2D, level, tex_data);
280 if (!inplace) glDeleteTextures(1, &comp_tex);
289 wxString &chart_path) {
292 ptd->map_array[0] = 0;
297 (
unsigned char *)calloc(ncrect.width * ncrect.height * 4, 1);
305 unsigned char *t_buf =
306 (
unsigned char *)malloc(ncrect.width * ncrect.height * 4);
307 pBSBChart->GetChartBits(ncrect, t_buf, 1);
310 ptd->map_array[0] = t_buf;
313 (
unsigned char *)calloc(ncrect.width * ncrect.height * 4, 1);
319 wxString chart_path,
int level) {
322 if (ptd->map_array[level])
return;
326 for (first_level = level; first_level; first_level--)
327 if (ptd->map_array[first_level - 1])
break;
331 GetLevel0Map(ptd, rect, chart_path);
335 int dim = g_GLOptions.m_iTextureDimension;
336 for (
int i = 0; i <= level; i++) {
337 if (i >= first_level) {
338 ptd->map_array[i] = (
unsigned char *)malloc(dim * dim * 3);
339 MipMap_24(2 * dim, 2 * dim, ptd->map_array[i - 1], ptd->map_array[i]);
345int TextureDim(
int level) {
346 int dim = g_GLOptions.m_iTextureDimension;
347 for (
int i = 0; i < level; i++) dim /= 2;
351int TextureTileSize(
int level,
bool compressed) {
357 for (
int i = 0; i < level; i++) {
359 if (size < 8) size = 8;
362 size = g_uncompressed_tile_size;
363 for (
int i = 0; i < level; i++) size /= 4;
369bool JobTicket::DoJob() {
370 if (!m_rect.IsEmpty())
return DoJob(m_rect);
374 if (!pchart)
return false;
377 if (!pBSBChart)
return false;
379 int size_X = pBSBChart->GetSize_X();
380 int size_Y = pBSBChart->GetSize_Y();
382 int dim = g_GLOptions.m_iTextureDimension;
384 int nx_tex = ceil((
float)size_X / dim);
385 int ny_tex = ceil((
float)size_Y / dim);
391 for (
int y = 0; y < ny_tex; y++) {
392 if (pthread && pthread->m_pMessageTarget) {
395 Nevent.nstat_max = ny_tex;
397 Nevent.SetTicket(
this);
398 pthread->m_pMessageTarget->AddPendingEvent(Nevent);
402 for (
int x = 0; x < nx_tex; x++) {
403 if (!DoJob(rect))
return false;
405 pFact->UpdateCacheAllLevels(rect, global_color_scheme,
406 compcomp_bits_array, compcomp_size_array);
409 free(comp_bits_array[i]), comp_bits_array[i] = 0;
410 free(compcomp_bits_array[i]), compcomp_bits_array[i] = 0;
413 rect.x += rect.width;
415 rect.y += rect.height;
427 void Start() { clock_gettime(CLOCK_REALTIME, &tp); }
431 clock_gettime(CLOCK_REALTIME, &tp_end);
432 return (tp_end.tv_sec - tp.tv_sec) * 1.e3 + (tp_end.tv_nsec - tp.tv_nsec) / 1.e6;
442static void throttle_func(
void *data) {
443 if (!wxThread::IsMain()) {
445 if (sww->Time() > 1) {
452static wxMutex s_mutexProtectingChartBitRead;
454bool JobTicket::DoJob(
const wxRect &rect) {
455 unsigned char *bit_array[10];
456 for (
int i = 0; i < 10; i++) bit_array[i] = 0;
460 bit_array[0] = level0_bits;
471 wxMutexLocker lock(s_mutexProtectingChartBitRead);
473 index =
ChartData->FinddbIndex(m_ChartPath);
474 pchart =
ChartData->OpenChartFromDBAndLock(index, FULL_INIT);
476 if (pchart &&
ChartData->IsChartLocked(index)) {
480 (
unsigned char *)malloc(ncrect.width * ncrect.height * 4);
481 pBSBChart->GetChartBits(ncrect, bit_array[0], 1);
491 if (!bit_array[0])
return false;
494 dim = g_GLOptions.m_iTextureDimension;
497 size_t nmalloc = wxMax(dim * dim * 3, 4 * 4 * 3);
498 bit_array[i] = (
unsigned char *)malloc(nmalloc);
499 MipMap_24(2 * dim, 2 * dim, bit_array[i - 1], bit_array[i]);
503 int texture_level = 0;
505 int dim = TextureDim(level);
506 int size = TextureTileSize(level,
true);
507 unsigned char *tex_data = (
unsigned char *)malloc(size);
510 int flags = squish::kDxt1 | squish::kColourRangeFit;
512 if (g_GLOptions.m_bTextureCompressionCaching) {
516 flags = squish::kDxt1 | squish::kColourClusterFit;
520 squish::CompressImageRGBpow2_Flatten_Throttle_Abort(
521 bit_array[level], dim, dim, tex_data, flags,
true,
522 b_throttle ? throttle_func : 0, &sww, b_abort);
525 CompressDataETC(bit_array[level], dim, size, tex_data, b_abort);
527 if (!CompressUsingGPU(bit_array[level], dim, size, tex_data,
528 texture_level, binplace)) {
533 if (binplace) g_tex_mem_used += size;
537 comp_bits_array[level] = tex_data;
554 if (b_throttle) wxThread::Sleep(1);
556 if (b_abort)
return false;
558 if (bpost_zip_compress) {
559 int max_compressed_size = LZ4_COMPRESSBOUND(g_tile_size);
562 if (b_abort)
return false;
564 unsigned char *compressed_data =
565 (
unsigned char *)malloc(max_compressed_size);
566 int csize = TextureTileSize(level,
true);
568 char *src = (
char *)comp_bits_array[level];
569 int compressed_size =
570 LZ4_compressHC2(src, (
char *)compressed_data, csize, 4);
575 (
unsigned char *)realloc(compressed_data, compressed_size);
576 compcomp_bits_array[level] = compressed_data;
577 compcomp_size_array[level] = compressed_size;
600 SE_Exception(
unsigned int n) : nSE(n) {}
602 unsigned int getSeNumber() {
return nSE; }
605void my_translate(
unsigned int code, _EXCEPTION_POINTERS *ep) {
606 throw SE_Exception();
610OCPN_CompressionThreadEvent::OCPN_CompressionThreadEvent(
611 wxEventType commandType,
int id)
612 : wxEvent(id, commandType) {
616OCPN_CompressionThreadEvent::~OCPN_CompressionThreadEvent() {}
618wxEvent *OCPN_CompressionThreadEvent::Clone()
const {
621 newevent->m_ticket = this->m_ticket;
622 newevent->type = this->type;
623 newevent->nstat = this->nstat;
624 newevent->nstat_max = this->nstat_max;
656CompressionPoolThread::CompressionPoolThread(
JobTicket *ticket,
657 wxEvtHandler *message_target) {
658 m_pMessageTarget = message_target;
664void *CompressionPoolThread::Entry() {
666 _set_se_translator(my_translate);
676 SetPriority(WXTHREAD_MIN_PRIORITY);
678 if (!m_ticket->DoJob()) m_ticket->b_isaborted =
true;
680 if (m_pMessageTarget) {
682 Nevent.SetTicket(m_ticket);
684 m_pMessageTarget->QueueEvent(Nevent.Clone());
692 catch (SE_Exception e) {
693 if (m_pMessageTarget) {
695 m_ticket->b_isaborted =
true;
696 Nevent.SetTicket(m_ticket);
698 m_pMessageTarget->QueueEvent(Nevent.Clone());
709glTextureManager::glTextureManager() {
712 int nCPU = wxMax(1, wxThread::GetCPUCount());
713 if (g_nCPUCount > 0) nCPU = g_nCPUCount;
719 m_max_jobs = wxMax(nCPU, 1);
722 if (bthread_debug) printf(
" nCPU: %d m_max_jobs :%d\n", nCPU, m_max_jobs);
726 for (
int i = 0; i < m_max_jobs; i++) progList.push_back(
new ProgressInfoItem);
731 wxEVT_OCPN_COMPRESSIONTHREAD,
732 (wxObjectEventFunction)(wxEventFunction)&glTextureManager::OnEvtThread);
739 m_timer.Connect(wxEVT_TIMER, wxTimerEventHandler(glTextureManager::OnTimer),
744glTextureManager::~glTextureManager() {
747 for (
int i = 0; i < m_max_jobs; i++) {
748 auto it = progList.begin();
753 for (
auto hash : m_chart_texfactory_hash) {
756 m_chart_texfactory_hash.clear();
759#define NBAR_LENGTH 40
764 if (event.type == 1) {
772 for (
auto tnode = progList.begin(); tnode != progList.end(); tnode++) {
774 if (item->file_path == ticket->m_ChartPath) {
782 for (
auto tnode = progList.begin(); tnode != progList.end(); tnode++) {
784 if (item->file_path.IsEmpty()) {
786 item->file_path = ticket->m_ChartPath;
795 int bar_length = NBAR_LENGTH;
796 if (m_bcompact) bar_length = 20;
799 wxString
block = wxString::Format(
"%c", 0x2588);
801 if (event.nstat_max != 0)
802 cutoff = ((
event.nstat + 1) / (
float)
event.nstat_max) * bar_length;
803 for (
int i = 0; i < bar_length; i++) {
813 msgy.Printf(
" [%3d/%3d] ", event.nstat + 1, event.nstat_max);
816 wxFileName fn(ticket->m_ChartPath);
817 msgx += fn.GetFullName();
820 msgx.Printf(
"\n %3d/%3d", event.nstat + 1, event.nstat_max);
827 for (
auto tnode = progList.begin(); tnode != progList.end(); tnode++) {
829 msg += item->msgx +
"\n";
832 if (m_skipout) m_progMsg =
"Skipping, please wait...\n\n";
834 if (!m_progDialog->Update(m_jcnt, m_progMsg + msg, &m_skip)) m_skip =
true;
835 if (m_skip) m_skipout =
true;
839 if (ticket->b_isaborted || ticket->b_abort) {
841 free(ticket->comp_bits_array[i]);
842 free(ticket->compcomp_bits_array[i]);
847 " Abort job: %08X Jobs running: %d Job count: %lu "
849 ticket->ident, GetRunningJobCount(), (
unsigned long)todo_list.size());
850 }
else if (!ticket->b_inCompressAll) {
855 ptd->comp_array[i] = ticket->comp_bits_array[i];
857 if (ticket->bpost_zip_compress) {
859 ptd->compcomp_array[i] = ticket->compcomp_bits_array[i];
860 ptd->compcomp_size[i] = ticket->compcomp_size_array[i];
867 gFrame->InvalidateAllGL();
868 ptd->compdata_ticks = 10;
873 " Finished job: %08X Jobs running: %d Job count: %lu "
875 ticket->ident, GetRunningJobCount(), (
unsigned long)todo_list.size());
879 if (ticket->b_inCompressAll) {
881 ChartData->OpenChartFromDB(ticket->m_ChartPath, FULL_INIT);
883 delete ticket->pFact;
886 for (
auto tnode = progList.begin(); tnode != progList.end(); ++tnode) {
888 if (item->file_path == ticket->m_ChartPath) item->file_path =
"";
892 auto found = std::find(running_list.begin(), running_list.end(), ticket);
893 if (found != running_list.end()) running_list.erase(found);
900void glTextureManager::OnTimer(wxTimerEvent &event) {
906 if (g_GLOptions.m_bTextureCompression) {
907 for (ChartPathHashTexfactType::iterator itt =
908 m_chart_texfactory_hash.begin();
909 itt != m_chart_texfactory_hash.end(); ++itt) {
911 if (ptf && ptf->OnTimer()) {
918 if((m_ticks % 4) == 0){
921 int mem_total, mem_used;
922 GetMemoryStatus(&mem_total, &mem_used);
926 int compcomp_size = 0;
928 for(ChartPathHashTexfactType::iterator itt = m_chart_texfactory_hash.begin();
929 itt != m_chart_texfactory_hash.end(); ++itt ) {
932 ptf->AccumulateMemStatistics(map_size, comp_size, compcomp_size);
935 int m1 = 1024 * 1024;
937 printf(
"%6d %6ld Map: %10d Comp:%10d CompComp: %10d \n", mem_used/1024, g_tex_mem_used/m1, map_size, comp_size, compcomp_size);
944bool glTextureManager::ScheduleJob(
glTexFactory *client,
const wxRect &rect,
945 int level,
bool b_throttle_thread,
946 bool b_nolimit,
bool b_postZip,
948 wxString chart_path = client->GetChartPath();
950 if (todo_list.size() >= 50) {
952 auto node = todo_list.rbegin();
954 auto found = std::find(todo_list.begin(), todo_list.end(), ticket);
955 todo_list.erase(found);
961 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
963 if ((ticket->m_ChartPath == chart_path) && (ticket->m_rect == rect)) {
965 auto found = std::find(todo_list.begin(), todo_list.end(), ticket);
966 if (found != todo_list.end()) todo_list.erase(found);
967 todo_list.insert(todo_list.begin(), ticket);
968 ticket->level_min_request = level;
974 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
976 if (ticket->m_rect == rect && ticket->m_ChartPath == chart_path) {
985 pt->level_min_request = level;
987 pt->ident = (ptd->tex_name << 16) + level;
988 pt->b_throttle = b_throttle_thread;
989 pt->m_ChartPath = chart_path;
991 pt->level0_bits = NULL;
993 pt->b_isaborted =
false;
994 pt->bpost_zip_compress = b_postZip;
995 pt->binplace = b_inplace;
996 pt->b_inCompressAll = b_inCompressAllCharts;
1009 todo_list.insert(todo_list.begin(), pt);
1010 if (bthread_debug) {
1012 GetMemoryStatus(0, &mem_used);
1013 printf(
"Adding job: %08X Job Count: %lu mem_used %d\n", pt->ident,
1014 (
unsigned long)todo_list.size(), mem_used);
1020 pt->level0_bits = ptd->map_array[0];
1021 ptd->map_array[0] = NULL;
1027 Nevent.SetTicket(pt);
1028 ProcessEventLocally(Nevent);
1034bool glTextureManager::StartTopJob() {
1035 auto node = todo_list.begin();
1036 if (node == todo_list.end())
return false;
1041 if (GetRunningJobCount() >= wxMax(m_max_jobs - ticket->b_throttle, 1))
1043 auto found = std::find(todo_list.begin(), todo_list.end(), ticket);
1044 if (found != todo_list.end()) todo_list.erase(found);
1048 if (ptd->comp_array[0]) {
1050 return StartTopJob();
1053 if (ptd->map_array[0]) {
1054 if (ticket->level_min_request == 0) {
1056 ticket->level0_bits = ptd->map_array[0];
1057 ptd->map_array[0] = NULL;
1060 int size = TextureTileSize(0,
false);
1061 ticket->level0_bits = (
unsigned char *)malloc(size);
1062 memcpy(ticket->level0_bits, ptd->map_array[0], size);
1066 running_list.push_back(ticket);
1067 DoThreadJob(ticket);
1072bool glTextureManager::DoThreadJob(
JobTicket *pticket) {
1074 printf(
" Starting job: %08X Jobs running: %d Jobs left: %lu\n",
1075 pticket->ident, GetRunningJobCount(),
1076 (
unsigned long)todo_list.size());
1081 pticket->pthread = t;
1088bool glTextureManager::AsJob(wxString
const &chart_path)
const {
1089 if (chart_path.Len()) {
1090 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
1092 if (ticket->m_ChartPath.IsSameAs(chart_path)) {
1100void glTextureManager::PurgeJobList(wxString chart_path) {
1101 if (chart_path.Len()) {
1103 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
1105 if (ticket->m_ChartPath.IsSameAs(chart_path)) {
1107 printf(
"Pool: Purge pending job for purged chart\n");
1108 auto found = std::find(todo_list.begin(), todo_list.end(), ticket);
1109 if (found != todo_list.end()) todo_list.erase(found);
1114 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
1116 if (ticket->m_ChartPath.IsSameAs(chart_path)) {
1117 ticket->b_abort =
true;
1122 printf(
"Pool: Purge, todo count: %lu\n",
1123 (
long unsigned)todo_list.size());
1125 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
1131 for (
auto node = running_list.begin(); node != running_list.end(); ++node) {
1133 ticket->b_abort =
true;
1138void glTextureManager::ClearJobList() {
1139 for (
auto node = todo_list.begin(); node != todo_list.end(); ++node) {
1146void glTextureManager::ClearAllRasterTextures(
void) {
1148 ChartPathHashTexfactType::iterator itt;
1149 for (itt = m_chart_texfactory_hash.begin();
1150 itt != m_chart_texfactory_hash.end(); ++itt) {
1155 m_chart_texfactory_hash.clear();
1157 if (g_tex_mem_used != 0)
1158 wxLogMessage(
"Texture memory use calculation error\n");
1161bool glTextureManager::PurgeChartTextures(
ChartBase *pc,
bool b_purge_factory) {
1163 ChartPathHashTexfactType::iterator ittf =
1164 m_chart_texfactory_hash.find(pc->GetHashKey());
1167 if (ittf != m_chart_texfactory_hash.end()) {
1171 if (b_purge_factory) {
1172 m_chart_texfactory_hash.erase(ittf);
1179 m_chart_texfactory_hash.erase(ittf);
1186bool glTextureManager::TextureCrunch(
double factor) {
1187 double hysteresis = 0.90;
1191 (double)(g_GLOptions.m_iTextureMemorySize * 1024 * 1024) * factor;
1192 if (!bGLMemCrunch)
return false;
1194 ChartPathHashTexfactType::iterator it0;
1195 for (it0 = m_chart_texfactory_hash.begin();
1196 it0 != m_chart_texfactory_hash.end(); ++it0) {
1199 wxString chart_full_path = ptf->GetChartPath();
1201 bGLMemCrunch = g_tex_mem_used >
1202 (double)(g_GLOptions.m_iTextureMemorySize * 1024 * 1024) *
1203 factor * hysteresis;
1204 if (!bGLMemCrunch)
break;
1207 for (
unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
1210 if (cc->GetVP().b_quilt)
1212 if (cc->m_pQuilt && cc->m_pQuilt->IsComposed() &&
1213 !cc->m_pQuilt->IsChartInQuilt(chart_full_path)) {
1214 ptf->DeleteSomeTextures(g_GLOptions.m_iTextureMemorySize * 1024 *
1215 1024 * factor * hysteresis);
1219 if (!cc->m_singleChart->GetFullPath().IsSameAs(chart_full_path)) {
1220 ptf->DeleteSomeTextures(g_GLOptions.m_iTextureMemorySize * 1024 *
1221 1024 * factor * hysteresis);
1231#define MAX_CACHE_FACTORY 50
1232bool glTextureManager::FactoryCrunch(
double factor) {
1233 if (m_chart_texfactory_hash.size() == 0) {
1239 GetMemoryStatus(0, &mem_used);
1240 double hysteresis = 0.90;
1241 ChartPathHashTexfactType::iterator it0;
1245 ((mem_used > (double)(g_memCacheLimit)*factor * hysteresis &&
1246 mem_used > (double)(m_prevMemUsed)*factor * hysteresis) ||
1247 (m_chart_texfactory_hash.size() > MAX_CACHE_FACTORY)));
1249 if (!bMemCrunch)
return false;
1253 int lru_oldest = 2147483647;
1256 for (it0 = m_chart_texfactory_hash.begin();
1257 it0 != m_chart_texfactory_hash.end(); ++it0) {
1260 wxString chart_full_path = ptf->GetChartPath();
1266 for (
unsigned int i = 0; i < g_canvasArray.GetCount(); i++) {
1269 if (cc->GetVP().b_quilt)
1271 if (cc->m_pQuilt && cc->m_pQuilt->IsComposed() &&
1272 !cc->m_pQuilt->IsChartInQuilt(chart_full_path)) {
1273 int lru = ptf->GetLRUTime();
1274 if (lru < lru_oldest && !ptf->BackgroundCompressionAsJob()) {
1280 if (!cc->m_singleChart->GetFullPath().IsSameAs(chart_full_path)) {
1281 int lru = ptf->GetLRUTime();
1282 if (lru < lru_oldest && !ptf->BackgroundCompressionAsJob()) {
1293 if (!ptf_oldest)
return false;
1295 ptf_oldest->FreeSome(g_memCacheLimit * factor * hysteresis);
1297 GetMemoryStatus(0, &mem_used);
1299 bMemCrunch = (g_memCacheLimit &&
1300 ((mem_used > (double)(g_memCacheLimit)*factor * hysteresis &&
1301 mem_used > (double)(m_prevMemUsed)*factor * hysteresis) ||
1302 (m_chart_texfactory_hash.size() > MAX_CACHE_FACTORY)));
1304 if (!bMemCrunch)
return false;
1308 m_chart_texfactory_hash.erase(
1309 ptf_oldest->GetHashKey());
1316void glTextureManager::BuildCompressedCache() {
1317 idx_sorted_by_distance.Clear();
1325 for (
int i = 0; i <
ChartData->GetChartTableEntries(); i++) {
1328 ChartTypeEnum chart_type = (ChartTypeEnum)cte.GetChartType();
1329 if (chart_type == CHART_TYPE_PLUGIN) {
1330 if (cte.GetChartFamily() != CHART_FAMILY_RASTER)
continue;
1332 if (chart_type != CHART_TYPE_KAP)
continue;
1335 wxString CompressedCacheFilePath =
1336 CompressedCachePath(
ChartData->GetDBChartFileName(i));
1337 wxFileName fn(CompressedCacheFilePath);
1341 idx_sorted_by_distance.Add(i);
1346 if (count == 0)
return;
1348 wxLogMessage(wxString::Format(
"BuildCompressedCache() count = %d", count));
1352 if (GetRunningJobCount()) {
1353 wxLogMessage(
"Starting compressor pool drain");
1354 wxDateTime now = wxDateTime::Now();
1355 time_t stall = now.GetTicks();
1356#define THREAD_WAIT_SECONDS 5
1357 time_t end = stall + THREAD_WAIT_SECONDS;
1360 while (stall < end) {
1361 wxDateTime later = wxDateTime::Now();
1362 stall = later.GetTicks();
1365 msg.Printf(
"Time: %d Job Count: %d", n_comploop, GetRunningJobCount());
1367 if (!GetRunningJobCount())
break;
1373 fmsg.Printf(
"Finished compressor pool drain..Time: %d Job Count: %d",
1374 n_comploop, GetRunningJobCount());
1377 ClearAllRasterTextures();
1378 b_inCompressAllCharts =
true;
1384 ArrayOfCompressTargets ct_array;
1385 for (
unsigned int j = 0; j < idx_sorted_by_distance.GetCount(); j++) {
1386 int i = idx_sorted_by_distance[j];
1389 double distance = chart_dist(i);
1391 wxString filename = cte.GetFullSystemPath();
1394 pct->distance = distance;
1395 pct->chart_path = filename;
1401 long style = wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME |
1402 wxPD_REMAINING_TIME | wxPD_CAN_ABORT;
1412 "longgggggggggggggggggggggggggggggggggggggggggggg\ngggggggggggggggggg"
1413 "gggggggggggggggggggggggggg top line ";
1416 for (
int i = 0; i < m_max_jobs + 1; i++)
1419 m_progDialog =
new wxGenericProgressDialog();
1422 int fontSize = qFont->GetPointSize();
1424 wxSize csz = gFrame->GetClientSize();
1425 if (csz.x < 500 || csz.y < 500)
1427 10, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
1431 wxFONTWEIGHT_NORMAL);
1433 m_progDialog->SetFont(*sFont);
1438 sdc.GetTextExtent(
"[WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW]", &width, &height, NULL,
1440 if (width > (csz.x / 2)) m_bcompact =
true;
1442 m_progDialog->Create(_(
"OpenCPN Compressed Cache Update"), msg0, count + 1,
1446 m_progDialog->Hide();
1447 wxSize sz = m_progDialog->GetSize();
1448 sz.x = csz.x * 9 / 10;
1449 m_progDialog->SetSize(sz);
1451 m_progDialog->Layout();
1452 wxSize sza = m_progDialog->GetSize();
1454 m_progDialog->Centre();
1455 m_progDialog->Show();
1456 m_progDialog->Raise();
1462 for (m_jcnt = 0; m_jcnt < ct_array.GetCount(); m_jcnt++) {
1463 wxString filename = ct_array[m_jcnt].chart_path;
1464 wxString CompressedCacheFilePath = CompressedCachePath(filename);
1465 double distance = ct_array[m_jcnt].distance;
1475 if (pBSBChart == 0)
continue;
1479 m_progMsg.Printf(_(
"Distance from Ownship: %4.0f NMi"), distance);
1481 m_progMsg.Prepend(
"Preparing RNC Cache...\n");
1490 int size_X = pBSBChart->GetSize_X();
1491 int size_Y = pBSBChart->GetSize_Y();
1493 int tex_dim = g_GLOptions.m_iTextureDimension;
1495 int nx_tex = ceil((
float)size_X / tex_dim);
1496 int ny_tex = ceil((
float)size_Y / tex_dim);
1500 rect.width = tex_dim;
1501 rect.height = tex_dim;
1502 for (
int y = 0; y < ny_tex; y++) {
1504 for (
int x = 0; x < nx_tex; x++) {
1506 if (!tex_fact->IsLevelInCache(level, rect, global_color_scheme)) {
1510 rect.x += rect.width;
1512 rect.y += rect.height;
1522 if (!m_progDialog->Update(m_jcnt)) {
1533 ScheduleJob(tex_fact, wxRect(), 0,
false,
true,
true,
false);
1536 int cnt = GetJobCount() - GetRunningJobCount();
1549 while (GetRunningJobCount()) {
1554 b_inCompressAllCharts =
false;
1557 delete m_progDialog;
1558 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.
int g_mipmap_max_level
Global instance.
Miscellaneous globals primarely used by gui layer.
Represents an entry in the chart table, containing information about a single chart.
Runtime representation of a plugin block.