* include/freetype/cache/ftccache.h, src/cache/ftccache.c,

src/cache/ftccache.i, src/cache/ftcsbits.c: adding various
          experimental optimisations to the cache manager

        * src/type42/t42parse.c: removing duplicate function
This commit is contained in:
David Turner 2002-06-07 20:07:44 +00:00
parent 7504e48eaa
commit 08b7ad4418
5 changed files with 344 additions and 130 deletions

View File

@ -1,5 +1,11 @@
2002-06-07 Graham Asher <graham.asher@btinternet.com>
* include/freetype/cache/ftccache.h, src/cache/ftccache.c,
src/cache/ftccache.i, src/cache/ftcsbits.c: adding various
experimental optimisations to the cache manager
* src/type42/t42parse.c: removing duplicate function
* src/base/ftobjs.c (FT_Render_Glyph_Internal): changed definition
from FT_EXPORT_DEF to FT_BASE_DEF

View File

@ -20,6 +20,12 @@
#define __FTCCACHE_H__
/* define to allow cache lookup inlining */
#undef FTC_CACHE_USE_INLINE
/* define to use linear hash table */
#undef FTC_CACHE_USE_LINEAR_HASHING
FT_BEGIN_HEADER
/* handle to cache object */
@ -174,8 +180,14 @@ FT_BEGIN_HEADER
FT_UInt cache_index; /* in manager's table */
FT_Pointer cache_data; /* used by cache node methods */
#ifdef FTC_CACHE_USE_LINEAR_HASHING
FT_UFast p;
FT_UFast mask;
FT_Long slack;
#else
FT_UFast nodes;
FT_UFast size;
#endif
FTC_Node* buckets;
FT_LruList_ClassRec family_class;
@ -290,7 +302,6 @@ FT_BEGIN_HEADER
/* */
FT_END_HEADER

313
src/cache/ftccache.c vendored
View File

@ -23,6 +23,21 @@
#include "ftcerror.h"
/* define for level-1 optimisations */
#undef OPT1
#ifdef FTC_CACHE_USE_LINEAR_HASHING
#define FTC_HASH_MAX_LOAD 2
#define FTC_HASH_MIN_LOAD 1
#define FTC_HASH_SUB_LOAD (FTC_HASH_MAX_LOAD-FTC_HASH_MIN_LOAD)
/* this one _must_ be a power of 2 !! */
#define FTC_HASH_INITIAL_SIZE 8
#endif /* FTC_CACHE_USE_LINEAR_HASHING */
/*************************************************************************/
/*************************************************************************/
@ -59,11 +74,13 @@
if ( first )
{
node->mru_prev = first->mru_prev;
FTC_Node last = first->mru_prev;
node->mru_prev = last;
node->mru_next = first;
first->mru_prev->mru_next = node;
first->mru_prev = node;
last->mru_next = node;
first->mru_prev = node;
}
else
{
@ -114,12 +131,104 @@
if ( node != first )
{
ftc_node_mru_unlink( node, manager );
ftc_node_mru_link( node, manager );
FTC_Node prev = node->mru_prev;
FTC_Node next = node->mru_next;
FTC_Node last = first->mru_prev;
prev->mru_next = next;
next->mru_prev = prev;
node->mru_next = first;
node->mru_prev = last;
first->mru_prev = node;
last->mru_next = node;
manager->nodes_list = node;
}
}
#ifdef FTC_CACHE_USE_LINEAR_HASHING
/* remove a node from its cache's hash table */
static FT_Error
ftc_node_hash_unlink( FTC_Node node,
FTC_Cache cache )
{
FT_Error error = 0;
FTC_Node *pnode;
FT_UInt index, num_buckets;
index = (FT_UInt)( node->hash & cache->mask );
if ( index < cache->p )
index = (FT_UInt)( node->hash & (2*cache->mask+1) );
pnode = cache->buckets + index;
for (;;)
{
if ( *pnode == NULL )
{
FT_ERROR(( "FreeType.cache.hash_unlink: unknown node!\n" ));
return 0;
}
if ( *pnode == node )
{
*pnode = node->link;
node->link = NULL;
break;
}
pnode = &(*pnode)->link;
}
num_buckets = ( cache->p + cache->mask + 1) ;
if ( ++ cache->slack > (FT_Long)num_buckets*FTC_HASH_SUB_LOAD )
{
FT_UInt p = cache->p;
FT_UInt mask = cache->mask;
FT_UInt old_index = p + mask;
FTC_Node* pold;
FT_ASSERT( old_index >= FTC_HASH_INITIAL_SIZE );
if ( p == 0 )
{
FT_Memory memory = cache->memory;
cache->mask >>= 1;
p = cache->mask;
if ( FT_RENEW_ARRAY( cache->buckets, (mask+1)*2, (mask) ) )
{
FT_ERROR(( "FreeType.cache.hash_unlink: couldn't shunk buckets !\n" ));
goto Exit;
}
}
else
p--;
pnode = cache->buckets + p;
while ( *pnode )
pnode = &(*pnode)->link;
pold = cache->buckets + old_index;
*pnode = *pold;
*pold = NULL;
cache->slack -= FTC_HASH_MAX_LOAD;
cache->p = p;
}
Exit:
return error;
}
#else /* !FTC_CACHE_USE_LINEAR_HASHING */
/* remove a node from its cache's hash table */
static void
ftc_node_hash_unlink( FTC_Node node,
@ -127,7 +236,6 @@
{
FTC_Node *pnode = cache->buckets + ( node->hash % cache->size );
for (;;)
{
if ( *pnode == NULL )
@ -149,6 +257,81 @@
}
}
#endif /* !FTC_CACHE_USE_LINEAR_HASHING */
#ifdef FTC_CACHE_USE_LINEAR_HASHING
/* add a node to the "top" of its cache's hash table */
static FT_Error
ftc_node_hash_link( FTC_Node node,
FTC_Cache cache )
{
FTC_Node *pnode;
FT_UInt index;
FT_Error error = 0;
index = (FT_UInt)( node->hash & cache->mask );
if ( index < cache->p )
index = (FT_UInt)( node->hash & (2*cache->mask+1) );
pnode = cache->buckets + index;
node->link = *pnode;
*pnode = node;
if ( --cache->slack < 0 )
{
FT_UInt p = cache->p;
FT_UInt mask = cache->mask;
FTC_Node new_list;
/* split a single bucket */
new_list = NULL;
pnode = cache->buckets + p;
for (;;)
{
node = *pnode;
if ( node == NULL )
break;
if ( node->hash & (mask+1) )
{
*pnode = node->link;
node->link = new_list;
new_list = node;
}
else
pnode = &node->link;
}
cache->buckets[ p + mask + 1 ] = new_list;
cache->slack += FTC_HASH_MAX_LOAD;
if ( p >= mask )
{
FT_Memory memory = cache->memory;
if ( FT_RENEW_ARRAY( cache->buckets, (mask+1)*2, (mask+1)*4 ) )
{
FT_ERROR(( "FreeType.cache.hash_unlink: couldn't expand buckets !\n" ));
goto Exit;
}
cache->mask = 2*mask + 1;
cache->p = 0;
}
else
cache->p = p + 1;
}
Exit:
return error;
}
#else /* !FTC_CACHE_USE_LINEAR_HASHING */
/* add a node to the "top" of its cache's hash table */
static void
@ -157,13 +340,15 @@
{
FTC_Node *pnode = cache->buckets + ( node->hash % cache->size );
node->link = *pnode;
*pnode = node;
cache->nodes++;
}
#endif /* !FTC_CACHE_USE_LINEAR_HASHING */
/* remove a node from the cache manager */
FT_EXPORT_DEF( void )
@ -276,6 +461,11 @@
/*************************************************************************/
/*************************************************************************/
#ifdef FTC_CACHE_USE_LINEAR_HASHING
#else /* !FTC_CACHE_USE_LINEAR_HASHING */
#define FTC_PRIMES_MIN 7
#define FTC_PRIMES_MAX 13845163
@ -388,6 +578,7 @@
}
}
#endif /* !FTC_CACHE_USE_LINEAR_HASHING */
FT_EXPORT_DEF( FT_Error )
ftc_cache_init( FTC_Cache cache )
@ -397,12 +588,24 @@
FT_Error error;
#ifdef FTC_CACHE_USE_LINEAR_HASHING
cache->p = 0;
cache->mask = FTC_HASH_INITIAL_SIZE-1;
cache->slack = FTC_HASH_INITIAL_SIZE*FTC_HASH_MAX_LOAD;
if ( FT_NEW_ARRAY( cache->buckets, FTC_HASH_INITIAL_SIZE*2 ) )
goto Exit;
#else /* !FTC_CACHE_USE_LINEAR_HASHING */
cache->nodes = 0;
cache->size = FTC_PRIMES_MIN;
if ( FT_NEW_ARRAY( cache->buckets, cache->size ) )
goto Exit;
#endif /* !FTC_CACHE_USE_LINEAR_HASHING */
/* now, initialize the lru list of families for this cache */
if ( clazz->family_size > 0 )
{
@ -442,9 +645,15 @@
FTC_Cache_Class clazz = cache->clazz;
FTC_Manager manager = cache->manager;
FT_UFast i;
FT_UInt count;
#ifdef FTC_CACHE_USE_LINEAR_HASHING
count = cache->p + cache->mask + 1;
#else
count = cache->size;
#endif
for ( i = 0; i < cache->size; i++ )
for ( i = 0; i < count; i++ )
{
FTC_Node *pnode = cache->buckets + i, next, node = *pnode;
@ -469,8 +678,11 @@
cache->buckets[i] = NULL;
}
#ifdef FTC_CACHE_USE_LINEAR_HASHING
cache->p = 0;
#else
cache->nodes = 0;
#endif
/* destroy the families */
if ( cache->families )
FT_LruList_Reset( cache->families );
@ -489,7 +701,12 @@
ftc_cache_clear( cache );
FT_FREE( cache->buckets );
#ifdef FTC_CACHE_USE_LINEAR_HASHING
cache->mask = 0;
cache->slack = 0;
#else
cache->size = 0;
#endif
if ( cache->families )
{
@ -508,7 +725,7 @@
FTC_Query query,
FTC_Node *anode )
{
FT_Error error;
FT_Error error = 0;
FT_LruNode lru;
@ -520,12 +737,67 @@
query->hash = 0;
query->family = NULL;
#ifdef OPT1
{
/* first of all, find the relevant family */
FT_LruList list = cache->families;
FT_LruNode fam, *pfam;
FT_LruNode_CompareFunc compare = list->clazz->node_compare;
pfam = &list->nodes;
for (;;)
{
fam = *pfam;
if ( fam == NULL )
{
error = FT_LruList_Lookup( list, query, &lru );
if ( error )
goto Exit;
goto Skip;
}
if ( compare( fam, query, list->data ) )
break;
pfam = &fam->next;
}
FT_ASSERT( fam != NULL );
/* move to top of list when needed */
if ( fam != list->nodes )
{
*pfam = fam->next;
fam->next = list->nodes;
list->nodes = fam;
}
lru = fam;
Skip:
}
#else
error = FT_LruList_Lookup( cache->families, query, &lru );
if ( !error )
#endif
{
FTC_Family family = (FTC_Family) lru;
FT_UFast hash = query->hash;
FTC_Node* bucket = cache->buckets + (hash % cache->size);
FTC_Node* bucket;
#ifdef FTC_CACHE_USE_LINEAR_HASHING
FT_UInt index;
index = hash & cache->mask;
if ( index < cache->p )
index = hash & (cache->mask*2+1);
bucket = cache->buckets + index;
#else
bucket = cache->buckets + (hash % cache->size);
#endif
if ( query->family != family ||
@ -551,8 +823,14 @@
if ( node == NULL )
break;
#ifdef OPT1
if ( node->hash == hash &&
(FT_UInt)node->fam_index == family->fam_index &&
compare( node, query, cache ) )
#else
if ( (FT_UInt)node->fam_index == family->fam_index &&
compare( node, query, cache ) )
#endif
{
/* move to head of bucket list */
if ( pnode != bucket )
@ -596,7 +874,18 @@
goto Exit;
}
#ifdef FTC_CACHE_USE_LINEAR_HASHING
error = ftc_node_hash_link( node, cache );
if ( error )
{
clazz->node_done( node, cache );
FT_FREE( node );
goto Exit;
}
#else
ftc_node_hash_link( node, cache );
#endif
ftc_node_mru_link( node, cache->manager );
cache->manager->cur_weight += clazz->node_weight( node, cache );
@ -609,9 +898,11 @@
node->ref_count--;
}
#ifndef FTC_CACHE_USE_LINEAR_HASHING
/* try to resize the hash table if appropriate */
if ( FTC_CACHE_RESIZE_TEST( cache ) )
ftc_cache_resize( cache );
#endif
*anode = node;
}

31
src/cache/ftcsbits.c vendored
View File

@ -63,8 +63,8 @@
FTC_ImageDesc desc;
} FTC_SBitFamilyRec;
#define FTC_SBIT_FAMILY( x ) ( (FTC_SBitFamily)( x ) )
#define FTC_SBIT_FAMILY_MEMORY( x ) FTC_GLYPH_FAMILY_MEMORY( &( x )->cset )
@ -462,6 +462,23 @@
/* documentation is in ftcsbits.h */
#ifdef FTC_CACHE_USE_INLINE
# define GEN_CACHE_FAMILY_COMPARE(f,q,c) \
ftc_sbit_family_compare( (FTC_SBitFamily)(f), (FTC_SBitQuery)(q) )
# define GEN_CACHE_NODE_COMPARE(n,q,c) \
ftc_sbit_node_compare( (FTC_SBitNode)(n), (FTC_SBitQuery)(q), c )
# define GEN_CACHE_LOOKUP ftc_sbit_cache_lookup
# include "ftccache.i"
#else /* !FTC_CACHE_USE_INLINE */
# define ftc_sbit_cache_lookup ftc_cache_lookup
#endif /* !FTC_CACHE_USE_INLINE */
FT_EXPORT_DEF( FT_Error )
FTC_SBitCache_Lookup( FTC_SBitCache cache,
FTC_ImageDesc* desc,
@ -486,9 +503,9 @@
squery.gquery.gindex = gindex;
squery.desc = *desc;
error = ftc_cache_lookup( FTC_CACHE( cache ),
FTC_QUERY( &squery ),
(FTC_Node*)&node );
error = ftc_sbit_cache_lookup( FTC_CACHE( cache ),
FTC_QUERY( &squery ),
(FTC_Node*)&node );
if ( !error )
{
*ansbit = node->sbits + ( gindex - FTC_GLYPH_NODE( node )->item_start );
@ -520,11 +537,11 @@
FTC_SBit *ansbit )
{
FTC_ImageDesc desc0;
if ( !desc )
return FTC_Err_Invalid_Argument;
desc0.font = desc->font;
desc0.type = (FT_UInt32)desc->image_type;

View File

@ -970,114 +970,3 @@
}
FT_LOCAL_DEF( FT_Error )
T42_Open_Face( T42_Face face )
{
T42_LoaderRec loader;
T42_Parser parser;
T1_Font type1 = &face->type1;
FT_Memory memory = face->root.memory;
FT_Error error;
PSAux_Service psaux = (PSAux_Service)face->psaux;
t42_loader_init( &loader, face );
parser = &loader.parser;
if ( FT_ALLOC( face->ttf_data, 12 ) )
goto Exit;
error = t42_parser_init( parser,
face->root.stream,
memory,
psaux);
if ( error )
goto Exit;
error = t42_parse_dict( face, &loader, parser->base_dict, parser->base_len );
if ( type1->font_type != 42 )
{
error = FT_Err_Unknown_File_Format;
goto Exit;
}
/* now, propagate the charstrings and glyphnames tables */
/* to the Type1 data */
type1->num_glyphs = loader.num_glyphs;
if ( !loader.charstrings.init ) {
FT_ERROR(( "T42_Open_Face: no charstrings array in face!\n" ));
error = FT_Err_Invalid_File_Format;
}
loader.charstrings.init = 0;
type1->charstrings_block = loader.charstrings.block;
type1->charstrings = loader.charstrings.elements;
type1->charstrings_len = loader.charstrings.lengths;
/* we copy the glyph names `block' and `elements' fields; */
/* the `lengths' field must be released later */
type1->glyph_names_block = loader.glyph_names.block;
type1->glyph_names = (FT_String**)loader.glyph_names.elements;
loader.glyph_names.block = 0;
loader.glyph_names.elements = 0;
/* we must now build type1.encoding when we have a custom array */
if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY )
{
FT_Int charcode, idx, min_char, max_char;
FT_Byte* char_name;
FT_Byte* glyph_name;
/* OK, we do the following: for each element in the encoding */
/* table, look up the index of the glyph having the same name */
/* as defined in the CharStrings array. */
/* The index is then stored in type1.encoding.char_index, and */
/* the name in type1.encoding.char_name */
min_char = +32000;
max_char = -32000;
charcode = 0;
for ( ; charcode < loader.encoding_table.max_elems; charcode++ )
{
type1->encoding.char_index[charcode] = 0;
type1->encoding.char_name [charcode] = (char *)".notdef";
char_name = loader.encoding_table.elements[charcode];
if ( char_name )
for ( idx = 0; idx < type1->num_glyphs; idx++ )
{
glyph_name = (FT_Byte*)type1->glyph_names[idx];
if ( ft_strcmp( (const char*)char_name,
(const char*)glyph_name ) == 0 )
{
type1->encoding.char_index[charcode] = (FT_UShort)idx;
type1->encoding.char_name [charcode] = (char*)glyph_name;
/* Change min/max encoded char only if glyph name is */
/* not /.notdef */
if ( ft_strcmp( (const char*)".notdef",
(const char*)glyph_name ) != 0 )
{
if ( charcode < min_char ) min_char = charcode;
if ( charcode > max_char ) max_char = charcode;
}
break;
}
}
}
type1->encoding.code_first = min_char;
type1->encoding.code_last = max_char;
type1->encoding.num_chars = loader.num_chars;
}
Exit:
t42_loader_done( &loader );
return error;
}