blob: c79ae777d051c51c7e0f93973bc2c71415b33abc [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"
Chris Craik083e7332015-02-27 17:04:20 -080029#include "utils/MathUtils.h"
Chris Craik96a5c4c2015-01-27 15:46:35 -080030#include "utils/Timing.h"
Romain Guy694b5192010-07-21 21:33:20 -070031
Derek Sollenbergerca79cf62012-08-14 16:44:52 -040032#include <SkGlyph.h>
Romain Guy694b5192010-07-21 21:33:20 -070033#include <SkUtils.h>
34
Romain Guy51769a62010-07-23 00:28:00 -070035#include <cutils/properties.h>
Romain Guye2d345e2010-09-24 18:39:22 -070036
Romain Guy51769a62010-07-23 00:28:00 -070037#include <utils/Log.h>
38
Dan Morrille4d9a012013-03-28 18:10:43 -070039#ifdef ANDROID_ENABLE_RENDERSCRIPT
Romain Guy6e200402013-03-08 11:28:22 -080040#include <RenderScript.h>
Dan Morrille4d9a012013-03-28 18:10:43 -070041#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -080042
Romain Guy694b5192010-07-21 21:33:20 -070043namespace android {
44namespace uirenderer {
45
Chris Craikf2d8ccc2013-02-13 16:14:17 -080046// blur inputs smaller than this constant will bypass renderscript
47#define RS_MIN_INPUT_CUTOFF 10000
48
Romain Guy694b5192010-07-21 21:33:20 -070049///////////////////////////////////////////////////////////////////////////////
Victoria Lease1e546812013-06-25 14:25:17 -070050// TextSetupFunctor
51///////////////////////////////////////////////////////////////////////////////
Victoria Lease1e546812013-06-25 14:25:17 -070052
Chris Craik82840732015-04-03 09:37:49 -070053void TextDrawFunctor::draw(CacheTexture& texture, bool linearFiltering) {
Chris Craike2bb3802015-03-13 15:07:52 -070054 int textureFillFlags = static_cast<int>(texture.getFormat() == GL_ALPHA
55 ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone);
56 if (linearFiltering) {
57 textureFillFlags |= TextureFillFlags::kForceFilter;
58 }
59 const Matrix4& transform = pureTranslate ? Matrix4::identity() : *(renderer->currentTransform());
60 Glop glop;
61 GlopBuilder(renderer->mRenderState, renderer->mCaches, &glop)
62 .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
63 .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, renderer->currentSnapshot()->alpha)
64 .setTransform(renderer->currentSnapshot()->getOrthoMatrix(), transform, false)
65 .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
66 .setRoundRectClipState(renderer->currentSnapshot()->roundRectClipState)
67 .build();
68 renderer->renderGlop(glop);
Victoria Lease1e546812013-06-25 14:25:17 -070069}
70
71///////////////////////////////////////////////////////////////////////////////
Romain Guy694b5192010-07-21 21:33:20 -070072// FontRenderer
73///////////////////////////////////////////////////////////////////////////////
74
Romain Guy514fb182011-01-19 14:38:29 -080075static bool sLogFontRendererCreate = true;
76
Chris Craik083e7332015-02-27 17:04:20 -080077FontRenderer::FontRenderer()
78 : mGammaTable(nullptr)
79 , mCurrentFont(nullptr)
80 , mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity)
81 , mCurrentCacheTexture(nullptr)
82 , mUploadTexture(false)
83 , mFunctor(nullptr)
84 , mClip(nullptr)
85 , mBounds(nullptr)
86 , mDrawn(false)
87 , mInitialized(false)
88 , mLinearFiltering(false) {
Romain Guye3a9b242013-01-08 11:15:30 -080089
Romain Guyc9855a52011-01-21 21:14:15 -080090 if (sLogFontRendererCreate) {
91 INIT_LOGD("Creating FontRenderer");
92 }
Romain Guy51769a62010-07-23 00:28:00 -070093
Chet Haaseeb32a492012-08-31 13:54:03 -070094 mSmallCacheWidth = DEFAULT_TEXT_SMALL_CACHE_WIDTH;
95 mSmallCacheHeight = DEFAULT_TEXT_SMALL_CACHE_HEIGHT;
96 mLargeCacheWidth = DEFAULT_TEXT_LARGE_CACHE_WIDTH;
97 mLargeCacheHeight = DEFAULT_TEXT_LARGE_CACHE_HEIGHT;
Romain Guy51769a62010-07-23 00:28:00 -070098
99 char property[PROPERTY_VALUE_MAX];
Chris Craikd41c4d82015-01-05 15:51:13 -0800100 if (property_get(PROPERTY_TEXT_SMALL_CACHE_WIDTH, property, nullptr) > 0) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800101 mSmallCacheWidth = atoi(property);
Romain Guy51769a62010-07-23 00:28:00 -0700102 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700103
Chris Craikd41c4d82015-01-05 15:51:13 -0800104 if (property_get(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, property, nullptr) > 0) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800105 mSmallCacheHeight = atoi(property);
Chet Haaseeb32a492012-08-31 13:54:03 -0700106 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700107
Chris Craikd41c4d82015-01-05 15:51:13 -0800108 if (property_get(PROPERTY_TEXT_LARGE_CACHE_WIDTH, property, nullptr) > 0) {
Chet Haaseeb32a492012-08-31 13:54:03 -0700109 mLargeCacheWidth = atoi(property);
110 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700111
Chris Craikd41c4d82015-01-05 15:51:13 -0800112 if (property_get(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, property, nullptr) > 0) {
Chet Haaseeb32a492012-08-31 13:54:03 -0700113 mLargeCacheHeight = atoi(property);
114 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700115
116 uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
Chris Craik083e7332015-02-27 17:04:20 -0800117
118 mSmallCacheWidth = MathUtils::min(mSmallCacheWidth, maxTextureSize);
119 mSmallCacheHeight = MathUtils::min(mSmallCacheHeight, maxTextureSize);
120 mLargeCacheWidth = MathUtils::min(mLargeCacheWidth, maxTextureSize);
121 mLargeCacheHeight = MathUtils::min(mLargeCacheHeight, maxTextureSize);
Romain Guy9f5dab32012-09-04 12:55:44 -0700122
Chet Haaseeb32a492012-08-31 13:54:03 -0700123 if (sLogFontRendererCreate) {
124 INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
125 mSmallCacheWidth, mSmallCacheHeight,
126 mLargeCacheWidth, mLargeCacheHeight >> 1,
127 mLargeCacheWidth, mLargeCacheHeight >> 1,
128 mLargeCacheWidth, mLargeCacheHeight);
Romain Guy51769a62010-07-23 00:28:00 -0700129 }
Romain Guy514fb182011-01-19 14:38:29 -0800130
131 sLogFontRendererCreate = false;
Romain Guy694b5192010-07-21 21:33:20 -0700132}
133
Victoria Lease1e546812013-06-25 14:25:17 -0700134void clearCacheTextures(Vector<CacheTexture*>& cacheTextures) {
135 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
136 delete cacheTextures[i];
Romain Guy694b5192010-07-21 21:33:20 -0700137 }
Victoria Lease1e546812013-06-25 14:25:17 -0700138 cacheTextures.clear();
139}
140
141FontRenderer::~FontRenderer() {
142 clearCacheTextures(mACacheTextures);
143 clearCacheTextures(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700144
Romain Guye3a9b242013-01-08 11:15:30 -0800145 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
146 while (it.next()) {
147 delete it.value();
Romain Guy694b5192010-07-21 21:33:20 -0700148 }
Romain Guye3a9b242013-01-08 11:15:30 -0800149 mActiveFonts.clear();
Romain Guy694b5192010-07-21 21:33:20 -0700150}
151
152void FontRenderer::flushAllAndInvalidate() {
Romain Guy661a87e2013-03-19 15:24:36 -0700153 issueDrawCommand();
Romain Guy9d9758a2012-05-14 15:19:58 -0700154
Romain Guye3a9b242013-01-08 11:15:30 -0800155 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
156 while (it.next()) {
157 it.value()->invalidateTextureCache();
Romain Guy694b5192010-07-21 21:33:20 -0700158 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700159
Victoria Lease1e546812013-06-25 14:25:17 -0700160 for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
161 mACacheTextures[i]->init();
162 }
163
164 for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
165 mRGBACacheTextures[i]->init();
Romain Guy694b5192010-07-21 21:33:20 -0700166 }
chaochen1f61b192014-08-28 18:45:27 -0700167
168 mDrawn = false;
Romain Guy694b5192010-07-21 21:33:20 -0700169}
170
Victoria Lease1e546812013-06-25 14:25:17 -0700171void FontRenderer::flushLargeCaches(Vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700172 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700173 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
174 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700175 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700176 cacheTexture->init();
Romain Guye3a9b242013-01-08 11:15:30 -0800177 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
178 while (it.next()) {
179 it.value()->invalidateTextureCache(cacheTexture);
Chet Haasee816bae2012-08-09 13:39:02 -0700180 }
Chris Craike2bb3802015-03-13 15:07:52 -0700181 cacheTexture->releasePixelBuffer();
Chet Haase9a824562011-12-16 15:44:59 -0800182 }
183 }
Chet Haase9a824562011-12-16 15:44:59 -0800184}
185
Victoria Lease1e546812013-06-25 14:25:17 -0700186void FontRenderer::flushLargeCaches() {
187 flushLargeCaches(mACacheTextures);
188 flushLargeCaches(mRGBACacheTextures);
189}
190
191CacheTexture* FontRenderer::cacheBitmapInTexture(Vector<CacheTexture*>& cacheTextures,
192 const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
193 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
194 if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
195 return cacheTextures[i];
Chet Haase378e9192012-08-15 15:54:54 -0700196 }
197 }
198 // Could not fit glyph into current cache textures
Chris Craikd41c4d82015-01-05 15:51:13 -0800199 return nullptr;
Chet Haase378e9192012-08-15 15:54:54 -0700200}
201
Chet Haase7de0cb12011-12-05 16:35:38 -0800202void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
Chet Haasef942cf12012-08-30 09:06:46 -0700203 uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700204 checkInit();
Romain Guya4adcf02013-02-28 12:15:35 -0800205
206 // If the glyph bitmap is empty let's assum the glyph is valid
207 // so we can avoid doing extra work later on
208 if (glyph.fWidth == 0 || glyph.fHeight == 0) {
209 cachedGlyph->mIsValid = true;
Chris Craikd41c4d82015-01-05 15:51:13 -0800210 cachedGlyph->mCacheTexture = nullptr;
Romain Guya4adcf02013-02-28 12:15:35 -0800211 return;
212 }
213
Chet Haase7de0cb12011-12-05 16:35:38 -0800214 cachedGlyph->mIsValid = false;
Romain Guya4adcf02013-02-28 12:15:35 -0800215
Victoria Lease1e546812013-06-25 14:25:17 -0700216 // choose an appropriate cache texture list for this glyph format
217 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
Chris Craikd41c4d82015-01-05 15:51:13 -0800218 Vector<CacheTexture*>* cacheTextures = nullptr;
Victoria Lease1e546812013-06-25 14:25:17 -0700219 switch (format) {
220 case SkMask::kA8_Format:
Victoria Lease723b2fe2013-08-12 14:38:44 -0700221 case SkMask::kBW_Format:
Victoria Lease1e546812013-06-25 14:25:17 -0700222 cacheTextures = &mACacheTextures;
223 break;
224 case SkMask::kARGB32_Format:
225 cacheTextures = &mRGBACacheTextures;
226 break;
227 default:
228#if DEBUG_FONT_RENDERER
229 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
230#endif
231 return;
232 }
233
Romain Guy694b5192010-07-21 21:33:20 -0700234 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700235 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
Victoria Lease1e546812013-06-25 14:25:17 -0700236 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700237 ALOGE("Font size too large to fit in cache. width, height = %i, %i",
238 (int) glyph.fWidth, (int) glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800239 return;
Romain Guy694b5192010-07-21 21:33:20 -0700240 }
241
242 // Now copy the bitmap into the cache texture
243 uint32_t startX = 0;
244 uint32_t startY = 0;
245
Victoria Lease1e546812013-06-25 14:25:17 -0700246 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700247
Chet Haase378e9192012-08-15 15:54:54 -0700248 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700249 if (!precaching) {
250 // If the new glyph didn't fit and we are not just trying to precache it,
251 // clear out the cache and try again
252 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700253 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700254 }
Romain Guy694b5192010-07-21 21:33:20 -0700255
Chet Haase378e9192012-08-15 15:54:54 -0700256 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700257 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800258 return;
Romain Guy694b5192010-07-21 21:33:20 -0700259 }
260 }
261
Chet Haase378e9192012-08-15 15:54:54 -0700262 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800263
Romain Guy694b5192010-07-21 21:33:20 -0700264 *retOriginX = startX;
265 *retOriginY = startY;
266
267 uint32_t endX = startX + glyph.fWidth;
268 uint32_t endY = startY + glyph.fHeight;
269
Romain Guy80872462012-09-04 16:42:01 -0700270 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700271
Romain Guycf51a412013-04-08 19:40:31 -0700272 if (!cacheTexture->getPixelBuffer()) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800273 Caches::getInstance().textureState().activateTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800274 // Large-glyph texture memory is allocated only as needed
Chris Craike2bb3802015-03-13 15:07:52 -0700275 cacheTexture->allocatePixelBuffer();
Chet Haase7de0cb12011-12-05 16:35:38 -0800276 }
Romain Guy661a87e2013-03-19 15:24:36 -0700277 if (!cacheTexture->mesh()) {
278 cacheTexture->allocateMesh();
279 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700280
Romain Guycf51a412013-04-08 19:40:31 -0700281 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
Victoria Lease1e546812013-06-25 14:25:17 -0700282 uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
283 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700284
Romain Guyb969a0d2013-02-05 14:38:40 -0800285 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800286 switch (format) {
287 case SkMask::kA8_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700288 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
289 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
290 - TEXTURE_BORDER_SIZE;
291 // write leading border line
292 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
293 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800294 if (mGammaTable) {
Victoria Lease1e546812013-06-25 14:25:17 -0700295 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800296 row = cacheY * cacheWidth;
297 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800298 for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
299 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800300 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800301 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800302 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800303 }
304 } else {
Victoria Lease1e546812013-06-25 14:25:17 -0700305 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800306 row = cacheY * cacheWidth;
307 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
308 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
309 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800310 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700311 }
Victoria Lease1e546812013-06-25 14:25:17 -0700312 // write trailing border line
313 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
314 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
315 break;
316 }
317 case SkMask::kARGB32_Format: {
318 // prep data lengths
319 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
320 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
321 size_t rowSize = formatSize * glyph.fWidth;
322 // prep advances
323 size_t dstStride = formatSize * cacheWidth;
324 // prep indices
325 // - we actually start one row early, and then increment before first copy
326 uint8_t* src = &bitmapBuffer[0 - srcStride];
327 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
328 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
329 uint8_t* dstL = dst - borderSize;
330 uint8_t* dstR = dst + rowSize;
331 // write leading border line
332 memset(dstL, 0, rowSize + 2 * borderSize);
333 // write glyph data
334 while (dst < dstEnd) {
335 memset(dstL += dstStride, 0, borderSize); // leading border column
336 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
337 memset(dstR += dstStride, 0, borderSize); // trailing border column
338 }
339 // write trailing border line
Victoria Lease16c84062013-09-19 15:38:21 -0700340 memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800341 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700342 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800343 case SkMask::kBW_Format: {
Andreas Gampe1e196742014-11-10 15:23:43 -0800344 uint32_t cacheX = 0, cacheY = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700345 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
346 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800347 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700348 // write leading border line
349 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
350 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800351 for (cacheY = startY; cacheY < endY; cacheY++) {
352 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700353 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800354 uint8_t* buffer = bitmapBuffer;
355
Romain Guy0b58a3d2013-03-05 12:16:27 -0800356 row = cacheY * cacheWidth;
357 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800358 while (--rowBytes >= 0) {
359 uint8_t b = *buffer++;
360 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
361 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
362 }
363 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800364 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800365
Victoria Lease1e546812013-06-25 14:25:17 -0700366 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700367 }
Victoria Lease1e546812013-06-25 14:25:17 -0700368 // write trailing border line
369 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
370 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800371 break;
Romain Guy694b5192010-07-21 21:33:20 -0700372 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800373 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700374 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800375 break;
Romain Guy694b5192010-07-21 21:33:20 -0700376 }
Romain Guy97771732012-02-28 18:17:02 -0800377
Chet Haase7de0cb12011-12-05 16:35:38 -0800378 cachedGlyph->mIsValid = true;
Romain Guy694b5192010-07-21 21:33:20 -0700379}
380
Victoria Lease1e546812013-06-25 14:25:17 -0700381CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
382 bool allocate) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800383 CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700384
Chet Haase2a47c142011-12-14 15:22:56 -0800385 if (allocate) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800386 Caches::getInstance().textureState().activateTexture(0);
Chris Craike2bb3802015-03-13 15:07:52 -0700387 cacheTexture->allocatePixelBuffer();
Romain Guy661a87e2013-03-19 15:24:36 -0700388 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800389 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700390
Chet Haase2a47c142011-12-14 15:22:56 -0800391 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800392}
393
394void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700395 clearCacheTextures(mACacheTextures);
396 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700397
Chet Haase7de0cb12011-12-05 16:35:38 -0800398 mUploadTexture = false;
Victoria Lease1e546812013-06-25 14:25:17 -0700399 mACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
400 GL_ALPHA, true));
401 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
402 GL_ALPHA, false));
403 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
404 GL_ALPHA, false));
405 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
406 GL_ALPHA, false));
407 mRGBACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
408 GL_RGBA, false));
409 mRGBACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
410 GL_RGBA, false));
411 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700412}
413
Romain Guy694b5192010-07-21 21:33:20 -0700414// We don't want to allocate anything unless we actually draw text
415void FontRenderer::checkInit() {
416 if (mInitialized) {
417 return;
418 }
419
420 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700421
422 mInitialized = true;
423}
424
Victoria Lease1e546812013-06-25 14:25:17 -0700425void checkTextureUpdateForCache(Caches& caches, Vector<CacheTexture*>& cacheTextures,
426 bool& resetPixelStore, GLuint& lastTextureId) {
427 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
428 CacheTexture* cacheTexture = cacheTextures[i];
429 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
430 if (cacheTexture->getTextureId() != lastTextureId) {
431 lastTextureId = cacheTexture->getTextureId();
Chris Craik44eb2c02015-01-29 09:45:09 -0800432 caches.textureState().activateTexture(0);
433 caches.textureState().bindTexture(lastTextureId);
Victoria Lease1e546812013-06-25 14:25:17 -0700434 }
435
436 if (cacheTexture->upload()) {
437 resetPixelStore = true;
438 }
439 }
440 }
441}
442
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700443void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900444 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700445 return;
Romain Guy694b5192010-07-21 21:33:20 -0700446 }
447
Romain Guy2d4fd362011-12-13 22:00:19 -0800448 Caches& caches = Caches::getInstance();
449 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700450
Romain Guycf51a412013-04-08 19:40:31 -0700451 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700452 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
453
Chet Haase378e9192012-08-15 15:54:54 -0700454 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700455 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
456 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700457
Romain Guycf51a412013-04-08 19:40:31 -0700458 // Unbind any PBO we might have used to update textures
Chris Craik44eb2c02015-01-29 09:45:09 -0800459 caches.pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700460
Romain Guy09087642013-04-04 12:27:54 -0700461 // Reset to default unpack row length to avoid affecting texture
462 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700463 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700464 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
465 }
466
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700467 mUploadTexture = false;
468}
469
Victoria Lease1e546812013-06-25 14:25:17 -0700470void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800471 if (!mFunctor) return;
472
Romain Guy661a87e2013-03-19 15:24:36 -0700473 bool first = true;
Chris Craik96a5c4c2015-01-27 15:46:35 -0800474 bool forceRebind = false;
Victoria Lease1e546812013-06-25 14:25:17 -0700475 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
476 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700477 if (texture->canDraw()) {
478 if (first) {
Chris Craike2bb3802015-03-13 15:07:52 -0700479 checkTextureUpdate();
Romain Guy661a87e2013-03-19 15:24:36 -0700480 first = false;
Chris Craik083e7332015-02-27 17:04:20 -0800481 mDrawn = true;
Romain Guy661a87e2013-03-19 15:24:36 -0700482 }
Chris Craik82840732015-04-03 09:37:49 -0700483
Chris Craike2bb3802015-03-13 15:07:52 -0700484 mFunctor->draw(*texture, mLinearFiltering);
Romain Guy661a87e2013-03-19 15:24:36 -0700485
Romain Guy661a87e2013-03-19 15:24:36 -0700486 texture->resetMesh();
Chris Craik96a5c4c2015-01-27 15:46:35 -0800487 forceRebind = false;
Romain Guy115096f2013-03-19 11:32:41 -0700488 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900489 }
Victoria Lease1e546812013-06-25 14:25:17 -0700490}
491
492void FontRenderer::issueDrawCommand() {
493 issueDrawCommand(mACacheTextures);
494 issueDrawCommand(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700495}
496
Romain Guy97771732012-02-28 18:17:02 -0800497void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
498 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
Chet Haase7de0cb12011-12-05 16:35:38 -0800499 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800500 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800501 // Now use the new texture id
502 mCurrentCacheTexture = texture;
503 }
Romain Guy09147fb2010-07-22 13:08:20 -0700504
Romain Guy661a87e2013-03-19 15:24:36 -0700505 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
506 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800507}
508
509void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
510 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
511 float x4, float y4, float u4, float v4, CacheTexture* texture) {
512
513 if (mClip &&
514 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
515 return;
516 }
517
518 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 -0700519
Romain Guy5b3b3522010-10-27 18:57:51 -0700520 if (mBounds) {
521 mBounds->left = fmin(mBounds->left, x1);
522 mBounds->top = fmin(mBounds->top, y3);
523 mBounds->right = fmax(mBounds->right, x3);
524 mBounds->bottom = fmax(mBounds->bottom, y1);
525 }
526
Romain Guy661a87e2013-03-19 15:24:36 -0700527 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700528 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700529 }
530}
531
Romain Guy97771732012-02-28 18:17:02 -0800532void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
533 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
534 float x4, float y4, float u4, float v4, CacheTexture* texture) {
535
536 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
537
538 if (mBounds) {
539 mBounds->left = fmin(mBounds->left, fmin(x1, fmin(x2, fmin(x3, x4))));
540 mBounds->top = fmin(mBounds->top, fmin(y1, fmin(y2, fmin(y3, y4))));
541 mBounds->right = fmax(mBounds->right, fmax(x1, fmax(x2, fmax(x3, x4))));
542 mBounds->bottom = fmax(mBounds->bottom, fmax(y1, fmax(y2, fmax(y3, y4))));
543 }
544
Romain Guy661a87e2013-03-19 15:24:36 -0700545 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800546 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800547 }
548}
549
Chris Craik59744b72014-07-01 17:56:52 -0700550void FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800551 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700552}
Romain Guy7975fb62010-10-01 16:36:14 -0700553
Chris Craikd218a922014-01-02 17:13:34 -0800554FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const char *text,
Derek Sollenbergere392c812014-05-21 11:25:22 -0400555 uint32_t startIndex, uint32_t len, int numGlyphs, float radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700556 checkInit();
557
Romain Guycf51a412013-04-08 19:40:31 -0700558 DropShadow image;
559 image.width = 0;
560 image.height = 0;
Chris Craikd41c4d82015-01-05 15:51:13 -0800561 image.image = nullptr;
Romain Guycf51a412013-04-08 19:40:31 -0700562 image.penX = 0;
563 image.penY = 0;
564
Romain Guy1e45aae2010-08-13 19:39:53 -0700565 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700566 return image;
567 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700568
Romain Guy2d4fd362011-12-13 22:00:19 -0800569 mDrawn = false;
Chris Craikd41c4d82015-01-05 15:51:13 -0800570 mClip = nullptr;
571 mBounds = nullptr;
Romain Guyff98fa52011-11-28 09:35:09 -0800572
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700573 Rect bounds;
Raph Levien416a8472012-07-19 22:48:17 -0700574 mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800575
Derek Sollenbergere392c812014-05-21 11:25:22 -0400576 uint32_t intRadius = Blur::convertRadiusToInt(radius);
577 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
578 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
Romain Guyff98fa52011-11-28 09:35:09 -0800579
Romain Guycf51a412013-04-08 19:40:31 -0700580 uint32_t maxSize = Caches::getInstance().maxTextureSize;
581 if (paddedWidth > maxSize || paddedHeight > maxSize) {
582 return image;
583 }
584
Dan Morrille4d9a012013-03-28 18:10:43 -0700585#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800586 // Align buffers for renderscript usage
587 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
588 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700589 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800590 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800591 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700592#else
593 int size = paddedWidth * paddedHeight;
594 uint8_t* dataBuffer = (uint8_t*) malloc(size);
595#endif
596
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800597 memset(dataBuffer, 0, size);
598
Derek Sollenbergere392c812014-05-21 11:25:22 -0400599 int penX = intRadius - bounds.left;
600 int penY = intRadius - bounds.bottom;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700601
Chris Craikdd8697c2013-02-22 10:41:36 -0800602 if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
603 // text has non-whitespace, so draw and blur to create the shadow
604 // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
605 // TODO: don't draw pure whitespace in the first place, and avoid needing this check
606 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
Chris Craikd41c4d82015-01-05 15:51:13 -0800607 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
Chris Craikdd8697c2013-02-22 10:41:36 -0800608
Romain Guycf51a412013-04-08 19:40:31 -0700609 // Unbind any PBO we might have used
Chris Craik44eb2c02015-01-29 09:45:09 -0800610 Caches::getInstance().pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700611
Chris Craikdd8697c2013-02-22 10:41:36 -0800612 blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
613 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700614
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700615 image.width = paddedWidth;
616 image.height = paddedHeight;
617 image.image = dataBuffer;
618 image.penX = penX;
619 image.penY = penY;
Romain Guy2d4fd362011-12-13 22:00:19 -0800620
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700621 return image;
622}
Romain Guy694b5192010-07-21 21:33:20 -0700623
Chris Craik82840732015-04-03 09:37:49 -0700624void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextDrawFunctor* functor) {
Romain Guy694b5192010-07-21 21:33:20 -0700625 checkInit();
626
Romain Guy5b3b3522010-10-27 18:57:51 -0700627 mDrawn = false;
628 mBounds = bounds;
Romain Guy257ae352013-03-20 16:31:12 -0700629 mFunctor = functor;
Romain Guy09147fb2010-07-22 13:08:20 -0700630 mClip = clip;
Romain Guy671d6cf2012-01-18 12:39:17 -0800631}
Romain Guyff98fa52011-11-28 09:35:09 -0800632
Romain Guy671d6cf2012-01-18 12:39:17 -0800633void FontRenderer::finishRender() {
Chris Craikd41c4d82015-01-05 15:51:13 -0800634 mBounds = nullptr;
635 mClip = nullptr;
Romain Guy694b5192010-07-21 21:33:20 -0700636
Romain Guy661a87e2013-03-19 15:24:36 -0700637 issueDrawCommand();
Romain Guy671d6cf2012-01-18 12:39:17 -0800638}
639
Chris Craikd218a922014-01-02 17:13:34 -0800640void FontRenderer::precache(const SkPaint* paint, const char* text, int numGlyphs,
Chris Craik59744b72014-07-01 17:56:52 -0700641 const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800642 Font* font = Font::create(this, paint, matrix);
Chet Haasee816bae2012-08-09 13:39:02 -0700643 font->precache(paint, text, numGlyphs);
644}
645
Romain Guycf51a412013-04-08 19:40:31 -0700646void FontRenderer::endPrecaching() {
647 checkTextureUpdate();
648}
649
Chris Craikd218a922014-01-02 17:13:34 -0800650bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
Romain Guy671d6cf2012-01-18 12:39:17 -0800651 uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
Chris Craik82840732015-04-03 09:37:49 -0700652 const float* positions, Rect* bounds, TextDrawFunctor* functor, bool forceFinish) {
Romain Guy671d6cf2012-01-18 12:39:17 -0800653 if (!mCurrentFont) {
654 ALOGE("No font set");
655 return false;
656 }
657
Romain Guy257ae352013-03-20 16:31:12 -0700658 initRender(clip, bounds, functor);
Romain Guy671d6cf2012-01-18 12:39:17 -0800659 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions);
Chris Craik527a3aa2013-03-04 10:19:31 -0800660
661 if (forceFinish) {
662 finishRender();
663 }
Romain Guy5b3b3522010-10-27 18:57:51 -0700664
665 return mDrawn;
Romain Guy694b5192010-07-21 21:33:20 -0700666}
667
Chris Craikd218a922014-01-02 17:13:34 -0800668bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
669 uint32_t startIndex, uint32_t len, int numGlyphs, const SkPath* path,
Chris Craik82840732015-04-03 09:37:49 -0700670 float hOffset, float vOffset, Rect* bounds, TextDrawFunctor* functor) {
Romain Guy97771732012-02-28 18:17:02 -0800671 if (!mCurrentFont) {
672 ALOGE("No font set");
673 return false;
674 }
675
Victoria Lease1e546812013-06-25 14:25:17 -0700676 initRender(clip, bounds, functor);
Romain Guy97771732012-02-28 18:17:02 -0800677 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset);
678 finishRender();
679
680 return mDrawn;
681}
682
Romain Guy9b1204b2012-09-04 15:22:57 -0700683void FontRenderer::removeFont(const Font* font) {
Romain Guye3a9b242013-01-08 11:15:30 -0800684 mActiveFonts.remove(font->getDescription());
Romain Guy9b1204b2012-09-04 15:22:57 -0700685
686 if (mCurrentFont == font) {
Chris Craikd41c4d82015-01-05 15:51:13 -0800687 mCurrentFont = nullptr;
Romain Guy9b1204b2012-09-04 15:22:57 -0700688 }
689}
690
Derek Sollenbergere392c812014-05-21 11:25:22 -0400691void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
692 uint32_t intRadius = Blur::convertRadiusToInt(radius);
Dan Morrille4d9a012013-03-28 18:10:43 -0700693#ifdef ANDROID_ENABLE_RENDERSCRIPT
Derek Sollenbergere392c812014-05-21 11:25:22 -0400694 if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700695 uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700696
Chris Craikd41c4d82015-01-05 15:51:13 -0800697 if (mRs == nullptr) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700698 mRs = new RSC::RS();
Tim Murrayabe55e92013-12-13 12:57:36 -0800699 // a null path is OK because there are no custom kernels used
700 // hence nothing gets cached by RS
701 if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800702 mRs.clear();
Dan Morrille4d9a012013-03-28 18:10:43 -0700703 ALOGE("blur RS failed to init");
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800704 } else {
705 mRsElement = RSC::Element::A_8(mRs);
706 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Dan Morrille4d9a012013-03-28 18:10:43 -0700707 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800708 }
Chris Craikd41c4d82015-01-05 15:51:13 -0800709 if (mRs != nullptr) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800710 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
711 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
712 RS_ALLOCATION_MIPMAP_NONE,
713 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
714 *image);
715 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
716 RS_ALLOCATION_MIPMAP_NONE,
717 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
718 outImage);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800719
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800720 mRsScript->setRadius(radius);
721 mRsScript->setInput(ain);
722 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700723
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800724 // replace the original image's pointer, avoiding a copy back to the original buffer
725 free(*image);
726 *image = outImage;
Dan Morrille4d9a012013-03-28 18:10:43 -0700727
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800728 return;
729 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800730 }
Dan Morrille4d9a012013-03-28 18:10:43 -0700731#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800732
Chris Craik51d6a3d2014-12-22 17:16:56 -0800733 std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
734 Blur::generateGaussianWeights(gaussian.get(), intRadius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800735
Chris Craik51d6a3d2014-12-22 17:16:56 -0800736 std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
737 Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
738 Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700739}
740
Victoria Lease1e546812013-06-25 14:25:17 -0700741static uint32_t calculateCacheSize(const Vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700742 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700743 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
744 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700745 if (cacheTexture && cacheTexture->getPixelBuffer()) {
746 size += cacheTexture->getPixelBuffer()->getSize();
747 }
748 }
749 return size;
750}
751
Victoria Lease1e546812013-06-25 14:25:17 -0700752uint32_t FontRenderer::getCacheSize(GLenum format) const {
753 switch (format) {
754 case GL_ALPHA: {
755 return calculateCacheSize(mACacheTextures);
756 }
757 case GL_RGBA: {
758 return calculateCacheSize(mRGBACacheTextures);
759 }
760 default: {
761 return 0;
762 }
763 }
764}
765
Romain Guy694b5192010-07-21 21:33:20 -0700766}; // namespace uirenderer
767}; // namespace android