blob: 1b2f6514268b00725ab062fcb8fd36de1e3faf9c [file] [log] [blame]
Romain Guy694b5192010-07-21 21:33:20 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "OpenGLRenderer"
18
Derek Sollenbergerca79cf62012-08-14 16:44:52 -040019#include <SkGlyph.h>
Romain Guy694b5192010-07-21 21:33:20 -070020#include <SkUtils.h>
21
Romain Guy51769a62010-07-23 00:28:00 -070022#include <cutils/properties.h>
Romain Guye2d345e2010-09-24 18:39:22 -070023
Romain Guy51769a62010-07-23 00:28:00 -070024#include <utils/Log.h>
25
Dan Morrille4d9a012013-03-28 18:10:43 -070026#ifdef ANDROID_ENABLE_RENDERSCRIPT
Romain Guy6e200402013-03-08 11:28:22 -080027#include <RenderScript.h>
Dan Morrille4d9a012013-03-28 18:10:43 -070028#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -080029
Romain Guy6e200402013-03-08 11:28:22 -080030#include "utils/Blur.h"
Chris Craikf2d8ccc2013-02-13 16:14:17 -080031#include "utils/Timing.h"
Romain Guy6e200402013-03-08 11:28:22 -080032
Romain Guy15bc6432011-12-13 13:11:32 -080033#include "Caches.h"
Romain Guyc9855a52011-01-21 21:14:15 -080034#include "Debug.h"
Romain Guy09087642013-04-04 12:27:54 -070035#include "Extensions.h"
Romain Guy51769a62010-07-23 00:28:00 -070036#include "FontRenderer.h"
Victoria Lease1e546812013-06-25 14:25:17 -070037#include "OpenGLRenderer.h"
Romain Guycf51a412013-04-08 19:40:31 -070038#include "PixelBuffer.h"
Romain Guy9f5dab32012-09-04 12:55:44 -070039#include "Rect.h"
Romain Guy51769a62010-07-23 00:28:00 -070040
Romain Guy694b5192010-07-21 21:33:20 -070041namespace android {
42namespace uirenderer {
43
Chris Craikf2d8ccc2013-02-13 16:14:17 -080044// blur inputs smaller than this constant will bypass renderscript
45#define RS_MIN_INPUT_CUTOFF 10000
46
Romain Guy694b5192010-07-21 21:33:20 -070047///////////////////////////////////////////////////////////////////////////////
Victoria Lease1e546812013-06-25 14:25:17 -070048// TextSetupFunctor
49///////////////////////////////////////////////////////////////////////////////
50status_t TextSetupFunctor::operator ()(int what, void* data) {
51 Data* typedData = reinterpret_cast<Data*>(data);
52 GLenum glyphFormat = typedData ? typedData->glyphFormat : GL_ALPHA;
53
54 renderer->setupDraw();
55 renderer->setupDrawTextGamma(paint);
56 renderer->setupDrawDirtyRegionsDisabled();
57 renderer->setupDrawWithTexture(glyphFormat == GL_ALPHA);
58 switch (glyphFormat) {
59 case GL_ALPHA: {
60 renderer->setupDrawAlpha8Color(paint->getColor(), alpha);
61 break;
62 }
63 case GL_RGBA: {
64 float floatAlpha = alpha / 255.0f;
65 renderer->setupDrawColor(floatAlpha, floatAlpha, floatAlpha, floatAlpha);
66 break;
67 }
68 default: {
69#if DEBUG_FONT_RENDERER
70 ALOGD("TextSetupFunctor: called with unknown glyph format %x", glyphFormat);
71#endif
72 break;
73 }
74 }
75 renderer->setupDrawColorFilter();
76 renderer->setupDrawShader();
77 renderer->setupDrawBlending(true, mode);
78 renderer->setupDrawProgram();
79 renderer->setupDrawModelView(x, y, x, y, pureTranslate, true);
80 // Calling setupDrawTexture with the name 0 will enable the
81 // uv attributes and increase the texture unit count
82 // texture binding will be performed by the font renderer as
83 // needed
84 renderer->setupDrawTexture(0);
85 renderer->setupDrawPureColorUniforms();
86 renderer->setupDrawColorFilterUniforms();
87 renderer->setupDrawShaderUniforms(pureTranslate);
88 renderer->setupDrawTextGammaUniforms();
89
90 return NO_ERROR;
91}
92
93///////////////////////////////////////////////////////////////////////////////
Romain Guy694b5192010-07-21 21:33:20 -070094// FontRenderer
95///////////////////////////////////////////////////////////////////////////////
96
Romain Guy514fb182011-01-19 14:38:29 -080097static bool sLogFontRendererCreate = true;
98
Romain Guye3a9b242013-01-08 11:15:30 -080099FontRenderer::FontRenderer() :
100 mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity) {
101
Romain Guyc9855a52011-01-21 21:14:15 -0800102 if (sLogFontRendererCreate) {
103 INIT_LOGD("Creating FontRenderer");
104 }
Romain Guy51769a62010-07-23 00:28:00 -0700105
Romain Guyb45c0c92010-08-26 20:35:23 -0700106 mGammaTable = NULL;
Romain Guy694b5192010-07-21 21:33:20 -0700107 mInitialized = false;
Romain Guy694b5192010-07-21 21:33:20 -0700108
Chet Haase7de0cb12011-12-05 16:35:38 -0800109 mCurrentCacheTexture = NULL;
Romain Guy9cccc2b92010-08-07 23:46:15 -0700110
Chet Haase2a47c142011-12-14 15:22:56 -0800111 mLinearFiltering = false;
112
Chet Haaseeb32a492012-08-31 13:54:03 -0700113 mSmallCacheWidth = DEFAULT_TEXT_SMALL_CACHE_WIDTH;
114 mSmallCacheHeight = DEFAULT_TEXT_SMALL_CACHE_HEIGHT;
115 mLargeCacheWidth = DEFAULT_TEXT_LARGE_CACHE_WIDTH;
116 mLargeCacheHeight = DEFAULT_TEXT_LARGE_CACHE_HEIGHT;
Romain Guy51769a62010-07-23 00:28:00 -0700117
118 char property[PROPERTY_VALUE_MAX];
Chet Haaseeb32a492012-08-31 13:54:03 -0700119 if (property_get(PROPERTY_TEXT_SMALL_CACHE_WIDTH, property, NULL) > 0) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800120 mSmallCacheWidth = atoi(property);
Romain Guy51769a62010-07-23 00:28:00 -0700121 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700122
Chet Haaseeb32a492012-08-31 13:54:03 -0700123 if (property_get(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, property, NULL) > 0) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800124 mSmallCacheHeight = atoi(property);
Chet Haaseeb32a492012-08-31 13:54:03 -0700125 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700126
Chet Haaseeb32a492012-08-31 13:54:03 -0700127 if (property_get(PROPERTY_TEXT_LARGE_CACHE_WIDTH, property, NULL) > 0) {
128 mLargeCacheWidth = atoi(property);
129 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700130
Chet Haaseeb32a492012-08-31 13:54:03 -0700131 if (property_get(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, property, NULL) > 0) {
132 mLargeCacheHeight = atoi(property);
133 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700134
135 uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
136 mSmallCacheWidth = mSmallCacheWidth > maxTextureSize ? maxTextureSize : mSmallCacheWidth;
137 mSmallCacheHeight = mSmallCacheHeight > maxTextureSize ? maxTextureSize : mSmallCacheHeight;
138 mLargeCacheWidth = mLargeCacheWidth > maxTextureSize ? maxTextureSize : mLargeCacheWidth;
139 mLargeCacheHeight = mLargeCacheHeight > maxTextureSize ? maxTextureSize : mLargeCacheHeight;
140
Chet Haaseeb32a492012-08-31 13:54:03 -0700141 if (sLogFontRendererCreate) {
142 INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
143 mSmallCacheWidth, mSmallCacheHeight,
144 mLargeCacheWidth, mLargeCacheHeight >> 1,
145 mLargeCacheWidth, mLargeCacheHeight >> 1,
146 mLargeCacheWidth, mLargeCacheHeight);
Romain Guy51769a62010-07-23 00:28:00 -0700147 }
Romain Guy514fb182011-01-19 14:38:29 -0800148
149 sLogFontRendererCreate = false;
Romain Guy694b5192010-07-21 21:33:20 -0700150}
151
Victoria Lease1e546812013-06-25 14:25:17 -0700152void clearCacheTextures(Vector<CacheTexture*>& cacheTextures) {
153 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
154 delete cacheTextures[i];
Romain Guy694b5192010-07-21 21:33:20 -0700155 }
Victoria Lease1e546812013-06-25 14:25:17 -0700156 cacheTextures.clear();
157}
158
159FontRenderer::~FontRenderer() {
160 clearCacheTextures(mACacheTextures);
161 clearCacheTextures(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700162
Romain Guye3a9b242013-01-08 11:15:30 -0800163 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
164 while (it.next()) {
165 delete it.value();
Romain Guy694b5192010-07-21 21:33:20 -0700166 }
Romain Guye3a9b242013-01-08 11:15:30 -0800167 mActiveFonts.clear();
Romain Guy694b5192010-07-21 21:33:20 -0700168}
169
170void FontRenderer::flushAllAndInvalidate() {
Romain Guy661a87e2013-03-19 15:24:36 -0700171 issueDrawCommand();
Romain Guy9d9758a2012-05-14 15:19:58 -0700172
Romain Guye3a9b242013-01-08 11:15:30 -0800173 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
174 while (it.next()) {
175 it.value()->invalidateTextureCache();
Romain Guy694b5192010-07-21 21:33:20 -0700176 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700177
Victoria Lease1e546812013-06-25 14:25:17 -0700178 for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
179 mACacheTextures[i]->init();
180 }
181
182 for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
183 mRGBACacheTextures[i]->init();
Romain Guy694b5192010-07-21 21:33:20 -0700184 }
185}
186
Victoria Lease1e546812013-06-25 14:25:17 -0700187void FontRenderer::flushLargeCaches(Vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700188 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700189 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
190 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700191 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700192 cacheTexture->init();
Romain Guye3a9b242013-01-08 11:15:30 -0800193 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
194 while (it.next()) {
195 it.value()->invalidateTextureCache(cacheTexture);
Chet Haasee816bae2012-08-09 13:39:02 -0700196 }
Romain Guy80872462012-09-04 16:42:01 -0700197 cacheTexture->releaseTexture();
Chet Haase9a824562011-12-16 15:44:59 -0800198 }
199 }
Chet Haase9a824562011-12-16 15:44:59 -0800200}
201
Victoria Lease1e546812013-06-25 14:25:17 -0700202void FontRenderer::flushLargeCaches() {
203 flushLargeCaches(mACacheTextures);
204 flushLargeCaches(mRGBACacheTextures);
205}
206
207CacheTexture* FontRenderer::cacheBitmapInTexture(Vector<CacheTexture*>& cacheTextures,
208 const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
209 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
210 if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
211 return cacheTextures[i];
Chet Haase378e9192012-08-15 15:54:54 -0700212 }
213 }
214 // Could not fit glyph into current cache textures
215 return NULL;
216}
217
Chet Haase7de0cb12011-12-05 16:35:38 -0800218void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
Chet Haasef942cf12012-08-30 09:06:46 -0700219 uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700220 checkInit();
Romain Guya4adcf02013-02-28 12:15:35 -0800221
222 // If the glyph bitmap is empty let's assum the glyph is valid
223 // so we can avoid doing extra work later on
224 if (glyph.fWidth == 0 || glyph.fHeight == 0) {
225 cachedGlyph->mIsValid = true;
226 cachedGlyph->mCacheTexture = NULL;
227 return;
228 }
229
Chet Haase7de0cb12011-12-05 16:35:38 -0800230 cachedGlyph->mIsValid = false;
Romain Guya4adcf02013-02-28 12:15:35 -0800231
Victoria Lease1e546812013-06-25 14:25:17 -0700232 // choose an appropriate cache texture list for this glyph format
233 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
234 Vector<CacheTexture*>* cacheTextures = NULL;
235 switch (format) {
236 case SkMask::kA8_Format:
237 cacheTextures = &mACacheTextures;
238 break;
239 case SkMask::kARGB32_Format:
240 cacheTextures = &mRGBACacheTextures;
241 break;
242 default:
243#if DEBUG_FONT_RENDERER
244 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
245#endif
246 return;
247 }
248
Romain Guy694b5192010-07-21 21:33:20 -0700249 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700250 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
Victoria Lease1e546812013-06-25 14:25:17 -0700251 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700252 ALOGE("Font size too large to fit in cache. width, height = %i, %i",
253 (int) glyph.fWidth, (int) glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800254 return;
Romain Guy694b5192010-07-21 21:33:20 -0700255 }
256
257 // Now copy the bitmap into the cache texture
258 uint32_t startX = 0;
259 uint32_t startY = 0;
260
Victoria Lease1e546812013-06-25 14:25:17 -0700261 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700262
Chet Haase378e9192012-08-15 15:54:54 -0700263 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700264 if (!precaching) {
265 // If the new glyph didn't fit and we are not just trying to precache it,
266 // clear out the cache and try again
267 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700268 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700269 }
Romain Guy694b5192010-07-21 21:33:20 -0700270
Chet Haase378e9192012-08-15 15:54:54 -0700271 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700272 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800273 return;
Romain Guy694b5192010-07-21 21:33:20 -0700274 }
275 }
276
Chet Haase378e9192012-08-15 15:54:54 -0700277 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800278
Romain Guy694b5192010-07-21 21:33:20 -0700279 *retOriginX = startX;
280 *retOriginY = startY;
281
282 uint32_t endX = startX + glyph.fWidth;
283 uint32_t endY = startY + glyph.fHeight;
284
Romain Guy80872462012-09-04 16:42:01 -0700285 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700286
Romain Guycf51a412013-04-08 19:40:31 -0700287 if (!cacheTexture->getPixelBuffer()) {
Romain Guy80872462012-09-04 16:42:01 -0700288 Caches::getInstance().activeTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800289 // Large-glyph texture memory is allocated only as needed
Romain Guy80872462012-09-04 16:42:01 -0700290 cacheTexture->allocateTexture();
Chet Haase7de0cb12011-12-05 16:35:38 -0800291 }
Romain Guy661a87e2013-03-19 15:24:36 -0700292 if (!cacheTexture->mesh()) {
293 cacheTexture->allocateMesh();
294 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700295
Romain Guycf51a412013-04-08 19:40:31 -0700296 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
Victoria Lease1e546812013-06-25 14:25:17 -0700297 uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
298 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700299
Romain Guyb969a0d2013-02-05 14:38:40 -0800300 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800301 switch (format) {
302 case SkMask::kA8_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700303 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
304 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
305 - TEXTURE_BORDER_SIZE;
306 // write leading border line
307 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
308 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800309 if (mGammaTable) {
Victoria Lease1e546812013-06-25 14:25:17 -0700310 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800311 row = cacheY * cacheWidth;
312 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800313 for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
314 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800315 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800316 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800317 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800318 }
319 } else {
Victoria Lease1e546812013-06-25 14:25:17 -0700320 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800321 row = cacheY * cacheWidth;
322 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
323 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
324 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800325 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700326 }
Victoria Lease1e546812013-06-25 14:25:17 -0700327 // write trailing border line
328 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
329 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
330 break;
331 }
332 case SkMask::kARGB32_Format: {
333 // prep data lengths
334 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
335 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
336 size_t rowSize = formatSize * glyph.fWidth;
337 // prep advances
338 size_t dstStride = formatSize * cacheWidth;
339 // prep indices
340 // - we actually start one row early, and then increment before first copy
341 uint8_t* src = &bitmapBuffer[0 - srcStride];
342 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
343 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
344 uint8_t* dstL = dst - borderSize;
345 uint8_t* dstR = dst + rowSize;
346 // write leading border line
347 memset(dstL, 0, rowSize + 2 * borderSize);
348 // write glyph data
349 while (dst < dstEnd) {
350 memset(dstL += dstStride, 0, borderSize); // leading border column
351 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
352 memset(dstR += dstStride, 0, borderSize); // trailing border column
353 }
354 // write trailing border line
355 memset(dstL, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800356 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700357 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800358 case SkMask::kBW_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700359 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
360 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
361 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800362 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700363 // write leading border line
364 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
365 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800366 for (cacheY = startY; cacheY < endY; cacheY++) {
367 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700368 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800369 uint8_t* buffer = bitmapBuffer;
370
Romain Guy0b58a3d2013-03-05 12:16:27 -0800371 row = cacheY * cacheWidth;
372 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800373 while (--rowBytes >= 0) {
374 uint8_t b = *buffer++;
375 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
376 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
377 }
378 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800379 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800380
Victoria Lease1e546812013-06-25 14:25:17 -0700381 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700382 }
Victoria Lease1e546812013-06-25 14:25:17 -0700383 // write trailing border line
384 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
385 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800386 break;
Romain Guy694b5192010-07-21 21:33:20 -0700387 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800388 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700389 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800390 break;
Romain Guy694b5192010-07-21 21:33:20 -0700391 }
Romain Guy97771732012-02-28 18:17:02 -0800392
Chet Haase7de0cb12011-12-05 16:35:38 -0800393 cachedGlyph->mIsValid = true;
Romain Guy694b5192010-07-21 21:33:20 -0700394}
395
Victoria Lease1e546812013-06-25 14:25:17 -0700396CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
397 bool allocate) {
398 CacheTexture* cacheTexture = new CacheTexture(width, height, format, gMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700399
Chet Haase2a47c142011-12-14 15:22:56 -0800400 if (allocate) {
Romain Guy80872462012-09-04 16:42:01 -0700401 Caches::getInstance().activeTexture(0);
402 cacheTexture->allocateTexture();
Romain Guy661a87e2013-03-19 15:24:36 -0700403 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800404 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700405
Chet Haase2a47c142011-12-14 15:22:56 -0800406 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800407}
408
409void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700410 clearCacheTextures(mACacheTextures);
411 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700412
Chet Haase7de0cb12011-12-05 16:35:38 -0800413 mUploadTexture = false;
Victoria Lease1e546812013-06-25 14:25:17 -0700414 mACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
415 GL_ALPHA, true));
416 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
417 GL_ALPHA, false));
418 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
419 GL_ALPHA, false));
420 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
421 GL_ALPHA, false));
422 mRGBACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
423 GL_RGBA, false));
424 mRGBACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
425 GL_RGBA, false));
426 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700427}
428
Romain Guy694b5192010-07-21 21:33:20 -0700429// We don't want to allocate anything unless we actually draw text
430void FontRenderer::checkInit() {
431 if (mInitialized) {
432 return;
433 }
434
435 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700436
437 mInitialized = true;
438}
439
Victoria Lease1e546812013-06-25 14:25:17 -0700440void checkTextureUpdateForCache(Caches& caches, Vector<CacheTexture*>& cacheTextures,
441 bool& resetPixelStore, GLuint& lastTextureId) {
442 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
443 CacheTexture* cacheTexture = cacheTextures[i];
444 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
445 if (cacheTexture->getTextureId() != lastTextureId) {
446 lastTextureId = cacheTexture->getTextureId();
447 caches.activeTexture(0);
448 caches.bindTexture(lastTextureId);
449 }
450
451 if (cacheTexture->upload()) {
452 resetPixelStore = true;
453 }
454 }
455 }
456}
457
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700458void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900459 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700460 return;
Romain Guy694b5192010-07-21 21:33:20 -0700461 }
462
Romain Guy2d4fd362011-12-13 22:00:19 -0800463 Caches& caches = Caches::getInstance();
464 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700465
Romain Guycf51a412013-04-08 19:40:31 -0700466 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700467 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
468
Chet Haase378e9192012-08-15 15:54:54 -0700469 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700470 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
471 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700472
Romain Guycf51a412013-04-08 19:40:31 -0700473 // Unbind any PBO we might have used to update textures
474 caches.unbindPixelBuffer();
475
Romain Guy09087642013-04-04 12:27:54 -0700476 // Reset to default unpack row length to avoid affecting texture
477 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700478 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700479 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
480 }
481
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700482 mUploadTexture = false;
483}
484
Victoria Lease1e546812013-06-25 14:25:17 -0700485void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
486 Caches& caches = Caches::getInstance();
Romain Guy661a87e2013-03-19 15:24:36 -0700487 bool first = true;
488 bool force = false;
Victoria Lease1e546812013-06-25 14:25:17 -0700489 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
490 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700491 if (texture->canDraw()) {
492 if (first) {
Victoria Lease1e546812013-06-25 14:25:17 -0700493 if (mFunctor) {
494 TextSetupFunctor::Data functorData(texture->getFormat());
495 (*mFunctor)(0, &functorData);
496 }
Romain Guy257ae352013-03-20 16:31:12 -0700497
Romain Guy661a87e2013-03-19 15:24:36 -0700498 checkTextureUpdate();
Romain Guy31e08e92013-06-18 15:53:53 -0700499 caches.bindIndicesBuffer();
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900500
Romain Guy661a87e2013-03-19 15:24:36 -0700501 if (!mDrawn) {
502 // If returns true, a VBO was bound and we must
503 // rebind our vertex attrib pointers even if
504 // they have the same values as the current pointers
505 force = caches.unbindMeshBuffer();
506 }
507
508 caches.activeTexture(0);
509 first = false;
510 }
511
Romain Guy8aa195d2013-06-04 18:00:09 -0700512 caches.bindTexture(texture->getTextureId());
Romain Guy661a87e2013-03-19 15:24:36 -0700513 texture->setLinearFiltering(mLinearFiltering, false);
514
515 TextureVertex* mesh = texture->mesh();
516 caches.bindPositionVertexPointer(force, &mesh[0].position[0]);
517 caches.bindTexCoordsVertexPointer(force, &mesh[0].texture[0]);
518 force = false;
519
520 glDrawElements(GL_TRIANGLES, texture->meshElementCount(),
521 GL_UNSIGNED_SHORT, texture->indices());
522
523 texture->resetMesh();
Romain Guy115096f2013-03-19 11:32:41 -0700524 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900525 }
Victoria Lease1e546812013-06-25 14:25:17 -0700526}
527
528void FontRenderer::issueDrawCommand() {
529 issueDrawCommand(mACacheTextures);
530 issueDrawCommand(mRGBACacheTextures);
Romain Guy5b3b3522010-10-27 18:57:51 -0700531
532 mDrawn = true;
Romain Guy694b5192010-07-21 21:33:20 -0700533}
534
Romain Guy97771732012-02-28 18:17:02 -0800535void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
536 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
Chet Haase7de0cb12011-12-05 16:35:38 -0800537 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800538 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800539 // Now use the new texture id
540 mCurrentCacheTexture = texture;
541 }
Romain Guy09147fb2010-07-22 13:08:20 -0700542
Romain Guy661a87e2013-03-19 15:24:36 -0700543 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
544 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800545}
546
547void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
548 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
549 float x4, float y4, float u4, float v4, CacheTexture* texture) {
550
551 if (mClip &&
552 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
553 return;
554 }
555
556 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
Romain Guy694b5192010-07-21 21:33:20 -0700557
Romain Guy5b3b3522010-10-27 18:57:51 -0700558 if (mBounds) {
559 mBounds->left = fmin(mBounds->left, x1);
560 mBounds->top = fmin(mBounds->top, y3);
561 mBounds->right = fmax(mBounds->right, x3);
562 mBounds->bottom = fmax(mBounds->bottom, y1);
563 }
564
Romain Guy661a87e2013-03-19 15:24:36 -0700565 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700566 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700567 }
568}
569
Romain Guy97771732012-02-28 18:17:02 -0800570void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
571 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
572 float x4, float y4, float u4, float v4, CacheTexture* texture) {
573
574 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
575
576 if (mBounds) {
577 mBounds->left = fmin(mBounds->left, fmin(x1, fmin(x2, fmin(x3, x4))));
578 mBounds->top = fmin(mBounds->top, fmin(y1, fmin(y2, fmin(y3, y4))));
579 mBounds->right = fmax(mBounds->right, fmax(x1, fmax(x2, fmax(x3, x4))));
580 mBounds->bottom = fmax(mBounds->bottom, fmax(y1, fmax(y2, fmax(y3, y4))));
581 }
582
Romain Guy661a87e2013-03-19 15:24:36 -0700583 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800584 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800585 }
586}
587
Romain Guye3a9b242013-01-08 11:15:30 -0800588void FontRenderer::setFont(SkPaint* paint, const mat4& matrix) {
589 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700590}
Romain Guy7975fb62010-10-01 16:36:14 -0700591
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700592FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text,
Raph Levien416a8472012-07-19 22:48:17 -0700593 uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700594 checkInit();
595
Romain Guycf51a412013-04-08 19:40:31 -0700596 DropShadow image;
597 image.width = 0;
598 image.height = 0;
599 image.image = NULL;
600 image.penX = 0;
601 image.penY = 0;
602
Romain Guy1e45aae2010-08-13 19:39:53 -0700603 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700604 return image;
605 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700606
Romain Guy2d4fd362011-12-13 22:00:19 -0800607 mDrawn = false;
Romain Guyff98fa52011-11-28 09:35:09 -0800608 mClip = NULL;
609 mBounds = NULL;
610
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700611 Rect bounds;
Raph Levien416a8472012-07-19 22:48:17 -0700612 mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800613
Romain Guy1e45aae2010-08-13 19:39:53 -0700614 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius;
615 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius;
Romain Guyff98fa52011-11-28 09:35:09 -0800616
Romain Guycf51a412013-04-08 19:40:31 -0700617 uint32_t maxSize = Caches::getInstance().maxTextureSize;
618 if (paddedWidth > maxSize || paddedHeight > maxSize) {
619 return image;
620 }
621
Dan Morrille4d9a012013-03-28 18:10:43 -0700622#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800623 // Align buffers for renderscript usage
624 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
625 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700626 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800627 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800628 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700629#else
630 int size = paddedWidth * paddedHeight;
631 uint8_t* dataBuffer = (uint8_t*) malloc(size);
632#endif
633
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800634 memset(dataBuffer, 0, size);
635
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700636 int penX = radius - bounds.left;
637 int penY = radius - bounds.bottom;
638
Chris Craikdd8697c2013-02-22 10:41:36 -0800639 if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
640 // text has non-whitespace, so draw and blur to create the shadow
641 // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
642 // TODO: don't draw pure whitespace in the first place, and avoid needing this check
643 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
644 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions);
645
Romain Guycf51a412013-04-08 19:40:31 -0700646 // Unbind any PBO we might have used
647 Caches::getInstance().unbindPixelBuffer();
648
Chris Craikdd8697c2013-02-22 10:41:36 -0800649 blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
650 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700651
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700652 image.width = paddedWidth;
653 image.height = paddedHeight;
654 image.image = dataBuffer;
655 image.penX = penX;
656 image.penY = penY;
Romain Guy2d4fd362011-12-13 22:00:19 -0800657
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700658 return image;
659}
Romain Guy694b5192010-07-21 21:33:20 -0700660
Romain Guy257ae352013-03-20 16:31:12 -0700661void FontRenderer::initRender(const Rect* clip, Rect* bounds, Functor* functor) {
Romain Guy694b5192010-07-21 21:33:20 -0700662 checkInit();
663
Romain Guy5b3b3522010-10-27 18:57:51 -0700664 mDrawn = false;
665 mBounds = bounds;
Romain Guy257ae352013-03-20 16:31:12 -0700666 mFunctor = functor;
Romain Guy09147fb2010-07-22 13:08:20 -0700667 mClip = clip;
Romain Guy671d6cf2012-01-18 12:39:17 -0800668}
Romain Guyff98fa52011-11-28 09:35:09 -0800669
Romain Guy671d6cf2012-01-18 12:39:17 -0800670void FontRenderer::finishRender() {
Romain Guy5b3b3522010-10-27 18:57:51 -0700671 mBounds = NULL;
Romain Guyff98fa52011-11-28 09:35:09 -0800672 mClip = NULL;
Romain Guy694b5192010-07-21 21:33:20 -0700673
Romain Guy661a87e2013-03-19 15:24:36 -0700674 issueDrawCommand();
Romain Guy671d6cf2012-01-18 12:39:17 -0800675}
676
Romain Guye3a9b242013-01-08 11:15:30 -0800677void FontRenderer::precache(SkPaint* paint, const char* text, int numGlyphs, const mat4& matrix) {
678 Font* font = Font::create(this, paint, matrix);
Chet Haasee816bae2012-08-09 13:39:02 -0700679 font->precache(paint, text, numGlyphs);
680}
681
Romain Guycf51a412013-04-08 19:40:31 -0700682void FontRenderer::endPrecaching() {
683 checkTextureUpdate();
684}
685
Romain Guy671d6cf2012-01-18 12:39:17 -0800686bool FontRenderer::renderPosText(SkPaint* paint, const Rect* clip, const char *text,
687 uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
Chris Craik527a3aa2013-03-04 10:19:31 -0800688 const float* positions, Rect* bounds, Functor* functor, bool forceFinish) {
Romain Guy671d6cf2012-01-18 12:39:17 -0800689 if (!mCurrentFont) {
690 ALOGE("No font set");
691 return false;
692 }
693
Romain Guy257ae352013-03-20 16:31:12 -0700694 initRender(clip, bounds, functor);
Romain Guy671d6cf2012-01-18 12:39:17 -0800695 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions);
Chris Craik527a3aa2013-03-04 10:19:31 -0800696
697 if (forceFinish) {
698 finishRender();
699 }
Romain Guy5b3b3522010-10-27 18:57:51 -0700700
701 return mDrawn;
Romain Guy694b5192010-07-21 21:33:20 -0700702}
703
Romain Guy97771732012-02-28 18:17:02 -0800704bool FontRenderer::renderTextOnPath(SkPaint* paint, const Rect* clip, const char *text,
705 uint32_t startIndex, uint32_t len, int numGlyphs, SkPath* path,
Victoria Lease1e546812013-06-25 14:25:17 -0700706 float hOffset, float vOffset, Rect* bounds, Functor* functor) {
Romain Guy97771732012-02-28 18:17:02 -0800707 if (!mCurrentFont) {
708 ALOGE("No font set");
709 return false;
710 }
711
Victoria Lease1e546812013-06-25 14:25:17 -0700712 initRender(clip, bounds, functor);
Romain Guy97771732012-02-28 18:17:02 -0800713 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset);
714 finishRender();
715
716 return mDrawn;
717}
718
Romain Guy9b1204b2012-09-04 15:22:57 -0700719void FontRenderer::removeFont(const Font* font) {
Romain Guye3a9b242013-01-08 11:15:30 -0800720 mActiveFonts.remove(font->getDescription());
Romain Guy9b1204b2012-09-04 15:22:57 -0700721
722 if (mCurrentFont == font) {
723 mCurrentFont = NULL;
724 }
725}
726
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800727void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, int32_t radius) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700728#ifdef ANDROID_ENABLE_RENDERSCRIPT
729 if (width * height * radius >= RS_MIN_INPUT_CUTOFF) {
730 uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700731
Dan Morrille4d9a012013-03-28 18:10:43 -0700732 if (mRs.get() == 0) {
733 mRs = new RSC::RS();
734 if (!mRs->init(true, true)) {
735 ALOGE("blur RS failed to init");
736 }
Romain Guyd71dd362011-12-12 19:03:35 -0800737
Dan Morrille4d9a012013-03-28 18:10:43 -0700738 mRsElement = RSC::Element::A_8(mRs);
739 mRsScript = new RSC::ScriptIntrinsicBlur(mRs, mRsElement);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800740 }
741
Dan Morrille4d9a012013-03-28 18:10:43 -0700742 sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
743 sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t, RS_ALLOCATION_MIPMAP_NONE,
744 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, *image);
745 sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t, RS_ALLOCATION_MIPMAP_NONE,
746 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, outImage);
747
748 mRsScript->setRadius(radius);
749 mRsScript->blur(ain, aout);
750
751 // replace the original image's pointer, avoiding a copy back to the original buffer
752 free(*image);
753 *image = outImage;
754
755 return;
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800756 }
Dan Morrille4d9a012013-03-28 18:10:43 -0700757#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800758
Dan Morrille4d9a012013-03-28 18:10:43 -0700759 float *gaussian = new float[2 * radius + 1];
760 Blur::generateGaussianWeights(gaussian, radius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800761
Dan Morrille4d9a012013-03-28 18:10:43 -0700762 uint8_t* scratch = new uint8_t[width * height];
763 Blur::horizontal(gaussian, radius, *image, scratch, width, height);
764 Blur::vertical(gaussian, radius, scratch, *image, width, height);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800765
Dan Morrille4d9a012013-03-28 18:10:43 -0700766 delete[] gaussian;
767 delete[] scratch;
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700768}
769
Victoria Lease1e546812013-06-25 14:25:17 -0700770static uint32_t calculateCacheSize(const Vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700771 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700772 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
773 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700774 if (cacheTexture && cacheTexture->getPixelBuffer()) {
775 size += cacheTexture->getPixelBuffer()->getSize();
776 }
777 }
778 return size;
779}
780
Victoria Lease1e546812013-06-25 14:25:17 -0700781uint32_t FontRenderer::getCacheSize(GLenum format) const {
782 switch (format) {
783 case GL_ALPHA: {
784 return calculateCacheSize(mACacheTextures);
785 }
786 case GL_RGBA: {
787 return calculateCacheSize(mRGBACacheTextures);
788 }
789 default: {
790 return 0;
791 }
792 }
793}
794
Romain Guy694b5192010-07-21 21:33:20 -0700795}; // namespace uirenderer
796}; // namespace android