blob: f907d64e9aa3a50c8eda47fd61cf20dbc123cbab [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();
Chris Craik4063a0e2013-11-15 16:06:56 -080079 renderer->setupDrawModelView(kModelViewMode_Translate, false,
80 0.0f, 0.0f, 0.0f, 0.0f, pureTranslate);
Victoria Lease1e546812013-06-25 14:25:17 -070081 // Calling setupDrawTexture with the name 0 will enable the
82 // uv attributes and increase the texture unit count
83 // texture binding will be performed by the font renderer as
84 // needed
85 renderer->setupDrawTexture(0);
86 renderer->setupDrawPureColorUniforms();
87 renderer->setupDrawColorFilterUniforms();
88 renderer->setupDrawShaderUniforms(pureTranslate);
89 renderer->setupDrawTextGammaUniforms();
90
91 return NO_ERROR;
92}
93
94///////////////////////////////////////////////////////////////////////////////
Romain Guy694b5192010-07-21 21:33:20 -070095// FontRenderer
96///////////////////////////////////////////////////////////////////////////////
97
Romain Guy514fb182011-01-19 14:38:29 -080098static bool sLogFontRendererCreate = true;
99
Romain Guye3a9b242013-01-08 11:15:30 -0800100FontRenderer::FontRenderer() :
101 mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity) {
102
Romain Guyc9855a52011-01-21 21:14:15 -0800103 if (sLogFontRendererCreate) {
104 INIT_LOGD("Creating FontRenderer");
105 }
Romain Guy51769a62010-07-23 00:28:00 -0700106
Romain Guyb45c0c92010-08-26 20:35:23 -0700107 mGammaTable = NULL;
Romain Guy694b5192010-07-21 21:33:20 -0700108 mInitialized = false;
Romain Guy694b5192010-07-21 21:33:20 -0700109
Chet Haase7de0cb12011-12-05 16:35:38 -0800110 mCurrentCacheTexture = NULL;
Romain Guy9cccc2b2010-08-07 23:46:15 -0700111
Chet Haase2a47c142011-12-14 15:22:56 -0800112 mLinearFiltering = false;
113
Chet Haaseeb32a492012-08-31 13:54:03 -0700114 mSmallCacheWidth = DEFAULT_TEXT_SMALL_CACHE_WIDTH;
115 mSmallCacheHeight = DEFAULT_TEXT_SMALL_CACHE_HEIGHT;
116 mLargeCacheWidth = DEFAULT_TEXT_LARGE_CACHE_WIDTH;
117 mLargeCacheHeight = DEFAULT_TEXT_LARGE_CACHE_HEIGHT;
Romain Guy51769a62010-07-23 00:28:00 -0700118
119 char property[PROPERTY_VALUE_MAX];
Chet Haaseeb32a492012-08-31 13:54:03 -0700120 if (property_get(PROPERTY_TEXT_SMALL_CACHE_WIDTH, property, NULL) > 0) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800121 mSmallCacheWidth = atoi(property);
Romain Guy51769a62010-07-23 00:28:00 -0700122 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700123
Chet Haaseeb32a492012-08-31 13:54:03 -0700124 if (property_get(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, property, NULL) > 0) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800125 mSmallCacheHeight = atoi(property);
Chet Haaseeb32a492012-08-31 13:54:03 -0700126 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700127
Chet Haaseeb32a492012-08-31 13:54:03 -0700128 if (property_get(PROPERTY_TEXT_LARGE_CACHE_WIDTH, property, NULL) > 0) {
129 mLargeCacheWidth = atoi(property);
130 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700131
Chet Haaseeb32a492012-08-31 13:54:03 -0700132 if (property_get(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, property, NULL) > 0) {
133 mLargeCacheHeight = atoi(property);
134 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700135
136 uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
137 mSmallCacheWidth = mSmallCacheWidth > maxTextureSize ? maxTextureSize : mSmallCacheWidth;
138 mSmallCacheHeight = mSmallCacheHeight > maxTextureSize ? maxTextureSize : mSmallCacheHeight;
139 mLargeCacheWidth = mLargeCacheWidth > maxTextureSize ? maxTextureSize : mLargeCacheWidth;
140 mLargeCacheHeight = mLargeCacheHeight > maxTextureSize ? maxTextureSize : mLargeCacheHeight;
141
Chet Haaseeb32a492012-08-31 13:54:03 -0700142 if (sLogFontRendererCreate) {
143 INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
144 mSmallCacheWidth, mSmallCacheHeight,
145 mLargeCacheWidth, mLargeCacheHeight >> 1,
146 mLargeCacheWidth, mLargeCacheHeight >> 1,
147 mLargeCacheWidth, mLargeCacheHeight);
Romain Guy51769a62010-07-23 00:28:00 -0700148 }
Romain Guy514fb182011-01-19 14:38:29 -0800149
150 sLogFontRendererCreate = false;
Romain Guy694b5192010-07-21 21:33:20 -0700151}
152
Victoria Lease1e546812013-06-25 14:25:17 -0700153void clearCacheTextures(Vector<CacheTexture*>& cacheTextures) {
154 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
155 delete cacheTextures[i];
Romain Guy694b5192010-07-21 21:33:20 -0700156 }
Victoria Lease1e546812013-06-25 14:25:17 -0700157 cacheTextures.clear();
158}
159
160FontRenderer::~FontRenderer() {
161 clearCacheTextures(mACacheTextures);
162 clearCacheTextures(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700163
Romain Guye3a9b242013-01-08 11:15:30 -0800164 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
165 while (it.next()) {
166 delete it.value();
Romain Guy694b5192010-07-21 21:33:20 -0700167 }
Romain Guye3a9b242013-01-08 11:15:30 -0800168 mActiveFonts.clear();
Romain Guy694b5192010-07-21 21:33:20 -0700169}
170
171void FontRenderer::flushAllAndInvalidate() {
Romain Guy661a87e2013-03-19 15:24:36 -0700172 issueDrawCommand();
Romain Guy9d9758a2012-05-14 15:19:58 -0700173
Romain Guye3a9b242013-01-08 11:15:30 -0800174 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
175 while (it.next()) {
176 it.value()->invalidateTextureCache();
Romain Guy694b5192010-07-21 21:33:20 -0700177 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700178
Victoria Lease1e546812013-06-25 14:25:17 -0700179 for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
180 mACacheTextures[i]->init();
181 }
182
183 for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
184 mRGBACacheTextures[i]->init();
Romain Guy694b5192010-07-21 21:33:20 -0700185 }
186}
187
Victoria Lease1e546812013-06-25 14:25:17 -0700188void FontRenderer::flushLargeCaches(Vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700189 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700190 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
191 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700192 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700193 cacheTexture->init();
Romain Guye3a9b242013-01-08 11:15:30 -0800194 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
195 while (it.next()) {
196 it.value()->invalidateTextureCache(cacheTexture);
Chet Haasee816bae2012-08-09 13:39:02 -0700197 }
Romain Guy80872462012-09-04 16:42:01 -0700198 cacheTexture->releaseTexture();
Chet Haase9a824562011-12-16 15:44:59 -0800199 }
200 }
Chet Haase9a824562011-12-16 15:44:59 -0800201}
202
Victoria Lease1e546812013-06-25 14:25:17 -0700203void FontRenderer::flushLargeCaches() {
204 flushLargeCaches(mACacheTextures);
205 flushLargeCaches(mRGBACacheTextures);
206}
207
208CacheTexture* FontRenderer::cacheBitmapInTexture(Vector<CacheTexture*>& cacheTextures,
209 const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
210 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
211 if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
212 return cacheTextures[i];
Chet Haase378e9192012-08-15 15:54:54 -0700213 }
214 }
215 // Could not fit glyph into current cache textures
216 return NULL;
217}
218
Chet Haase7de0cb12011-12-05 16:35:38 -0800219void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
Chet Haasef942cf12012-08-30 09:06:46 -0700220 uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700221 checkInit();
Romain Guya4adcf02013-02-28 12:15:35 -0800222
223 // If the glyph bitmap is empty let's assum the glyph is valid
224 // so we can avoid doing extra work later on
225 if (glyph.fWidth == 0 || glyph.fHeight == 0) {
226 cachedGlyph->mIsValid = true;
227 cachedGlyph->mCacheTexture = NULL;
228 return;
229 }
230
Chet Haase7de0cb12011-12-05 16:35:38 -0800231 cachedGlyph->mIsValid = false;
Romain Guya4adcf02013-02-28 12:15:35 -0800232
Victoria Lease1e546812013-06-25 14:25:17 -0700233 // choose an appropriate cache texture list for this glyph format
234 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
235 Vector<CacheTexture*>* cacheTextures = NULL;
236 switch (format) {
237 case SkMask::kA8_Format:
Victoria Lease723b2fe2013-08-12 14:38:44 -0700238 case SkMask::kBW_Format:
Victoria Lease1e546812013-06-25 14:25:17 -0700239 cacheTextures = &mACacheTextures;
240 break;
241 case SkMask::kARGB32_Format:
242 cacheTextures = &mRGBACacheTextures;
243 break;
244 default:
245#if DEBUG_FONT_RENDERER
246 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
247#endif
248 return;
249 }
250
Romain Guy694b5192010-07-21 21:33:20 -0700251 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700252 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
Victoria Lease1e546812013-06-25 14:25:17 -0700253 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700254 ALOGE("Font size too large to fit in cache. width, height = %i, %i",
255 (int) glyph.fWidth, (int) glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800256 return;
Romain Guy694b5192010-07-21 21:33:20 -0700257 }
258
259 // Now copy the bitmap into the cache texture
260 uint32_t startX = 0;
261 uint32_t startY = 0;
262
Victoria Lease1e546812013-06-25 14:25:17 -0700263 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700264
Chet Haase378e9192012-08-15 15:54:54 -0700265 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700266 if (!precaching) {
267 // If the new glyph didn't fit and we are not just trying to precache it,
268 // clear out the cache and try again
269 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700270 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700271 }
Romain Guy694b5192010-07-21 21:33:20 -0700272
Chet Haase378e9192012-08-15 15:54:54 -0700273 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700274 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800275 return;
Romain Guy694b5192010-07-21 21:33:20 -0700276 }
277 }
278
Chet Haase378e9192012-08-15 15:54:54 -0700279 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800280
Romain Guy694b5192010-07-21 21:33:20 -0700281 *retOriginX = startX;
282 *retOriginY = startY;
283
284 uint32_t endX = startX + glyph.fWidth;
285 uint32_t endY = startY + glyph.fHeight;
286
Romain Guy80872462012-09-04 16:42:01 -0700287 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700288
Romain Guycf51a412013-04-08 19:40:31 -0700289 if (!cacheTexture->getPixelBuffer()) {
Romain Guy80872462012-09-04 16:42:01 -0700290 Caches::getInstance().activeTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800291 // Large-glyph texture memory is allocated only as needed
Romain Guy80872462012-09-04 16:42:01 -0700292 cacheTexture->allocateTexture();
Chet Haase7de0cb12011-12-05 16:35:38 -0800293 }
Romain Guy661a87e2013-03-19 15:24:36 -0700294 if (!cacheTexture->mesh()) {
295 cacheTexture->allocateMesh();
296 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700297
Romain Guycf51a412013-04-08 19:40:31 -0700298 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
Victoria Lease1e546812013-06-25 14:25:17 -0700299 uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
300 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700301
Romain Guyb969a0d2013-02-05 14:38:40 -0800302 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800303 switch (format) {
304 case SkMask::kA8_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700305 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
306 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
307 - TEXTURE_BORDER_SIZE;
308 // write leading border line
309 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
310 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800311 if (mGammaTable) {
Victoria Lease1e546812013-06-25 14:25:17 -0700312 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800313 row = cacheY * cacheWidth;
314 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800315 for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
316 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800317 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800318 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800319 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800320 }
321 } else {
Victoria Lease1e546812013-06-25 14:25:17 -0700322 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800323 row = cacheY * cacheWidth;
324 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
325 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
326 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800327 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700328 }
Victoria Lease1e546812013-06-25 14:25:17 -0700329 // write trailing border line
330 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
331 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
332 break;
333 }
334 case SkMask::kARGB32_Format: {
335 // prep data lengths
336 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
337 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
338 size_t rowSize = formatSize * glyph.fWidth;
339 // prep advances
340 size_t dstStride = formatSize * cacheWidth;
341 // prep indices
342 // - we actually start one row early, and then increment before first copy
343 uint8_t* src = &bitmapBuffer[0 - srcStride];
344 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
345 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
346 uint8_t* dstL = dst - borderSize;
347 uint8_t* dstR = dst + rowSize;
348 // write leading border line
349 memset(dstL, 0, rowSize + 2 * borderSize);
350 // write glyph data
351 while (dst < dstEnd) {
352 memset(dstL += dstStride, 0, borderSize); // leading border column
353 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
354 memset(dstR += dstStride, 0, borderSize); // trailing border column
355 }
356 // write trailing border line
Victoria Lease16c84062013-09-19 15:38:21 -0700357 memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800358 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700359 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800360 case SkMask::kBW_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700361 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
362 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
363 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800364 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700365 // write leading border line
366 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
367 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800368 for (cacheY = startY; cacheY < endY; cacheY++) {
369 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700370 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800371 uint8_t* buffer = bitmapBuffer;
372
Romain Guy0b58a3d2013-03-05 12:16:27 -0800373 row = cacheY * cacheWidth;
374 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800375 while (--rowBytes >= 0) {
376 uint8_t b = *buffer++;
377 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
378 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
379 }
380 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800381 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800382
Victoria Lease1e546812013-06-25 14:25:17 -0700383 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700384 }
Victoria Lease1e546812013-06-25 14:25:17 -0700385 // write trailing border line
386 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
387 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800388 break;
Romain Guy694b5192010-07-21 21:33:20 -0700389 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800390 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700391 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800392 break;
Romain Guy694b5192010-07-21 21:33:20 -0700393 }
Romain Guy97771732012-02-28 18:17:02 -0800394
Chet Haase7de0cb12011-12-05 16:35:38 -0800395 cachedGlyph->mIsValid = true;
Romain Guy694b5192010-07-21 21:33:20 -0700396}
397
Victoria Lease1e546812013-06-25 14:25:17 -0700398CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
399 bool allocate) {
400 CacheTexture* cacheTexture = new CacheTexture(width, height, format, gMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700401
Chet Haase2a47c142011-12-14 15:22:56 -0800402 if (allocate) {
Romain Guy80872462012-09-04 16:42:01 -0700403 Caches::getInstance().activeTexture(0);
404 cacheTexture->allocateTexture();
Romain Guy661a87e2013-03-19 15:24:36 -0700405 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800406 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700407
Chet Haase2a47c142011-12-14 15:22:56 -0800408 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800409}
410
411void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700412 clearCacheTextures(mACacheTextures);
413 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700414
Chet Haase7de0cb12011-12-05 16:35:38 -0800415 mUploadTexture = false;
Victoria Lease1e546812013-06-25 14:25:17 -0700416 mACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
417 GL_ALPHA, true));
418 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
419 GL_ALPHA, false));
420 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
421 GL_ALPHA, false));
422 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
423 GL_ALPHA, false));
424 mRGBACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
425 GL_RGBA, false));
426 mRGBACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
427 GL_RGBA, false));
428 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700429}
430
Romain Guy694b5192010-07-21 21:33:20 -0700431// We don't want to allocate anything unless we actually draw text
432void FontRenderer::checkInit() {
433 if (mInitialized) {
434 return;
435 }
436
437 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700438
439 mInitialized = true;
440}
441
Victoria Lease1e546812013-06-25 14:25:17 -0700442void checkTextureUpdateForCache(Caches& caches, Vector<CacheTexture*>& cacheTextures,
443 bool& resetPixelStore, GLuint& lastTextureId) {
444 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
445 CacheTexture* cacheTexture = cacheTextures[i];
446 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
447 if (cacheTexture->getTextureId() != lastTextureId) {
448 lastTextureId = cacheTexture->getTextureId();
449 caches.activeTexture(0);
450 caches.bindTexture(lastTextureId);
451 }
452
453 if (cacheTexture->upload()) {
454 resetPixelStore = true;
455 }
456 }
457 }
458}
459
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700460void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900461 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700462 return;
Romain Guy694b5192010-07-21 21:33:20 -0700463 }
464
Romain Guy2d4fd362011-12-13 22:00:19 -0800465 Caches& caches = Caches::getInstance();
466 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700467
Romain Guycf51a412013-04-08 19:40:31 -0700468 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700469 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
470
Chet Haase378e9192012-08-15 15:54:54 -0700471 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700472 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
473 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700474
Romain Guycf51a412013-04-08 19:40:31 -0700475 // Unbind any PBO we might have used to update textures
476 caches.unbindPixelBuffer();
477
Romain Guy09087642013-04-04 12:27:54 -0700478 // Reset to default unpack row length to avoid affecting texture
479 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700480 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700481 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
482 }
483
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700484 mUploadTexture = false;
485}
486
Victoria Lease1e546812013-06-25 14:25:17 -0700487void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
488 Caches& caches = Caches::getInstance();
Romain Guy661a87e2013-03-19 15:24:36 -0700489 bool first = true;
490 bool force = false;
Victoria Lease1e546812013-06-25 14:25:17 -0700491 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
492 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700493 if (texture->canDraw()) {
494 if (first) {
Victoria Lease1e546812013-06-25 14:25:17 -0700495 if (mFunctor) {
496 TextSetupFunctor::Data functorData(texture->getFormat());
497 (*mFunctor)(0, &functorData);
498 }
Romain Guy257ae352013-03-20 16:31:12 -0700499
Romain Guy661a87e2013-03-19 15:24:36 -0700500 checkTextureUpdate();
Romain Guy31e08e92013-06-18 15:53:53 -0700501 caches.bindIndicesBuffer();
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900502
Romain Guy661a87e2013-03-19 15:24:36 -0700503 if (!mDrawn) {
504 // If returns true, a VBO was bound and we must
505 // rebind our vertex attrib pointers even if
506 // they have the same values as the current pointers
507 force = caches.unbindMeshBuffer();
508 }
509
510 caches.activeTexture(0);
511 first = false;
512 }
513
Romain Guy8aa195d2013-06-04 18:00:09 -0700514 caches.bindTexture(texture->getTextureId());
Romain Guy661a87e2013-03-19 15:24:36 -0700515 texture->setLinearFiltering(mLinearFiltering, false);
516
517 TextureVertex* mesh = texture->mesh();
Romain Guy3380cfd2013-08-15 16:57:57 -0700518 caches.bindPositionVertexPointer(force, &mesh[0].x);
519 caches.bindTexCoordsVertexPointer(force, &mesh[0].u);
Romain Guy661a87e2013-03-19 15:24:36 -0700520 force = false;
521
522 glDrawElements(GL_TRIANGLES, texture->meshElementCount(),
523 GL_UNSIGNED_SHORT, texture->indices());
524
525 texture->resetMesh();
Romain Guy115096f2013-03-19 11:32:41 -0700526 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900527 }
Victoria Lease1e546812013-06-25 14:25:17 -0700528}
529
530void FontRenderer::issueDrawCommand() {
531 issueDrawCommand(mACacheTextures);
532 issueDrawCommand(mRGBACacheTextures);
Romain Guy5b3b3522010-10-27 18:57:51 -0700533
534 mDrawn = true;
Romain Guy694b5192010-07-21 21:33:20 -0700535}
536
Romain Guy97771732012-02-28 18:17:02 -0800537void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
538 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
Chet Haase7de0cb12011-12-05 16:35:38 -0800539 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800540 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800541 // Now use the new texture id
542 mCurrentCacheTexture = texture;
543 }
Romain Guy09147fb2010-07-22 13:08:20 -0700544
Romain Guy661a87e2013-03-19 15:24:36 -0700545 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
546 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800547}
548
549void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
550 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
551 float x4, float y4, float u4, float v4, CacheTexture* texture) {
552
553 if (mClip &&
554 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
555 return;
556 }
557
558 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 -0700559
Romain Guy5b3b3522010-10-27 18:57:51 -0700560 if (mBounds) {
561 mBounds->left = fmin(mBounds->left, x1);
562 mBounds->top = fmin(mBounds->top, y3);
563 mBounds->right = fmax(mBounds->right, x3);
564 mBounds->bottom = fmax(mBounds->bottom, y1);
565 }
566
Romain Guy661a87e2013-03-19 15:24:36 -0700567 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700568 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700569 }
570}
571
Romain Guy97771732012-02-28 18:17:02 -0800572void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
573 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
574 float x4, float y4, float u4, float v4, CacheTexture* texture) {
575
576 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
577
578 if (mBounds) {
579 mBounds->left = fmin(mBounds->left, fmin(x1, fmin(x2, fmin(x3, x4))));
580 mBounds->top = fmin(mBounds->top, fmin(y1, fmin(y2, fmin(y3, y4))));
581 mBounds->right = fmax(mBounds->right, fmax(x1, fmax(x2, fmax(x3, x4))));
582 mBounds->bottom = fmax(mBounds->bottom, fmax(y1, fmax(y2, fmax(y3, y4))));
583 }
584
Romain Guy661a87e2013-03-19 15:24:36 -0700585 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800586 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800587 }
588}
589
Chris Craikd218a922014-01-02 17:13:34 -0800590void FontRenderer::setFont(const SkPaint* paint, const mat4& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800591 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700592}
Romain Guy7975fb62010-10-01 16:36:14 -0700593
Chris Craikd218a922014-01-02 17:13:34 -0800594FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const char *text,
Raph Levien416a8472012-07-19 22:48:17 -0700595 uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700596 checkInit();
597
Romain Guycf51a412013-04-08 19:40:31 -0700598 DropShadow image;
599 image.width = 0;
600 image.height = 0;
601 image.image = NULL;
602 image.penX = 0;
603 image.penY = 0;
604
Romain Guy1e45aae2010-08-13 19:39:53 -0700605 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700606 return image;
607 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700608
Romain Guy2d4fd362011-12-13 22:00:19 -0800609 mDrawn = false;
Romain Guyff98fa52011-11-28 09:35:09 -0800610 mClip = NULL;
611 mBounds = NULL;
612
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700613 Rect bounds;
Raph Levien416a8472012-07-19 22:48:17 -0700614 mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800615
Romain Guy1e45aae2010-08-13 19:39:53 -0700616 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius;
617 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius;
Romain Guyff98fa52011-11-28 09:35:09 -0800618
Romain Guycf51a412013-04-08 19:40:31 -0700619 uint32_t maxSize = Caches::getInstance().maxTextureSize;
620 if (paddedWidth > maxSize || paddedHeight > maxSize) {
621 return image;
622 }
623
Dan Morrille4d9a012013-03-28 18:10:43 -0700624#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800625 // Align buffers for renderscript usage
626 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
627 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700628 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800629 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800630 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700631#else
632 int size = paddedWidth * paddedHeight;
633 uint8_t* dataBuffer = (uint8_t*) malloc(size);
634#endif
635
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800636 memset(dataBuffer, 0, size);
637
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700638 int penX = radius - bounds.left;
639 int penY = radius - bounds.bottom;
640
Chris Craikdd8697c2013-02-22 10:41:36 -0800641 if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
642 // text has non-whitespace, so draw and blur to create the shadow
643 // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
644 // TODO: don't draw pure whitespace in the first place, and avoid needing this check
645 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
646 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions);
647
Romain Guycf51a412013-04-08 19:40:31 -0700648 // Unbind any PBO we might have used
649 Caches::getInstance().unbindPixelBuffer();
650
Chris Craikdd8697c2013-02-22 10:41:36 -0800651 blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
652 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700653
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700654 image.width = paddedWidth;
655 image.height = paddedHeight;
656 image.image = dataBuffer;
657 image.penX = penX;
658 image.penY = penY;
Romain Guy2d4fd362011-12-13 22:00:19 -0800659
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700660 return image;
661}
Romain Guy694b5192010-07-21 21:33:20 -0700662
Romain Guy257ae352013-03-20 16:31:12 -0700663void FontRenderer::initRender(const Rect* clip, Rect* bounds, Functor* functor) {
Romain Guy694b5192010-07-21 21:33:20 -0700664 checkInit();
665
Romain Guy5b3b3522010-10-27 18:57:51 -0700666 mDrawn = false;
667 mBounds = bounds;
Romain Guy257ae352013-03-20 16:31:12 -0700668 mFunctor = functor;
Romain Guy09147fb2010-07-22 13:08:20 -0700669 mClip = clip;
Romain Guy671d6cf2012-01-18 12:39:17 -0800670}
Romain Guyff98fa52011-11-28 09:35:09 -0800671
Romain Guy671d6cf2012-01-18 12:39:17 -0800672void FontRenderer::finishRender() {
Romain Guy5b3b3522010-10-27 18:57:51 -0700673 mBounds = NULL;
Romain Guyff98fa52011-11-28 09:35:09 -0800674 mClip = NULL;
Romain Guy694b5192010-07-21 21:33:20 -0700675
Romain Guy661a87e2013-03-19 15:24:36 -0700676 issueDrawCommand();
Romain Guy671d6cf2012-01-18 12:39:17 -0800677}
678
Chris Craikd218a922014-01-02 17:13:34 -0800679void FontRenderer::precache(const SkPaint* paint, const char* text, int numGlyphs,
680 const mat4& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800681 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
Chris Craikd218a922014-01-02 17:13:34 -0800689bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
Romain Guy671d6cf2012-01-18 12:39:17 -0800690 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
Chris Craikd218a922014-01-02 17:13:34 -0800707bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
708 uint32_t startIndex, uint32_t len, int numGlyphs, const 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 Murrayabe55e92013-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)) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700740 ALOGE("blur RS failed to init");
741 }
Romain Guyd71dd362011-12-12 19:03:35 -0800742
Dan Morrille4d9a012013-03-28 18:10:43 -0700743 mRsElement = RSC::Element::A_8(mRs);
Tim Murrayd8c8aaa2013-08-19 12:04:38 -0700744 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800745 }
746
Tim Murray250b1cf2013-08-01 14:49:22 -0700747 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
748 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
749 RS_ALLOCATION_MIPMAP_NONE, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
750 *image);
751 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
752 RS_ALLOCATION_MIPMAP_NONE, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
753 outImage);
Dan Morrille4d9a012013-03-28 18:10:43 -0700754
755 mRsScript->setRadius(radius);
Tim Murrayd8c8aaa2013-08-19 12:04:38 -0700756 mRsScript->setInput(ain);
757 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700758
759 // replace the original image's pointer, avoiding a copy back to the original buffer
760 free(*image);
761 *image = outImage;
762
763 return;
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800764 }
Dan Morrille4d9a012013-03-28 18:10:43 -0700765#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800766
Dan Morrille4d9a012013-03-28 18:10:43 -0700767 float *gaussian = new float[2 * radius + 1];
768 Blur::generateGaussianWeights(gaussian, radius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800769
Dan Morrille4d9a012013-03-28 18:10:43 -0700770 uint8_t* scratch = new uint8_t[width * height];
771 Blur::horizontal(gaussian, radius, *image, scratch, width, height);
772 Blur::vertical(gaussian, radius, scratch, *image, width, height);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800773
Dan Morrille4d9a012013-03-28 18:10:43 -0700774 delete[] gaussian;
775 delete[] scratch;
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700776}
777
Victoria Lease1e546812013-06-25 14:25:17 -0700778static uint32_t calculateCacheSize(const Vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700779 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700780 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
781 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700782 if (cacheTexture && cacheTexture->getPixelBuffer()) {
783 size += cacheTexture->getPixelBuffer()->getSize();
784 }
785 }
786 return size;
787}
788
Victoria Lease1e546812013-06-25 14:25:17 -0700789uint32_t FontRenderer::getCacheSize(GLenum format) const {
790 switch (format) {
791 case GL_ALPHA: {
792 return calculateCacheSize(mACacheTextures);
793 }
794 case GL_RGBA: {
795 return calculateCacheSize(mRGBACacheTextures);
796 }
797 default: {
798 return 0;
799 }
800 }
801}
802
Romain Guy694b5192010-07-21 21:33:20 -0700803}; // namespace uirenderer
804}; // namespace android