blob: 0be17ff868b4ef76c870f004361e69933d32887e [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 Guy9cccc2b2010-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:
Victoria Lease723b2fe2013-08-12 14:38:44 -0700237 case SkMask::kBW_Format:
Victoria Lease1e546812013-06-25 14:25:17 -0700238 cacheTextures = &mACacheTextures;
239 break;
240 case SkMask::kARGB32_Format:
241 cacheTextures = &mRGBACacheTextures;
242 break;
243 default:
244#if DEBUG_FONT_RENDERER
245 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
246#endif
247 return;
248 }
249
Romain Guy694b5192010-07-21 21:33:20 -0700250 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700251 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
Victoria Lease1e546812013-06-25 14:25:17 -0700252 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700253 ALOGE("Font size too large to fit in cache. width, height = %i, %i",
254 (int) glyph.fWidth, (int) glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800255 return;
Romain Guy694b5192010-07-21 21:33:20 -0700256 }
257
258 // Now copy the bitmap into the cache texture
259 uint32_t startX = 0;
260 uint32_t startY = 0;
261
Victoria Lease1e546812013-06-25 14:25:17 -0700262 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700263
Chet Haase378e9192012-08-15 15:54:54 -0700264 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700265 if (!precaching) {
266 // If the new glyph didn't fit and we are not just trying to precache it,
267 // clear out the cache and try again
268 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700269 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700270 }
Romain Guy694b5192010-07-21 21:33:20 -0700271
Chet Haase378e9192012-08-15 15:54:54 -0700272 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700273 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800274 return;
Romain Guy694b5192010-07-21 21:33:20 -0700275 }
276 }
277
Chet Haase378e9192012-08-15 15:54:54 -0700278 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800279
Romain Guy694b5192010-07-21 21:33:20 -0700280 *retOriginX = startX;
281 *retOriginY = startY;
282
283 uint32_t endX = startX + glyph.fWidth;
284 uint32_t endY = startY + glyph.fHeight;
285
Romain Guy80872462012-09-04 16:42:01 -0700286 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700287
Romain Guycf51a412013-04-08 19:40:31 -0700288 if (!cacheTexture->getPixelBuffer()) {
Romain Guy80872462012-09-04 16:42:01 -0700289 Caches::getInstance().activeTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800290 // Large-glyph texture memory is allocated only as needed
Romain Guy80872462012-09-04 16:42:01 -0700291 cacheTexture->allocateTexture();
Chet Haase7de0cb12011-12-05 16:35:38 -0800292 }
Romain Guy661a87e2013-03-19 15:24:36 -0700293 if (!cacheTexture->mesh()) {
294 cacheTexture->allocateMesh();
295 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700296
Romain Guycf51a412013-04-08 19:40:31 -0700297 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
Victoria Lease1e546812013-06-25 14:25:17 -0700298 uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
299 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700300
Romain Guyb969a0d2013-02-05 14:38:40 -0800301 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800302 switch (format) {
303 case SkMask::kA8_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700304 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
305 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
306 - TEXTURE_BORDER_SIZE;
307 // write leading border line
308 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
309 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800310 if (mGammaTable) {
Victoria Lease1e546812013-06-25 14:25:17 -0700311 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800312 row = cacheY * cacheWidth;
313 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800314 for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
315 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800316 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800317 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800318 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800319 }
320 } else {
Victoria Lease1e546812013-06-25 14:25:17 -0700321 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800322 row = cacheY * cacheWidth;
323 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
324 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
325 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800326 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700327 }
Victoria Lease1e546812013-06-25 14:25:17 -0700328 // write trailing border line
329 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
330 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
331 break;
332 }
333 case SkMask::kARGB32_Format: {
334 // prep data lengths
335 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
336 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
337 size_t rowSize = formatSize * glyph.fWidth;
338 // prep advances
339 size_t dstStride = formatSize * cacheWidth;
340 // prep indices
341 // - we actually start one row early, and then increment before first copy
342 uint8_t* src = &bitmapBuffer[0 - srcStride];
343 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
344 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
345 uint8_t* dstL = dst - borderSize;
346 uint8_t* dstR = dst + rowSize;
347 // write leading border line
348 memset(dstL, 0, rowSize + 2 * borderSize);
349 // write glyph data
350 while (dst < dstEnd) {
351 memset(dstL += dstStride, 0, borderSize); // leading border column
352 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
353 memset(dstR += dstStride, 0, borderSize); // trailing border column
354 }
355 // write trailing border line
Victoria Lease16c84062013-09-19 15:38:21 -0700356 memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800357 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700358 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800359 case SkMask::kBW_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700360 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
361 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
362 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800363 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700364 // write leading border line
365 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
366 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800367 for (cacheY = startY; cacheY < endY; cacheY++) {
368 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700369 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800370 uint8_t* buffer = bitmapBuffer;
371
Romain Guy0b58a3d2013-03-05 12:16:27 -0800372 row = cacheY * cacheWidth;
373 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800374 while (--rowBytes >= 0) {
375 uint8_t b = *buffer++;
376 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
377 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
378 }
379 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800380 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800381
Victoria Lease1e546812013-06-25 14:25:17 -0700382 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700383 }
Victoria Lease1e546812013-06-25 14:25:17 -0700384 // write trailing border line
385 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
386 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800387 break;
Romain Guy694b5192010-07-21 21:33:20 -0700388 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800389 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700390 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800391 break;
Romain Guy694b5192010-07-21 21:33:20 -0700392 }
Romain Guy97771732012-02-28 18:17:02 -0800393
Chet Haase7de0cb12011-12-05 16:35:38 -0800394 cachedGlyph->mIsValid = true;
Romain Guy694b5192010-07-21 21:33:20 -0700395}
396
Victoria Lease1e546812013-06-25 14:25:17 -0700397CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
398 bool allocate) {
399 CacheTexture* cacheTexture = new CacheTexture(width, height, format, gMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700400
Chet Haase2a47c142011-12-14 15:22:56 -0800401 if (allocate) {
Romain Guy80872462012-09-04 16:42:01 -0700402 Caches::getInstance().activeTexture(0);
403 cacheTexture->allocateTexture();
Romain Guy661a87e2013-03-19 15:24:36 -0700404 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800405 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700406
Chet Haase2a47c142011-12-14 15:22:56 -0800407 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800408}
409
410void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700411 clearCacheTextures(mACacheTextures);
412 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700413
Chet Haase7de0cb12011-12-05 16:35:38 -0800414 mUploadTexture = false;
Victoria Lease1e546812013-06-25 14:25:17 -0700415 mACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
416 GL_ALPHA, true));
417 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
418 GL_ALPHA, false));
419 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
420 GL_ALPHA, false));
421 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
422 GL_ALPHA, false));
423 mRGBACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
424 GL_RGBA, false));
425 mRGBACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
426 GL_RGBA, false));
427 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700428}
429
Romain Guy694b5192010-07-21 21:33:20 -0700430// We don't want to allocate anything unless we actually draw text
431void FontRenderer::checkInit() {
432 if (mInitialized) {
433 return;
434 }
435
436 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700437
438 mInitialized = true;
439}
440
Victoria Lease1e546812013-06-25 14:25:17 -0700441void checkTextureUpdateForCache(Caches& caches, Vector<CacheTexture*>& cacheTextures,
442 bool& resetPixelStore, GLuint& lastTextureId) {
443 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
444 CacheTexture* cacheTexture = cacheTextures[i];
445 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
446 if (cacheTexture->getTextureId() != lastTextureId) {
447 lastTextureId = cacheTexture->getTextureId();
448 caches.activeTexture(0);
449 caches.bindTexture(lastTextureId);
450 }
451
452 if (cacheTexture->upload()) {
453 resetPixelStore = true;
454 }
455 }
456 }
457}
458
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700459void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900460 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700461 return;
Romain Guy694b5192010-07-21 21:33:20 -0700462 }
463
Romain Guy2d4fd362011-12-13 22:00:19 -0800464 Caches& caches = Caches::getInstance();
465 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700466
Romain Guycf51a412013-04-08 19:40:31 -0700467 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700468 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
469
Chet Haase378e9192012-08-15 15:54:54 -0700470 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700471 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
472 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700473
Romain Guycf51a412013-04-08 19:40:31 -0700474 // Unbind any PBO we might have used to update textures
475 caches.unbindPixelBuffer();
476
Romain Guy09087642013-04-04 12:27:54 -0700477 // Reset to default unpack row length to avoid affecting texture
478 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700479 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700480 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
481 }
482
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700483 mUploadTexture = false;
484}
485
Victoria Lease1e546812013-06-25 14:25:17 -0700486void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
487 Caches& caches = Caches::getInstance();
Romain Guy661a87e2013-03-19 15:24:36 -0700488 bool first = true;
489 bool force = false;
Victoria Lease1e546812013-06-25 14:25:17 -0700490 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
491 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700492 if (texture->canDraw()) {
493 if (first) {
Victoria Lease1e546812013-06-25 14:25:17 -0700494 if (mFunctor) {
495 TextSetupFunctor::Data functorData(texture->getFormat());
496 (*mFunctor)(0, &functorData);
497 }
Romain Guy257ae352013-03-20 16:31:12 -0700498
Romain Guy661a87e2013-03-19 15:24:36 -0700499 checkTextureUpdate();
Romain Guy31e08e92013-06-18 15:53:53 -0700500 caches.bindIndicesBuffer();
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900501
Romain Guy661a87e2013-03-19 15:24:36 -0700502 if (!mDrawn) {
503 // If returns true, a VBO was bound and we must
504 // rebind our vertex attrib pointers even if
505 // they have the same values as the current pointers
506 force = caches.unbindMeshBuffer();
507 }
508
509 caches.activeTexture(0);
510 first = false;
511 }
512
Romain Guy8aa195d2013-06-04 18:00:09 -0700513 caches.bindTexture(texture->getTextureId());
Romain Guy661a87e2013-03-19 15:24:36 -0700514 texture->setLinearFiltering(mLinearFiltering, false);
515
516 TextureVertex* mesh = texture->mesh();
517 caches.bindPositionVertexPointer(force, &mesh[0].position[0]);
518 caches.bindTexCoordsVertexPointer(force, &mesh[0].texture[0]);
519 force = false;
520
521 glDrawElements(GL_TRIANGLES, texture->meshElementCount(),
522 GL_UNSIGNED_SHORT, texture->indices());
523
524 texture->resetMesh();
Romain Guy115096f2013-03-19 11:32:41 -0700525 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900526 }
Victoria Lease1e546812013-06-25 14:25:17 -0700527}
528
529void FontRenderer::issueDrawCommand() {
530 issueDrawCommand(mACacheTextures);
531 issueDrawCommand(mRGBACacheTextures);
Romain Guy5b3b3522010-10-27 18:57:51 -0700532
533 mDrawn = true;
Romain Guy694b5192010-07-21 21:33:20 -0700534}
535
Romain Guy97771732012-02-28 18:17:02 -0800536void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
537 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
Chet Haase7de0cb12011-12-05 16:35:38 -0800538 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800539 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800540 // Now use the new texture id
541 mCurrentCacheTexture = texture;
542 }
Romain Guy09147fb2010-07-22 13:08:20 -0700543
Romain Guy661a87e2013-03-19 15:24:36 -0700544 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
545 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800546}
547
548void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
549 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
550 float x4, float y4, float u4, float v4, CacheTexture* texture) {
551
552 if (mClip &&
553 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
554 return;
555 }
556
557 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 -0700558
Romain Guy5b3b3522010-10-27 18:57:51 -0700559 if (mBounds) {
560 mBounds->left = fmin(mBounds->left, x1);
561 mBounds->top = fmin(mBounds->top, y3);
562 mBounds->right = fmax(mBounds->right, x3);
563 mBounds->bottom = fmax(mBounds->bottom, y1);
564 }
565
Romain Guy661a87e2013-03-19 15:24:36 -0700566 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700567 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700568 }
569}
570
Romain Guy97771732012-02-28 18:17:02 -0800571void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
572 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
573 float x4, float y4, float u4, float v4, CacheTexture* texture) {
574
575 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
576
577 if (mBounds) {
578 mBounds->left = fmin(mBounds->left, fmin(x1, fmin(x2, fmin(x3, x4))));
579 mBounds->top = fmin(mBounds->top, fmin(y1, fmin(y2, fmin(y3, y4))));
580 mBounds->right = fmax(mBounds->right, fmax(x1, fmax(x2, fmax(x3, x4))));
581 mBounds->bottom = fmax(mBounds->bottom, fmax(y1, fmax(y2, fmax(y3, y4))));
582 }
583
Romain Guy661a87e2013-03-19 15:24:36 -0700584 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800585 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800586 }
587}
588
Romain Guye3a9b242013-01-08 11:15:30 -0800589void FontRenderer::setFont(SkPaint* paint, const mat4& matrix) {
590 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700591}
Romain Guy7975fb62010-10-01 16:36:14 -0700592
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700593FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text,
Raph Levien416a8472012-07-19 22:48:17 -0700594 uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700595 checkInit();
596
Romain Guycf51a412013-04-08 19:40:31 -0700597 DropShadow image;
598 image.width = 0;
599 image.height = 0;
600 image.image = NULL;
601 image.penX = 0;
602 image.penY = 0;
603
Romain Guy1e45aae2010-08-13 19:39:53 -0700604 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700605 return image;
606 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700607
Romain Guy2d4fd362011-12-13 22:00:19 -0800608 mDrawn = false;
Romain Guyff98fa52011-11-28 09:35:09 -0800609 mClip = NULL;
610 mBounds = NULL;
611
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700612 Rect bounds;
Raph Levien416a8472012-07-19 22:48:17 -0700613 mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800614
Romain Guy1e45aae2010-08-13 19:39:53 -0700615 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius;
616 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius;
Romain Guyff98fa52011-11-28 09:35:09 -0800617
Romain Guycf51a412013-04-08 19:40:31 -0700618 uint32_t maxSize = Caches::getInstance().maxTextureSize;
619 if (paddedWidth > maxSize || paddedHeight > maxSize) {
620 return image;
621 }
622
Dan Morrille4d9a012013-03-28 18:10:43 -0700623#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800624 // Align buffers for renderscript usage
625 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
626 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700627 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800628 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800629 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700630#else
631 int size = paddedWidth * paddedHeight;
632 uint8_t* dataBuffer = (uint8_t*) malloc(size);
633#endif
634
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800635 memset(dataBuffer, 0, size);
636
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700637 int penX = radius - bounds.left;
638 int penY = radius - bounds.bottom;
639
Chris Craikdd8697c2013-02-22 10:41:36 -0800640 if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
641 // text has non-whitespace, so draw and blur to create the shadow
642 // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
643 // TODO: don't draw pure whitespace in the first place, and avoid needing this check
644 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
645 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions);
646
Romain Guycf51a412013-04-08 19:40:31 -0700647 // Unbind any PBO we might have used
648 Caches::getInstance().unbindPixelBuffer();
649
Chris Craikdd8697c2013-02-22 10:41:36 -0800650 blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
651 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700652
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700653 image.width = paddedWidth;
654 image.height = paddedHeight;
655 image.image = dataBuffer;
656 image.penX = penX;
657 image.penY = penY;
Romain Guy2d4fd362011-12-13 22:00:19 -0800658
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700659 return image;
660}
Romain Guy694b5192010-07-21 21:33:20 -0700661
Romain Guy257ae352013-03-20 16:31:12 -0700662void FontRenderer::initRender(const Rect* clip, Rect* bounds, Functor* functor) {
Romain Guy694b5192010-07-21 21:33:20 -0700663 checkInit();
664
Romain Guy5b3b3522010-10-27 18:57:51 -0700665 mDrawn = false;
666 mBounds = bounds;
Romain Guy257ae352013-03-20 16:31:12 -0700667 mFunctor = functor;
Romain Guy09147fb2010-07-22 13:08:20 -0700668 mClip = clip;
Romain Guy671d6cf2012-01-18 12:39:17 -0800669}
Romain Guyff98fa52011-11-28 09:35:09 -0800670
Romain Guy671d6cf2012-01-18 12:39:17 -0800671void FontRenderer::finishRender() {
Romain Guy5b3b3522010-10-27 18:57:51 -0700672 mBounds = NULL;
Romain Guyff98fa52011-11-28 09:35:09 -0800673 mClip = NULL;
Romain Guy694b5192010-07-21 21:33:20 -0700674
Romain Guy661a87e2013-03-19 15:24:36 -0700675 issueDrawCommand();
Romain Guy671d6cf2012-01-18 12:39:17 -0800676}
677
Romain Guye3a9b242013-01-08 11:15:30 -0800678void FontRenderer::precache(SkPaint* paint, const char* text, int numGlyphs, const mat4& matrix) {
679 Font* font = Font::create(this, paint, matrix);
Chet Haasee816bae2012-08-09 13:39:02 -0700680 font->precache(paint, text, numGlyphs);
681}
682
Romain Guycf51a412013-04-08 19:40:31 -0700683void FontRenderer::endPrecaching() {
684 checkTextureUpdate();
685}
686
Romain Guy671d6cf2012-01-18 12:39:17 -0800687bool FontRenderer::renderPosText(SkPaint* paint, const Rect* clip, const char *text,
688 uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
Chris Craik527a3aa2013-03-04 10:19:31 -0800689 const float* positions, Rect* bounds, Functor* functor, bool forceFinish) {
Romain Guy671d6cf2012-01-18 12:39:17 -0800690 if (!mCurrentFont) {
691 ALOGE("No font set");
692 return false;
693 }
694
Romain Guy257ae352013-03-20 16:31:12 -0700695 initRender(clip, bounds, functor);
Romain Guy671d6cf2012-01-18 12:39:17 -0800696 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions);
Chris Craik527a3aa2013-03-04 10:19:31 -0800697
698 if (forceFinish) {
699 finishRender();
700 }
Romain Guy5b3b3522010-10-27 18:57:51 -0700701
702 return mDrawn;
Romain Guy694b5192010-07-21 21:33:20 -0700703}
704
Romain Guy97771732012-02-28 18:17:02 -0800705bool FontRenderer::renderTextOnPath(SkPaint* paint, const Rect* clip, const char *text,
706 uint32_t startIndex, uint32_t len, int numGlyphs, SkPath* path,
Victoria Lease1e546812013-06-25 14:25:17 -0700707 float hOffset, float vOffset, Rect* bounds, Functor* functor) {
Romain Guy97771732012-02-28 18:17:02 -0800708 if (!mCurrentFont) {
709 ALOGE("No font set");
710 return false;
711 }
712
Victoria Lease1e546812013-06-25 14:25:17 -0700713 initRender(clip, bounds, functor);
Romain Guy97771732012-02-28 18:17:02 -0800714 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset);
715 finishRender();
716
717 return mDrawn;
718}
719
Romain Guy9b1204b2012-09-04 15:22:57 -0700720void FontRenderer::removeFont(const Font* font) {
Romain Guye3a9b242013-01-08 11:15:30 -0800721 mActiveFonts.remove(font->getDescription());
Romain Guy9b1204b2012-09-04 15:22:57 -0700722
723 if (mCurrentFont == font) {
724 mCurrentFont = NULL;
725 }
726}
727
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800728void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, int32_t radius) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700729#ifdef ANDROID_ENABLE_RENDERSCRIPT
730 if (width * height * radius >= RS_MIN_INPUT_CUTOFF) {
731 uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700732
Tim Murray250b1cf2013-08-01 14:49:22 -0700733 if (mRs == 0) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700734 mRs = new RSC::RS();
Tim Murray804ff382013-12-13 12:57:36 -0800735 // a null path is OK because there are no custom kernels used
736 // hence nothing gets cached by RS
737 if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700738 ALOGE("blur RS failed to init");
739 }
Romain Guyd71dd362011-12-12 19:03:35 -0800740
Dan Morrille4d9a012013-03-28 18:10:43 -0700741 mRsElement = RSC::Element::A_8(mRs);
Tim Murrayd8c8aaa2013-08-19 12:04:38 -0700742 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800743 }
744
Tim Murray250b1cf2013-08-01 14:49:22 -0700745 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
746 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
747 RS_ALLOCATION_MIPMAP_NONE, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
748 *image);
749 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
750 RS_ALLOCATION_MIPMAP_NONE, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
751 outImage);
Dan Morrille4d9a012013-03-28 18:10:43 -0700752
753 mRsScript->setRadius(radius);
Tim Murrayd8c8aaa2013-08-19 12:04:38 -0700754 mRsScript->setInput(ain);
755 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700756
757 // replace the original image's pointer, avoiding a copy back to the original buffer
758 free(*image);
759 *image = outImage;
760
761 return;
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800762 }
Dan Morrille4d9a012013-03-28 18:10:43 -0700763#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800764
Dan Morrille4d9a012013-03-28 18:10:43 -0700765 float *gaussian = new float[2 * radius + 1];
766 Blur::generateGaussianWeights(gaussian, radius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800767
Dan Morrille4d9a012013-03-28 18:10:43 -0700768 uint8_t* scratch = new uint8_t[width * height];
769 Blur::horizontal(gaussian, radius, *image, scratch, width, height);
770 Blur::vertical(gaussian, radius, scratch, *image, width, height);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800771
Dan Morrille4d9a012013-03-28 18:10:43 -0700772 delete[] gaussian;
773 delete[] scratch;
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700774}
775
Victoria Lease1e546812013-06-25 14:25:17 -0700776static uint32_t calculateCacheSize(const Vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700777 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700778 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
779 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700780 if (cacheTexture && cacheTexture->getPixelBuffer()) {
781 size += cacheTexture->getPixelBuffer()->getSize();
782 }
783 }
784 return size;
785}
786
Victoria Lease1e546812013-06-25 14:25:17 -0700787uint32_t FontRenderer::getCacheSize(GLenum format) const {
788 switch (format) {
789 case GL_ALPHA: {
790 return calculateCacheSize(mACacheTextures);
791 }
792 case GL_RGBA: {
793 return calculateCacheSize(mRGBACacheTextures);
794 }
795 default: {
796 return 0;
797 }
798 }
799}
800
Romain Guy694b5192010-07-21 21:33:20 -0700801}; // namespace uirenderer
802}; // namespace android