blob: 4b9d4f90675c5f17c992c4b9e51da7432ae49916 [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
Chris Craik96a5c4c2015-01-27 15:46:35 -080017#include "FontRenderer.h"
18
19#include "Caches.h"
20#include "Debug.h"
21#include "Extensions.h"
Chris Craike2bb3802015-03-13 15:07:52 -070022#include "Glop.h"
23#include "GlopBuilder.h"
Chris Craik96a5c4c2015-01-27 15:46:35 -080024#include "OpenGLRenderer.h"
25#include "PixelBuffer.h"
26#include "Rect.h"
27#include "renderstate/RenderState.h"
28#include "utils/Blur.h"
29#include "utils/Timing.h"
Romain Guy694b5192010-07-21 21:33:20 -070030
Chris Craik9db58c02015-08-19 15:19:18 -070031#include <algorithm>
32#include <cutils/properties.h>
Derek Sollenbergerca79cf62012-08-14 16:44:52 -040033#include <SkGlyph.h>
Romain Guy694b5192010-07-21 21:33:20 -070034#include <SkUtils.h>
Romain Guy51769a62010-07-23 00:28:00 -070035#include <utils/Log.h>
36
Dan Morrille4d9a012013-03-28 18:10:43 -070037#ifdef ANDROID_ENABLE_RENDERSCRIPT
Romain Guy6e200402013-03-08 11:28:22 -080038#include <RenderScript.h>
Dan Morrille4d9a012013-03-28 18:10:43 -070039#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -080040
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///////////////////////////////////////////////////////////////////////////////
Victoria Lease1e546812013-06-25 14:25:17 -070050
Chris Craik82840732015-04-03 09:37:49 -070051void TextDrawFunctor::draw(CacheTexture& texture, bool linearFiltering) {
Chris Craik53e51e42015-06-01 10:35:35 -070052 int textureFillFlags = TextureFillFlags::None;
53 if (texture.getFormat() == GL_ALPHA) {
54 textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture;
Chris Craike2bb3802015-03-13 15:07:52 -070055 }
Chris Craik53e51e42015-06-01 10:35:35 -070056 if (linearFiltering) {
57 textureFillFlags |= TextureFillFlags::ForceFilter;
58 }
59 int transformFlags = pureTranslate
60 ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
Chris Craike2bb3802015-03-13 15:07:52 -070061 Glop glop;
62 GlopBuilder(renderer->mRenderState, renderer->mCaches, &glop)
63 .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
64 .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, renderer->currentSnapshot()->alpha)
Chris Craik53e51e42015-06-01 10:35:35 -070065 .setTransform(*(renderer->currentSnapshot()), transformFlags)
Chris Craike2bb3802015-03-13 15:07:52 -070066 .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
67 .setRoundRectClipState(renderer->currentSnapshot()->roundRectClipState)
68 .build();
69 renderer->renderGlop(glop);
Victoria Lease1e546812013-06-25 14:25:17 -070070}
71
72///////////////////////////////////////////////////////////////////////////////
Romain Guy694b5192010-07-21 21:33:20 -070073// FontRenderer
74///////////////////////////////////////////////////////////////////////////////
75
Romain Guy514fb182011-01-19 14:38:29 -080076static bool sLogFontRendererCreate = true;
77
Chris Craikc08820f2015-09-22 14:22:29 -070078FontRenderer::FontRenderer(const uint8_t* gammaTable)
79 : mGammaTable(gammaTable)
Chris Craik083e7332015-02-27 17:04:20 -080080 , mCurrentFont(nullptr)
81 , mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity)
82 , mCurrentCacheTexture(nullptr)
83 , mUploadTexture(false)
84 , mFunctor(nullptr)
85 , mClip(nullptr)
86 , mBounds(nullptr)
87 , mDrawn(false)
88 , mInitialized(false)
89 , mLinearFiltering(false) {
Romain Guye3a9b242013-01-08 11:15:30 -080090
Romain Guyc9855a52011-01-21 21:14:15 -080091 if (sLogFontRendererCreate) {
92 INIT_LOGD("Creating FontRenderer");
93 }
Romain Guy51769a62010-07-23 00:28:00 -070094
Chris Craikc08820f2015-09-22 14:22:29 -070095 mSmallCacheWidth = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_WIDTH,
96 DEFAULT_TEXT_SMALL_CACHE_WIDTH);
97 mSmallCacheHeight = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_HEIGHT,
98 DEFAULT_TEXT_SMALL_CACHE_HEIGHT);
Romain Guy51769a62010-07-23 00:28:00 -070099
Chris Craikc08820f2015-09-22 14:22:29 -0700100 mLargeCacheWidth = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_WIDTH,
101 DEFAULT_TEXT_LARGE_CACHE_WIDTH);
102 mLargeCacheHeight = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_HEIGHT,
103 DEFAULT_TEXT_LARGE_CACHE_HEIGHT);
Romain Guy9f5dab32012-09-04 12:55:44 -0700104
105 uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
Chris Craik083e7332015-02-27 17:04:20 -0800106
Chris Craik9db58c02015-08-19 15:19:18 -0700107 mSmallCacheWidth = std::min(mSmallCacheWidth, maxTextureSize);
108 mSmallCacheHeight = std::min(mSmallCacheHeight, maxTextureSize);
109 mLargeCacheWidth = std::min(mLargeCacheWidth, maxTextureSize);
110 mLargeCacheHeight = std::min(mLargeCacheHeight, maxTextureSize);
Romain Guy9f5dab32012-09-04 12:55:44 -0700111
Chet Haaseeb32a492012-08-31 13:54:03 -0700112 if (sLogFontRendererCreate) {
113 INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
114 mSmallCacheWidth, mSmallCacheHeight,
115 mLargeCacheWidth, mLargeCacheHeight >> 1,
116 mLargeCacheWidth, mLargeCacheHeight >> 1,
117 mLargeCacheWidth, mLargeCacheHeight);
Romain Guy51769a62010-07-23 00:28:00 -0700118 }
Romain Guy514fb182011-01-19 14:38:29 -0800119
120 sLogFontRendererCreate = false;
Romain Guy694b5192010-07-21 21:33:20 -0700121}
122
John Reck272a6852015-07-29 16:48:58 -0700123void clearCacheTextures(std::vector<CacheTexture*>& cacheTextures) {
Victoria Lease1e546812013-06-25 14:25:17 -0700124 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
125 delete cacheTextures[i];
Romain Guy694b5192010-07-21 21:33:20 -0700126 }
Victoria Lease1e546812013-06-25 14:25:17 -0700127 cacheTextures.clear();
128}
129
130FontRenderer::~FontRenderer() {
131 clearCacheTextures(mACacheTextures);
132 clearCacheTextures(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700133
Romain Guye3a9b242013-01-08 11:15:30 -0800134 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
135 while (it.next()) {
136 delete it.value();
Romain Guy694b5192010-07-21 21:33:20 -0700137 }
Romain Guye3a9b242013-01-08 11:15:30 -0800138 mActiveFonts.clear();
Romain Guy694b5192010-07-21 21:33:20 -0700139}
140
141void FontRenderer::flushAllAndInvalidate() {
Romain Guy661a87e2013-03-19 15:24:36 -0700142 issueDrawCommand();
Romain Guy9d9758a2012-05-14 15:19:58 -0700143
Romain Guye3a9b242013-01-08 11:15:30 -0800144 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
145 while (it.next()) {
146 it.value()->invalidateTextureCache();
Romain Guy694b5192010-07-21 21:33:20 -0700147 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700148
Victoria Lease1e546812013-06-25 14:25:17 -0700149 for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
150 mACacheTextures[i]->init();
151 }
152
153 for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
154 mRGBACacheTextures[i]->init();
Romain Guy694b5192010-07-21 21:33:20 -0700155 }
chaochen1f61b192014-08-28 18:45:27 -0700156
157 mDrawn = false;
Romain Guy694b5192010-07-21 21:33:20 -0700158}
159
John Reck272a6852015-07-29 16:48:58 -0700160void FontRenderer::flushLargeCaches(std::vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700161 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700162 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
163 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700164 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700165 cacheTexture->init();
Romain Guye3a9b242013-01-08 11:15:30 -0800166 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
167 while (it.next()) {
168 it.value()->invalidateTextureCache(cacheTexture);
Chet Haasee816bae2012-08-09 13:39:02 -0700169 }
Chris Craike2bb3802015-03-13 15:07:52 -0700170 cacheTexture->releasePixelBuffer();
Chet Haase9a824562011-12-16 15:44:59 -0800171 }
172 }
Chet Haase9a824562011-12-16 15:44:59 -0800173}
174
Victoria Lease1e546812013-06-25 14:25:17 -0700175void FontRenderer::flushLargeCaches() {
176 flushLargeCaches(mACacheTextures);
177 flushLargeCaches(mRGBACacheTextures);
178}
179
John Reck272a6852015-07-29 16:48:58 -0700180CacheTexture* FontRenderer::cacheBitmapInTexture(std::vector<CacheTexture*>& cacheTextures,
Victoria Lease1e546812013-06-25 14:25:17 -0700181 const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
182 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
183 if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
184 return cacheTextures[i];
Chet Haase378e9192012-08-15 15:54:54 -0700185 }
186 }
187 // Could not fit glyph into current cache textures
Chris Craikd41c4d82015-01-05 15:51:13 -0800188 return nullptr;
Chet Haase378e9192012-08-15 15:54:54 -0700189}
190
Chet Haase7de0cb12011-12-05 16:35:38 -0800191void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
Chet Haasef942cf12012-08-30 09:06:46 -0700192 uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700193 checkInit();
Romain Guya4adcf02013-02-28 12:15:35 -0800194
195 // If the glyph bitmap is empty let's assum the glyph is valid
196 // so we can avoid doing extra work later on
197 if (glyph.fWidth == 0 || glyph.fHeight == 0) {
198 cachedGlyph->mIsValid = true;
Chris Craikd41c4d82015-01-05 15:51:13 -0800199 cachedGlyph->mCacheTexture = nullptr;
Romain Guya4adcf02013-02-28 12:15:35 -0800200 return;
201 }
202
Chet Haase7de0cb12011-12-05 16:35:38 -0800203 cachedGlyph->mIsValid = false;
Romain Guya4adcf02013-02-28 12:15:35 -0800204
Victoria Lease1e546812013-06-25 14:25:17 -0700205 // choose an appropriate cache texture list for this glyph format
206 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
John Reck272a6852015-07-29 16:48:58 -0700207 std::vector<CacheTexture*>* cacheTextures = nullptr;
Victoria Lease1e546812013-06-25 14:25:17 -0700208 switch (format) {
209 case SkMask::kA8_Format:
Victoria Lease723b2fe2013-08-12 14:38:44 -0700210 case SkMask::kBW_Format:
Victoria Lease1e546812013-06-25 14:25:17 -0700211 cacheTextures = &mACacheTextures;
212 break;
213 case SkMask::kARGB32_Format:
214 cacheTextures = &mRGBACacheTextures;
215 break;
216 default:
217#if DEBUG_FONT_RENDERER
218 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
219#endif
220 return;
221 }
222
Romain Guy694b5192010-07-21 21:33:20 -0700223 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700224 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
Victoria Lease1e546812013-06-25 14:25:17 -0700225 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700226 ALOGE("Font size too large to fit in cache. width, height = %i, %i",
227 (int) glyph.fWidth, (int) glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800228 return;
Romain Guy694b5192010-07-21 21:33:20 -0700229 }
230
231 // Now copy the bitmap into the cache texture
232 uint32_t startX = 0;
233 uint32_t startY = 0;
234
Victoria Lease1e546812013-06-25 14:25:17 -0700235 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700236
Chet Haase378e9192012-08-15 15:54:54 -0700237 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700238 if (!precaching) {
239 // If the new glyph didn't fit and we are not just trying to precache it,
240 // clear out the cache and try again
241 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700242 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700243 }
Romain Guy694b5192010-07-21 21:33:20 -0700244
Chet Haase378e9192012-08-15 15:54:54 -0700245 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700246 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800247 return;
Romain Guy694b5192010-07-21 21:33:20 -0700248 }
249 }
250
Chet Haase378e9192012-08-15 15:54:54 -0700251 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800252
Romain Guy694b5192010-07-21 21:33:20 -0700253 *retOriginX = startX;
254 *retOriginY = startY;
255
256 uint32_t endX = startX + glyph.fWidth;
257 uint32_t endY = startY + glyph.fHeight;
258
Romain Guy80872462012-09-04 16:42:01 -0700259 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700260
Romain Guycf51a412013-04-08 19:40:31 -0700261 if (!cacheTexture->getPixelBuffer()) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800262 Caches::getInstance().textureState().activateTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800263 // Large-glyph texture memory is allocated only as needed
Chris Craike2bb3802015-03-13 15:07:52 -0700264 cacheTexture->allocatePixelBuffer();
Chet Haase7de0cb12011-12-05 16:35:38 -0800265 }
Romain Guy661a87e2013-03-19 15:24:36 -0700266 if (!cacheTexture->mesh()) {
267 cacheTexture->allocateMesh();
268 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700269
Romain Guycf51a412013-04-08 19:40:31 -0700270 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
Victoria Lease1e546812013-06-25 14:25:17 -0700271 uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
272 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700273
Romain Guyb969a0d2013-02-05 14:38:40 -0800274 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800275 switch (format) {
276 case SkMask::kA8_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700277 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
278 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
279 - TEXTURE_BORDER_SIZE;
280 // write leading border line
281 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
282 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800283 if (mGammaTable) {
Victoria Lease1e546812013-06-25 14:25:17 -0700284 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800285 row = cacheY * cacheWidth;
286 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800287 for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
288 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800289 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800290 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800291 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800292 }
293 } else {
Victoria Lease1e546812013-06-25 14:25:17 -0700294 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800295 row = cacheY * cacheWidth;
296 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
297 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
298 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800299 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700300 }
Victoria Lease1e546812013-06-25 14:25:17 -0700301 // write trailing border line
302 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
303 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
304 break;
305 }
306 case SkMask::kARGB32_Format: {
307 // prep data lengths
308 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
309 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
310 size_t rowSize = formatSize * glyph.fWidth;
311 // prep advances
312 size_t dstStride = formatSize * cacheWidth;
313 // prep indices
314 // - we actually start one row early, and then increment before first copy
315 uint8_t* src = &bitmapBuffer[0 - srcStride];
316 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
317 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
318 uint8_t* dstL = dst - borderSize;
319 uint8_t* dstR = dst + rowSize;
320 // write leading border line
321 memset(dstL, 0, rowSize + 2 * borderSize);
322 // write glyph data
323 while (dst < dstEnd) {
324 memset(dstL += dstStride, 0, borderSize); // leading border column
325 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
326 memset(dstR += dstStride, 0, borderSize); // trailing border column
327 }
328 // write trailing border line
Victoria Lease16c84062013-09-19 15:38:21 -0700329 memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800330 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700331 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800332 case SkMask::kBW_Format: {
Andreas Gampe1e196742014-11-10 15:23:43 -0800333 uint32_t cacheX = 0, cacheY = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700334 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
335 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800336 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700337 // write leading border line
338 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
339 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800340 for (cacheY = startY; cacheY < endY; cacheY++) {
341 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700342 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800343 uint8_t* buffer = bitmapBuffer;
344
Romain Guy0b58a3d2013-03-05 12:16:27 -0800345 row = cacheY * cacheWidth;
346 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800347 while (--rowBytes >= 0) {
348 uint8_t b = *buffer++;
349 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
350 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
351 }
352 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800353 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800354
Victoria Lease1e546812013-06-25 14:25:17 -0700355 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700356 }
Victoria Lease1e546812013-06-25 14:25:17 -0700357 // write trailing border line
358 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
359 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800360 break;
Romain Guy694b5192010-07-21 21:33:20 -0700361 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800362 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700363 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800364 break;
Romain Guy694b5192010-07-21 21:33:20 -0700365 }
Romain Guy97771732012-02-28 18:17:02 -0800366
Chet Haase7de0cb12011-12-05 16:35:38 -0800367 cachedGlyph->mIsValid = true;
Romain Guy694b5192010-07-21 21:33:20 -0700368}
369
Victoria Lease1e546812013-06-25 14:25:17 -0700370CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
371 bool allocate) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800372 CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700373
Chet Haase2a47c142011-12-14 15:22:56 -0800374 if (allocate) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800375 Caches::getInstance().textureState().activateTexture(0);
Chris Craike2bb3802015-03-13 15:07:52 -0700376 cacheTexture->allocatePixelBuffer();
Romain Guy661a87e2013-03-19 15:24:36 -0700377 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800378 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700379
Chet Haase2a47c142011-12-14 15:22:56 -0800380 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800381}
382
383void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700384 clearCacheTextures(mACacheTextures);
385 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700386
Chet Haase7de0cb12011-12-05 16:35:38 -0800387 mUploadTexture = false;
John Reck272a6852015-07-29 16:48:58 -0700388 mACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700389 GL_ALPHA, true));
John Reck272a6852015-07-29 16:48:58 -0700390 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700391 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700392 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700393 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700394 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700395 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700396 mRGBACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700397 GL_RGBA, false));
John Reck272a6852015-07-29 16:48:58 -0700398 mRGBACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700399 GL_RGBA, false));
400 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700401}
402
Romain Guy694b5192010-07-21 21:33:20 -0700403// We don't want to allocate anything unless we actually draw text
404void FontRenderer::checkInit() {
405 if (mInitialized) {
406 return;
407 }
408
409 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700410
411 mInitialized = true;
412}
413
John Reck272a6852015-07-29 16:48:58 -0700414void checkTextureUpdateForCache(Caches& caches, std::vector<CacheTexture*>& cacheTextures,
Victoria Lease1e546812013-06-25 14:25:17 -0700415 bool& resetPixelStore, GLuint& lastTextureId) {
416 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
417 CacheTexture* cacheTexture = cacheTextures[i];
418 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
419 if (cacheTexture->getTextureId() != lastTextureId) {
420 lastTextureId = cacheTexture->getTextureId();
Chris Craik44eb2c02015-01-29 09:45:09 -0800421 caches.textureState().activateTexture(0);
422 caches.textureState().bindTexture(lastTextureId);
Victoria Lease1e546812013-06-25 14:25:17 -0700423 }
424
425 if (cacheTexture->upload()) {
426 resetPixelStore = true;
427 }
428 }
429 }
430}
431
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700432void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900433 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700434 return;
Romain Guy694b5192010-07-21 21:33:20 -0700435 }
436
Romain Guy2d4fd362011-12-13 22:00:19 -0800437 Caches& caches = Caches::getInstance();
438 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700439
Romain Guycf51a412013-04-08 19:40:31 -0700440 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700441 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
442
Chet Haase378e9192012-08-15 15:54:54 -0700443 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700444 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
445 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700446
Romain Guycf51a412013-04-08 19:40:31 -0700447 // Unbind any PBO we might have used to update textures
Chris Craik44eb2c02015-01-29 09:45:09 -0800448 caches.pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700449
Romain Guy09087642013-04-04 12:27:54 -0700450 // Reset to default unpack row length to avoid affecting texture
451 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700452 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700453 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
454 }
455
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700456 mUploadTexture = false;
457}
458
John Reck272a6852015-07-29 16:48:58 -0700459void FontRenderer::issueDrawCommand(std::vector<CacheTexture*>& cacheTextures) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800460 if (!mFunctor) return;
461
Romain Guy661a87e2013-03-19 15:24:36 -0700462 bool first = true;
Victoria Lease1e546812013-06-25 14:25:17 -0700463 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
464 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700465 if (texture->canDraw()) {
466 if (first) {
Chris Craike2bb3802015-03-13 15:07:52 -0700467 checkTextureUpdate();
Romain Guy661a87e2013-03-19 15:24:36 -0700468 first = false;
Chris Craik083e7332015-02-27 17:04:20 -0800469 mDrawn = true;
Romain Guy661a87e2013-03-19 15:24:36 -0700470 }
Chris Craik82840732015-04-03 09:37:49 -0700471
Chris Craike2bb3802015-03-13 15:07:52 -0700472 mFunctor->draw(*texture, mLinearFiltering);
Romain Guy661a87e2013-03-19 15:24:36 -0700473
Romain Guy661a87e2013-03-19 15:24:36 -0700474 texture->resetMesh();
Romain Guy115096f2013-03-19 11:32:41 -0700475 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900476 }
Victoria Lease1e546812013-06-25 14:25:17 -0700477}
478
479void FontRenderer::issueDrawCommand() {
480 issueDrawCommand(mACacheTextures);
481 issueDrawCommand(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700482}
483
Romain Guy97771732012-02-28 18:17:02 -0800484void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
485 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
Chet Haase7de0cb12011-12-05 16:35:38 -0800486 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800487 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800488 // Now use the new texture id
489 mCurrentCacheTexture = texture;
490 }
Romain Guy09147fb2010-07-22 13:08:20 -0700491
Romain Guy661a87e2013-03-19 15:24:36 -0700492 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
493 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800494}
495
496void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
497 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
498 float x4, float y4, float u4, float v4, CacheTexture* texture) {
499
500 if (mClip &&
501 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
502 return;
503 }
504
505 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 -0700506
Romain Guy5b3b3522010-10-27 18:57:51 -0700507 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700508 mBounds->left = std::min(mBounds->left, x1);
509 mBounds->top = std::min(mBounds->top, y3);
510 mBounds->right = std::max(mBounds->right, x3);
511 mBounds->bottom = std::max(mBounds->bottom, y1);
Romain Guy5b3b3522010-10-27 18:57:51 -0700512 }
513
Romain Guy661a87e2013-03-19 15:24:36 -0700514 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700515 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700516 }
517}
518
Romain Guy97771732012-02-28 18:17:02 -0800519void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
520 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
521 float x4, float y4, float u4, float v4, CacheTexture* texture) {
522
523 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
524
525 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700526 mBounds->left = std::min(mBounds->left, std::min(x1, std::min(x2, std::min(x3, x4))));
527 mBounds->top = std::min(mBounds->top, std::min(y1, std::min(y2, std::min(y3, y4))));
528 mBounds->right = std::max(mBounds->right, std::max(x1, std::max(x2, std::max(x3, x4))));
529 mBounds->bottom = std::max(mBounds->bottom, std::max(y1, std::max(y2, std::max(y3, y4))));
Romain Guy97771732012-02-28 18:17:02 -0800530 }
531
Romain Guy661a87e2013-03-19 15:24:36 -0700532 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800533 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800534 }
535}
536
Chris Craik59744b72014-07-01 17:56:52 -0700537void FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800538 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700539}
Romain Guy7975fb62010-10-01 16:36:14 -0700540
Chris Craikd218a922014-01-02 17:13:34 -0800541FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const char *text,
Derek Sollenbergere392c812014-05-21 11:25:22 -0400542 uint32_t startIndex, uint32_t len, int numGlyphs, float radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700543 checkInit();
544
Romain Guycf51a412013-04-08 19:40:31 -0700545 DropShadow image;
546 image.width = 0;
547 image.height = 0;
Chris Craikd41c4d82015-01-05 15:51:13 -0800548 image.image = nullptr;
Romain Guycf51a412013-04-08 19:40:31 -0700549 image.penX = 0;
550 image.penY = 0;
551
Romain Guy1e45aae2010-08-13 19:39:53 -0700552 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700553 return image;
554 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700555
Romain Guy2d4fd362011-12-13 22:00:19 -0800556 mDrawn = false;
Chris Craikd41c4d82015-01-05 15:51:13 -0800557 mClip = nullptr;
558 mBounds = nullptr;
Romain Guyff98fa52011-11-28 09:35:09 -0800559
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700560 Rect bounds;
Raph Levien416a8472012-07-19 22:48:17 -0700561 mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800562
Derek Sollenbergere392c812014-05-21 11:25:22 -0400563 uint32_t intRadius = Blur::convertRadiusToInt(radius);
564 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
565 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
Romain Guyff98fa52011-11-28 09:35:09 -0800566
Romain Guycf51a412013-04-08 19:40:31 -0700567 uint32_t maxSize = Caches::getInstance().maxTextureSize;
568 if (paddedWidth > maxSize || paddedHeight > maxSize) {
569 return image;
570 }
571
Dan Morrille4d9a012013-03-28 18:10:43 -0700572#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800573 // Align buffers for renderscript usage
574 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
575 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700576 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800577 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800578 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700579#else
580 int size = paddedWidth * paddedHeight;
581 uint8_t* dataBuffer = (uint8_t*) malloc(size);
582#endif
583
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800584 memset(dataBuffer, 0, size);
585
Derek Sollenbergere392c812014-05-21 11:25:22 -0400586 int penX = intRadius - bounds.left;
587 int penY = intRadius - bounds.bottom;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700588
Chris Craikdd8697c2013-02-22 10:41:36 -0800589 if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
590 // text has non-whitespace, so draw and blur to create the shadow
591 // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
592 // TODO: don't draw pure whitespace in the first place, and avoid needing this check
593 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
Chris Craikd41c4d82015-01-05 15:51:13 -0800594 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
Chris Craikdd8697c2013-02-22 10:41:36 -0800595
Romain Guycf51a412013-04-08 19:40:31 -0700596 // Unbind any PBO we might have used
Chris Craik44eb2c02015-01-29 09:45:09 -0800597 Caches::getInstance().pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700598
Chris Craikdd8697c2013-02-22 10:41:36 -0800599 blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
600 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700601
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700602 image.width = paddedWidth;
603 image.height = paddedHeight;
604 image.image = dataBuffer;
605 image.penX = penX;
606 image.penY = penY;
Romain Guy2d4fd362011-12-13 22:00:19 -0800607
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700608 return image;
609}
Romain Guy694b5192010-07-21 21:33:20 -0700610
Chris Craik82840732015-04-03 09:37:49 -0700611void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextDrawFunctor* functor) {
Romain Guy694b5192010-07-21 21:33:20 -0700612 checkInit();
613
Romain Guy5b3b3522010-10-27 18:57:51 -0700614 mDrawn = false;
615 mBounds = bounds;
Romain Guy257ae352013-03-20 16:31:12 -0700616 mFunctor = functor;
Romain Guy09147fb2010-07-22 13:08:20 -0700617 mClip = clip;
Romain Guy671d6cf2012-01-18 12:39:17 -0800618}
Romain Guyff98fa52011-11-28 09:35:09 -0800619
Romain Guy671d6cf2012-01-18 12:39:17 -0800620void FontRenderer::finishRender() {
Chris Craikd41c4d82015-01-05 15:51:13 -0800621 mBounds = nullptr;
622 mClip = nullptr;
Romain Guy694b5192010-07-21 21:33:20 -0700623
Romain Guy661a87e2013-03-19 15:24:36 -0700624 issueDrawCommand();
Romain Guy671d6cf2012-01-18 12:39:17 -0800625}
626
Chris Craikd218a922014-01-02 17:13:34 -0800627void FontRenderer::precache(const SkPaint* paint, const char* text, int numGlyphs,
Chris Craik59744b72014-07-01 17:56:52 -0700628 const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800629 Font* font = Font::create(this, paint, matrix);
Chet Haasee816bae2012-08-09 13:39:02 -0700630 font->precache(paint, text, numGlyphs);
631}
632
Romain Guycf51a412013-04-08 19:40:31 -0700633void FontRenderer::endPrecaching() {
634 checkTextureUpdate();
635}
636
Chris Craikd218a922014-01-02 17:13:34 -0800637bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
Romain Guy671d6cf2012-01-18 12:39:17 -0800638 uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
Chris Craik82840732015-04-03 09:37:49 -0700639 const float* positions, Rect* bounds, TextDrawFunctor* functor, bool forceFinish) {
Romain Guy671d6cf2012-01-18 12:39:17 -0800640 if (!mCurrentFont) {
641 ALOGE("No font set");
642 return false;
643 }
644
Romain Guy257ae352013-03-20 16:31:12 -0700645 initRender(clip, bounds, functor);
Romain Guy671d6cf2012-01-18 12:39:17 -0800646 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions);
Chris Craik527a3aa2013-03-04 10:19:31 -0800647
648 if (forceFinish) {
649 finishRender();
650 }
Romain Guy5b3b3522010-10-27 18:57:51 -0700651
652 return mDrawn;
Romain Guy694b5192010-07-21 21:33:20 -0700653}
654
Chris Craikd218a922014-01-02 17:13:34 -0800655bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
656 uint32_t startIndex, uint32_t len, int numGlyphs, const SkPath* path,
Chris Craik82840732015-04-03 09:37:49 -0700657 float hOffset, float vOffset, Rect* bounds, TextDrawFunctor* functor) {
Romain Guy97771732012-02-28 18:17:02 -0800658 if (!mCurrentFont) {
659 ALOGE("No font set");
660 return false;
661 }
662
Victoria Lease1e546812013-06-25 14:25:17 -0700663 initRender(clip, bounds, functor);
Romain Guy97771732012-02-28 18:17:02 -0800664 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset);
665 finishRender();
666
667 return mDrawn;
668}
669
Romain Guy9b1204b2012-09-04 15:22:57 -0700670void FontRenderer::removeFont(const Font* font) {
Romain Guye3a9b242013-01-08 11:15:30 -0800671 mActiveFonts.remove(font->getDescription());
Romain Guy9b1204b2012-09-04 15:22:57 -0700672
673 if (mCurrentFont == font) {
Chris Craikd41c4d82015-01-05 15:51:13 -0800674 mCurrentFont = nullptr;
Romain Guy9b1204b2012-09-04 15:22:57 -0700675 }
676}
677
Derek Sollenbergere392c812014-05-21 11:25:22 -0400678void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
679 uint32_t intRadius = Blur::convertRadiusToInt(radius);
Dan Morrille4d9a012013-03-28 18:10:43 -0700680#ifdef ANDROID_ENABLE_RENDERSCRIPT
Derek Sollenbergere392c812014-05-21 11:25:22 -0400681 if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700682 uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700683
Chris Craikd41c4d82015-01-05 15:51:13 -0800684 if (mRs == nullptr) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700685 mRs = new RSC::RS();
Tim Murrayabe55e92013-12-13 12:57:36 -0800686 // a null path is OK because there are no custom kernels used
687 // hence nothing gets cached by RS
688 if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800689 mRs.clear();
Dan Morrille4d9a012013-03-28 18:10:43 -0700690 ALOGE("blur RS failed to init");
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800691 } else {
692 mRsElement = RSC::Element::A_8(mRs);
693 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Dan Morrille4d9a012013-03-28 18:10:43 -0700694 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800695 }
Chris Craikd41c4d82015-01-05 15:51:13 -0800696 if (mRs != nullptr) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800697 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
698 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
699 RS_ALLOCATION_MIPMAP_NONE,
700 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
701 *image);
702 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
703 RS_ALLOCATION_MIPMAP_NONE,
704 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
705 outImage);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800706
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800707 mRsScript->setRadius(radius);
708 mRsScript->setInput(ain);
709 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700710
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800711 // replace the original image's pointer, avoiding a copy back to the original buffer
712 free(*image);
713 *image = outImage;
Dan Morrille4d9a012013-03-28 18:10:43 -0700714
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800715 return;
716 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800717 }
Dan Morrille4d9a012013-03-28 18:10:43 -0700718#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800719
Chris Craik51d6a3d2014-12-22 17:16:56 -0800720 std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
huanhuan.x.wanga46ca5e2015-04-14 16:23:15 +0200721 Blur::generateGaussianWeights(gaussian.get(), radius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800722
Chris Craik51d6a3d2014-12-22 17:16:56 -0800723 std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
724 Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
725 Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700726}
727
John Reck272a6852015-07-29 16:48:58 -0700728static uint32_t calculateCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700729 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700730 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
731 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700732 if (cacheTexture && cacheTexture->getPixelBuffer()) {
733 size += cacheTexture->getPixelBuffer()->getSize();
734 }
735 }
736 return size;
737}
738
Victoria Lease1e546812013-06-25 14:25:17 -0700739uint32_t FontRenderer::getCacheSize(GLenum format) const {
740 switch (format) {
741 case GL_ALPHA: {
742 return calculateCacheSize(mACacheTextures);
743 }
744 case GL_RGBA: {
745 return calculateCacheSize(mRGBACacheTextures);
746 }
747 default: {
748 return 0;
749 }
750 }
751}
752
Romain Guy694b5192010-07-21 21:33:20 -0700753}; // namespace uirenderer
754}; // namespace android