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 |