From 548bd3cf6218b3857ec63abcbeaa3605a5c56347 Mon Sep 17 00:00:00 2001 From: Anuj Verma Date: Sun, 12 Jul 2020 08:12:24 +0530 Subject: [PATCH] [sdf] Optimize the coarse grid optimization. * src/sdf/ftsdf.c (sdf_generate_coarse_grid): Merge the relevant edge finding loop and shortest dist- ance search loop. We can find the relevant edges of a coarse grid and immediately use them to find the shortest distance of the points in the coarse grid. This drastically reduce memory usage and performance. Also, do the sign assignment of the edges which was missing. --- [GSoC]ChangeLog | 14 ++++++++ src/sdf/ftsdf.c | 91 ++++++++++++++++++++++++------------------------- 2 files changed, 58 insertions(+), 47 deletions(-) diff --git a/[GSoC]ChangeLog b/[GSoC]ChangeLog index ae1fee174..cc9de5962 100644 --- a/[GSoC]ChangeLog +++ b/[GSoC]ChangeLog @@ -1,3 +1,17 @@ +2020-07-12 Anuj Verma + + [sdf] Optimize the coarse grid optimization. + + * src/sdf/ftsdf.c (sdf_generate_coarse_grid): Merge + the relevant edge finding loop and shortest dist- + ance search loop. We can find the relevant edges + of a coarse grid and immediately use them to find + the shortest distance of the points in the coarse + grid. This drastically reduce memory usage and + performance. + Also, do the sign assignment of the edges which was + missing. + 2020-07-11 Anuj Verma * src/sdf/ftsdf.c (*): Fixed warnings. diff --git a/src/sdf/ftsdf.c b/src/sdf/ftsdf.c index ab3aa08eb..458e74597 100644 --- a/src/sdf/ftsdf.c +++ b/src/sdf/ftsdf.c @@ -2754,14 +2754,11 @@ FT_UInt c_width, c_rows; /* coarse grid dimensions */ FT_16D16 sp_sq; /* max value to check */ FT_16D16 cg_sq; /* max value to check for coarse grid */ - FT_16D16 cg_max; + FT_16D16 cg_diagon; SDF_Contour* contours; /* list of all contours */ FT_Short* buffer; /* the bitmap buffer */ - /* coarse grid to hold the list of edges */ - SDF_Edge* coarse_grid[ CG_DIMEN * CG_DIMEN ]; - if ( !shape || !bitmap ) { error = FT_THROW( Invalid_Argument ); @@ -2794,19 +2791,20 @@ c_width = width / CG_DIMEN + ( width % CG_DIMEN == 0 ? 0 : 1 ); c_rows = rows / CG_DIMEN + ( rows % CG_DIMEN == 0 ? 0 : 1 ); - cg_max = c_width > c_rows ? c_width : c_rows; + cg_diagon = FT_INT_16D16( c_width * c_width ) + + FT_INT_16D16( c_rows * c_rows ); /* `cg_sq' is the max value for which we add an edge */ /* to the coarse grid list. */ if ( USE_SQUARED_DISTANCES ) { sp_sq = FT_INT_16D16( spread * spread ); - cg_sq = sp_sq + FT_INT_16D16( cg_max * cg_max ) / 4; + cg_sq = sp_sq + cg_diagon; } else { sp_sq = FT_INT_16D16( spread ); - cg_sq = sp_sq + FT_INT_16D16( cg_max / 2 ); + cg_sq = sp_sq + square_root( cg_diagon ); } /* if the coarse grid is too small then simply */ @@ -2826,10 +2824,15 @@ FT_Int cindex = j * CG_DIMEN + i; SDF_Contour* cont = contours; SDF_Edge* edge; + SDF_Edge* relevant_list; FT_26D6_Vec cpoint; + FT_BBox sample_region; + FT_Int x, y; + + SDF_Signed_Distance min_cg_dist = max_sdf; - coarse_grid[cindex] = NULL; + relevant_list = NULL; /* we check from the center of the coarse grid */ cpoint.x = FT_INT_26D6( i * c_width ) + FT_INT_26D6( c_width / 2 ); @@ -2855,32 +2858,25 @@ FT_CALL( sdf_edge_new( memory, &temp ) ); ft_memcpy( temp, edge, sizeof( *edge ) ); - temp->next = coarse_grid[cindex]; - coarse_grid[cindex] = temp; + temp->next = relevant_list; + relevant_list = temp; } + if ( dist.distance < min_cg_dist.distance ) + min_cg_dist = dist; + else if ( FT_ABS( dist.distance - min_cg_dist.distance ) < + CORNER_CHECK_EPSILON ) + min_cg_dist = resolve_corner( min_cg_dist, dist ); + edge = edge->next; } cont = cont->next; } - } - } - /* Now that we have the list of edges relevant for the pixels */ - /* inside a coarse grid, we only need to check those pixels */ - /* against the list of edges. */ - - /* again loop through the coarse grid */ - for ( j = 0; j < CG_DIMEN; j++ ) - { - for ( i = 0; i < CG_DIMEN; i++ ) - { - FT_BBox sample_region; - FT_Int x, y; - - - if ( !coarse_grid[j * CG_DIMEN + i] ) continue; + /* Now that we have the list of edges relevant for the pixels */ + /* inside a coarse grid, we only need to check those pixels */ + /* against the list of edges. */ /* this gives the pixels inside the coarse grid */ sample_region.xMin = i * c_width; @@ -2888,7 +2884,6 @@ sample_region.yMin = j * c_rows; sample_region.yMax = sample_region.yMin + c_rows; - /* for all the pixes inside the coarse grid */ for ( y = sample_region.yMin; y < sample_region.yMax; y++ ) { @@ -2896,12 +2891,20 @@ { FT_26D6_Vec current_pos; SDF_Signed_Distance min_dist = max_sdf; - SDF_Edge* edges = coarse_grid[j * CG_DIMEN + i]; + SDF_Edge* edges = relevant_list; + FT_Int index = ( rows - y - 1 ) * width + x; if ( x < 0 || x >= width ) continue; if ( y < 0 || y >= rows ) continue; + /* If there is no relevant edge for the */ + /* coarse grid then it's fare than the */ + /* `spread'. In that case simply assign */ + /* `min_dist' = `min_cg_dist'. */ + if ( !relevant_list ) + min_dist = min_cg_dist; + /* we check from the center of a pixel */ current_pos.x = FT_INT_26D6( x ) + FT_INT_26D6( 1 ) / 2; current_pos.y = FT_INT_26D6( y ) + FT_INT_26D6( 1 ) / 2; @@ -2917,6 +2920,9 @@ if ( dist.distance < min_dist.distance ) min_dist = dist; + else if ( FT_ABS( dist.distance - min_dist.distance ) < + CORNER_CHECK_EPSILON ) + min_dist = resolve_corner( min_dist, dist ); edges = edges->next; } @@ -2930,31 +2936,22 @@ min_dist.distance /= 64; - buffer[( rows - y - 1 ) * width + x] = (FT_Short)min_dist.distance; + buffer[index] = (FT_Short)min_dist.distance * min_dist.sign; } } + + /* release the allocated lists */ + while ( relevant_list ) + { + edge = relevant_list; + relevant_list = relevant_list->next; + + sdf_edge_done( memory, &edge ); + } } } - /* release the allocated lists */ - for ( i = 0; i < CG_DIMEN * CG_DIMEN; i++ ) - { - SDF_Edge* edge = coarse_grid[i]; - SDF_Edge* temp; - - - while ( edge ) - { - temp = edge; - edge = edge->next; - - sdf_edge_done( memory, &temp ); - } - - coarse_grid[i] = NULL; - } - Exit: return error; }