Skip to content

Commit

Permalink
Improve OpenGL texture memory management
Browse files Browse the repository at this point in the history
  • Loading branch information
David Register committed Jul 12, 2014
1 parent 5ef230f commit c28f3c5
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 83 deletions.
1 change: 1 addition & 0 deletions include/glTexCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class glTexFactory
wxString GetChartPath(){ return m_ChartPath; }
void DeleteTexture(const wxRect &rect);
void DeleteAllTextures( void );
void DeleteSomeTextures( long target );
void DeleteAllDescriptors( void );
void PurgeBackgroundCompressionPool();

Expand Down
4 changes: 3 additions & 1 deletion src/chart1.cpp
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -1032,6 +1032,7 @@ bool MyApp::OnInit()

// On MSW, force the entire process to run on one CPU core only
// This resolves some difficulty with wxThread syncronization
#if 0
#ifdef __WXMSW__
//Gets the current process handle
HANDLE hProc = GetCurrentProcess();
Expand Down Expand Up @@ -1060,6 +1061,7 @@ bool MyApp::OnInit()
//Error setting affinity mask!!
}
#endif
#endif

//Fulup: force floating point to use dot as separation.
// This needs to be set early to catch numerics in config file.
Expand Down Expand Up @@ -1221,7 +1223,7 @@ bool MyApp::OnInit()
wxString large_log_message;
if( ::wxFileExists( glog_file ) ) {
if( wxFileName::GetSize( glog_file ) > 1000000 ) {
wxString oldlog = glog_file; // pjotrc 2010.02.09
wxString oldlog = glog_file;
oldlog.Append( _T(".log") );
// Defer the showing of this messagebox until the system locale is established.
large_log_message = ( _("Old log will be moved to opencpn.log.log") );
Expand Down
23 changes: 15 additions & 8 deletions src/glChartCanvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ GLuint g_raster_format = GL_RGB;
long g_tex_mem_used;

int g_tile_size;
int g_uncompressed_tile_size;

wxProgressDialog *pprog;
bool b_skipout;
Expand Down Expand Up @@ -879,7 +880,7 @@ void glChartCanvas::SetupOpenGL()
void glChartCanvas::SetupCompression()
{
int dim = g_GLOptions.m_iTextureDimension;
int uncompressed_tile_size = dim*dim*3;
g_uncompressed_tile_size = dim*dim*3;
if(g_GLOptions.m_bTextureCompression) {
/* because s3tc is patented, many foss drivers disable
support by default, however the extension dxt1 allows
Expand Down Expand Up @@ -935,11 +936,11 @@ void glChartCanvas::SetupCompression()

wxLogMessage( wxString::Format( _T("OpenGL-> Compressed tile size: %dkb (%d:1)"),
g_tile_size / 1024,
uncompressed_tile_size / g_tile_size));
g_uncompressed_tile_size / g_tile_size));
} else
if(!g_GLOptions.m_bTextureCompression) {
no_compression:
g_tile_size = uncompressed_tile_size;
g_tile_size = g_uncompressed_tile_size;
g_raster_format = GL_RGB;
wxLogMessage( wxString::Format( _T("OpenGL-> Not Using compression")));
}
Expand Down Expand Up @@ -2197,9 +2198,15 @@ void glChartCanvas::RenderQuiltViewGL( ViewPort &vp, const OCPNRegion &Region, b
ChartBase *chart = cc1->m_pQuilt->GetFirstChart();

while( chart ) {
if( ! cc1->IsChartLargeEnoughToRender( chart, vp ) ) {
chart = cc1->m_pQuilt->GetNextChart();
continue;

// This test does not need to be done for raster charts, since
// we can assume that texture binding is acceptably fast regardless of the render region,
// and that the quilt zoom methods choose a reasonable reference chart.
if(chart->GetChartFamily() != CHART_FAMILY_RASTER){
if( ! cc1->IsChartLargeEnoughToRender( chart, vp ) ) {
chart = cc1->m_pQuilt->GetNextChart();
continue;
}
}

QuiltPatch *pqp = cc1->m_pQuilt->GetCurrentPatch();
Expand Down Expand Up @@ -2545,13 +2552,13 @@ void glChartCanvas::Render()
{
if( cc1->m_pQuilt && cc1->m_pQuilt->IsComposed() &&
!cc1->m_pQuilt->IsChartInQuilt( pc ) ) {
ptf->DeleteAllTextures();
ptf->DeleteSomeTextures( (g_GLOptions.m_iTextureMemorySize * 1024 * 1024 * 8) / 10);
}
}
else // not quilted
{
if( Current_Ch != pc ) {
ptf->DeleteAllTextures();
ptf->DeleteSomeTextures( (g_GLOptions.m_iTextureMemorySize * 1024 * 1024 * 8) / 10 );
}
}
}
Expand Down
141 changes: 69 additions & 72 deletions src/glTexCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ extern ocpnGLOptions g_GLOptions;
extern wxString g_PrivateDataDir;

extern int g_tile_size;
extern int g_uncompressed_tile_size;

class CompressionWorkerPool;
CompressionWorkerPool *g_CompressorPool;
Expand Down Expand Up @@ -639,21 +640,14 @@ bool CompressionWorkerPool::ScheduleJob(glTexFactory* client, const wxRect &rect
pt->m_raster_format = client->GetRasterFormat();
pt->m_ChartPath = client->GetChartPath();

/*
// Grab a copy of the level0 chart bits
unsigned char *t_buf = (unsigned char *) malloc( rect.width * rect.height * 4 );
wxRect ncrect(rect);
memcpy(t_buf, client->GetpTD( ncrect )->map_array[0], rect.width * rect.height * 4);
pt->level0_bits = t_buf;
*/

if(!b_immediate){
todo_list.Append(pt);
if(bthread_debug){
int mem_total, mem_used;
GetMemoryStatus(&mem_total, &mem_used);

printf( "Adding job: %08X Job Count: %d mem_used %d\n", pt->ident, todo_list.GetCount(), mem_used);
if(bthread_debug)
printf( "Adding job: %08X Job Count: %d mem_used %d\n", pt->ident, todo_list.GetCount(), mem_used);
}

StartTopJob();
Expand Down Expand Up @@ -889,14 +883,37 @@ void glTexFactory::DeleteAllTextures( void )
glTextureDescriptor *ptd = m_td_array[i] ;

if( ptd ) {
if(bthread_debug)
printf("Delete Texture %d resulting g_tex_mem_used, mb: %ld\n", ptd->tex_name, g_tex_mem_used/(1024 * 1024));
if(ptd->tex_name && bthread_debug)
printf("DAT::Delete Texture %d resulting g_tex_mem_used, mb: %ld\n", ptd->tex_name, g_tex_mem_used/(1024 * 1024));

DeleteSingleTexture( ptd);
}
}
}


void glTexFactory::DeleteSomeTextures( long target )
{
// iterate over all the textures presently loaded
// and delete the OpenGL texture from the GPU
// until the target g_tex_mem_used is reached
// but keep the private texture descriptor for now

for(int i=0 ; i < m_ntex ; i++){
glTextureDescriptor *ptd = m_td_array[i] ;

if( ptd ) {
if(ptd->tex_name && bthread_debug)
printf("DST::Delete Texture %d resulting g_tex_mem_used, mb: %ld\n", ptd->tex_name, g_tex_mem_used/(1024 * 1024));

DeleteSingleTexture( ptd);
}

if(g_tex_mem_used <= target)
break;
}
}

void glTexFactory::DeleteAllDescriptors( void )
{
// iterate over all the texture descriptors
Expand Down Expand Up @@ -924,7 +941,9 @@ void glTexFactory::DeleteSingleTexture( glTextureDescriptor *ptd )
{
/* compute space saved */
int dim = g_GLOptions.m_iTextureDimension;
int size = g_tile_size, orig_min = ptd->level_min;
int size = g_tile_size;
if( ptd->nGPU_compressed == GPU_TEXTURE_UNCOMPRESSED)
size = g_uncompressed_tile_size;

for(int level = 0; level < g_mipmap_max_level + 1; level++) {
if(level == ptd->level_min) {
Expand Down Expand Up @@ -1039,23 +1058,7 @@ void glTexFactory::PrepareTexture( int base_level, const wxRect &rect, ColorSche
ptd = p;
}

// If the GPU does not know about this texture, create it
if( ptd->tex_name == 0 ) {
glGenTextures( 1, &ptd->tex_name );

glBindTexture( GL_TEXTURE_2D, ptd->tex_name );

glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

#ifdef ocpnUSE_GLES /* this is slightly faster */
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
#else /* looks nicer */
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
#endif
}


#ifdef ocpnUSE_GLES /* gles requires a complete set of mipmaps starting at 0 */
base_level = 0;
#endif
Expand Down Expand Up @@ -1104,9 +1107,11 @@ void glTexFactory::PrepareTexture( int base_level, const wxRect &rect, ColorSche
// So, free some unneeded uncompressed mipmaps, and prepare the TD for compressed use.
if(b_all_cmm_built){
if(bthread_debug)
printf("Convert Texture %X resulting g_tex_mem_used, mb: %ld\n", ptd->tex_name, g_tex_mem_used/(1024 * 1024));
printf("Convert Texture %04X resulting g_tex_mem_used, mb: %ld\n", ptd->tex_name, g_tex_mem_used/(1024 * 1024));

ptd->FreeMap();

// Delete and rebuild the actual GPU texture
DeleteSingleTexture(ptd);

// We know that the compressed mipmaps are now available, so...
Expand All @@ -1132,7 +1137,23 @@ void glTexFactory::PrepareTexture( int base_level, const wxRect &rect, ColorSche
}


// If the GPU does not know about this texture, create it
if( ptd->tex_name == 0 ) {
glGenTextures( 1, &ptd->tex_name );

glBindTexture( GL_TEXTURE_2D, ptd->tex_name );

glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

#ifdef ocpnUSE_GLES /* this is slightly faster */
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
#else /* looks nicer */
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
#endif
}




Expand All @@ -1149,7 +1170,8 @@ void glTexFactory::PrepareTexture( int base_level, const wxRect &rect, ColorSche

int dim = g_GLOptions.m_iTextureDimension;
int size = g_tile_size;

int uncompressed_size = g_uncompressed_tile_size;


/* optimization: when supported generate uncompressed mipmaps
with hardware acceleration */
Expand Down Expand Up @@ -1182,25 +1204,34 @@ void glTexFactory::PrepareTexture( int base_level, const wxRect &rect, ColorSche
s_glCompressedTexImage2D( GL_TEXTURE_2D, level, g_raster_format,
dim, dim, 0, size,
ptd->CompressedArrayAccess( CA_READ, NULL, level));
g_tex_mem_used += size;

}
else {
if(bthread_debug)
printf("Upload Un-Compressed Texture %d level: %d g_tex_mem_used: %ld\n", ptd->tex_name, level, g_tex_mem_used/(1024*1024));
ptd->nGPU_compressed = GPU_TEXTURE_UNCOMPRESSED;
glTexImage2D( GL_TEXTURE_2D, level, GL_RGB,
dim, dim, 0, FORMAT_BITS, GL_UNSIGNED_BYTE, ptd->map_array[level] );

g_tex_mem_used += uncompressed_size;

// his level has not been compressed yet, and is not in the cache
// So, need to start a compression job
b_need_compress = true;
}

}
else {
if(bthread_debug)
printf("Upload Un-Compressed Texture %d level: %d g_tex_mem_used: %ld\n", ptd->tex_name, level, g_tex_mem_used/(1024*1024));
ptd->nGPU_compressed = GPU_TEXTURE_UNCOMPRESSED;
glTexImage2D( GL_TEXTURE_2D, level, g_raster_format,
dim, dim, 0, FORMAT_BITS, GL_UNSIGNED_BYTE, ptd->map_array[level] );
g_tex_mem_used += uncompressed_size;

}

g_tex_mem_used += size;
}

if( hw_mipmap && (ptd->nGPU_compressed == GPU_TEXTURE_UNCOMPRESSED) ) {
Expand All @@ -1209,12 +1240,12 @@ void glTexFactory::PrepareTexture( int base_level, const wxRect &rect, ColorSche
// Use OGL driver to generate the rest of the mipmaps, and then break the loop
/* compute memory used for mipmaps */
dim /= 2;
size /= 4;
uncompressed_size /= 4;

for(int slevel = base_level + 1; slevel < g_mipmap_max_level+1; slevel++ ) {
g_tex_mem_used += size;
g_tex_mem_used += uncompressed_size;
dim /= 2;
size /= 4;
uncompressed_size /= 4;
}


Expand All @@ -1233,8 +1264,9 @@ void glTexFactory::PrepareTexture( int base_level, const wxRect &rect, ColorSche

dim /= 2;
size /= 4;
if(size < 8)
size = 8;
if(size < 8) size = 8;
uncompressed_size /= 4;

}


Expand Down Expand Up @@ -1424,41 +1456,6 @@ int glTexFactory::GetTextureLevel( glTextureDescriptor *ptd, const wxRect &rect,
return COMPRESSED_BUFFER_PENDING;


}
else {
#if 0
// We are using the OpenGL driver to do the compression
// Use a temporary texture to do the work so that it can be safely deleted and memory recovered

GLuint temp_tex_name;
glGenTextures( 1, &temp_tex_name );
glBindTexture( GL_TEXTURE_2D, temp_tex_name );

glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

#ifdef ocpnUSE_GLES /* this is slightly faster */
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
#else /* looks nicer */
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
#endif

glTexImage2D( GL_TEXTURE_2D, level, m_raster_format,
dim, dim, 0, FORMAT_BITS, GL_UNSIGNED_BYTE, ptd->map_array[level] );

// Now read it back
unsigned char *cb = (unsigned char*)malloc(size);
ptd->CompressedArrayAccess( CA_WRITE, cb, level);
// ptd->comp_array[ level ] = (unsigned char*)malloc(size);
s_glGetCompressedTexImage(GL_TEXTURE_2D, level, cb);

glDeleteTextures( 1, &temp_tex_name );

// Re-Bind the method target texture
glBindTexture( GL_TEXTURE_2D, ptd->tex_name );
#endif

}

return COMPRESSED_BUFFER_OK;
Expand Down
9 changes: 7 additions & 2 deletions src/texcmp/squish/squish.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,13 @@ void CompressImageRGB_Flatten_Flip_Throttle( u8 const* rgb, int width, int heigh
// advance
targetBlock += bytesPerBlock;
}
if( b_throttle && !wxThread::IsMain() )
wxThread::Sleep(1);
if( b_throttle && !wxThread::IsMain() ) {
// Sleep a random time, 0-5 msec.
// This gives most of the processing to the main GUI thread
long u = (long)floor(((double)rand() / ((double)(RAND_MAX) + 1) * 5) + 0.5);

wxThread::Sleep((int)u);
}
}
}

Expand Down

0 comments on commit c28f3c5

Please sign in to comment.