freetype-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Git][freetype/freetype][master] [truetype] Reduce heap allocation of `d


From: Werner Lemberg (@wl)
Subject: [Git][freetype/freetype][master] [truetype] Reduce heap allocation of `deltaSet` variation data.
Date: Fri, 19 May 2023 04:52:39 +0000

Werner Lemberg pushed to branch master at FreeType / FreeType

Commits:

  • 115e9275
    by Seigo Nonaka at 2023-05-19T06:50:28+02:00
    [truetype] Reduce heap allocation of `deltaSet` variation data.
    
    `deltaSet` is an array of packed integers that can be 32 bits, 16 bits, or
    8 bits.  Before this change, these values were unpacked to 32-bit integers.
    However, this can cause big heap allocations, e.g., around 500 KByte for
    'NotoSansCJK'.  To reduce this amount, store the packed integers and unpack
    them just before passing to the calculation.  At calculation time, due to
    the variable length of region indices, temporary heap allocations are
    necessary.  This heap allocation is not negligible and visible in `ftbench`
    results.  So, use stack-allocated arrays for short array calculations.
    
    Fixes #1230.
    
    * include/freetype/internal/ftmmtypes.h (GX_ItemVarDataRec): New fields
    `wordDeltaCount` and `longWords`.
    
    * src/truetype/ttgxvar.c (tt_var_load_item_variation_store): Load packed
    data.
    (tt_var_get_item_delta): Unpack data before applying.
    

2 changed files:

Changes:

  • include/freetype/internal/ftmmtypes.h
    ... ... @@ -28,13 +28,19 @@ FT_BEGIN_HEADER
    28 28
     
    
    29 29
       typedef struct  GX_ItemVarDataRec_
    
    30 30
       {
    
    31
    -    FT_UInt            itemCount;       /* number of delta sets per item    */
    
    32
    -    FT_UInt            regionIdxCount;  /* number of region indices         */
    
    33
    -    FT_UInt*           regionIndices;   /* array of `regionCount' indices;  */
    
    34
    -                                        /* these index `varRegionList'      */
    
    35
    -    FT_ItemVarDelta*   deltaSet;        /* array of `itemCount' deltas      */
    
    36
    -                                        /* use `innerIndex' for this array  */
    
    37
    -
    
    31
    +    FT_UInt            itemCount;      /* Number of delta sets per item.   */
    
    32
    +    FT_UInt            regionIdxCount; /* Number of region indices.        */
    
    33
    +    FT_UInt*           regionIndices;  /* Array of `regionCount` indices;  */
    
    34
    +                                       /* these index `varRegionList`.     */
    
    35
    +    FT_Byte*           deltaSet;       /* Array of `itemCount` deltas;     */
    
    36
    +                                       /* use `innerIndex` for this array. */
    
    37
    +    FT_UShort          wordDeltaCount; /* Number of the first 32-bit ints  */
    
    38
    +                                       /* or 16-bit ints of `deltaSet`     */
    
    39
    +                                       /* depending on `longWords`.        */
    
    40
    +    FT_Bool            longWords;      /* If true, `deltaSet` is a 32-bit  */
    
    41
    +                                       /* array followed by a 16-bit       */
    
    42
    +                                       /* array, otherwise a 16-bit array  */
    
    43
    +                                       /* followed by an 8-bit array.      */
    
    38 44
       } GX_ItemVarDataRec, *GX_ItemVarData;
    
    39 45
     
    
    40 46
     
    

  • src/truetype/ttgxvar.c
    ... ... @@ -509,7 +509,7 @@
    509 509
         FT_UShort  axis_count;
    
    510 510
         FT_UInt    region_count;
    
    511 511
     
    
    512
    -    FT_UInt  i, j, k;
    
    512
    +    FT_UInt  i, j;
    
    513 513
         FT_Bool  long_words;
    
    514 514
     
    
    515 515
         GX_Blend   blend           = ttface->blend;
    
    ... ... @@ -624,6 +624,7 @@
    624 624
           FT_UInt  item_count;
    
    625 625
           FT_UInt  word_delta_count;
    
    626 626
           FT_UInt  region_idx_count;
    
    627
    +      FT_UInt  per_region_size;
    
    627 628
     
    
    628 629
     
    
    629 630
           if ( FT_STREAM_SEEK( offset + dataOffsetArray[i] ) )
    
    ... ... @@ -660,6 +661,8 @@
    660 661
           if ( FT_NEW_ARRAY( varData->regionIndices, region_idx_count ) )
    
    661 662
             goto Exit;
    
    662 663
           varData->regionIdxCount = region_idx_count;
    
    664
    +      varData->wordDeltaCount = word_delta_count;
    
    665
    +      varData->longWords      = long_words;
    
    663 666
     
    
    664 667
           for ( j = 0; j < varData->regionIdxCount; j++ )
    
    665 668
           {
    
    ... ... @@ -675,37 +678,22 @@
    675 678
             }
    
    676 679
           }
    
    677 680
     
    
    678
    -      /* Parse delta set.                                                  */
    
    679
    -      /*                                                                   */
    
    680
    -      /* On input, deltas are (word_delta_count + region_idx_count) bytes  */
    
    681
    -      /* each if `long_words` isn't set, and twice as much otherwise.      */
    
    682
    -      /*                                                                   */
    
    683
    -      /* On output, deltas are expanded to `region_idx_count` shorts each. */
    
    684
    -      if ( FT_NEW_ARRAY( varData->deltaSet, item_count * region_idx_count ) )
    
    685
    -        goto Exit;
    
    686
    -      varData->itemCount = item_count;
    
    681
    +      per_region_size = word_delta_count + region_idx_count;
    
    682
    +      if ( long_words )
    
    683
    +        per_region_size *= 2;
    
    687 684
     
    
    688
    -      for ( j = 0; j < item_count * region_idx_count; )
    
    685
    +      if ( FT_NEW_ARRAY( varData->deltaSet, per_region_size * item_count ) )
    
    686
    +        goto Exit;
    
    687
    +      if ( FT_Stream_Read( stream,
    
    688
    +                           varData->deltaSet,
    
    689
    +                           per_region_size * item_count ) )
    
    689 690
           {
    
    690
    -        if ( long_words )
    
    691
    -        {
    
    692
    -          for ( k = 0; k < word_delta_count; k++, j++ )
    
    693
    -            if ( FT_READ_LONG( varData->deltaSet[j] ) )
    
    694
    -              goto Exit;
    
    695
    -          for ( ; k < region_idx_count; k++, j++ )
    
    696
    -            if ( FT_READ_SHORT( varData->deltaSet[j] ) )
    
    697
    -              goto Exit;
    
    698
    -        }
    
    699
    -        else
    
    700
    -        {
    
    701
    -          for ( k = 0; k < word_delta_count; k++, j++ )
    
    702
    -            if ( FT_READ_SHORT( varData->deltaSet[j] ) )
    
    703
    -              goto Exit;
    
    704
    -          for ( ; k < region_idx_count; k++, j++ )
    
    705
    -            if ( FT_READ_CHAR( varData->deltaSet[j] ) )
    
    706
    -              goto Exit;
    
    707
    -        }
    
    691
    +        FT_TRACE2(( "deltaSet read failed." ));
    
    692
    +        error = FT_THROW( Invalid_Table );
    
    693
    +        goto Exit;
    
    708 694
           }
    
    695
    +
    
    696
    +      varData->itemCount = item_count;
    
    709 697
         }
    
    710 698
     
    
    711 699
       Exit:
    
    ... ... @@ -1005,11 +993,16 @@
    1005 993
         FT_Error   error  = FT_Err_Ok;
    
    1006 994
     
    
    1007 995
         GX_ItemVarData    varData;
    
    1008
    -    FT_ItemVarDelta*  deltaSet;
    
    996
    +    FT_ItemVarDelta*  deltaSet = NULL;
    
    997
    +    FT_ItemVarDelta   deltaSetStack[16];
    
    998
    +
    
    999
    +    FT_Fixed*  scalars = NULL;
    
    1000
    +    FT_Fixed   scalarsStack[16];
    
    1009 1001
     
    
    1010 1002
         FT_UInt          master, j;
    
    1011
    -    FT_Fixed*        scalars = NULL;
    
    1012
    -    FT_ItemVarDelta  returnValue;
    
    1003
    +    FT_ItemVarDelta  returnValue = 0;
    
    1004
    +    FT_UInt          per_region_size;
    
    1005
    +    FT_Byte*         bytes;
    
    1013 1006
     
    
    1014 1007
     
    
    1015 1008
         if ( !ttface->blend || !ttface->blend->normalizedcoords )
    
    ... ... @@ -1026,15 +1019,48 @@
    1026 1019
         if ( outerIndex >= itemStore->dataCount )
    
    1027 1020
           return 0; /* Out of range. */
    
    1028 1021
     
    
    1029
    -    varData  = &itemStore->varData[outerIndex];
    
    1030
    -    deltaSet = FT_OFFSET( varData->deltaSet,
    
    1031
    -                          varData->regionIdxCount * innerIndex );
    
    1022
    +    varData = &itemStore->varData[outerIndex];
    
    1032 1023
     
    
    1033 1024
         if ( innerIndex >= varData->itemCount )
    
    1034 1025
           return 0; /* Out of range. */
    
    1035 1026
     
    
    1036
    -    if ( FT_QNEW_ARRAY( scalars, varData->regionIdxCount ) )
    
    1037
    -      return 0;
    
    1027
    +    if ( varData->regionIdxCount < 16 )
    
    1028
    +    {
    
    1029
    +      deltaSet = deltaSetStack;
    
    1030
    +      scalars  = scalarsStack;
    
    1031
    +    }
    
    1032
    +    else
    
    1033
    +    {
    
    1034
    +      if ( FT_QNEW_ARRAY( deltaSet, varData->regionIdxCount ) )
    
    1035
    +        goto Exit;
    
    1036
    +      if ( FT_QNEW_ARRAY( scalars, varData->regionIdxCount ) )
    
    1037
    +        goto Exit;
    
    1038
    +    }
    
    1039
    +
    
    1040
    +    /* Parse delta set.                                            */
    
    1041
    +    /*                                                             */
    
    1042
    +    /* Deltas are (word_delta_count + region_idx_count) bytes each */
    
    1043
    +    /* if `longWords` isn't set, and twice as much otherwise.      */
    
    1044
    +    per_region_size = varData->wordDeltaCount + varData->regionIdxCount;
    
    1045
    +    if ( varData->longWords )
    
    1046
    +      per_region_size *= 2;
    
    1047
    +
    
    1048
    +    bytes = varData->deltaSet + per_region_size * innerIndex;
    
    1049
    +
    
    1050
    +    if ( varData->longWords )
    
    1051
    +    {
    
    1052
    +      for ( master = 0; master < varData->wordDeltaCount; master++ )
    
    1053
    +        deltaSet[master] = FT_NEXT_LONG( bytes );
    
    1054
    +      for ( ; master < varData->regionIdxCount; master++ )
    
    1055
    +        deltaSet[master] = FT_NEXT_SHORT( bytes );
    
    1056
    +    }
    
    1057
    +    else
    
    1058
    +    {
    
    1059
    +      for ( master = 0; master < varData->wordDeltaCount; master++ )
    
    1060
    +        deltaSet[master] = FT_NEXT_SHORT( bytes );
    
    1061
    +      for ( ; master < varData->regionIdxCount; master++ )
    
    1062
    +        deltaSet[master] = FT_NEXT_CHAR( bytes );
    
    1063
    +    }
    
    1038 1064
     
    
    1039 1065
         /* outer loop steps through master designs to be blended */
    
    1040 1066
         for ( master = 0; master < varData->regionIdxCount; master++ )
    
    ... ... @@ -1109,7 +1135,11 @@
    1109 1135
          */
    
    1110 1136
         returnValue = FT_MulAddFix( scalars, deltaSet, varData->regionIdxCount );
    
    1111 1137
     
    
    1112
    -    FT_FREE( scalars );
    
    1138
    +  Exit:
    
    1139
    +    if ( scalars != scalarsStack )
    
    1140
    +      FT_FREE( scalars );
    
    1141
    +    if ( deltaSet != deltaSetStack )
    
    1142
    +      FT_FREE( deltaSet );
    
    1113 1143
     
    
    1114 1144
         return returnValue;
    
    1115 1145
       }
    


  • reply via email to

    [Prev in Thread] Current Thread [Next in Thread]