blob: f44cdc049488fc4381a8087323f97728d437246a [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 }
chaochen1f61b192014-08-28 18:45:27 -0700185
186 mDrawn = false;
Romain Guy694b5192010-07-21 21:33:20 -0700187}
188
Victoria Lease1e546812013-06-25 14:25:17 -0700189void FontRenderer::flushLargeCaches(Vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700190 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700191 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
192 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700193 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700194 cacheTexture->init();
Romain Guye3a9b242013-01-08 11:15:30 -0800195 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
196 while (it.next()) {
197 it.value()->invalidateTextureCache(cacheTexture);
Chet Haasee816bae2012-08-09 13:39:02 -0700198 }
Romain Guy80872462012-09-04 16:42:01 -0700199 cacheTexture->releaseTexture();
Chet Haase9a824562011-12-16 15:44:59 -0800200 }
201 }
Chet Haase9a824562011-12-16 15:44:59 -0800202}
203
Victoria Lease1e546812013-06-25 14:25:17 -0700204void FontRenderer::flushLargeCaches() {
205 flushLargeCaches(mACacheTextures);
206 flushLargeCaches(mRGBACacheTextures);
207}
208
209CacheTexture* FontRenderer::cacheBitmapInTexture(Vector<CacheTexture*>& cacheTextures,
210 const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
211 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
212 if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
213 return cacheTextures[i];
Chet Haase378e9192012-08-15 15:54:54 -0700214 }
215 }
216 // Could not fit glyph into current cache textures
217 return NULL;
218}
219
Chet Haase7de0cb12011-12-05 16:35:38 -0800220void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
Chet Haasef942cf12012-08-30 09:06:46 -0700221 uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700222 checkInit();
Romain Guya4adcf02013-02-28 12:15:35 -0800223
224 // If the glyph bitmap is empty let's assum the glyph is valid
225 // so we can avoid doing extra work later on
226 if (glyph.fWidth == 0 || glyph.fHeight == 0) {
227 cachedGlyph->mIsValid = true;
228 cachedGlyph->mCacheTexture = NULL;
229 return;
230 }
231
Chet Haase7de0cb12011-12-05 16:35:38 -0800232 cachedGlyph->mIsValid = false;
Romain Guya4adcf02013-02-28 12:15:35 -0800233
Victoria Lease1e546812013-06-25 14:25:17 -0700234 // choose an appropriate cache texture list for this glyph format
235 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
236 Vector<CacheTexture*>* cacheTextures = NULL;
237 switch (format) {
238 case SkMask::kA8_Format:
Victoria Lease723b2fe2013-08-12 14:38:44 -0700239 case SkMask::kBW_Format:
Victoria Lease1e546812013-06-25 14:25:17 -0700240 cacheTextures = &mACacheTextures;
241 break;
242 case SkMask::kARGB32_Format:
243 cacheTextures = &mRGBACacheTextures;
244 break;
245 default:
246#if DEBUG_FONT_RENDERER
247 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
248#endif
249 return;
250 }
251
Romain Guy694b5192010-07-21 21:33:20 -0700252 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700253 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
Victoria Lease1e546812013-06-25 14:25:17 -0700254 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700255 ALOGE("Font size too large to fit in cache. width, height = %i, %i",
256 (int) glyph.fWidth, (int) glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800257 return;
Romain Guy694b5192010-07-21 21:33:20 -0700258 }
259
260 // Now copy the bitmap into the cache texture
261 uint32_t startX = 0;
262 uint32_t startY = 0;
263
Victoria Lease1e546812013-06-25 14:25:17 -0700264 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700265
Chet Haase378e9192012-08-15 15:54:54 -0700266 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700267 if (!precaching) {
268 // If the new glyph didn't fit and we are not just trying to precache it,
269 // clear out the cache and try again
270 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700271 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700272 }
Romain Guy694b5192010-07-21 21:33:20 -0700273
Chet Haase378e9192012-08-15 15:54:54 -0700274 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700275 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800276 return;
Romain Guy694b5192010-07-21 21:33:20 -0700277 }
278 }
279
Chet Haase378e9192012-08-15 15:54:54 -0700280 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800281
Romain Guy694b5192010-07-21 21:33:20 -0700282 *retOriginX = startX;
283 *retOriginY = startY;
284
285 uint32_t endX = startX + glyph.fWidth;
286 uint32_t endY = startY + glyph.fHeight;
287
Romain Guy80872462012-09-04 16:42:01 -0700288 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700289
Romain Guycf51a412013-04-08 19:40:31 -0700290 if (!cacheTexture->getPixelBuffer()) {
Romain Guy80872462012-09-04 16:42:01 -0700291 Caches::getInstance().activeTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800292 // Large-glyph texture memory is allocated only as needed
Romain Guy80872462012-09-04 16:42:01 -0700293 cacheTexture->allocateTexture();
Chet Haase7de0cb12011-12-05 16:35:38 -0800294 }
Romain Guy661a87e2013-03-19 15:24:36 -0700295 if (!cacheTexture->mesh()) {
296 cacheTexture->allocateMesh();
297 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700298
Romain Guycf51a412013-04-08 19:40:31 -0700299 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
Victoria Lease1e546812013-06-25 14:25:17 -0700300 uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
301 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700302
Romain Guyb969a0d2013-02-05 14:38:40 -0800303 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800304 switch (format) {
305 case SkMask::kA8_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700306 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
307 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
308 - TEXTURE_BORDER_SIZE;
309 // write leading border line
310 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
311 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800312 if (mGammaTable) {
Victoria Lease1e546812013-06-25 14:25:17 -0700313 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800314 row = cacheY * cacheWidth;
315 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800316 for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
317 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800318 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800319 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800320 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800321 }
322 } else {
Victoria Lease1e546812013-06-25 14:25:17 -0700323 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800324 row = cacheY * cacheWidth;
325 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
326 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
327 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800328 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700329 }
Victoria Lease1e546812013-06-25 14:25:17 -0700330 // write trailing border line
331 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
332 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
333 break;
334 }
335 case SkMask::kARGB32_Format: {
336 // prep data lengths
337 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
338 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
339 size_t rowSize = formatSize * glyph.fWidth;
340 // prep advances
341 size_t dstStride = formatSize * cacheWidth;
342 // prep indices
343 // - we actually start one row early, and then increment before first copy
344 uint8_t* src = &bitmapBuffer[0 - srcStride];
345 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
346 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
347 uint8_t* dstL = dst - borderSize;
348 uint8_t* dstR = dst + rowSize;
349 // write leading border line
350 memset(dstL, 0, rowSize + 2 * borderSize);
351 // write glyph data
352 while (dst < dstEnd) {
353 memset(dstL += dstStride, 0, borderSize); // leading border column
354 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
355 memset(dstR += dstStride, 0, borderSize); // trailing border column
356 }
357 // write trailing border line
Victoria Lease16c84062013-09-19 15:38:21 -0700358 memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800359 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700360 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800361 case SkMask::kBW_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700362 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
363 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
364 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800365 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700366 // write leading border line
367 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
368 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800369 for (cacheY = startY; cacheY < endY; cacheY++) {
370 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700371 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800372 uint8_t* buffer = bitmapBuffer;
373
Romain Guy0b58a3d2013-03-05 12:16:27 -0800374 row = cacheY * cacheWidth;
375 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800376 while (--rowBytes >= 0) {
377 uint8_t b = *buffer++;
378 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
379 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
380 }
381 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800382 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800383
Victoria Lease1e546812013-06-25 14:25:17 -0700384 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700385 }
Victoria Lease1e546812013-06-25 14:25:17 -0700386 // write trailing border line
387 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
388 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800389 break;
Romain Guy694b5192010-07-21 21:33:20 -0700390 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800391 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700392 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800393 break;
Romain Guy694b5192010-07-21 21:33:20 -0700394 }
Romain Guy97771732012-02-28 18:17:02 -0800395
Chet Haase7de0cb12011-12-05 16:35:38 -0800396 cachedGlyph->mIsValid = true;
Romain Guy694b5192010-07-21 21:33:20 -0700397}
398
Victoria Lease1e546812013-06-25 14:25:17 -0700399CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
400 bool allocate) {
401 CacheTexture* cacheTexture = new CacheTexture(width, height, format, gMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700402
Chet Haase2a47c142011-12-14 15:22:56 -0800403 if (allocate) {
Romain Guy80872462012-09-04 16:42:01 -0700404 Caches::getInstance().activeTexture(0);
405 cacheTexture->allocateTexture();
Romain Guy661a87e2013-03-19 15:24:36 -0700406 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800407 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700408
Chet Haase2a47c142011-12-14 15:22:56 -0800409 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800410}
411
412void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700413 clearCacheTextures(mACacheTextures);
414 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700415
Chet Haase7de0cb12011-12-05 16:35:38 -0800416 mUploadTexture = false;
Victoria Lease1e546812013-06-25 14:25:17 -0700417 mACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
418 GL_ALPHA, true));
419 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
420 GL_ALPHA, false));
421 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
422 GL_ALPHA, false));
423 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
424 GL_ALPHA, false));
425 mRGBACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
426 GL_RGBA, false));
427 mRGBACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
428 GL_RGBA, false));
429 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700430}
431
Romain Guy694b5192010-07-21 21:33:20 -0700432// We don't want to allocate anything unless we actually draw text
433void FontRenderer::checkInit() {
434 if (mInitialized) {
435 return;
436 }
437
438 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700439
440 mInitialized = true;
441}
442
Victoria Lease1e546812013-06-25 14:25:17 -0700443void checkTextureUpdateForCache(Caches& caches, Vector<CacheTexture*>& cacheTextures,
444 bool& resetPixelStore, GLuint& lastTextureId) {
445 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
446 CacheTexture* cacheTexture = cacheTextures[i];
447 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
448 if (cacheTexture->getTextureId() != lastTextureId) {
449 lastTextureId = cacheTexture->getTextureId();
450 caches.activeTexture(0);
451 caches.bindTexture(lastTextureId);
452 }
453
454 if (cacheTexture->upload()) {
455 resetPixelStore = true;
456 }
457 }
458 }
459}
460
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700461void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900462 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700463 return;
Romain Guy694b5192010-07-21 21:33:20 -0700464 }
465
Romain Guy2d4fd362011-12-13 22:00:19 -0800466 Caches& caches = Caches::getInstance();
467 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700468
Romain Guycf51a412013-04-08 19:40:31 -0700469 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700470 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
471
Chet Haase378e9192012-08-15 15:54:54 -0700472 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700473 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
474 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700475
Romain Guycf51a412013-04-08 19:40:31 -0700476 // Unbind any PBO we might have used to update textures
477 caches.unbindPixelBuffer();
478
Romain Guy09087642013-04-04 12:27:54 -0700479 // Reset to default unpack row length to avoid affecting texture
480 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700481 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700482 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
483 }
484
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700485 mUploadTexture = false;
486}
487
Victoria Lease1e546812013-06-25 14:25:17 -0700488void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
489 Caches& caches = Caches::getInstance();
Romain Guy661a87e2013-03-19 15:24:36 -0700490 bool first = true;
491 bool force = false;
Victoria Lease1e546812013-06-25 14:25:17 -0700492 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
493 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700494 if (texture->canDraw()) {
495 if (first) {
Victoria Lease1e546812013-06-25 14:25:17 -0700496 if (mFunctor) {
497 TextSetupFunctor::Data functorData(texture->getFormat());
498 (*mFunctor)(0, &functorData);
499 }
Romain Guy257ae352013-03-20 16:31:12 -0700500
Romain Guy661a87e2013-03-19 15:24:36 -0700501 checkTextureUpdate();
Romain Guy31e08e92013-06-18 15:53:53 -0700502 caches.bindIndicesBuffer();
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900503
Romain Guy661a87e2013-03-19 15:24:36 -0700504 if (!mDrawn) {
505 // If returns true, a VBO was bound and we must
506 // rebind our vertex attrib pointers even if
507 // they have the same values as the current pointers
508 force = caches.unbindMeshBuffer();
509 }
510
511 caches.activeTexture(0);
512 first = false;
513 }
514
Romain Guy8aa195d2013-06-04 18:00:09 -0700515 caches.bindTexture(texture->getTextureId());
Romain Guy661a87e2013-03-19 15:24:36 -0700516 texture->setLinearFiltering(mLinearFiltering, false);
517
518 TextureVertex* mesh = texture->mesh();
519 caches.bindPositionVertexPointer(force, &mesh[0].position[0]);
520 caches.bindTexCoordsVertexPointer(force, &mesh[0].texture[0]);
521 force = false;
522
523 glDrawElements(GL_TRIANGLES, texture->meshElementCount(),
524 GL_UNSIGNED_SHORT, texture->indices());
525
526 texture->resetMesh();
Romain Guy115096f2013-03-19 11:32:41 -0700527 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900528 }
Victoria Lease1e546812013-06-25 14:25:17 -0700529}
530
531void FontRenderer::issueDrawCommand() {
532 issueDrawCommand(mACacheTextures);
533 issueDrawCommand(mRGBACacheTextures);
Romain Guy5b3b3522010-10-27 18:57:51 -0700534
535 mDrawn = true;
Romain Guy694b5192010-07-21 21:33:20 -0700536}
537
Romain Guy97771732012-02-28 18:17:02 -0800538void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
539 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
Chet Haase7de0cb12011-12-05 16:35:38 -0800540 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800541 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800542 // Now use the new texture id
543 mCurrentCacheTexture = texture;
544 }
Romain Guy09147fb2010-07-22 13:08:20 -0700545
Romain Guy661a87e2013-03-19 15:24:36 -0700546 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
547 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800548}
549
550void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
551 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
552 float x4, float y4, float u4, float v4, CacheTexture* texture) {
553
554 if (mClip &&
555 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
556 return;
557 }
558
559 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 -0700560
Romain Guy5b3b3522010-10-27 18:57:51 -0700561 if (mBounds) {
562 mBounds->left = fmin(mBounds->left, x1);
563 mBounds->top = fmin(mBounds->top, y3);
564 mBounds->right = fmax(mBounds->right, x3);
565 mBounds->bottom = fmax(mBounds->bottom, y1);
566 }
567
Romain Guy661a87e2013-03-19 15:24:36 -0700568 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700569 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700570 }
571}
572
Romain Guy97771732012-02-28 18:17:02 -0800573void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
574 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
575 float x4, float y4, float u4, float v4, CacheTexture* texture) {
576
577 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
578
579 if (mBounds) {
580 mBounds->left = fmin(mBounds->left, fmin(x1, fmin(x2, fmin(x3, x4))));
581 mBounds->top = fmin(mBounds->top, fmin(y1, fmin(y2, fmin(y3, y4))));
582 mBounds->right = fmax(mBounds->right, fmax(x1, fmax(x2, fmax(x3, x4))));
583 mBounds->bottom = fmax(mBounds->bottom, fmax(y1, fmax(y2, fmax(y3, y4))));
584 }
585
Romain Guy661a87e2013-03-19 15:24:36 -0700586 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800587 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800588 }
589}
590
Romain Guye3a9b242013-01-08 11:15:30 -0800591void FontRenderer::setFont(SkPaint* paint, const mat4& matrix) {
592 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700593}
Romain Guy7975fb62010-10-01 16:36:14 -0700594
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700595FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text,
Raph Levien416a8472012-07-19 22:48:17 -0700596 uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700597 checkInit();
598
Romain Guycf51a412013-04-08 19:40:31 -0700599 DropShadow image;
600 image.width = 0;
601 image.height = 0;
602 image.image = NULL;
603 image.penX = 0;
604 image.penY = 0;
605
Romain Guy1e45aae2010-08-13 19:39:53 -0700606 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700607 return image;
608 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700609
Romain Guy2d4fd362011-12-13 22:00:19 -0800610 mDrawn = false;
Romain Guyff98fa52011-11-28 09:35:09 -0800611 mClip = NULL;
612 mBounds = NULL;
613
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700614 Rect bounds;
Raph Levien416a8472012-07-19 22:48:17 -0700615 mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800616
Romain Guy1e45aae2010-08-13 19:39:53 -0700617 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius;
618 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius;
Romain Guyff98fa52011-11-28 09:35:09 -0800619
Romain Guycf51a412013-04-08 19:40:31 -0700620 uint32_t maxSize = Caches::getInstance().maxTextureSize;
621 if (paddedWidth > maxSize || paddedHeight > maxSize) {
622 return image;
623 }
624
Dan Morrille4d9a012013-03-28 18:10:43 -0700625#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800626 // Align buffers for renderscript usage
627 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
628 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700629 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800630 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800631 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700632#else
633 int size = paddedWidth * paddedHeight;
634 uint8_t* dataBuffer = (uint8_t*) malloc(size);
635#endif
636
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800637 memset(dataBuffer, 0, size);
638
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700639 int penX = radius - bounds.left;
640 int penY = radius - bounds.bottom;
641
Chris Craikdd8697c2013-02-22 10:41:36 -0800642 if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
643 // text has non-whitespace, so draw and blur to create the shadow
644 // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
645 // TODO: don't draw pure whitespace in the first place, and avoid needing this check
646 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
647 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions);
648
Romain Guycf51a412013-04-08 19:40:31 -0700649 // Unbind any PBO we might have used
650 Caches::getInstance().unbindPixelBuffer();
651
Chris Craikdd8697c2013-02-22 10:41:36 -0800652 blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
653 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700654
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700655 image.width = paddedWidth;
656 image.height = paddedHeight;
657 image.image = dataBuffer;
658 image.penX = penX;
659 image.penY = penY;
Romain Guy2d4fd362011-12-13 22:00:19 -0800660
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700661 return image;
662}
Romain Guy694b5192010-07-21 21:33:20 -0700663
Romain Guy257ae352013-03-20 16:31:12 -0700664void FontRenderer::initRender(const Rect* clip, Rect* bounds, Functor* functor) {
Romain Guy694b5192010-07-21 21:33:20 -0700665 checkInit();
666
Romain Guy5b3b3522010-10-27 18:57:51 -0700667 mDrawn = false;
668 mBounds = bounds;
Romain Guy257ae352013-03-20 16:31:12 -0700669 mFunctor = functor;
Romain Guy09147fb2010-07-22 13:08:20 -0700670 mClip = clip;
Romain Guy671d6cf2012-01-18 12:39:17 -0800671}
Romain Guyff98fa52011-11-28 09:35:09 -0800672
Romain Guy671d6cf2012-01-18 12:39:17 -0800673void FontRenderer::finishRender() {
Romain Guy5b3b3522010-10-27 18:57:51 -0700674 mBounds = NULL;
Romain Guyff98fa52011-11-28 09:35:09 -0800675 mClip = NULL;
Romain Guy694b5192010-07-21 21:33:20 -0700676
Romain Guy661a87e2013-03-19 15:24:36 -0700677 issueDrawCommand();
Romain Guy671d6cf2012-01-18 12:39:17 -0800678}
679
Romain Guye3a9b242013-01-08 11:15:30 -0800680void FontRenderer::precache(SkPaint* paint, const char* text, int numGlyphs, const mat4& matrix) {
681 Font* font = Font::create(this, paint, matrix);
Chet Haasee816bae2012-08-09 13:39:02 -0700682 font->precache(paint, text, numGlyphs);
683}
684
Romain Guycf51a412013-04-08 19:40:31 -0700685void FontRenderer::endPrecaching() {
686 checkTextureUpdate();
687}
688
Romain Guy671d6cf2012-01-18 12:39:17 -0800689bool FontRenderer::renderPosText(SkPaint* paint, const Rect* clip, const char *text,
690 uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
Chris Craik527a3aa2013-03-04 10:19:31 -0800691 const float* positions, Rect* bounds, Functor* functor, bool forceFinish) {
Romain Guy671d6cf2012-01-18 12:39:17 -0800692 if (!mCurrentFont) {
693 ALOGE("No font set");
694 return false;
695 }
696
Romain Guy257ae352013-03-20 16:31:12 -0700697 initRender(clip, bounds, functor);
Romain Guy671d6cf2012-01-18 12:39:17 -0800698 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions);
Chris Craik527a3aa2013-03-04 10:19:31 -0800699
700 if (forceFinish) {
701 finishRender();
702 }
Romain Guy5b3b3522010-10-27 18:57:51 -0700703
704 return mDrawn;
Romain Guy694b5192010-07-21 21:33:20 -0700705}
706
Romain Guy97771732012-02-28 18:17:02 -0800707bool FontRenderer::renderTextOnPath(SkPaint* paint, const Rect* clip, const char *text,
708 uint32_t startIndex, uint32_t len, int numGlyphs, SkPath* path,
Victoria Lease1e546812013-06-25 14:25:17 -0700709 float hOffset, float vOffset, Rect* bounds, Functor* functor) {
Romain Guy97771732012-02-28 18:17:02 -0800710 if (!mCurrentFont) {
711 ALOGE("No font set");
712 return false;
713 }
714
Victoria Lease1e546812013-06-25 14:25:17 -0700715 initRender(clip, bounds, functor);
Romain Guy97771732012-02-28 18:17:02 -0800716 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset);
717 finishRender();
718
719 return mDrawn;
720}
721
Romain Guy9b1204b2012-09-04 15:22:57 -0700722void FontRenderer::removeFont(const Font* font) {
Romain Guye3a9b242013-01-08 11:15:30 -0800723 mActiveFonts.remove(font->getDescription());
Romain Guy9b1204b2012-09-04 15:22:57 -0700724
725 if (mCurrentFont == font) {
726 mCurrentFont = NULL;
727 }
728}
729
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800730void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, int32_t radius) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700731#ifdef ANDROID_ENABLE_RENDERSCRIPT
732 if (width * height * radius >= RS_MIN_INPUT_CUTOFF) {
733 uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700734
Tim Murray250b1cf2013-08-01 14:49:22 -0700735 if (mRs == 0) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700736 mRs = new RSC::RS();
Tim Murray804ff382013-12-13 12:57:36 -0800737 // a null path is OK because there are no custom kernels used
738 // hence nothing gets cached by RS
739 if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800740 mRs.clear();
Dan Morrille4d9a012013-03-28 18:10:43 -0700741 ALOGE("blur RS failed to init");
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800742 } else {
743 mRsElement = RSC::Element::A_8(mRs);
744 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Dan Morrille4d9a012013-03-28 18:10:43 -0700745 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800746 }
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800747 if (mRs != 0) {
748 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
749 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
750 RS_ALLOCATION_MIPMAP_NONE,
751 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
752 *image);
753 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
754 RS_ALLOCATION_MIPMAP_NONE,
755 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
756 outImage);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800757
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800758 mRsScript->setRadius(radius);
759 mRsScript->setInput(ain);
760 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700761
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800762 // replace the original image's pointer, avoiding a copy back to the original buffer
763 free(*image);
764 *image = outImage;
Dan Morrille4d9a012013-03-28 18:10:43 -0700765
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800766 return;
767 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800768 }
Dan Morrille4d9a012013-03-28 18:10:43 -0700769#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800770
Dan Morrille4d9a012013-03-28 18:10:43 -0700771 float *gaussian = new float[2 * radius + 1];
772 Blur::generateGaussianWeights(gaussian, radius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800773
Dan Morrille4d9a012013-03-28 18:10:43 -0700774 uint8_t* scratch = new uint8_t[width * height];
775 Blur::horizontal(gaussian, radius, *image, scratch, width, height);
776 Blur::vertical(gaussian, radius, scratch, *image, width, height);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800777
Dan Morrille4d9a012013-03-28 18:10:43 -0700778 delete[] gaussian;
779 delete[] scratch;
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700780}
781
Victoria Lease1e546812013-06-25 14:25:17 -0700782static uint32_t calculateCacheSize(const Vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700783 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700784 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
785 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700786 if (cacheTexture && cacheTexture->getPixelBuffer()) {
787 size += cacheTexture->getPixelBuffer()->getSize();
788 }
789 }
790 return size;
791}
792
Victoria Lease1e546812013-06-25 14:25:17 -0700793uint32_t FontRenderer::getCacheSize(GLenum format) const {
794 switch (format) {
795 case GL_ALPHA: {
796 return calculateCacheSize(mACacheTextures);
797 }
798 case GL_RGBA: {
799 return calculateCacheSize(mRGBACacheTextures);
800 }
801 default: {
802 return 0;
803 }
804 }
805}
806
Romain Guy694b5192010-07-21 21:33:20 -0700807}; // namespace uirenderer
808}; // namespace android