blob: ee99018fb65240892b0f47169ea18e89f771620b [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
Chris Craik5e00c7c2016-07-06 16:10:09 -070019#include "BakedOpDispatcher.h"
20#include "BakedOpRenderer.h"
21#include "BakedOpState.h"
Chris Craik96a5c4c2015-01-27 15:46:35 -080022#include "Caches.h"
23#include "Debug.h"
24#include "Extensions.h"
Derek Sollenbergerb29b16e2017-01-04 14:57:43 -050025#include "font/Font.h"
Chris Craike2bb3802015-03-13 15:07:52 -070026#include "Glop.h"
27#include "GlopBuilder.h"
Chris Craik96a5c4c2015-01-27 15:46:35 -080028#include "PixelBuffer.h"
29#include "Rect.h"
30#include "renderstate/RenderState.h"
31#include "utils/Blur.h"
32#include "utils/Timing.h"
Romain Guy694b5192010-07-21 21:33:20 -070033
Chris Craik9db58c02015-08-19 15:19:18 -070034#include <algorithm>
35#include <cutils/properties.h>
Po-Chien Hsuehc5ae5952017-02-09 10:38:34 +080036#include <RenderScript.h>
Derek Sollenbergerca79cf62012-08-14 16:44:52 -040037#include <SkGlyph.h>
Romain Guy694b5192010-07-21 21:33:20 -070038#include <SkUtils.h>
Romain Guy51769a62010-07-23 00:28:00 -070039#include <utils/Log.h>
40
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;
Romain Guy253f2c22016-09-28 17:34:42 -070061#ifdef ANDROID_ENABLE_LINEAR_BLENDING
62 bool gammaCorrection = true;
63#else
64 bool gammaCorrection = false;
65#endif
Chris Craike2bb3802015-03-13 15:07:52 -070066 Glop glop;
Chris Craika1717272015-11-19 13:02:43 -080067 GlopBuilder(renderer->renderState(), renderer->caches(), &glop)
68 .setRoundRectClipState(bakedState->roundRectClipState)
69 .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
70 .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, bakedState->alpha)
Romain Guy253f2c22016-09-28 17:34:42 -070071 .setGammaCorrection(gammaCorrection)
Chris Craika1717272015-11-19 13:02:43 -080072 .setTransform(bakedState->computedState.transform, transformFlags)
Chris Craikf09ff5a2015-12-08 17:21:58 -080073 .setModelViewIdentityEmptyBounds()
Chris Craika1717272015-11-19 13:02:43 -080074 .build();
Chris Craik15c3f192015-12-03 12:16:56 -080075 // Note: don't pass dirty bounds here, so user must manage passing dirty bounds to renderer
76 renderer->renderGlop(nullptr, clip, glop);
Victoria Lease1e546812013-06-25 14:25:17 -070077}
78
79///////////////////////////////////////////////////////////////////////////////
Romain Guy694b5192010-07-21 21:33:20 -070080// FontRenderer
81///////////////////////////////////////////////////////////////////////////////
82
Romain Guy514fb182011-01-19 14:38:29 -080083static bool sLogFontRendererCreate = true;
84
Chris Craikc08820f2015-09-22 14:22:29 -070085FontRenderer::FontRenderer(const uint8_t* gammaTable)
86 : mGammaTable(gammaTable)
Chris Craik083e7332015-02-27 17:04:20 -080087 , mCurrentFont(nullptr)
88 , mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity)
89 , mCurrentCacheTexture(nullptr)
90 , mUploadTexture(false)
91 , mFunctor(nullptr)
92 , mClip(nullptr)
93 , mBounds(nullptr)
94 , mDrawn(false)
95 , mInitialized(false)
96 , mLinearFiltering(false) {
Romain Guye3a9b242013-01-08 11:15:30 -080097
Romain Guyc9855a52011-01-21 21:14:15 -080098 if (sLogFontRendererCreate) {
99 INIT_LOGD("Creating FontRenderer");
100 }
Romain Guy51769a62010-07-23 00:28:00 -0700101
Chris Craikc08820f2015-09-22 14:22:29 -0700102 mSmallCacheWidth = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_WIDTH,
103 DEFAULT_TEXT_SMALL_CACHE_WIDTH);
104 mSmallCacheHeight = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_HEIGHT,
105 DEFAULT_TEXT_SMALL_CACHE_HEIGHT);
Romain Guy51769a62010-07-23 00:28:00 -0700106
Chris Craikc08820f2015-09-22 14:22:29 -0700107 mLargeCacheWidth = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_WIDTH,
108 DEFAULT_TEXT_LARGE_CACHE_WIDTH);
109 mLargeCacheHeight = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_HEIGHT,
110 DEFAULT_TEXT_LARGE_CACHE_HEIGHT);
Romain Guy9f5dab32012-09-04 12:55:44 -0700111
112 uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
Chris Craik083e7332015-02-27 17:04:20 -0800113
Chris Craik9db58c02015-08-19 15:19:18 -0700114 mSmallCacheWidth = std::min(mSmallCacheWidth, maxTextureSize);
115 mSmallCacheHeight = std::min(mSmallCacheHeight, maxTextureSize);
116 mLargeCacheWidth = std::min(mLargeCacheWidth, maxTextureSize);
117 mLargeCacheHeight = std::min(mLargeCacheHeight, maxTextureSize);
Romain Guy9f5dab32012-09-04 12:55:44 -0700118
Chet Haaseeb32a492012-08-31 13:54:03 -0700119 if (sLogFontRendererCreate) {
120 INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
121 mSmallCacheWidth, mSmallCacheHeight,
122 mLargeCacheWidth, mLargeCacheHeight >> 1,
123 mLargeCacheWidth, mLargeCacheHeight >> 1,
124 mLargeCacheWidth, mLargeCacheHeight);
Romain Guy51769a62010-07-23 00:28:00 -0700125 }
Romain Guy514fb182011-01-19 14:38:29 -0800126
127 sLogFontRendererCreate = false;
Romain Guy694b5192010-07-21 21:33:20 -0700128}
129
John Reck272a6852015-07-29 16:48:58 -0700130void clearCacheTextures(std::vector<CacheTexture*>& cacheTextures) {
Victoria Lease1e546812013-06-25 14:25:17 -0700131 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
132 delete cacheTextures[i];
Romain Guy694b5192010-07-21 21:33:20 -0700133 }
Victoria Lease1e546812013-06-25 14:25:17 -0700134 cacheTextures.clear();
135}
136
137FontRenderer::~FontRenderer() {
138 clearCacheTextures(mACacheTextures);
139 clearCacheTextures(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700140
Romain Guye3a9b242013-01-08 11:15:30 -0800141 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
142 while (it.next()) {
143 delete it.value();
Romain Guy694b5192010-07-21 21:33:20 -0700144 }
Romain Guye3a9b242013-01-08 11:15:30 -0800145 mActiveFonts.clear();
Romain Guy694b5192010-07-21 21:33:20 -0700146}
147
148void FontRenderer::flushAllAndInvalidate() {
Romain Guy661a87e2013-03-19 15:24:36 -0700149 issueDrawCommand();
Romain Guy9d9758a2012-05-14 15:19:58 -0700150
Romain Guye3a9b242013-01-08 11:15:30 -0800151 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
152 while (it.next()) {
153 it.value()->invalidateTextureCache();
Romain Guy694b5192010-07-21 21:33:20 -0700154 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700155
Victoria Lease1e546812013-06-25 14:25:17 -0700156 for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
157 mACacheTextures[i]->init();
sergeyvaf102be2016-09-09 18:02:07 -0700158
159#ifdef BUGREPORT_FONT_CACHE_USAGE
160 mHistoryTracker.glyphsCleared(mACacheTextures[i]);
161#endif
Victoria Lease1e546812013-06-25 14:25:17 -0700162 }
163
164 for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
165 mRGBACacheTextures[i]->init();
sergeyvaf102be2016-09-09 18:02:07 -0700166#ifdef BUGREPORT_FONT_CACHE_USAGE
167 mHistoryTracker.glyphsCleared(mRGBACacheTextures[i]);
168#endif
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
John Reck272a6852015-07-29 16:48:58 -0700174void FontRenderer::flushLargeCaches(std::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();
sergeyvaf102be2016-09-09 18:02:07 -0700180#ifdef BUGREPORT_FONT_CACHE_USAGE
181 mHistoryTracker.glyphsCleared(cacheTexture);
182#endif
Romain Guye3a9b242013-01-08 11:15:30 -0800183 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
184 while (it.next()) {
185 it.value()->invalidateTextureCache(cacheTexture);
Chet Haasee816bae2012-08-09 13:39:02 -0700186 }
Chris Craike2bb3802015-03-13 15:07:52 -0700187 cacheTexture->releasePixelBuffer();
Chet Haase9a824562011-12-16 15:44:59 -0800188 }
189 }
Chet Haase9a824562011-12-16 15:44:59 -0800190}
191
Victoria Lease1e546812013-06-25 14:25:17 -0700192void FontRenderer::flushLargeCaches() {
193 flushLargeCaches(mACacheTextures);
194 flushLargeCaches(mRGBACacheTextures);
195}
196
John Reck272a6852015-07-29 16:48:58 -0700197CacheTexture* FontRenderer::cacheBitmapInTexture(std::vector<CacheTexture*>& cacheTextures,
Victoria Lease1e546812013-06-25 14:25:17 -0700198 const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
199 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
200 if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
201 return cacheTextures[i];
Chet Haase378e9192012-08-15 15:54:54 -0700202 }
203 }
204 // Could not fit glyph into current cache textures
Chris Craikd41c4d82015-01-05 15:51:13 -0800205 return nullptr;
Chet Haase378e9192012-08-15 15:54:54 -0700206}
207
Chet Haase7de0cb12011-12-05 16:35:38 -0800208void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
Chet Haasef942cf12012-08-30 09:06:46 -0700209 uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700210 checkInit();
Romain Guya4adcf02013-02-28 12:15:35 -0800211
212 // If the glyph bitmap is empty let's assum the glyph is valid
213 // so we can avoid doing extra work later on
214 if (glyph.fWidth == 0 || glyph.fHeight == 0) {
215 cachedGlyph->mIsValid = true;
Chris Craikd41c4d82015-01-05 15:51:13 -0800216 cachedGlyph->mCacheTexture = nullptr;
Romain Guya4adcf02013-02-28 12:15:35 -0800217 return;
218 }
219
Chet Haase7de0cb12011-12-05 16:35:38 -0800220 cachedGlyph->mIsValid = false;
Romain Guya4adcf02013-02-28 12:15:35 -0800221
Victoria Lease1e546812013-06-25 14:25:17 -0700222 // choose an appropriate cache texture list for this glyph format
223 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
John Reck272a6852015-07-29 16:48:58 -0700224 std::vector<CacheTexture*>* cacheTextures = nullptr;
Victoria Lease1e546812013-06-25 14:25:17 -0700225 switch (format) {
226 case SkMask::kA8_Format:
Victoria Lease723b2fe2013-08-12 14:38:44 -0700227 case SkMask::kBW_Format:
Victoria Lease1e546812013-06-25 14:25:17 -0700228 cacheTextures = &mACacheTextures;
229 break;
230 case SkMask::kARGB32_Format:
231 cacheTextures = &mRGBACacheTextures;
232 break;
233 default:
234#if DEBUG_FONT_RENDERER
235 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
236#endif
237 return;
238 }
239
Romain Guy694b5192010-07-21 21:33:20 -0700240 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700241 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
Victoria Lease1e546812013-06-25 14:25:17 -0700242 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700243 ALOGE("Font size too large to fit in cache. width, height = %i, %i",
244 (int) glyph.fWidth, (int) glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800245 return;
Romain Guy694b5192010-07-21 21:33:20 -0700246 }
247
248 // Now copy the bitmap into the cache texture
249 uint32_t startX = 0;
250 uint32_t startY = 0;
251
Victoria Lease1e546812013-06-25 14:25:17 -0700252 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700253
Chet Haase378e9192012-08-15 15:54:54 -0700254 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700255 if (!precaching) {
256 // If the new glyph didn't fit and we are not just trying to precache it,
257 // clear out the cache and try again
258 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700259 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700260 }
Romain Guy694b5192010-07-21 21:33:20 -0700261
Chet Haase378e9192012-08-15 15:54:54 -0700262 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700263 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800264 return;
Romain Guy694b5192010-07-21 21:33:20 -0700265 }
266 }
267
Chet Haase378e9192012-08-15 15:54:54 -0700268 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800269
Romain Guy694b5192010-07-21 21:33:20 -0700270 *retOriginX = startX;
271 *retOriginY = startY;
272
273 uint32_t endX = startX + glyph.fWidth;
274 uint32_t endY = startY + glyph.fHeight;
275
Romain Guy80872462012-09-04 16:42:01 -0700276 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700277
Romain Guycf51a412013-04-08 19:40:31 -0700278 if (!cacheTexture->getPixelBuffer()) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800279 Caches::getInstance().textureState().activateTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800280 // Large-glyph texture memory is allocated only as needed
Chris Craike2bb3802015-03-13 15:07:52 -0700281 cacheTexture->allocatePixelBuffer();
Chet Haase7de0cb12011-12-05 16:35:38 -0800282 }
Romain Guy661a87e2013-03-19 15:24:36 -0700283 if (!cacheTexture->mesh()) {
284 cacheTexture->allocateMesh();
285 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700286
Romain Guycf51a412013-04-08 19:40:31 -0700287 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
Victoria Lease1e546812013-06-25 14:25:17 -0700288 uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
289 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700290
Romain Guyb969a0d2013-02-05 14:38:40 -0800291 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800292 switch (format) {
293 case SkMask::kA8_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700294 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
295 - TEXTURE_BORDER_SIZE;
296 // write leading border line
297 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
298 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800299 if (mGammaTable) {
Romain Guy253f2c22016-09-28 17:34:42 -0700300 for (uint32_t cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800301 row = cacheY * cacheWidth;
302 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guy253f2c22016-09-28 17:34:42 -0700303 for (uint32_t cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
Romain Guyb969a0d2013-02-05 14:38:40 -0800304 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800305 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800306 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800307 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800308 }
309 } else {
Romain Guy253f2c22016-09-28 17:34:42 -0700310 for (uint32_t cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800311 row = cacheY * cacheWidth;
312 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
313 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
314 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800315 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700316 }
Victoria Lease1e546812013-06-25 14:25:17 -0700317 // write trailing border line
318 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
319 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
320 break;
321 }
322 case SkMask::kARGB32_Format: {
323 // prep data lengths
324 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
325 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
326 size_t rowSize = formatSize * glyph.fWidth;
327 // prep advances
328 size_t dstStride = formatSize * cacheWidth;
329 // prep indices
330 // - we actually start one row early, and then increment before first copy
331 uint8_t* src = &bitmapBuffer[0 - srcStride];
332 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
333 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
334 uint8_t* dstL = dst - borderSize;
335 uint8_t* dstR = dst + rowSize;
336 // write leading border line
337 memset(dstL, 0, rowSize + 2 * borderSize);
338 // write glyph data
339 while (dst < dstEnd) {
340 memset(dstL += dstStride, 0, borderSize); // leading border column
341 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
342 memset(dstR += dstStride, 0, borderSize); // trailing border column
343 }
344 // write trailing border line
Victoria Lease16c84062013-09-19 15:38:21 -0700345 memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800346 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700347 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800348 case SkMask::kBW_Format: {
Andreas Gampe1e196742014-11-10 15:23:43 -0800349 uint32_t cacheX = 0, cacheY = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700350 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
351 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800352 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700353 // write leading border line
354 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
355 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800356 for (cacheY = startY; cacheY < endY; cacheY++) {
357 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700358 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800359 uint8_t* buffer = bitmapBuffer;
360
Romain Guy0b58a3d2013-03-05 12:16:27 -0800361 row = cacheY * cacheWidth;
362 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800363 while (--rowBytes >= 0) {
364 uint8_t b = *buffer++;
365 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
366 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
367 }
368 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800369 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800370
Victoria Lease1e546812013-06-25 14:25:17 -0700371 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700372 }
Victoria Lease1e546812013-06-25 14:25:17 -0700373 // write trailing border line
374 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
375 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800376 break;
Romain Guy694b5192010-07-21 21:33:20 -0700377 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800378 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700379 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800380 break;
Romain Guy694b5192010-07-21 21:33:20 -0700381 }
Romain Guy97771732012-02-28 18:17:02 -0800382
Chet Haase7de0cb12011-12-05 16:35:38 -0800383 cachedGlyph->mIsValid = true;
sergeyvaf102be2016-09-09 18:02:07 -0700384
385#ifdef BUGREPORT_FONT_CACHE_USAGE
386 mHistoryTracker.glyphUploaded(cacheTexture, startX, startY, glyph.fWidth, glyph.fHeight);
387#endif
Romain Guy694b5192010-07-21 21:33:20 -0700388}
389
Victoria Lease1e546812013-06-25 14:25:17 -0700390CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
391 bool allocate) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800392 CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700393
Chet Haase2a47c142011-12-14 15:22:56 -0800394 if (allocate) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800395 Caches::getInstance().textureState().activateTexture(0);
Chris Craike2bb3802015-03-13 15:07:52 -0700396 cacheTexture->allocatePixelBuffer();
Romain Guy661a87e2013-03-19 15:24:36 -0700397 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800398 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700399
Chet Haase2a47c142011-12-14 15:22:56 -0800400 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800401}
402
403void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700404 clearCacheTextures(mACacheTextures);
405 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700406
Chet Haase7de0cb12011-12-05 16:35:38 -0800407 mUploadTexture = false;
John Reck272a6852015-07-29 16:48:58 -0700408 mACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700409 GL_ALPHA, true));
John Reck272a6852015-07-29 16:48:58 -0700410 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700411 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700412 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700413 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700414 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700415 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700416 mRGBACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700417 GL_RGBA, false));
John Reck272a6852015-07-29 16:48:58 -0700418 mRGBACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700419 GL_RGBA, false));
420 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700421}
422
Romain Guy694b5192010-07-21 21:33:20 -0700423// We don't want to allocate anything unless we actually draw text
424void FontRenderer::checkInit() {
425 if (mInitialized) {
426 return;
427 }
428
429 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700430
431 mInitialized = true;
432}
433
John Reck272a6852015-07-29 16:48:58 -0700434void checkTextureUpdateForCache(Caches& caches, std::vector<CacheTexture*>& cacheTextures,
Victoria Lease1e546812013-06-25 14:25:17 -0700435 bool& resetPixelStore, GLuint& lastTextureId) {
436 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
437 CacheTexture* cacheTexture = cacheTextures[i];
438 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
439 if (cacheTexture->getTextureId() != lastTextureId) {
440 lastTextureId = cacheTexture->getTextureId();
Chris Craik44eb2c02015-01-29 09:45:09 -0800441 caches.textureState().activateTexture(0);
442 caches.textureState().bindTexture(lastTextureId);
Victoria Lease1e546812013-06-25 14:25:17 -0700443 }
444
445 if (cacheTexture->upload()) {
446 resetPixelStore = true;
447 }
448 }
449 }
450}
451
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700452void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900453 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700454 return;
Romain Guy694b5192010-07-21 21:33:20 -0700455 }
456
Romain Guy2d4fd362011-12-13 22:00:19 -0800457 Caches& caches = Caches::getInstance();
458 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700459
Romain Guycf51a412013-04-08 19:40:31 -0700460 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700461
Chet Haase378e9192012-08-15 15:54:54 -0700462 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700463 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
464 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700465
Romain Guycf51a412013-04-08 19:40:31 -0700466 // Unbind any PBO we might have used to update textures
Chris Craik44eb2c02015-01-29 09:45:09 -0800467 caches.pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700468
Romain Guy09087642013-04-04 12:27:54 -0700469 // Reset to default unpack row length to avoid affecting texture
470 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700471 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700472 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
473 }
474
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700475 mUploadTexture = false;
476}
477
John Reck272a6852015-07-29 16:48:58 -0700478void FontRenderer::issueDrawCommand(std::vector<CacheTexture*>& cacheTextures) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800479 if (!mFunctor) return;
480
Romain Guy661a87e2013-03-19 15:24:36 -0700481 bool first = true;
Victoria Lease1e546812013-06-25 14:25:17 -0700482 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
483 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700484 if (texture->canDraw()) {
485 if (first) {
Chris Craike2bb3802015-03-13 15:07:52 -0700486 checkTextureUpdate();
Romain Guy661a87e2013-03-19 15:24:36 -0700487 first = false;
Chris Craik083e7332015-02-27 17:04:20 -0800488 mDrawn = true;
Romain Guy661a87e2013-03-19 15:24:36 -0700489 }
Chris Craik82840732015-04-03 09:37:49 -0700490
Chris Craike2bb3802015-03-13 15:07:52 -0700491 mFunctor->draw(*texture, mLinearFiltering);
Romain Guy661a87e2013-03-19 15:24:36 -0700492
Romain Guy661a87e2013-03-19 15:24:36 -0700493 texture->resetMesh();
Romain Guy115096f2013-03-19 11:32:41 -0700494 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900495 }
Victoria Lease1e546812013-06-25 14:25:17 -0700496}
497
498void FontRenderer::issueDrawCommand() {
499 issueDrawCommand(mACacheTextures);
500 issueDrawCommand(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700501}
502
Romain Guy97771732012-02-28 18:17:02 -0800503void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
504 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
Chet Haase7de0cb12011-12-05 16:35:38 -0800505 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800506 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800507 // Now use the new texture id
508 mCurrentCacheTexture = texture;
509 }
Romain Guy09147fb2010-07-22 13:08:20 -0700510
Romain Guy661a87e2013-03-19 15:24:36 -0700511 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
512 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800513}
514
515void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
516 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
517 float x4, float y4, float u4, float v4, CacheTexture* texture) {
518
519 if (mClip &&
520 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
521 return;
522 }
523
524 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 -0700525
Romain Guy5b3b3522010-10-27 18:57:51 -0700526 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700527 mBounds->left = std::min(mBounds->left, x1);
528 mBounds->top = std::min(mBounds->top, y3);
529 mBounds->right = std::max(mBounds->right, x3);
530 mBounds->bottom = std::max(mBounds->bottom, y1);
Romain Guy5b3b3522010-10-27 18:57:51 -0700531 }
532
Romain Guy661a87e2013-03-19 15:24:36 -0700533 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700534 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700535 }
536}
537
Romain Guy97771732012-02-28 18:17:02 -0800538void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
539 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
540 float x4, float y4, float u4, float v4, CacheTexture* texture) {
541
542 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
543
544 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700545 mBounds->left = std::min(mBounds->left, std::min(x1, std::min(x2, std::min(x3, x4))));
546 mBounds->top = std::min(mBounds->top, std::min(y1, std::min(y2, std::min(y3, y4))));
547 mBounds->right = std::max(mBounds->right, std::max(x1, std::max(x2, std::max(x3, x4))));
548 mBounds->bottom = std::max(mBounds->bottom, std::max(y1, std::max(y2, std::max(y3, y4))));
Romain Guy97771732012-02-28 18:17:02 -0800549 }
550
Romain Guy661a87e2013-03-19 15:24:36 -0700551 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800552 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800553 }
554}
555
Chris Craik59744b72014-07-01 17:56:52 -0700556void FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800557 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700558}
Romain Guy7975fb62010-10-01 16:36:14 -0700559
Chris Craike8c3c812016-02-05 20:10:50 -0800560FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const glyph_t *glyphs,
Chris Craika1717272015-11-19 13:02:43 -0800561 int numGlyphs, float radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700562 checkInit();
563
Romain Guycf51a412013-04-08 19:40:31 -0700564 DropShadow image;
565 image.width = 0;
566 image.height = 0;
Chris Craikd41c4d82015-01-05 15:51:13 -0800567 image.image = nullptr;
Romain Guycf51a412013-04-08 19:40:31 -0700568 image.penX = 0;
569 image.penY = 0;
570
Romain Guy1e45aae2010-08-13 19:39:53 -0700571 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700572 return image;
573 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700574
Romain Guy2d4fd362011-12-13 22:00:19 -0800575 mDrawn = false;
Chris Craikd41c4d82015-01-05 15:51:13 -0800576 mClip = nullptr;
577 mBounds = nullptr;
Romain Guyff98fa52011-11-28 09:35:09 -0800578
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700579 Rect bounds;
Chris Craike8c3c812016-02-05 20:10:50 -0800580 mCurrentFont->measure(paint, glyphs, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800581
Derek Sollenbergere392c812014-05-21 11:25:22 -0400582 uint32_t intRadius = Blur::convertRadiusToInt(radius);
583 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
584 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
Romain Guyff98fa52011-11-28 09:35:09 -0800585
Romain Guycf51a412013-04-08 19:40:31 -0700586 uint32_t maxSize = Caches::getInstance().maxTextureSize;
587 if (paddedWidth > maxSize || paddedHeight > maxSize) {
588 return image;
589 }
590
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800591 // Align buffers for renderscript usage
592 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
593 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700594 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800595 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800596 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700597
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
Chris Craike8c3c812016-02-05 20:10:50 -0800607 mCurrentFont->render(paint, glyphs, 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 Craike8c3c812016-02-05 20:10:50 -0800641void FontRenderer::precache(const SkPaint* paint, const glyph_t* glyphs, 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);
Chris Craike8c3c812016-02-05 20:10:50 -0800644 font->precache(paint, glyphs, numGlyphs);
Chet Haasee816bae2012-08-09 13:39:02 -0700645}
646
Romain Guycf51a412013-04-08 19:40:31 -0700647void FontRenderer::endPrecaching() {
648 checkTextureUpdate();
649}
650
Chris Craike8c3c812016-02-05 20:10:50 -0800651bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
Chris Craika1717272015-11-19 13:02:43 -0800652 int numGlyphs, int x, int y, const float* positions,
653 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);
Chris Craike8c3c812016-02-05 20:10:50 -0800660 mCurrentFont->render(paint, glyphs, 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 Craike8c3c812016-02-05 20:10:50 -0800669bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
Chris Craika1717272015-11-19 13:02:43 -0800670 int numGlyphs, const SkPath* path, float hOffset, float vOffset,
671 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);
Chris Craike8c3c812016-02-05 20:10:50 -0800678 mCurrentFont->render(paint, glyphs, numGlyphs, path, hOffset, vOffset);
Romain Guy97771732012-02-28 18:17:02 -0800679 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);
Chris Craikf3754a82016-04-19 18:13:21 -0700686 if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF && radius <= 25.0f) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700687 uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700688
Chris Craikd41c4d82015-01-05 15:51:13 -0800689 if (mRs == nullptr) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700690 mRs = new RSC::RS();
Tim Murrayabe55e92013-12-13 12:57:36 -0800691 // a null path is OK because there are no custom kernels used
692 // hence nothing gets cached by RS
693 if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800694 mRs.clear();
Dan Morrille4d9a012013-03-28 18:10:43 -0700695 ALOGE("blur RS failed to init");
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800696 } else {
697 mRsElement = RSC::Element::A_8(mRs);
698 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Dan Morrille4d9a012013-03-28 18:10:43 -0700699 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800700 }
Chris Craikd41c4d82015-01-05 15:51:13 -0800701 if (mRs != nullptr) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800702 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
703 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
704 RS_ALLOCATION_MIPMAP_NONE,
705 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
706 *image);
707 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
708 RS_ALLOCATION_MIPMAP_NONE,
709 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
710 outImage);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800711
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800712 mRsScript->setRadius(radius);
713 mRsScript->setInput(ain);
714 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700715
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800716 // replace the original image's pointer, avoiding a copy back to the original buffer
717 free(*image);
718 *image = outImage;
Dan Morrille4d9a012013-03-28 18:10:43 -0700719
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800720 return;
721 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800722 }
723
Chris Craik51d6a3d2014-12-22 17:16:56 -0800724 std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
huanhuan.x.wanga46ca5e2015-04-14 16:23:15 +0200725 Blur::generateGaussianWeights(gaussian.get(), radius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800726
Chris Craik51d6a3d2014-12-22 17:16:56 -0800727 std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
728 Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
729 Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700730}
731
John Reck272a6852015-07-29 16:48:58 -0700732static uint32_t calculateCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700733 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700734 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
735 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700736 if (cacheTexture && cacheTexture->getPixelBuffer()) {
737 size += cacheTexture->getPixelBuffer()->getSize();
738 }
739 }
740 return size;
741}
742
sergeyvbaf29e72016-09-08 11:09:34 -0700743static uint32_t calculateFreeCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
744 uint32_t size = 0;
745 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
746 CacheTexture* cacheTexture = cacheTextures[i];
747 if (cacheTexture && cacheTexture->getPixelBuffer()) {
748 size += cacheTexture->calculateFreeMemory();
Victoria Lease1e546812013-06-25 14:25:17 -0700749 }
750 }
sergeyvbaf29e72016-09-08 11:09:34 -0700751 return size;
752}
753
754const std::vector<CacheTexture*>& FontRenderer::cacheTexturesForFormat(GLenum format) const {
755 switch (format) {
756 case GL_ALPHA: {
757 return mACacheTextures;
758 }
759 case GL_RGBA: {
760 return mRGBACacheTextures;
761 }
762 default: {
763 LOG_ALWAYS_FATAL("Unsupported format: %d", format);
764 // Impossible to hit this, but the compiler doesn't know that
765 return *(new std::vector<CacheTexture*>());
766 }
767 }
768}
769
770static void dumpTextures(String8& log, const char* tag,
771 const std::vector<CacheTexture*>& cacheTextures) {
772 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
773 CacheTexture* cacheTexture = cacheTextures[i];
774 if (cacheTexture && cacheTexture->getPixelBuffer()) {
775 uint32_t free = cacheTexture->calculateFreeMemory();
776 uint32_t total = cacheTexture->getPixelBuffer()->getSize();
777 log.appendFormat(" %-4s texture %d %8d / %8d\n", tag, i, total - free, total);
778 }
779 }
780}
781
782void FontRenderer::dumpMemoryUsage(String8& log) const {
783 const uint32_t sizeA8 = getCacheSize(GL_ALPHA);
784 const uint32_t usedA8 = sizeA8 - getFreeCacheSize(GL_ALPHA);
785 const uint32_t sizeRGBA = getCacheSize(GL_RGBA);
786 const uint32_t usedRGBA = sizeRGBA - getFreeCacheSize(GL_RGBA);
787 log.appendFormat(" FontRenderer A8 %8d / %8d\n", usedA8, sizeA8);
788 dumpTextures(log, "A8", cacheTexturesForFormat(GL_ALPHA));
789 log.appendFormat(" FontRenderer RGBA %8d / %8d\n", usedRGBA, sizeRGBA);
790 dumpTextures(log, "RGBA", cacheTexturesForFormat(GL_RGBA));
791 log.appendFormat(" FontRenderer total %8d / %8d\n", usedA8 + usedRGBA, sizeA8 + sizeRGBA);
792}
793
794uint32_t FontRenderer::getCacheSize(GLenum format) const {
795 return calculateCacheSize(cacheTexturesForFormat(format));
796}
797
798uint32_t FontRenderer::getFreeCacheSize(GLenum format) const {
799 return calculateFreeCacheSize(cacheTexturesForFormat(format));
800}
801
802uint32_t FontRenderer::getSize() const {
803 return getCacheSize(GL_ALPHA) + getCacheSize(GL_RGBA);
Victoria Lease1e546812013-06-25 14:25:17 -0700804}
805
Romain Guy694b5192010-07-21 21:33:20 -0700806}; // namespace uirenderer
807}; // namespace android