blob: 9b60dfcb58671199ca9c0199bc3f413c6c9f32fc [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"
Chris Craike2bb3802015-03-13 15:07:52 -070025#include "Glop.h"
26#include "GlopBuilder.h"
Chris Craik96a5c4c2015-01-27 15:46:35 -080027#include "PixelBuffer.h"
28#include "Rect.h"
29#include "renderstate/RenderState.h"
30#include "utils/Blur.h"
31#include "utils/Timing.h"
Romain Guy694b5192010-07-21 21:33:20 -070032
Chris Craik9db58c02015-08-19 15:19:18 -070033#include <algorithm>
34#include <cutils/properties.h>
Derek Sollenbergerca79cf62012-08-14 16:44:52 -040035#include <SkGlyph.h>
Romain Guy694b5192010-07-21 21:33:20 -070036#include <SkUtils.h>
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;
Chris Craika1717272015-11-19 13:02:43 -080064 GlopBuilder(renderer->renderState(), renderer->caches(), &glop)
65 .setRoundRectClipState(bakedState->roundRectClipState)
66 .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
67 .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, bakedState->alpha)
68 .setTransform(bakedState->computedState.transform, transformFlags)
Chris Craikf09ff5a2015-12-08 17:21:58 -080069 .setModelViewIdentityEmptyBounds()
Chris Craika1717272015-11-19 13:02:43 -080070 .build();
Chris Craik15c3f192015-12-03 12:16:56 -080071 // Note: don't pass dirty bounds here, so user must manage passing dirty bounds to renderer
72 renderer->renderGlop(nullptr, clip, glop);
Victoria Lease1e546812013-06-25 14:25:17 -070073}
74
75///////////////////////////////////////////////////////////////////////////////
Romain Guy694b5192010-07-21 21:33:20 -070076// FontRenderer
77///////////////////////////////////////////////////////////////////////////////
78
Romain Guy514fb182011-01-19 14:38:29 -080079static bool sLogFontRendererCreate = true;
80
Chris Craikc08820f2015-09-22 14:22:29 -070081FontRenderer::FontRenderer(const uint8_t* gammaTable)
82 : mGammaTable(gammaTable)
Chris Craik083e7332015-02-27 17:04:20 -080083 , mCurrentFont(nullptr)
84 , mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity)
85 , mCurrentCacheTexture(nullptr)
86 , mUploadTexture(false)
87 , mFunctor(nullptr)
88 , mClip(nullptr)
89 , mBounds(nullptr)
90 , mDrawn(false)
91 , mInitialized(false)
92 , mLinearFiltering(false) {
Romain Guye3a9b242013-01-08 11:15:30 -080093
Romain Guyc9855a52011-01-21 21:14:15 -080094 if (sLogFontRendererCreate) {
95 INIT_LOGD("Creating FontRenderer");
96 }
Romain Guy51769a62010-07-23 00:28:00 -070097
Chris Craikc08820f2015-09-22 14:22:29 -070098 mSmallCacheWidth = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_WIDTH,
99 DEFAULT_TEXT_SMALL_CACHE_WIDTH);
100 mSmallCacheHeight = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_HEIGHT,
101 DEFAULT_TEXT_SMALL_CACHE_HEIGHT);
Romain Guy51769a62010-07-23 00:28:00 -0700102
Chris Craikc08820f2015-09-22 14:22:29 -0700103 mLargeCacheWidth = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_WIDTH,
104 DEFAULT_TEXT_LARGE_CACHE_WIDTH);
105 mLargeCacheHeight = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_HEIGHT,
106 DEFAULT_TEXT_LARGE_CACHE_HEIGHT);
Romain Guy9f5dab32012-09-04 12:55:44 -0700107
108 uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
Chris Craik083e7332015-02-27 17:04:20 -0800109
Chris Craik9db58c02015-08-19 15:19:18 -0700110 mSmallCacheWidth = std::min(mSmallCacheWidth, maxTextureSize);
111 mSmallCacheHeight = std::min(mSmallCacheHeight, maxTextureSize);
112 mLargeCacheWidth = std::min(mLargeCacheWidth, maxTextureSize);
113 mLargeCacheHeight = std::min(mLargeCacheHeight, maxTextureSize);
Romain Guy9f5dab32012-09-04 12:55:44 -0700114
Chet Haaseeb32a492012-08-31 13:54:03 -0700115 if (sLogFontRendererCreate) {
116 INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
117 mSmallCacheWidth, mSmallCacheHeight,
118 mLargeCacheWidth, mLargeCacheHeight >> 1,
119 mLargeCacheWidth, mLargeCacheHeight >> 1,
120 mLargeCacheWidth, mLargeCacheHeight);
Romain Guy51769a62010-07-23 00:28:00 -0700121 }
Romain Guy514fb182011-01-19 14:38:29 -0800122
123 sLogFontRendererCreate = false;
Romain Guy694b5192010-07-21 21:33:20 -0700124}
125
John Reck272a6852015-07-29 16:48:58 -0700126void clearCacheTextures(std::vector<CacheTexture*>& cacheTextures) {
Victoria Lease1e546812013-06-25 14:25:17 -0700127 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
128 delete cacheTextures[i];
Romain Guy694b5192010-07-21 21:33:20 -0700129 }
Victoria Lease1e546812013-06-25 14:25:17 -0700130 cacheTextures.clear();
131}
132
133FontRenderer::~FontRenderer() {
134 clearCacheTextures(mACacheTextures);
135 clearCacheTextures(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700136
Romain Guye3a9b242013-01-08 11:15:30 -0800137 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
138 while (it.next()) {
139 delete it.value();
Romain Guy694b5192010-07-21 21:33:20 -0700140 }
Romain Guye3a9b242013-01-08 11:15:30 -0800141 mActiveFonts.clear();
Romain Guy694b5192010-07-21 21:33:20 -0700142}
143
144void FontRenderer::flushAllAndInvalidate() {
Romain Guy661a87e2013-03-19 15:24:36 -0700145 issueDrawCommand();
Romain Guy9d9758a2012-05-14 15:19:58 -0700146
Romain Guye3a9b242013-01-08 11:15:30 -0800147 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
148 while (it.next()) {
149 it.value()->invalidateTextureCache();
Romain Guy694b5192010-07-21 21:33:20 -0700150 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700151
Victoria Lease1e546812013-06-25 14:25:17 -0700152 for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
153 mACacheTextures[i]->init();
sergeyvaf102be2016-09-09 18:02:07 -0700154
155#ifdef BUGREPORT_FONT_CACHE_USAGE
156 mHistoryTracker.glyphsCleared(mACacheTextures[i]);
157#endif
Victoria Lease1e546812013-06-25 14:25:17 -0700158 }
159
160 for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
161 mRGBACacheTextures[i]->init();
sergeyvaf102be2016-09-09 18:02:07 -0700162#ifdef BUGREPORT_FONT_CACHE_USAGE
163 mHistoryTracker.glyphsCleared(mRGBACacheTextures[i]);
164#endif
Romain Guy694b5192010-07-21 21:33:20 -0700165 }
chaochen1f61b192014-08-28 18:45:27 -0700166
167 mDrawn = false;
Romain Guy694b5192010-07-21 21:33:20 -0700168}
169
John Reck272a6852015-07-29 16:48:58 -0700170void FontRenderer::flushLargeCaches(std::vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700171 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700172 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
173 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700174 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700175 cacheTexture->init();
sergeyvaf102be2016-09-09 18:02:07 -0700176#ifdef BUGREPORT_FONT_CACHE_USAGE
177 mHistoryTracker.glyphsCleared(cacheTexture);
178#endif
Romain Guye3a9b242013-01-08 11:15:30 -0800179 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
180 while (it.next()) {
181 it.value()->invalidateTextureCache(cacheTexture);
Chet Haasee816bae2012-08-09 13:39:02 -0700182 }
Chris Craike2bb3802015-03-13 15:07:52 -0700183 cacheTexture->releasePixelBuffer();
Chet Haase9a824562011-12-16 15:44:59 -0800184 }
185 }
Chet Haase9a824562011-12-16 15:44:59 -0800186}
187
Victoria Lease1e546812013-06-25 14:25:17 -0700188void FontRenderer::flushLargeCaches() {
189 flushLargeCaches(mACacheTextures);
190 flushLargeCaches(mRGBACacheTextures);
191}
192
John Reck272a6852015-07-29 16:48:58 -0700193CacheTexture* FontRenderer::cacheBitmapInTexture(std::vector<CacheTexture*>& cacheTextures,
Victoria Lease1e546812013-06-25 14:25:17 -0700194 const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
195 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
196 if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
197 return cacheTextures[i];
Chet Haase378e9192012-08-15 15:54:54 -0700198 }
199 }
200 // Could not fit glyph into current cache textures
Chris Craikd41c4d82015-01-05 15:51:13 -0800201 return nullptr;
Chet Haase378e9192012-08-15 15:54:54 -0700202}
203
Chet Haase7de0cb12011-12-05 16:35:38 -0800204void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
Chet Haasef942cf12012-08-30 09:06:46 -0700205 uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700206 checkInit();
Romain Guya4adcf02013-02-28 12:15:35 -0800207
208 // If the glyph bitmap is empty let's assum the glyph is valid
209 // so we can avoid doing extra work later on
210 if (glyph.fWidth == 0 || glyph.fHeight == 0) {
211 cachedGlyph->mIsValid = true;
Chris Craikd41c4d82015-01-05 15:51:13 -0800212 cachedGlyph->mCacheTexture = nullptr;
Romain Guya4adcf02013-02-28 12:15:35 -0800213 return;
214 }
215
Chet Haase7de0cb12011-12-05 16:35:38 -0800216 cachedGlyph->mIsValid = false;
Romain Guya4adcf02013-02-28 12:15:35 -0800217
Victoria Lease1e546812013-06-25 14:25:17 -0700218 // choose an appropriate cache texture list for this glyph format
219 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
John Reck272a6852015-07-29 16:48:58 -0700220 std::vector<CacheTexture*>* cacheTextures = nullptr;
Victoria Lease1e546812013-06-25 14:25:17 -0700221 switch (format) {
222 case SkMask::kA8_Format:
Victoria Lease723b2fe2013-08-12 14:38:44 -0700223 case SkMask::kBW_Format:
Victoria Lease1e546812013-06-25 14:25:17 -0700224 cacheTextures = &mACacheTextures;
225 break;
226 case SkMask::kARGB32_Format:
227 cacheTextures = &mRGBACacheTextures;
228 break;
229 default:
230#if DEBUG_FONT_RENDERER
231 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
232#endif
233 return;
234 }
235
Romain Guy694b5192010-07-21 21:33:20 -0700236 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700237 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
Victoria Lease1e546812013-06-25 14:25:17 -0700238 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700239 ALOGE("Font size too large to fit in cache. width, height = %i, %i",
240 (int) glyph.fWidth, (int) glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800241 return;
Romain Guy694b5192010-07-21 21:33:20 -0700242 }
243
244 // Now copy the bitmap into the cache texture
245 uint32_t startX = 0;
246 uint32_t startY = 0;
247
Victoria Lease1e546812013-06-25 14:25:17 -0700248 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700249
Chet Haase378e9192012-08-15 15:54:54 -0700250 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700251 if (!precaching) {
252 // If the new glyph didn't fit and we are not just trying to precache it,
253 // clear out the cache and try again
254 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700255 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700256 }
Romain Guy694b5192010-07-21 21:33:20 -0700257
Chet Haase378e9192012-08-15 15:54:54 -0700258 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700259 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800260 return;
Romain Guy694b5192010-07-21 21:33:20 -0700261 }
262 }
263
Chet Haase378e9192012-08-15 15:54:54 -0700264 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800265
Romain Guy694b5192010-07-21 21:33:20 -0700266 *retOriginX = startX;
267 *retOriginY = startY;
268
269 uint32_t endX = startX + glyph.fWidth;
270 uint32_t endY = startY + glyph.fHeight;
271
Romain Guy80872462012-09-04 16:42:01 -0700272 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700273
Romain Guycf51a412013-04-08 19:40:31 -0700274 if (!cacheTexture->getPixelBuffer()) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800275 Caches::getInstance().textureState().activateTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800276 // Large-glyph texture memory is allocated only as needed
Chris Craike2bb3802015-03-13 15:07:52 -0700277 cacheTexture->allocatePixelBuffer();
Chet Haase7de0cb12011-12-05 16:35:38 -0800278 }
Romain Guy661a87e2013-03-19 15:24:36 -0700279 if (!cacheTexture->mesh()) {
280 cacheTexture->allocateMesh();
281 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700282
Romain Guycf51a412013-04-08 19:40:31 -0700283 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
Victoria Lease1e546812013-06-25 14:25:17 -0700284 uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
285 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700286
Romain Guyb969a0d2013-02-05 14:38:40 -0800287 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800288 switch (format) {
289 case SkMask::kA8_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700290 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
291 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
292 - TEXTURE_BORDER_SIZE;
293 // write leading border line
294 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
295 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800296 if (mGammaTable) {
Victoria Lease1e546812013-06-25 14:25:17 -0700297 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800298 row = cacheY * cacheWidth;
299 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800300 for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
301 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800302 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800303 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800304 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800305 }
306 } else {
Victoria Lease1e546812013-06-25 14:25:17 -0700307 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800308 row = cacheY * cacheWidth;
309 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
310 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
311 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800312 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700313 }
Victoria Lease1e546812013-06-25 14:25:17 -0700314 // write trailing border line
315 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
316 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
317 break;
318 }
319 case SkMask::kARGB32_Format: {
320 // prep data lengths
321 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
322 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
323 size_t rowSize = formatSize * glyph.fWidth;
324 // prep advances
325 size_t dstStride = formatSize * cacheWidth;
326 // prep indices
327 // - we actually start one row early, and then increment before first copy
328 uint8_t* src = &bitmapBuffer[0 - srcStride];
329 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
330 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
331 uint8_t* dstL = dst - borderSize;
332 uint8_t* dstR = dst + rowSize;
333 // write leading border line
334 memset(dstL, 0, rowSize + 2 * borderSize);
335 // write glyph data
336 while (dst < dstEnd) {
337 memset(dstL += dstStride, 0, borderSize); // leading border column
338 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
339 memset(dstR += dstStride, 0, borderSize); // trailing border column
340 }
341 // write trailing border line
Victoria Lease16c84062013-09-19 15:38:21 -0700342 memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800343 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700344 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800345 case SkMask::kBW_Format: {
Andreas Gampe1e196742014-11-10 15:23:43 -0800346 uint32_t cacheX = 0, cacheY = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700347 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
348 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800349 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700350 // write leading border line
351 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
352 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800353 for (cacheY = startY; cacheY < endY; cacheY++) {
354 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700355 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800356 uint8_t* buffer = bitmapBuffer;
357
Romain Guy0b58a3d2013-03-05 12:16:27 -0800358 row = cacheY * cacheWidth;
359 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800360 while (--rowBytes >= 0) {
361 uint8_t b = *buffer++;
362 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
363 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
364 }
365 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800366 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800367
Victoria Lease1e546812013-06-25 14:25:17 -0700368 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700369 }
Victoria Lease1e546812013-06-25 14:25:17 -0700370 // write trailing border line
371 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
372 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800373 break;
Romain Guy694b5192010-07-21 21:33:20 -0700374 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800375 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700376 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800377 break;
Romain Guy694b5192010-07-21 21:33:20 -0700378 }
Romain Guy97771732012-02-28 18:17:02 -0800379
Chet Haase7de0cb12011-12-05 16:35:38 -0800380 cachedGlyph->mIsValid = true;
sergeyvaf102be2016-09-09 18:02:07 -0700381
382#ifdef BUGREPORT_FONT_CACHE_USAGE
383 mHistoryTracker.glyphUploaded(cacheTexture, startX, startY, glyph.fWidth, glyph.fHeight);
384#endif
Romain Guy694b5192010-07-21 21:33:20 -0700385}
386
Victoria Lease1e546812013-06-25 14:25:17 -0700387CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
388 bool allocate) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800389 CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700390
Chet Haase2a47c142011-12-14 15:22:56 -0800391 if (allocate) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800392 Caches::getInstance().textureState().activateTexture(0);
Chris Craike2bb3802015-03-13 15:07:52 -0700393 cacheTexture->allocatePixelBuffer();
Romain Guy661a87e2013-03-19 15:24:36 -0700394 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800395 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700396
Chet Haase2a47c142011-12-14 15:22:56 -0800397 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800398}
399
400void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700401 clearCacheTextures(mACacheTextures);
402 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700403
Chet Haase7de0cb12011-12-05 16:35:38 -0800404 mUploadTexture = false;
John Reck272a6852015-07-29 16:48:58 -0700405 mACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700406 GL_ALPHA, true));
John Reck272a6852015-07-29 16:48:58 -0700407 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700408 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700409 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700410 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700411 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700412 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700413 mRGBACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700414 GL_RGBA, false));
John Reck272a6852015-07-29 16:48:58 -0700415 mRGBACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700416 GL_RGBA, false));
417 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700418}
419
Romain Guy694b5192010-07-21 21:33:20 -0700420// We don't want to allocate anything unless we actually draw text
421void FontRenderer::checkInit() {
422 if (mInitialized) {
423 return;
424 }
425
426 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700427
428 mInitialized = true;
429}
430
John Reck272a6852015-07-29 16:48:58 -0700431void checkTextureUpdateForCache(Caches& caches, std::vector<CacheTexture*>& cacheTextures,
Victoria Lease1e546812013-06-25 14:25:17 -0700432 bool& resetPixelStore, GLuint& lastTextureId) {
433 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
434 CacheTexture* cacheTexture = cacheTextures[i];
435 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
436 if (cacheTexture->getTextureId() != lastTextureId) {
437 lastTextureId = cacheTexture->getTextureId();
Chris Craik44eb2c02015-01-29 09:45:09 -0800438 caches.textureState().activateTexture(0);
439 caches.textureState().bindTexture(lastTextureId);
Victoria Lease1e546812013-06-25 14:25:17 -0700440 }
441
442 if (cacheTexture->upload()) {
443 resetPixelStore = true;
444 }
445 }
446 }
447}
448
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700449void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900450 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700451 return;
Romain Guy694b5192010-07-21 21:33:20 -0700452 }
453
Romain Guy2d4fd362011-12-13 22:00:19 -0800454 Caches& caches = Caches::getInstance();
455 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700456
Romain Guycf51a412013-04-08 19:40:31 -0700457 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700458
Chet Haase378e9192012-08-15 15:54:54 -0700459 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700460 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
461 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700462
Romain Guycf51a412013-04-08 19:40:31 -0700463 // Unbind any PBO we might have used to update textures
Chris Craik44eb2c02015-01-29 09:45:09 -0800464 caches.pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700465
Romain Guy09087642013-04-04 12:27:54 -0700466 // Reset to default unpack row length to avoid affecting texture
467 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700468 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700469 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
470 }
471
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700472 mUploadTexture = false;
473}
474
John Reck272a6852015-07-29 16:48:58 -0700475void FontRenderer::issueDrawCommand(std::vector<CacheTexture*>& cacheTextures) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800476 if (!mFunctor) return;
477
Romain Guy661a87e2013-03-19 15:24:36 -0700478 bool first = true;
Victoria Lease1e546812013-06-25 14:25:17 -0700479 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
480 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700481 if (texture->canDraw()) {
482 if (first) {
Chris Craike2bb3802015-03-13 15:07:52 -0700483 checkTextureUpdate();
Romain Guy661a87e2013-03-19 15:24:36 -0700484 first = false;
Chris Craik083e7332015-02-27 17:04:20 -0800485 mDrawn = true;
Romain Guy661a87e2013-03-19 15:24:36 -0700486 }
Chris Craik82840732015-04-03 09:37:49 -0700487
Chris Craike2bb3802015-03-13 15:07:52 -0700488 mFunctor->draw(*texture, mLinearFiltering);
Romain Guy661a87e2013-03-19 15:24:36 -0700489
Romain Guy661a87e2013-03-19 15:24:36 -0700490 texture->resetMesh();
Romain Guy115096f2013-03-19 11:32:41 -0700491 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900492 }
Victoria Lease1e546812013-06-25 14:25:17 -0700493}
494
495void FontRenderer::issueDrawCommand() {
496 issueDrawCommand(mACacheTextures);
497 issueDrawCommand(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700498}
499
Romain Guy97771732012-02-28 18:17:02 -0800500void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
501 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
Chet Haase7de0cb12011-12-05 16:35:38 -0800502 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800503 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800504 // Now use the new texture id
505 mCurrentCacheTexture = texture;
506 }
Romain Guy09147fb2010-07-22 13:08:20 -0700507
Romain Guy661a87e2013-03-19 15:24:36 -0700508 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
509 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800510}
511
512void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
513 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
514 float x4, float y4, float u4, float v4, CacheTexture* texture) {
515
516 if (mClip &&
517 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
518 return;
519 }
520
521 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 -0700522
Romain Guy5b3b3522010-10-27 18:57:51 -0700523 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700524 mBounds->left = std::min(mBounds->left, x1);
525 mBounds->top = std::min(mBounds->top, y3);
526 mBounds->right = std::max(mBounds->right, x3);
527 mBounds->bottom = std::max(mBounds->bottom, y1);
Romain Guy5b3b3522010-10-27 18:57:51 -0700528 }
529
Romain Guy661a87e2013-03-19 15:24:36 -0700530 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700531 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700532 }
533}
534
Romain Guy97771732012-02-28 18:17:02 -0800535void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
536 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
537 float x4, float y4, float u4, float v4, CacheTexture* texture) {
538
539 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
540
541 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700542 mBounds->left = std::min(mBounds->left, std::min(x1, std::min(x2, std::min(x3, x4))));
543 mBounds->top = std::min(mBounds->top, std::min(y1, std::min(y2, std::min(y3, y4))));
544 mBounds->right = std::max(mBounds->right, std::max(x1, std::max(x2, std::max(x3, x4))));
545 mBounds->bottom = std::max(mBounds->bottom, std::max(y1, std::max(y2, std::max(y3, y4))));
Romain Guy97771732012-02-28 18:17:02 -0800546 }
547
Romain Guy661a87e2013-03-19 15:24:36 -0700548 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800549 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800550 }
551}
552
Chris Craik59744b72014-07-01 17:56:52 -0700553void FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800554 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700555}
Romain Guy7975fb62010-10-01 16:36:14 -0700556
Chris Craike8c3c812016-02-05 20:10:50 -0800557FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const glyph_t *glyphs,
Chris Craika1717272015-11-19 13:02:43 -0800558 int numGlyphs, float radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700559 checkInit();
560
Romain Guycf51a412013-04-08 19:40:31 -0700561 DropShadow image;
562 image.width = 0;
563 image.height = 0;
Chris Craikd41c4d82015-01-05 15:51:13 -0800564 image.image = nullptr;
Romain Guycf51a412013-04-08 19:40:31 -0700565 image.penX = 0;
566 image.penY = 0;
567
Romain Guy1e45aae2010-08-13 19:39:53 -0700568 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700569 return image;
570 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700571
Romain Guy2d4fd362011-12-13 22:00:19 -0800572 mDrawn = false;
Chris Craikd41c4d82015-01-05 15:51:13 -0800573 mClip = nullptr;
574 mBounds = nullptr;
Romain Guyff98fa52011-11-28 09:35:09 -0800575
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700576 Rect bounds;
Chris Craike8c3c812016-02-05 20:10:50 -0800577 mCurrentFont->measure(paint, glyphs, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800578
Derek Sollenbergere392c812014-05-21 11:25:22 -0400579 uint32_t intRadius = Blur::convertRadiusToInt(radius);
580 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
581 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
Romain Guyff98fa52011-11-28 09:35:09 -0800582
Romain Guycf51a412013-04-08 19:40:31 -0700583 uint32_t maxSize = Caches::getInstance().maxTextureSize;
584 if (paddedWidth > maxSize || paddedHeight > maxSize) {
585 return image;
586 }
587
Dan Morrille4d9a012013-03-28 18:10:43 -0700588#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800589 // Align buffers for renderscript usage
590 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
591 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700592 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800593 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800594 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700595#else
596 int size = paddedWidth * paddedHeight;
597 uint8_t* dataBuffer = (uint8_t*) malloc(size);
598#endif
599
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800600 memset(dataBuffer, 0, size);
601
Derek Sollenbergere392c812014-05-21 11:25:22 -0400602 int penX = intRadius - bounds.left;
603 int penY = intRadius - bounds.bottom;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700604
Chris Craikdd8697c2013-02-22 10:41:36 -0800605 if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
606 // text has non-whitespace, so draw and blur to create the shadow
607 // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
608 // TODO: don't draw pure whitespace in the first place, and avoid needing this check
Chris Craike8c3c812016-02-05 20:10:50 -0800609 mCurrentFont->render(paint, glyphs, numGlyphs, penX, penY,
Chris Craikd41c4d82015-01-05 15:51:13 -0800610 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
Chris Craikdd8697c2013-02-22 10:41:36 -0800611
Romain Guycf51a412013-04-08 19:40:31 -0700612 // Unbind any PBO we might have used
Chris Craik44eb2c02015-01-29 09:45:09 -0800613 Caches::getInstance().pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700614
Chris Craikdd8697c2013-02-22 10:41:36 -0800615 blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
616 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700617
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700618 image.width = paddedWidth;
619 image.height = paddedHeight;
620 image.image = dataBuffer;
621 image.penX = penX;
622 image.penY = penY;
Romain Guy2d4fd362011-12-13 22:00:19 -0800623
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700624 return image;
625}
Romain Guy694b5192010-07-21 21:33:20 -0700626
Chris Craik82840732015-04-03 09:37:49 -0700627void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextDrawFunctor* functor) {
Romain Guy694b5192010-07-21 21:33:20 -0700628 checkInit();
629
Romain Guy5b3b3522010-10-27 18:57:51 -0700630 mDrawn = false;
631 mBounds = bounds;
Romain Guy257ae352013-03-20 16:31:12 -0700632 mFunctor = functor;
Romain Guy09147fb2010-07-22 13:08:20 -0700633 mClip = clip;
Romain Guy671d6cf2012-01-18 12:39:17 -0800634}
Romain Guyff98fa52011-11-28 09:35:09 -0800635
Romain Guy671d6cf2012-01-18 12:39:17 -0800636void FontRenderer::finishRender() {
Chris Craikd41c4d82015-01-05 15:51:13 -0800637 mBounds = nullptr;
638 mClip = nullptr;
Romain Guy694b5192010-07-21 21:33:20 -0700639
Romain Guy661a87e2013-03-19 15:24:36 -0700640 issueDrawCommand();
Romain Guy671d6cf2012-01-18 12:39:17 -0800641}
642
Chris Craike8c3c812016-02-05 20:10:50 -0800643void FontRenderer::precache(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs,
Chris Craik59744b72014-07-01 17:56:52 -0700644 const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800645 Font* font = Font::create(this, paint, matrix);
Chris Craike8c3c812016-02-05 20:10:50 -0800646 font->precache(paint, glyphs, numGlyphs);
Chet Haasee816bae2012-08-09 13:39:02 -0700647}
648
Romain Guycf51a412013-04-08 19:40:31 -0700649void FontRenderer::endPrecaching() {
650 checkTextureUpdate();
651}
652
Chris Craike8c3c812016-02-05 20:10:50 -0800653bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
Chris Craika1717272015-11-19 13:02:43 -0800654 int numGlyphs, int x, int y, const float* positions,
655 Rect* bounds, TextDrawFunctor* functor, bool forceFinish) {
Romain Guy671d6cf2012-01-18 12:39:17 -0800656 if (!mCurrentFont) {
657 ALOGE("No font set");
658 return false;
659 }
660
Romain Guy257ae352013-03-20 16:31:12 -0700661 initRender(clip, bounds, functor);
Chris Craike8c3c812016-02-05 20:10:50 -0800662 mCurrentFont->render(paint, glyphs, numGlyphs, x, y, positions);
Chris Craik527a3aa2013-03-04 10:19:31 -0800663
664 if (forceFinish) {
665 finishRender();
666 }
Romain Guy5b3b3522010-10-27 18:57:51 -0700667
668 return mDrawn;
Romain Guy694b5192010-07-21 21:33:20 -0700669}
670
Chris Craike8c3c812016-02-05 20:10:50 -0800671bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
Chris Craika1717272015-11-19 13:02:43 -0800672 int numGlyphs, const SkPath* path, float hOffset, float vOffset,
673 Rect* bounds, TextDrawFunctor* functor) {
Romain Guy97771732012-02-28 18:17:02 -0800674 if (!mCurrentFont) {
675 ALOGE("No font set");
676 return false;
677 }
678
Victoria Lease1e546812013-06-25 14:25:17 -0700679 initRender(clip, bounds, functor);
Chris Craike8c3c812016-02-05 20:10:50 -0800680 mCurrentFont->render(paint, glyphs, numGlyphs, path, hOffset, vOffset);
Romain Guy97771732012-02-28 18:17:02 -0800681 finishRender();
682
683 return mDrawn;
684}
685
Derek Sollenbergere392c812014-05-21 11:25:22 -0400686void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
687 uint32_t intRadius = Blur::convertRadiusToInt(radius);
Dan Morrille4d9a012013-03-28 18:10:43 -0700688#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf3754a82016-04-19 18:13:21 -0700689 if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF && radius <= 25.0f) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700690 uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700691
Chris Craikd41c4d82015-01-05 15:51:13 -0800692 if (mRs == nullptr) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700693 mRs = new RSC::RS();
Tim Murrayabe55e92013-12-13 12:57:36 -0800694 // a null path is OK because there are no custom kernels used
695 // hence nothing gets cached by RS
696 if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800697 mRs.clear();
Dan Morrille4d9a012013-03-28 18:10:43 -0700698 ALOGE("blur RS failed to init");
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800699 } else {
700 mRsElement = RSC::Element::A_8(mRs);
701 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Dan Morrille4d9a012013-03-28 18:10:43 -0700702 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800703 }
Chris Craikd41c4d82015-01-05 15:51:13 -0800704 if (mRs != nullptr) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800705 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
706 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
707 RS_ALLOCATION_MIPMAP_NONE,
708 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
709 *image);
710 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
711 RS_ALLOCATION_MIPMAP_NONE,
712 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
713 outImage);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800714
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800715 mRsScript->setRadius(radius);
716 mRsScript->setInput(ain);
717 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700718
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800719 // replace the original image's pointer, avoiding a copy back to the original buffer
720 free(*image);
721 *image = outImage;
Dan Morrille4d9a012013-03-28 18:10:43 -0700722
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800723 return;
724 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800725 }
Dan Morrille4d9a012013-03-28 18:10:43 -0700726#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800727
Chris Craik51d6a3d2014-12-22 17:16:56 -0800728 std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
huanhuan.x.wanga46ca5e2015-04-14 16:23:15 +0200729 Blur::generateGaussianWeights(gaussian.get(), radius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800730
Chris Craik51d6a3d2014-12-22 17:16:56 -0800731 std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
732 Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
733 Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700734}
735
John Reck272a6852015-07-29 16:48:58 -0700736static uint32_t calculateCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700737 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700738 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
739 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700740 if (cacheTexture && cacheTexture->getPixelBuffer()) {
741 size += cacheTexture->getPixelBuffer()->getSize();
742 }
743 }
744 return size;
745}
746
sergeyvbaf29e72016-09-08 11:09:34 -0700747static uint32_t calculateFreeCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
748 uint32_t size = 0;
749 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
750 CacheTexture* cacheTexture = cacheTextures[i];
751 if (cacheTexture && cacheTexture->getPixelBuffer()) {
752 size += cacheTexture->calculateFreeMemory();
Victoria Lease1e546812013-06-25 14:25:17 -0700753 }
754 }
sergeyvbaf29e72016-09-08 11:09:34 -0700755 return size;
756}
757
758const std::vector<CacheTexture*>& FontRenderer::cacheTexturesForFormat(GLenum format) const {
759 switch (format) {
760 case GL_ALPHA: {
761 return mACacheTextures;
762 }
763 case GL_RGBA: {
764 return mRGBACacheTextures;
765 }
766 default: {
767 LOG_ALWAYS_FATAL("Unsupported format: %d", format);
768 // Impossible to hit this, but the compiler doesn't know that
769 return *(new std::vector<CacheTexture*>());
770 }
771 }
772}
773
774static void dumpTextures(String8& log, const char* tag,
775 const std::vector<CacheTexture*>& cacheTextures) {
776 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
777 CacheTexture* cacheTexture = cacheTextures[i];
778 if (cacheTexture && cacheTexture->getPixelBuffer()) {
779 uint32_t free = cacheTexture->calculateFreeMemory();
780 uint32_t total = cacheTexture->getPixelBuffer()->getSize();
781 log.appendFormat(" %-4s texture %d %8d / %8d\n", tag, i, total - free, total);
782 }
783 }
784}
785
786void FontRenderer::dumpMemoryUsage(String8& log) const {
787 const uint32_t sizeA8 = getCacheSize(GL_ALPHA);
788 const uint32_t usedA8 = sizeA8 - getFreeCacheSize(GL_ALPHA);
789 const uint32_t sizeRGBA = getCacheSize(GL_RGBA);
790 const uint32_t usedRGBA = sizeRGBA - getFreeCacheSize(GL_RGBA);
791 log.appendFormat(" FontRenderer A8 %8d / %8d\n", usedA8, sizeA8);
792 dumpTextures(log, "A8", cacheTexturesForFormat(GL_ALPHA));
793 log.appendFormat(" FontRenderer RGBA %8d / %8d\n", usedRGBA, sizeRGBA);
794 dumpTextures(log, "RGBA", cacheTexturesForFormat(GL_RGBA));
795 log.appendFormat(" FontRenderer total %8d / %8d\n", usedA8 + usedRGBA, sizeA8 + sizeRGBA);
796}
797
798uint32_t FontRenderer::getCacheSize(GLenum format) const {
799 return calculateCacheSize(cacheTexturesForFormat(format));
800}
801
802uint32_t FontRenderer::getFreeCacheSize(GLenum format) const {
803 return calculateFreeCacheSize(cacheTexturesForFormat(format));
804}
805
806uint32_t FontRenderer::getSize() const {
807 return getCacheSize(GL_ALPHA) + getCacheSize(GL_RGBA);
Victoria Lease1e546812013-06-25 14:25:17 -0700808}
809
Romain Guy694b5192010-07-21 21:33:20 -0700810}; // namespace uirenderer
811}; // namespace android