blob: 9a2a879e594eaa439ee03a729a171413d21f5197 [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 Craik53e51e42015-06-01 10:35:35 -070054 int textureFillFlags = TextureFillFlags::None;
55 if (texture.getFormat() == GL_ALPHA) {
56 textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture;
Chris Craike2bb3802015-03-13 15:07:52 -070057 }
Chris Craik53e51e42015-06-01 10:35:35 -070058 if (linearFiltering) {
59 textureFillFlags |= TextureFillFlags::ForceFilter;
60 }
61 int transformFlags = pureTranslate
62 ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
Chris Craike2bb3802015-03-13 15:07:52 -070063 Glop glop;
64 GlopBuilder(renderer->mRenderState, renderer->mCaches, &glop)
65 .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
66 .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, renderer->currentSnapshot()->alpha)
Chris Craik53e51e42015-06-01 10:35:35 -070067 .setTransform(*(renderer->currentSnapshot()), transformFlags)
Chris Craike2bb3802015-03-13 15:07:52 -070068 .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
69 .setRoundRectClipState(renderer->currentSnapshot()->roundRectClipState)
70 .build();
71 renderer->renderGlop(glop);
Victoria Lease1e546812013-06-25 14:25:17 -070072}
73
74///////////////////////////////////////////////////////////////////////////////
Romain Guy694b5192010-07-21 21:33:20 -070075// FontRenderer
76///////////////////////////////////////////////////////////////////////////////
77
Romain Guy514fb182011-01-19 14:38:29 -080078static bool sLogFontRendererCreate = true;
79
Chris Craik083e7332015-02-27 17:04:20 -080080FontRenderer::FontRenderer()
81 : mGammaTable(nullptr)
82 , mCurrentFont(nullptr)
83 , mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity)
84 , mCurrentCacheTexture(nullptr)
85 , mUploadTexture(false)
86 , mFunctor(nullptr)
87 , mClip(nullptr)
88 , mBounds(nullptr)
89 , mDrawn(false)
90 , mInitialized(false)
91 , mLinearFiltering(false) {
Romain Guye3a9b242013-01-08 11:15:30 -080092
Romain Guyc9855a52011-01-21 21:14:15 -080093 if (sLogFontRendererCreate) {
94 INIT_LOGD("Creating FontRenderer");
95 }
Romain Guy51769a62010-07-23 00:28:00 -070096
Chet Haaseeb32a492012-08-31 13:54:03 -070097 mSmallCacheWidth = DEFAULT_TEXT_SMALL_CACHE_WIDTH;
98 mSmallCacheHeight = DEFAULT_TEXT_SMALL_CACHE_HEIGHT;
99 mLargeCacheWidth = DEFAULT_TEXT_LARGE_CACHE_WIDTH;
100 mLargeCacheHeight = DEFAULT_TEXT_LARGE_CACHE_HEIGHT;
Romain Guy51769a62010-07-23 00:28:00 -0700101
102 char property[PROPERTY_VALUE_MAX];
Chris Craikd41c4d82015-01-05 15:51:13 -0800103 if (property_get(PROPERTY_TEXT_SMALL_CACHE_WIDTH, property, nullptr) > 0) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800104 mSmallCacheWidth = atoi(property);
Romain Guy51769a62010-07-23 00:28:00 -0700105 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700106
Chris Craikd41c4d82015-01-05 15:51:13 -0800107 if (property_get(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, property, nullptr) > 0) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800108 mSmallCacheHeight = atoi(property);
Chet Haaseeb32a492012-08-31 13:54:03 -0700109 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700110
Chris Craikd41c4d82015-01-05 15:51:13 -0800111 if (property_get(PROPERTY_TEXT_LARGE_CACHE_WIDTH, property, nullptr) > 0) {
Chet Haaseeb32a492012-08-31 13:54:03 -0700112 mLargeCacheWidth = atoi(property);
113 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700114
Chris Craikd41c4d82015-01-05 15:51:13 -0800115 if (property_get(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, property, nullptr) > 0) {
Chet Haaseeb32a492012-08-31 13:54:03 -0700116 mLargeCacheHeight = atoi(property);
117 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700118
119 uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
Chris Craik083e7332015-02-27 17:04:20 -0800120
121 mSmallCacheWidth = MathUtils::min(mSmallCacheWidth, maxTextureSize);
122 mSmallCacheHeight = MathUtils::min(mSmallCacheHeight, maxTextureSize);
123 mLargeCacheWidth = MathUtils::min(mLargeCacheWidth, maxTextureSize);
124 mLargeCacheHeight = MathUtils::min(mLargeCacheHeight, maxTextureSize);
Romain Guy9f5dab32012-09-04 12:55:44 -0700125
Chet Haaseeb32a492012-08-31 13:54:03 -0700126 if (sLogFontRendererCreate) {
127 INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
128 mSmallCacheWidth, mSmallCacheHeight,
129 mLargeCacheWidth, mLargeCacheHeight >> 1,
130 mLargeCacheWidth, mLargeCacheHeight >> 1,
131 mLargeCacheWidth, mLargeCacheHeight);
Romain Guy51769a62010-07-23 00:28:00 -0700132 }
Romain Guy514fb182011-01-19 14:38:29 -0800133
134 sLogFontRendererCreate = false;
Romain Guy694b5192010-07-21 21:33:20 -0700135}
136
Victoria Lease1e546812013-06-25 14:25:17 -0700137void clearCacheTextures(Vector<CacheTexture*>& cacheTextures) {
138 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
139 delete cacheTextures[i];
Romain Guy694b5192010-07-21 21:33:20 -0700140 }
Victoria Lease1e546812013-06-25 14:25:17 -0700141 cacheTextures.clear();
142}
143
144FontRenderer::~FontRenderer() {
145 clearCacheTextures(mACacheTextures);
146 clearCacheTextures(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700147
Romain Guye3a9b242013-01-08 11:15:30 -0800148 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
149 while (it.next()) {
150 delete it.value();
Romain Guy694b5192010-07-21 21:33:20 -0700151 }
Romain Guye3a9b242013-01-08 11:15:30 -0800152 mActiveFonts.clear();
Romain Guy694b5192010-07-21 21:33:20 -0700153}
154
155void FontRenderer::flushAllAndInvalidate() {
Romain Guy661a87e2013-03-19 15:24:36 -0700156 issueDrawCommand();
Romain Guy9d9758a2012-05-14 15:19:58 -0700157
Romain Guye3a9b242013-01-08 11:15:30 -0800158 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
159 while (it.next()) {
160 it.value()->invalidateTextureCache();
Romain Guy694b5192010-07-21 21:33:20 -0700161 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700162
Victoria Lease1e546812013-06-25 14:25:17 -0700163 for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
164 mACacheTextures[i]->init();
165 }
166
167 for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
168 mRGBACacheTextures[i]->init();
Romain Guy694b5192010-07-21 21:33:20 -0700169 }
chaochen1f61b192014-08-28 18:45:27 -0700170
171 mDrawn = false;
Romain Guy694b5192010-07-21 21:33:20 -0700172}
173
Victoria Lease1e546812013-06-25 14:25:17 -0700174void FontRenderer::flushLargeCaches(Vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700175 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700176 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
177 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700178 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700179 cacheTexture->init();
Romain Guye3a9b242013-01-08 11:15:30 -0800180 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
181 while (it.next()) {
182 it.value()->invalidateTextureCache(cacheTexture);
Chet Haasee816bae2012-08-09 13:39:02 -0700183 }
Chris Craike2bb3802015-03-13 15:07:52 -0700184 cacheTexture->releasePixelBuffer();
Chet Haase9a824562011-12-16 15:44:59 -0800185 }
186 }
Chet Haase9a824562011-12-16 15:44:59 -0800187}
188
Victoria Lease1e546812013-06-25 14:25:17 -0700189void FontRenderer::flushLargeCaches() {
190 flushLargeCaches(mACacheTextures);
191 flushLargeCaches(mRGBACacheTextures);
192}
193
194CacheTexture* FontRenderer::cacheBitmapInTexture(Vector<CacheTexture*>& cacheTextures,
195 const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
196 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
197 if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
198 return cacheTextures[i];
Chet Haase378e9192012-08-15 15:54:54 -0700199 }
200 }
201 // Could not fit glyph into current cache textures
Chris Craikd41c4d82015-01-05 15:51:13 -0800202 return nullptr;
Chet Haase378e9192012-08-15 15:54:54 -0700203}
204
Chet Haase7de0cb12011-12-05 16:35:38 -0800205void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
Chet Haasef942cf12012-08-30 09:06:46 -0700206 uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700207 checkInit();
Romain Guya4adcf02013-02-28 12:15:35 -0800208
209 // If the glyph bitmap is empty let's assum the glyph is valid
210 // so we can avoid doing extra work later on
211 if (glyph.fWidth == 0 || glyph.fHeight == 0) {
212 cachedGlyph->mIsValid = true;
Chris Craikd41c4d82015-01-05 15:51:13 -0800213 cachedGlyph->mCacheTexture = nullptr;
Romain Guya4adcf02013-02-28 12:15:35 -0800214 return;
215 }
216
Chet Haase7de0cb12011-12-05 16:35:38 -0800217 cachedGlyph->mIsValid = false;
Romain Guya4adcf02013-02-28 12:15:35 -0800218
Victoria Lease1e546812013-06-25 14:25:17 -0700219 // choose an appropriate cache texture list for this glyph format
220 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
Chris Craikd41c4d82015-01-05 15:51:13 -0800221 Vector<CacheTexture*>* cacheTextures = nullptr;
Victoria Lease1e546812013-06-25 14:25:17 -0700222 switch (format) {
223 case SkMask::kA8_Format:
Victoria Lease723b2fe2013-08-12 14:38:44 -0700224 case SkMask::kBW_Format:
Victoria Lease1e546812013-06-25 14:25:17 -0700225 cacheTextures = &mACacheTextures;
226 break;
227 case SkMask::kARGB32_Format:
228 cacheTextures = &mRGBACacheTextures;
229 break;
230 default:
231#if DEBUG_FONT_RENDERER
232 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
233#endif
234 return;
235 }
236
Romain Guy694b5192010-07-21 21:33:20 -0700237 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700238 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
Victoria Lease1e546812013-06-25 14:25:17 -0700239 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700240 ALOGE("Font size too large to fit in cache. width, height = %i, %i",
241 (int) glyph.fWidth, (int) glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800242 return;
Romain Guy694b5192010-07-21 21:33:20 -0700243 }
244
245 // Now copy the bitmap into the cache texture
246 uint32_t startX = 0;
247 uint32_t startY = 0;
248
Victoria Lease1e546812013-06-25 14:25:17 -0700249 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700250
Chet Haase378e9192012-08-15 15:54:54 -0700251 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700252 if (!precaching) {
253 // If the new glyph didn't fit and we are not just trying to precache it,
254 // clear out the cache and try again
255 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700256 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700257 }
Romain Guy694b5192010-07-21 21:33:20 -0700258
Chet Haase378e9192012-08-15 15:54:54 -0700259 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700260 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800261 return;
Romain Guy694b5192010-07-21 21:33:20 -0700262 }
263 }
264
Chet Haase378e9192012-08-15 15:54:54 -0700265 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800266
Romain Guy694b5192010-07-21 21:33:20 -0700267 *retOriginX = startX;
268 *retOriginY = startY;
269
270 uint32_t endX = startX + glyph.fWidth;
271 uint32_t endY = startY + glyph.fHeight;
272
Romain Guy80872462012-09-04 16:42:01 -0700273 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700274
Romain Guycf51a412013-04-08 19:40:31 -0700275 if (!cacheTexture->getPixelBuffer()) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800276 Caches::getInstance().textureState().activateTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800277 // Large-glyph texture memory is allocated only as needed
Chris Craike2bb3802015-03-13 15:07:52 -0700278 cacheTexture->allocatePixelBuffer();
Chet Haase7de0cb12011-12-05 16:35:38 -0800279 }
Romain Guy661a87e2013-03-19 15:24:36 -0700280 if (!cacheTexture->mesh()) {
281 cacheTexture->allocateMesh();
282 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700283
Romain Guycf51a412013-04-08 19:40:31 -0700284 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
Victoria Lease1e546812013-06-25 14:25:17 -0700285 uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
286 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700287
Romain Guyb969a0d2013-02-05 14:38:40 -0800288 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800289 switch (format) {
290 case SkMask::kA8_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700291 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
292 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
293 - TEXTURE_BORDER_SIZE;
294 // write leading border line
295 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
296 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800297 if (mGammaTable) {
Victoria Lease1e546812013-06-25 14:25:17 -0700298 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800299 row = cacheY * cacheWidth;
300 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800301 for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
302 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800303 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800304 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800305 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800306 }
307 } else {
Victoria Lease1e546812013-06-25 14:25:17 -0700308 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800309 row = cacheY * cacheWidth;
310 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
311 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
312 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800313 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700314 }
Victoria Lease1e546812013-06-25 14:25:17 -0700315 // write trailing border line
316 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
317 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
318 break;
319 }
320 case SkMask::kARGB32_Format: {
321 // prep data lengths
322 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
323 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
324 size_t rowSize = formatSize * glyph.fWidth;
325 // prep advances
326 size_t dstStride = formatSize * cacheWidth;
327 // prep indices
328 // - we actually start one row early, and then increment before first copy
329 uint8_t* src = &bitmapBuffer[0 - srcStride];
330 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
331 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
332 uint8_t* dstL = dst - borderSize;
333 uint8_t* dstR = dst + rowSize;
334 // write leading border line
335 memset(dstL, 0, rowSize + 2 * borderSize);
336 // write glyph data
337 while (dst < dstEnd) {
338 memset(dstL += dstStride, 0, borderSize); // leading border column
339 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
340 memset(dstR += dstStride, 0, borderSize); // trailing border column
341 }
342 // write trailing border line
Victoria Lease16c84062013-09-19 15:38:21 -0700343 memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800344 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700345 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800346 case SkMask::kBW_Format: {
Andreas Gampe1e196742014-11-10 15:23:43 -0800347 uint32_t cacheX = 0, cacheY = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700348 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
349 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800350 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700351 // write leading border line
352 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
353 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800354 for (cacheY = startY; cacheY < endY; cacheY++) {
355 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700356 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800357 uint8_t* buffer = bitmapBuffer;
358
Romain Guy0b58a3d2013-03-05 12:16:27 -0800359 row = cacheY * cacheWidth;
360 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800361 while (--rowBytes >= 0) {
362 uint8_t b = *buffer++;
363 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
364 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
365 }
366 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800367 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800368
Victoria Lease1e546812013-06-25 14:25:17 -0700369 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700370 }
Victoria Lease1e546812013-06-25 14:25:17 -0700371 // write trailing border line
372 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
373 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800374 break;
Romain Guy694b5192010-07-21 21:33:20 -0700375 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800376 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700377 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800378 break;
Romain Guy694b5192010-07-21 21:33:20 -0700379 }
Romain Guy97771732012-02-28 18:17:02 -0800380
Chet Haase7de0cb12011-12-05 16:35:38 -0800381 cachedGlyph->mIsValid = true;
Romain Guy694b5192010-07-21 21:33:20 -0700382}
383
Victoria Lease1e546812013-06-25 14:25:17 -0700384CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
385 bool allocate) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800386 CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700387
Chet Haase2a47c142011-12-14 15:22:56 -0800388 if (allocate) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800389 Caches::getInstance().textureState().activateTexture(0);
Chris Craike2bb3802015-03-13 15:07:52 -0700390 cacheTexture->allocatePixelBuffer();
Romain Guy661a87e2013-03-19 15:24:36 -0700391 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800392 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700393
Chet Haase2a47c142011-12-14 15:22:56 -0800394 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800395}
396
397void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700398 clearCacheTextures(mACacheTextures);
399 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700400
Chet Haase7de0cb12011-12-05 16:35:38 -0800401 mUploadTexture = false;
Victoria Lease1e546812013-06-25 14:25:17 -0700402 mACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
403 GL_ALPHA, true));
404 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
405 GL_ALPHA, false));
406 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
407 GL_ALPHA, false));
408 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
409 GL_ALPHA, false));
410 mRGBACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
411 GL_RGBA, false));
412 mRGBACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
413 GL_RGBA, false));
414 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700415}
416
Romain Guy694b5192010-07-21 21:33:20 -0700417// We don't want to allocate anything unless we actually draw text
418void FontRenderer::checkInit() {
419 if (mInitialized) {
420 return;
421 }
422
423 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700424
425 mInitialized = true;
426}
427
Victoria Lease1e546812013-06-25 14:25:17 -0700428void checkTextureUpdateForCache(Caches& caches, Vector<CacheTexture*>& cacheTextures,
429 bool& resetPixelStore, GLuint& lastTextureId) {
430 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
431 CacheTexture* cacheTexture = cacheTextures[i];
432 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
433 if (cacheTexture->getTextureId() != lastTextureId) {
434 lastTextureId = cacheTexture->getTextureId();
Chris Craik44eb2c02015-01-29 09:45:09 -0800435 caches.textureState().activateTexture(0);
436 caches.textureState().bindTexture(lastTextureId);
Victoria Lease1e546812013-06-25 14:25:17 -0700437 }
438
439 if (cacheTexture->upload()) {
440 resetPixelStore = true;
441 }
442 }
443 }
444}
445
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700446void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900447 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700448 return;
Romain Guy694b5192010-07-21 21:33:20 -0700449 }
450
Romain Guy2d4fd362011-12-13 22:00:19 -0800451 Caches& caches = Caches::getInstance();
452 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700453
Romain Guycf51a412013-04-08 19:40:31 -0700454 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700455 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
456
Chet Haase378e9192012-08-15 15:54:54 -0700457 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700458 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
459 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700460
Romain Guycf51a412013-04-08 19:40:31 -0700461 // Unbind any PBO we might have used to update textures
Chris Craik44eb2c02015-01-29 09:45:09 -0800462 caches.pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700463
Romain Guy09087642013-04-04 12:27:54 -0700464 // Reset to default unpack row length to avoid affecting texture
465 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700466 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700467 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
468 }
469
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700470 mUploadTexture = false;
471}
472
Victoria Lease1e546812013-06-25 14:25:17 -0700473void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800474 if (!mFunctor) return;
475
Romain Guy661a87e2013-03-19 15:24:36 -0700476 bool first = true;
Victoria Lease1e546812013-06-25 14:25:17 -0700477 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
478 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700479 if (texture->canDraw()) {
480 if (first) {
Chris Craike2bb3802015-03-13 15:07:52 -0700481 checkTextureUpdate();
Romain Guy661a87e2013-03-19 15:24:36 -0700482 first = false;
Chris Craik083e7332015-02-27 17:04:20 -0800483 mDrawn = true;
Romain Guy661a87e2013-03-19 15:24:36 -0700484 }
Chris Craik82840732015-04-03 09:37:49 -0700485
Chris Craike2bb3802015-03-13 15:07:52 -0700486 mFunctor->draw(*texture, mLinearFiltering);
Romain Guy661a87e2013-03-19 15:24:36 -0700487
Romain Guy661a87e2013-03-19 15:24:36 -0700488 texture->resetMesh();
Romain Guy115096f2013-03-19 11:32:41 -0700489 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900490 }
Victoria Lease1e546812013-06-25 14:25:17 -0700491}
492
493void FontRenderer::issueDrawCommand() {
494 issueDrawCommand(mACacheTextures);
495 issueDrawCommand(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700496}
497
Romain Guy97771732012-02-28 18:17:02 -0800498void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
499 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
Chet Haase7de0cb12011-12-05 16:35:38 -0800500 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800501 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800502 // Now use the new texture id
503 mCurrentCacheTexture = texture;
504 }
Romain Guy09147fb2010-07-22 13:08:20 -0700505
Romain Guy661a87e2013-03-19 15:24:36 -0700506 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
507 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800508}
509
510void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
511 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
512 float x4, float y4, float u4, float v4, CacheTexture* texture) {
513
514 if (mClip &&
515 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
516 return;
517 }
518
519 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 -0700520
Romain Guy5b3b3522010-10-27 18:57:51 -0700521 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700522 mBounds->left = std::min(mBounds->left, x1);
523 mBounds->top = std::min(mBounds->top, y3);
524 mBounds->right = std::max(mBounds->right, x3);
525 mBounds->bottom = std::max(mBounds->bottom, y1);
Romain Guy5b3b3522010-10-27 18:57:51 -0700526 }
527
Romain Guy661a87e2013-03-19 15:24:36 -0700528 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700529 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700530 }
531}
532
Romain Guy97771732012-02-28 18:17:02 -0800533void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
534 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
535 float x4, float y4, float u4, float v4, CacheTexture* texture) {
536
537 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
538
539 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700540 mBounds->left = std::min(mBounds->left, std::min(x1, std::min(x2, std::min(x3, x4))));
541 mBounds->top = std::min(mBounds->top, std::min(y1, std::min(y2, std::min(y3, y4))));
542 mBounds->right = std::max(mBounds->right, std::max(x1, std::max(x2, std::max(x3, x4))));
543 mBounds->bottom = std::max(mBounds->bottom, std::max(y1, std::max(y2, std::max(y3, y4))));
Romain Guy97771732012-02-28 18:17:02 -0800544 }
545
Romain Guy661a87e2013-03-19 15:24:36 -0700546 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800547 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800548 }
549}
550
Chris Craik59744b72014-07-01 17:56:52 -0700551void FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800552 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700553}
Romain Guy7975fb62010-10-01 16:36:14 -0700554
Chris Craikd218a922014-01-02 17:13:34 -0800555FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const char *text,
Derek Sollenbergere392c812014-05-21 11:25:22 -0400556 uint32_t startIndex, uint32_t len, int numGlyphs, float radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700557 checkInit();
558
Romain Guycf51a412013-04-08 19:40:31 -0700559 DropShadow image;
560 image.width = 0;
561 image.height = 0;
Chris Craikd41c4d82015-01-05 15:51:13 -0800562 image.image = nullptr;
Romain Guycf51a412013-04-08 19:40:31 -0700563 image.penX = 0;
564 image.penY = 0;
565
Romain Guy1e45aae2010-08-13 19:39:53 -0700566 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700567 return image;
568 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700569
Romain Guy2d4fd362011-12-13 22:00:19 -0800570 mDrawn = false;
Chris Craikd41c4d82015-01-05 15:51:13 -0800571 mClip = nullptr;
572 mBounds = nullptr;
Romain Guyff98fa52011-11-28 09:35:09 -0800573
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700574 Rect bounds;
Raph Levien416a8472012-07-19 22:48:17 -0700575 mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800576
Derek Sollenbergere392c812014-05-21 11:25:22 -0400577 uint32_t intRadius = Blur::convertRadiusToInt(radius);
578 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
579 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
Romain Guyff98fa52011-11-28 09:35:09 -0800580
Romain Guycf51a412013-04-08 19:40:31 -0700581 uint32_t maxSize = Caches::getInstance().maxTextureSize;
582 if (paddedWidth > maxSize || paddedHeight > maxSize) {
583 return image;
584 }
585
Dan Morrille4d9a012013-03-28 18:10:43 -0700586#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800587 // Align buffers for renderscript usage
588 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
589 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700590 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800591 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800592 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700593#else
594 int size = paddedWidth * paddedHeight;
595 uint8_t* dataBuffer = (uint8_t*) malloc(size);
596#endif
597
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800598 memset(dataBuffer, 0, size);
599
Derek Sollenbergere392c812014-05-21 11:25:22 -0400600 int penX = intRadius - bounds.left;
601 int penY = intRadius - bounds.bottom;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700602
Chris Craikdd8697c2013-02-22 10:41:36 -0800603 if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
604 // text has non-whitespace, so draw and blur to create the shadow
605 // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
606 // TODO: don't draw pure whitespace in the first place, and avoid needing this check
607 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
Chris Craikd41c4d82015-01-05 15:51:13 -0800608 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
Chris Craikdd8697c2013-02-22 10:41:36 -0800609
Romain Guycf51a412013-04-08 19:40:31 -0700610 // Unbind any PBO we might have used
Chris Craik44eb2c02015-01-29 09:45:09 -0800611 Caches::getInstance().pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700612
Chris Craikdd8697c2013-02-22 10:41:36 -0800613 blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
614 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700615
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700616 image.width = paddedWidth;
617 image.height = paddedHeight;
618 image.image = dataBuffer;
619 image.penX = penX;
620 image.penY = penY;
Romain Guy2d4fd362011-12-13 22:00:19 -0800621
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700622 return image;
623}
Romain Guy694b5192010-07-21 21:33:20 -0700624
Chris Craik82840732015-04-03 09:37:49 -0700625void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextDrawFunctor* functor) {
Romain Guy694b5192010-07-21 21:33:20 -0700626 checkInit();
627
Romain Guy5b3b3522010-10-27 18:57:51 -0700628 mDrawn = false;
629 mBounds = bounds;
Romain Guy257ae352013-03-20 16:31:12 -0700630 mFunctor = functor;
Romain Guy09147fb2010-07-22 13:08:20 -0700631 mClip = clip;
Romain Guy671d6cf2012-01-18 12:39:17 -0800632}
Romain Guyff98fa52011-11-28 09:35:09 -0800633
Romain Guy671d6cf2012-01-18 12:39:17 -0800634void FontRenderer::finishRender() {
Chris Craikd41c4d82015-01-05 15:51:13 -0800635 mBounds = nullptr;
636 mClip = nullptr;
Romain Guy694b5192010-07-21 21:33:20 -0700637
Romain Guy661a87e2013-03-19 15:24:36 -0700638 issueDrawCommand();
Romain Guy671d6cf2012-01-18 12:39:17 -0800639}
640
Chris Craikd218a922014-01-02 17:13:34 -0800641void FontRenderer::precache(const SkPaint* paint, const char* text, int numGlyphs,
Chris Craik59744b72014-07-01 17:56:52 -0700642 const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800643 Font* font = Font::create(this, paint, matrix);
Chet Haasee816bae2012-08-09 13:39:02 -0700644 font->precache(paint, text, numGlyphs);
645}
646
Romain Guycf51a412013-04-08 19:40:31 -0700647void FontRenderer::endPrecaching() {
648 checkTextureUpdate();
649}
650
Chris Craikd218a922014-01-02 17:13:34 -0800651bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
Romain Guy671d6cf2012-01-18 12:39:17 -0800652 uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
Chris Craik82840732015-04-03 09:37:49 -0700653 const float* positions, Rect* bounds, TextDrawFunctor* functor, bool forceFinish) {
Romain Guy671d6cf2012-01-18 12:39:17 -0800654 if (!mCurrentFont) {
655 ALOGE("No font set");
656 return false;
657 }
658
Romain Guy257ae352013-03-20 16:31:12 -0700659 initRender(clip, bounds, functor);
Romain Guy671d6cf2012-01-18 12:39:17 -0800660 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions);
Chris Craik527a3aa2013-03-04 10:19:31 -0800661
662 if (forceFinish) {
663 finishRender();
664 }
Romain Guy5b3b3522010-10-27 18:57:51 -0700665
666 return mDrawn;
Romain Guy694b5192010-07-21 21:33:20 -0700667}
668
Chris Craikd218a922014-01-02 17:13:34 -0800669bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
670 uint32_t startIndex, uint32_t len, int numGlyphs, const SkPath* path,
Chris Craik82840732015-04-03 09:37:49 -0700671 float hOffset, float vOffset, Rect* bounds, TextDrawFunctor* functor) {
Romain Guy97771732012-02-28 18:17:02 -0800672 if (!mCurrentFont) {
673 ALOGE("No font set");
674 return false;
675 }
676
Victoria Lease1e546812013-06-25 14:25:17 -0700677 initRender(clip, bounds, functor);
Romain Guy97771732012-02-28 18:17:02 -0800678 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset);
679 finishRender();
680
681 return mDrawn;
682}
683
Derek Sollenbergere392c812014-05-21 11:25:22 -0400684void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
685 uint32_t intRadius = Blur::convertRadiusToInt(radius);
Dan Morrille4d9a012013-03-28 18:10:43 -0700686#ifdef ANDROID_ENABLE_RENDERSCRIPT
Derek Sollenbergere392c812014-05-21 11:25:22 -0400687 if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700688 uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700689
Chris Craikd41c4d82015-01-05 15:51:13 -0800690 if (mRs == nullptr) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700691 mRs = new RSC::RS();
Tim Murrayabe55e92013-12-13 12:57:36 -0800692 // a null path is OK because there are no custom kernels used
693 // hence nothing gets cached by RS
694 if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800695 mRs.clear();
Dan Morrille4d9a012013-03-28 18:10:43 -0700696 ALOGE("blur RS failed to init");
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800697 } else {
698 mRsElement = RSC::Element::A_8(mRs);
699 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Dan Morrille4d9a012013-03-28 18:10:43 -0700700 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800701 }
Chris Craikd41c4d82015-01-05 15:51:13 -0800702 if (mRs != nullptr) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800703 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
704 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
705 RS_ALLOCATION_MIPMAP_NONE,
706 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
707 *image);
708 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
709 RS_ALLOCATION_MIPMAP_NONE,
710 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
711 outImage);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800712
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800713 mRsScript->setRadius(radius);
714 mRsScript->setInput(ain);
715 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700716
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800717 // replace the original image's pointer, avoiding a copy back to the original buffer
718 free(*image);
719 *image = outImage;
Dan Morrille4d9a012013-03-28 18:10:43 -0700720
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800721 return;
722 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800723 }
Dan Morrille4d9a012013-03-28 18:10:43 -0700724#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800725
Chris Craik51d6a3d2014-12-22 17:16:56 -0800726 std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
727 Blur::generateGaussianWeights(gaussian.get(), intRadius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800728
Chris Craik51d6a3d2014-12-22 17:16:56 -0800729 std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
730 Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
731 Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700732}
733
Victoria Lease1e546812013-06-25 14:25:17 -0700734static uint32_t calculateCacheSize(const Vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700735 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700736 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
737 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700738 if (cacheTexture && cacheTexture->getPixelBuffer()) {
739 size += cacheTexture->getPixelBuffer()->getSize();
740 }
741 }
742 return size;
743}
744
Victoria Lease1e546812013-06-25 14:25:17 -0700745uint32_t FontRenderer::getCacheSize(GLenum format) const {
746 switch (format) {
747 case GL_ALPHA: {
748 return calculateCacheSize(mACacheTextures);
749 }
750 case GL_RGBA: {
751 return calculateCacheSize(mRGBACacheTextures);
752 }
753 default: {
754 return 0;
755 }
756 }
757}
758
Romain Guy694b5192010-07-21 21:33:20 -0700759}; // namespace uirenderer
760}; // namespace android