| OLD | NEW |
| (Empty) |
| 1 #include "SkGLTextCache.h" | |
| 2 #include "SkScalerContext.h" | |
| 3 #include "SkTSearch.h" | |
| 4 | |
| 5 const GLenum gTextTextureFormat = GL_ALPHA; | |
| 6 const GLenum gTextTextureType = GL_UNSIGNED_BYTE; | |
| 7 | |
| 8 SkGLTextCache::Strike::Strike(Strike* next, int width, int height) { | |
| 9 fStrikeWidth = SkNextPow2(SkMax32(kMinStrikeWidth, width)); | |
| 10 fStrikeHeight = SkNextPow2(height); | |
| 11 fGlyphCount = 0; | |
| 12 fNextFreeOffsetX = 0; | |
| 13 fNext = next; | |
| 14 | |
| 15 fStrikeWidthShift = SkNextLog2(fStrikeWidth); | |
| 16 fStrikeHeightShift = SkNextLog2(fStrikeHeight); | |
| 17 | |
| 18 if (next) { | |
| 19 SkASSERT(next->fStrikeHeight == fStrikeHeight); | |
| 20 } | |
| 21 | |
| 22 // create an empty texture to receive glyphs | |
| 23 fTexName = 0; | |
| 24 glGenTextures(1, &fTexName); | |
| 25 glBindTexture(GL_TEXTURE_2D, fTexName); | |
| 26 glTexImage2D(GL_TEXTURE_2D, 0, gTextTextureFormat, | |
| 27 fStrikeWidth, fStrikeHeight, 0, | |
| 28 gTextTextureFormat, gTextTextureType, NULL); | |
| 29 | |
| 30 SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
| 31 SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
| 32 SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| 33 SK_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| 34 } | |
| 35 | |
| 36 SkGLTextCache::Strike::~Strike() { | |
| 37 if (fTexName != 0) { | |
| 38 glDeleteTextures(1, &fTexName); | |
| 39 } | |
| 40 } | |
| 41 | |
| 42 SkGLTextCache::Strike* | |
| 43 SkGLTextCache::Strike::findGlyph(const SkGlyph& glyph, int* offset) { | |
| 44 Strike* strike = this; | |
| 45 SkDEBUGCODE(const int height = SkNextPow2(glyph.fHeight);) | |
| 46 | |
| 47 do { | |
| 48 SkASSERT(height == strike->fStrikeHeight); | |
| 49 | |
| 50 int index = SkTSearch(strike->fGlyphIDArray, strike->fGlyphCount, | |
| 51 glyph.fID, sizeof(strike->fGlyphIDArray[0])); | |
| 52 if (index >= 0) { | |
| 53 if (offset) { | |
| 54 *offset = strike->fGlyphOffsetX[index]; | |
| 55 } | |
| 56 return strike; | |
| 57 } | |
| 58 strike = strike->fNext; | |
| 59 } while (NULL != strike); | |
| 60 return NULL; | |
| 61 } | |
| 62 | |
| 63 static void make_a_whole(void* buffer, int index, int count, size_t elemSize) { | |
| 64 SkASSERT(index >= 0 && index <= count); | |
| 65 size_t offset = index * elemSize; | |
| 66 memmove((char*)buffer + offset + elemSize, | |
| 67 (const char*)buffer + offset, | |
| 68 (count - index) * elemSize); | |
| 69 } | |
| 70 | |
| 71 SkGLTextCache::Strike* | |
| 72 SkGLTextCache::Strike::addGlyphAndBind(const SkGlyph& glyph, | |
| 73 const uint8_t image[], int* offset) { | |
| 74 #ifdef SK_DEBUG | |
| 75 SkASSERT(this->findGlyph(glyph, NULL) == NULL); | |
| 76 const int height = SkNextPow2(glyph.fHeight); | |
| 77 SkASSERT(height <= fStrikeHeight && height > (fStrikeHeight >> 1)); | |
| 78 #endif | |
| 79 | |
| 80 int rowBytes = glyph.rowBytes(); | |
| 81 SkASSERT(rowBytes >= glyph.fWidth); | |
| 82 | |
| 83 Strike* strike; | |
| 84 if (fGlyphCount == kMaxGlyphCount || | |
| 85 fNextFreeOffsetX + rowBytes >= fStrikeWidth) { | |
| 86 // this will bind the next texture for us | |
| 87 // SkDebugf("--- extend strike %p\n", this); | |
| 88 strike = SkNEW_ARGS(Strike, (this, rowBytes, glyph.fHeight)); | |
| 89 } else { | |
| 90 glBindTexture(GL_TEXTURE_2D, fTexName); | |
| 91 strike = this; | |
| 92 } | |
| 93 | |
| 94 uint32_t* idArray = strike->fGlyphIDArray; | |
| 95 uint16_t* offsetArray = strike->fGlyphOffsetX; | |
| 96 const int glyphCount = strike->fGlyphCount; | |
| 97 | |
| 98 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |
| 99 glTexSubImage2D(GL_TEXTURE_2D, 0, strike->fNextFreeOffsetX, 0, rowBytes, | |
| 100 glyph.fHeight, gTextTextureFormat, gTextTextureType, | |
| 101 image); | |
| 102 | |
| 103 // need to insert the offset | |
| 104 int index = SkTSearch(idArray, glyphCount, glyph.fID, sizeof(idArray[0])); | |
| 105 SkASSERT(index < 0); | |
| 106 index = ~index; // this is where we should insert it | |
| 107 make_a_whole(idArray, index, glyphCount, sizeof(idArray)); | |
| 108 make_a_whole(offsetArray, index, glyphCount, sizeof(offsetArray[0])); | |
| 109 idArray[index] = glyph.fID; | |
| 110 offsetArray[index] = strike->fNextFreeOffsetX; | |
| 111 if (offset) { | |
| 112 *offset = strike->fNextFreeOffsetX; | |
| 113 } | |
| 114 | |
| 115 #if 0 | |
| 116 SkDebugf("--- strike %p glyph %x [%d %d] offset %d count %d\n", | |
| 117 strike, glyph.fID, glyph.fWidth, glyph.fHeight, | |
| 118 strike->fNextFreeOffsetX, glyphCount + 1); | |
| 119 #endif | |
| 120 | |
| 121 // now update our header | |
| 122 strike->fGlyphCount = glyphCount + 1; | |
| 123 strike->fNextFreeOffsetX += glyph.fWidth; | |
| 124 return strike; | |
| 125 } | |
| 126 | |
| 127 /////////////////////////////////////////////////////////////////////////////// | |
| 128 | |
| 129 SkGLTextCache::SkGLTextCache() { | |
| 130 bzero(fStrikeList, sizeof(fStrikeList)); | |
| 131 } | |
| 132 | |
| 133 SkGLTextCache::~SkGLTextCache() { | |
| 134 this->deleteAllStrikes(true); | |
| 135 } | |
| 136 | |
| 137 void SkGLTextCache::deleteAllStrikes(bool texturesAreValid) { | |
| 138 for (size_t i = 0; i < SK_ARRAY_COUNT(fStrikeList); i++) { | |
| 139 Strike* strike = fStrikeList[i]; | |
| 140 while (strike != NULL) { | |
| 141 Strike* next = strike->fNext; | |
| 142 if (!texturesAreValid) { | |
| 143 strike->abandonTexture(); | |
| 144 } | |
| 145 SkDELETE(strike); | |
| 146 strike = next; | |
| 147 } | |
| 148 } | |
| 149 bzero(fStrikeList, sizeof(fStrikeList)); | |
| 150 } | |
| 151 | |
| 152 SkGLTextCache::Strike* SkGLTextCache::findGlyph(const SkGlyph& glyph, | |
| 153 int* offset) { | |
| 154 SkASSERT(glyph.fWidth != 0); | |
| 155 SkASSERT(glyph.fHeight != 0); | |
| 156 | |
| 157 size_t index = SkNextLog2(glyph.fHeight); | |
| 158 if (index >= SK_ARRAY_COUNT(fStrikeList)) { | |
| 159 // too big for us to cache; | |
| 160 return NULL; | |
| 161 } | |
| 162 | |
| 163 Strike* strike = fStrikeList[index]; | |
| 164 if (strike) { | |
| 165 strike = strike->findGlyph(glyph, offset); | |
| 166 } | |
| 167 return strike; | |
| 168 } | |
| 169 | |
| 170 SkGLTextCache::Strike* SkGLTextCache::addGlyphAndBind(const SkGlyph& glyph, | |
| 171 const uint8_t image[], int* offset) { | |
| 172 SkASSERT(image != NULL); | |
| 173 SkASSERT(glyph.fWidth != 0); | |
| 174 SkASSERT(glyph.fHeight != 0); | |
| 175 | |
| 176 size_t index = SkNextLog2(glyph.fHeight); | |
| 177 if (index >= SK_ARRAY_COUNT(fStrikeList)) { | |
| 178 // too big for us to cache; | |
| 179 return NULL; | |
| 180 } | |
| 181 | |
| 182 Strike* strike = fStrikeList[index]; | |
| 183 if (NULL == strike) { | |
| 184 strike = SkNEW_ARGS(Strike, (NULL, glyph.rowBytes(), glyph.fHeight)); | |
| 185 // SkDebugf("--- create strike [%d] %p cache %p\n", index, strike, this); | |
| 186 } | |
| 187 strike = strike->addGlyphAndBind(glyph, image, offset); | |
| 188 fStrikeList[index] = strike; | |
| 189 return strike; | |
| 190 } | |
| 191 | |
| OLD | NEW |