blob: bbcedb15335d6a51320ab5e918799ca9f548c38c [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"
John Reck1bcacfd2017-11-03 10:12:19 -070029#include "font/Font.h"
Chris Craik96a5c4c2015-01-27 15:46:35 -080030#include "renderstate/RenderState.h"
31#include "utils/Blur.h"
32#include "utils/Timing.h"
Romain Guy694b5192010-07-21 21:33:20 -070033
Po-Chien Hsuehc5ae5952017-02-09 10:38:34 +080034#include <RenderScript.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>
John Reck1bcacfd2017-11-03 10:12:19 -070038#include <algorithm>
Romain Guy51769a62010-07-23 00:28:00 -070039
Romain Guy694b5192010-07-21 21:33:20 -070040namespace android {
41namespace uirenderer {
42
Chris Craikf2d8ccc2013-02-13 16:14:17 -080043// blur inputs smaller than this constant will bypass renderscript
44#define RS_MIN_INPUT_CUTOFF 10000
45
Romain Guy694b5192010-07-21 21:33:20 -070046///////////////////////////////////////////////////////////////////////////////
Victoria Lease1e546812013-06-25 14:25:17 -070047// TextSetupFunctor
48///////////////////////////////////////////////////////////////////////////////
Victoria Lease1e546812013-06-25 14:25:17 -070049
Chris Craik82840732015-04-03 09:37:49 -070050void TextDrawFunctor::draw(CacheTexture& texture, bool linearFiltering) {
Chris Craik53e51e42015-06-01 10:35:35 -070051 int textureFillFlags = TextureFillFlags::None;
52 if (texture.getFormat() == GL_ALPHA) {
53 textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture;
Chris Craike2bb3802015-03-13 15:07:52 -070054 }
Chris Craik53e51e42015-06-01 10:35:35 -070055 if (linearFiltering) {
56 textureFillFlags |= TextureFillFlags::ForceFilter;
57 }
John Reck1bcacfd2017-11-03 10:12:19 -070058 int transformFlags =
59 pureTranslate ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
Romain Guy253f2c22016-09-28 17:34:42 -070060#ifdef ANDROID_ENABLE_LINEAR_BLENDING
61 bool gammaCorrection = true;
62#else
63 bool gammaCorrection = false;
64#endif
Chris Craike2bb3802015-03-13 15:07:52 -070065 Glop glop;
Chris Craika1717272015-11-19 13:02:43 -080066 GlopBuilder(renderer->renderState(), renderer->caches(), &glop)
67 .setRoundRectClipState(bakedState->roundRectClipState)
68 .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
69 .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, bakedState->alpha)
Romain Guy253f2c22016-09-28 17:34:42 -070070 .setGammaCorrection(gammaCorrection)
Chris Craika1717272015-11-19 13:02:43 -080071 .setTransform(bakedState->computedState.transform, transformFlags)
Chris Craikf09ff5a2015-12-08 17:21:58 -080072 .setModelViewIdentityEmptyBounds()
Chris Craika1717272015-11-19 13:02:43 -080073 .build();
Chris Craik15c3f192015-12-03 12:16:56 -080074 // Note: don't pass dirty bounds here, so user must manage passing dirty bounds to renderer
75 renderer->renderGlop(nullptr, clip, glop);
Victoria Lease1e546812013-06-25 14:25:17 -070076}
77
78///////////////////////////////////////////////////////////////////////////////
Romain Guy694b5192010-07-21 21:33:20 -070079// FontRenderer
80///////////////////////////////////////////////////////////////////////////////
81
Romain Guy514fb182011-01-19 14:38:29 -080082static bool sLogFontRendererCreate = true;
83
Chris Craikc08820f2015-09-22 14:22:29 -070084FontRenderer::FontRenderer(const uint8_t* gammaTable)
85 : mGammaTable(gammaTable)
Chris Craik083e7332015-02-27 17:04:20 -080086 , mCurrentFont(nullptr)
87 , mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity)
88 , mCurrentCacheTexture(nullptr)
89 , mUploadTexture(false)
90 , mFunctor(nullptr)
91 , mClip(nullptr)
92 , mBounds(nullptr)
93 , mDrawn(false)
94 , mInitialized(false)
95 , mLinearFiltering(false) {
Romain Guyc9855a52011-01-21 21:14:15 -080096 if (sLogFontRendererCreate) {
97 INIT_LOGD("Creating FontRenderer");
98 }
Romain Guy51769a62010-07-23 00:28:00 -070099
John Reck642ebea2017-07-17 09:55:02 -0700100 auto deviceInfo = DeviceInfo::get();
Seigo Nonaka7cc3ee72017-08-14 14:22:56 -0700101 auto displayInfo = deviceInfo->displayInfo();
John Reck642ebea2017-07-17 09:55:02 -0700102 int maxTextureSize = deviceInfo->maxTextureSize();
Romain Guy51769a62010-07-23 00:28:00 -0700103
Seigo Nonaka7cc3ee72017-08-14 14:22:56 -0700104 // Adjust cache size based on Pixel's desnsity.
105 constexpr float PIXEL_DENSITY = 2.6;
106 const float densityRatio = displayInfo.density / PIXEL_DENSITY;
107
John Reck642ebea2017-07-17 09:55:02 -0700108 // TODO: Most devices are hardcoded with this configuration, does it need to be dynamic?
Seigo Nonaka7cc3ee72017-08-14 14:22:56 -0700109 mSmallCacheWidth =
110 OffscreenBuffer::computeIdealDimension(std::min(1024, maxTextureSize) * densityRatio);
111 mSmallCacheHeight =
112 OffscreenBuffer::computeIdealDimension(std::min(1024, maxTextureSize) * densityRatio);
113 mLargeCacheWidth =
114 OffscreenBuffer::computeIdealDimension(std::min(2048, maxTextureSize) * densityRatio);
115 mLargeCacheHeight =
116 OffscreenBuffer::computeIdealDimension(std::min(1024, maxTextureSize) * densityRatio);
Romain Guy9f5dab32012-09-04 12:55:44 -0700117
Chet Haaseeb32a492012-08-31 13:54:03 -0700118 if (sLogFontRendererCreate) {
119 INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
John Reck1bcacfd2017-11-03 10:12:19 -0700120 mSmallCacheWidth, mSmallCacheHeight, mLargeCacheWidth, mLargeCacheHeight >> 1,
121 mLargeCacheWidth, mLargeCacheHeight >> 1, mLargeCacheWidth, mLargeCacheHeight);
Romain Guy51769a62010-07-23 00:28:00 -0700122 }
Romain Guy514fb182011-01-19 14:38:29 -0800123
124 sLogFontRendererCreate = false;
Romain Guy694b5192010-07-21 21:33:20 -0700125}
126
John Reck272a6852015-07-29 16:48:58 -0700127void clearCacheTextures(std::vector<CacheTexture*>& cacheTextures) {
Victoria Lease1e546812013-06-25 14:25:17 -0700128 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
129 delete cacheTextures[i];
Romain Guy694b5192010-07-21 21:33:20 -0700130 }
Victoria Lease1e546812013-06-25 14:25:17 -0700131 cacheTextures.clear();
132}
133
134FontRenderer::~FontRenderer() {
135 clearCacheTextures(mACacheTextures);
136 clearCacheTextures(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700137
Romain Guye3a9b242013-01-08 11:15:30 -0800138 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
139 while (it.next()) {
140 delete it.value();
Romain Guy694b5192010-07-21 21:33:20 -0700141 }
Romain Guye3a9b242013-01-08 11:15:30 -0800142 mActiveFonts.clear();
Romain Guy694b5192010-07-21 21:33:20 -0700143}
144
145void FontRenderer::flushAllAndInvalidate() {
Romain Guy661a87e2013-03-19 15:24:36 -0700146 issueDrawCommand();
Romain Guy9d9758a2012-05-14 15:19:58 -0700147
Romain Guye3a9b242013-01-08 11:15:30 -0800148 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
149 while (it.next()) {
150 it.value()->invalidateTextureCache();
Romain Guy694b5192010-07-21 21:33:20 -0700151 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700152
Victoria Lease1e546812013-06-25 14:25:17 -0700153 for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
154 mACacheTextures[i]->init();
sergeyvaf102be2016-09-09 18:02:07 -0700155
156#ifdef BUGREPORT_FONT_CACHE_USAGE
157 mHistoryTracker.glyphsCleared(mACacheTextures[i]);
158#endif
Victoria Lease1e546812013-06-25 14:25:17 -0700159 }
160
161 for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
162 mRGBACacheTextures[i]->init();
sergeyvaf102be2016-09-09 18:02:07 -0700163#ifdef BUGREPORT_FONT_CACHE_USAGE
164 mHistoryTracker.glyphsCleared(mRGBACacheTextures[i]);
165#endif
Romain Guy694b5192010-07-21 21:33:20 -0700166 }
chaochen1f61b192014-08-28 18:45:27 -0700167
168 mDrawn = false;
Romain Guy694b5192010-07-21 21:33:20 -0700169}
170
John Reck272a6852015-07-29 16:48:58 -0700171void FontRenderer::flushLargeCaches(std::vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700172 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700173 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
174 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700175 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700176 cacheTexture->init();
sergeyvaf102be2016-09-09 18:02:07 -0700177#ifdef BUGREPORT_FONT_CACHE_USAGE
178 mHistoryTracker.glyphsCleared(cacheTexture);
179#endif
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
John Reck272a6852015-07-29 16:48:58 -0700194CacheTexture* FontRenderer::cacheBitmapInTexture(std::vector<CacheTexture*>& cacheTextures,
John Reck1bcacfd2017-11-03 10:12:19 -0700195 const SkGlyph& glyph, uint32_t* startX,
196 uint32_t* startY) {
Victoria Lease1e546812013-06-25 14:25:17 -0700197 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
198 if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
199 return cacheTextures[i];
Chet Haase378e9192012-08-15 15:54:54 -0700200 }
201 }
202 // Could not fit glyph into current cache textures
Chris Craikd41c4d82015-01-05 15:51:13 -0800203 return nullptr;
Chet Haase378e9192012-08-15 15:54:54 -0700204}
205
Chet Haase7de0cb12011-12-05 16:35:38 -0800206void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
John Reck1bcacfd2017-11-03 10:12:19 -0700207 uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700208 checkInit();
Romain Guya4adcf02013-02-28 12:15:35 -0800209
210 // If the glyph bitmap is empty let's assum the glyph is valid
211 // so we can avoid doing extra work later on
212 if (glyph.fWidth == 0 || glyph.fHeight == 0) {
213 cachedGlyph->mIsValid = true;
Chris Craikd41c4d82015-01-05 15:51:13 -0800214 cachedGlyph->mCacheTexture = nullptr;
Romain Guya4adcf02013-02-28 12:15:35 -0800215 return;
216 }
217
Chet Haase7de0cb12011-12-05 16:35:38 -0800218 cachedGlyph->mIsValid = false;
Romain Guya4adcf02013-02-28 12:15:35 -0800219
Victoria Lease1e546812013-06-25 14:25:17 -0700220 // choose an appropriate cache texture list for this glyph format
221 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
John Reck272a6852015-07-29 16:48:58 -0700222 std::vector<CacheTexture*>* cacheTextures = nullptr;
Victoria Lease1e546812013-06-25 14:25:17 -0700223 switch (format) {
224 case SkMask::kA8_Format:
Victoria Lease723b2fe2013-08-12 14:38:44 -0700225 case SkMask::kBW_Format:
Victoria Lease1e546812013-06-25 14:25:17 -0700226 cacheTextures = &mACacheTextures;
227 break;
228 case SkMask::kARGB32_Format:
229 cacheTextures = &mRGBACacheTextures;
230 break;
231 default:
232#if DEBUG_FONT_RENDERER
233 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
234#endif
John Reck1bcacfd2017-11-03 10:12:19 -0700235 return;
Victoria Lease1e546812013-06-25 14:25:17 -0700236 }
237
Romain Guy694b5192010-07-21 21:33:20 -0700238 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700239 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
John Reck1bcacfd2017-11-03 10:12:19 -0700240 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
241 ALOGE("Font size too large to fit in cache. width, height = %i, %i", (int)glyph.fWidth,
242 (int)glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800243 return;
Romain Guy694b5192010-07-21 21:33:20 -0700244 }
245
246 // Now copy the bitmap into the cache texture
247 uint32_t startX = 0;
248 uint32_t startY = 0;
249
Victoria Lease1e546812013-06-25 14:25:17 -0700250 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700251
Chet Haase378e9192012-08-15 15:54:54 -0700252 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700253 if (!precaching) {
254 // If the new glyph didn't fit and we are not just trying to precache it,
255 // clear out the cache and try again
256 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700257 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700258 }
Romain Guy694b5192010-07-21 21:33:20 -0700259
Chet Haase378e9192012-08-15 15:54:54 -0700260 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700261 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800262 return;
Romain Guy694b5192010-07-21 21:33:20 -0700263 }
264 }
265
Chet Haase378e9192012-08-15 15:54:54 -0700266 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800267
Romain Guy694b5192010-07-21 21:33:20 -0700268 *retOriginX = startX;
269 *retOriginY = startY;
270
271 uint32_t endX = startX + glyph.fWidth;
272 uint32_t endY = startY + glyph.fHeight;
273
Romain Guy80872462012-09-04 16:42:01 -0700274 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700275
Romain Guycf51a412013-04-08 19:40:31 -0700276 if (!cacheTexture->getPixelBuffer()) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800277 Caches::getInstance().textureState().activateTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800278 // Large-glyph texture memory is allocated only as needed
Chris Craike2bb3802015-03-13 15:07:52 -0700279 cacheTexture->allocatePixelBuffer();
Chet Haase7de0cb12011-12-05 16:35:38 -0800280 }
Romain Guy661a87e2013-03-19 15:24:36 -0700281 if (!cacheTexture->mesh()) {
282 cacheTexture->allocateMesh();
283 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700284
Romain Guycf51a412013-04-08 19:40:31 -0700285 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
John Reck1bcacfd2017-11-03 10:12:19 -0700286 uint8_t* bitmapBuffer = (uint8_t*)glyph.fImage;
Victoria Lease1e546812013-06-25 14:25:17 -0700287 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700288
Romain Guyb969a0d2013-02-05 14:38:40 -0800289 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800290 switch (format) {
291 case SkMask::kA8_Format: {
John Reck1bcacfd2017-11-03 10:12:19 -0700292 uint32_t row =
293 (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
Victoria Lease1e546812013-06-25 14:25:17 -0700294 // 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) {
Romain Guy253f2c22016-09-28 17:34:42 -0700298 for (uint32_t 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 Guy253f2c22016-09-28 17:34:42 -0700301 for (uint32_t cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
Romain Guyb969a0d2013-02-05 14:38:40 -0800302 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 {
Romain Guy253f2c22016-09-28 17:34:42 -0700308 for (uint32_t 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) {
John Reck1bcacfd2017-11-03 10:12:19 -0700338 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
Victoria Lease1e546812013-06-25 14:25:17 -0700341 }
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;
John Reck1bcacfd2017-11-03 10:12:19 -0700348 uint32_t row =
349 (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
350 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;
sergeyvaf102be2016-09-09 18:02:07 -0700382
383#ifdef BUGREPORT_FONT_CACHE_USAGE
384 mHistoryTracker.glyphUploaded(cacheTexture, startX, startY, glyph.fWidth, glyph.fHeight);
385#endif
Romain Guy694b5192010-07-21 21:33:20 -0700386}
387
Victoria Lease1e546812013-06-25 14:25:17 -0700388CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
John Reck1bcacfd2017-11-03 10:12:19 -0700389 bool allocate) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800390 CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700391
Chet Haase2a47c142011-12-14 15:22:56 -0800392 if (allocate) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800393 Caches::getInstance().textureState().activateTexture(0);
Chris Craike2bb3802015-03-13 15:07:52 -0700394 cacheTexture->allocatePixelBuffer();
Romain Guy661a87e2013-03-19 15:24:36 -0700395 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800396 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700397
Chet Haase2a47c142011-12-14 15:22:56 -0800398 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800399}
400
401void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700402 clearCacheTextures(mACacheTextures);
403 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700404
Chet Haase7de0cb12011-12-05 16:35:38 -0800405 mUploadTexture = false;
John Reck1bcacfd2017-11-03 10:12:19 -0700406 mACacheTextures.push_back(
407 createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, GL_ALPHA, true));
408 mACacheTextures.push_back(
409 createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, GL_ALPHA, false));
410 mACacheTextures.push_back(
411 createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, GL_ALPHA, false));
412 mACacheTextures.push_back(
413 createCacheTexture(mLargeCacheWidth, mLargeCacheHeight, GL_ALPHA, false));
414 mRGBACacheTextures.push_back(
415 createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, GL_RGBA, false));
416 mRGBACacheTextures.push_back(
417 createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, GL_RGBA, false));
Victoria Lease1e546812013-06-25 14:25:17 -0700418 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700419}
420
Romain Guy694b5192010-07-21 21:33:20 -0700421// We don't want to allocate anything unless we actually draw text
422void FontRenderer::checkInit() {
423 if (mInitialized) {
424 return;
425 }
426
427 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700428
429 mInitialized = true;
430}
431
John Reck272a6852015-07-29 16:48:58 -0700432void checkTextureUpdateForCache(Caches& caches, std::vector<CacheTexture*>& cacheTextures,
John Reck1bcacfd2017-11-03 10:12:19 -0700433 bool& resetPixelStore, GLuint& lastTextureId) {
Victoria Lease1e546812013-06-25 14:25:17 -0700434 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
435 CacheTexture* cacheTexture = cacheTextures[i];
436 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
437 if (cacheTexture->getTextureId() != lastTextureId) {
438 lastTextureId = cacheTexture->getTextureId();
Chris Craik44eb2c02015-01-29 09:45:09 -0800439 caches.textureState().activateTexture(0);
440 caches.textureState().bindTexture(lastTextureId);
Victoria Lease1e546812013-06-25 14:25:17 -0700441 }
442
443 if (cacheTexture->upload()) {
444 resetPixelStore = true;
445 }
446 }
447 }
448}
449
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700450void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900451 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700452 return;
Romain Guy694b5192010-07-21 21:33:20 -0700453 }
454
Romain Guy2d4fd362011-12-13 22:00:19 -0800455 Caches& caches = Caches::getInstance();
456 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700457
Romain Guycf51a412013-04-08 19:40:31 -0700458 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700459
Chet Haase378e9192012-08-15 15:54:54 -0700460 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700461 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
462 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700463
Romain Guycf51a412013-04-08 19:40:31 -0700464 // Unbind any PBO we might have used to update textures
Chris Craik44eb2c02015-01-29 09:45:09 -0800465 caches.pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700466
Romain Guy09087642013-04-04 12:27:54 -0700467 // Reset to default unpack row length to avoid affecting texture
468 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700469 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700470 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
471 }
472
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700473 mUploadTexture = false;
474}
475
John Reck272a6852015-07-29 16:48:58 -0700476void FontRenderer::issueDrawCommand(std::vector<CacheTexture*>& cacheTextures) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800477 if (!mFunctor) return;
478
Romain Guy661a87e2013-03-19 15:24:36 -0700479 bool first = true;
Victoria Lease1e546812013-06-25 14:25:17 -0700480 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
481 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700482 if (texture->canDraw()) {
483 if (first) {
Chris Craike2bb3802015-03-13 15:07:52 -0700484 checkTextureUpdate();
Romain Guy661a87e2013-03-19 15:24:36 -0700485 first = false;
Chris Craik083e7332015-02-27 17:04:20 -0800486 mDrawn = true;
Romain Guy661a87e2013-03-19 15:24:36 -0700487 }
Chris Craik82840732015-04-03 09:37:49 -0700488
Chris Craike2bb3802015-03-13 15:07:52 -0700489 mFunctor->draw(*texture, mLinearFiltering);
Romain Guy661a87e2013-03-19 15:24:36 -0700490
Romain Guy661a87e2013-03-19 15:24:36 -0700491 texture->resetMesh();
Romain Guy115096f2013-03-19 11:32:41 -0700492 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900493 }
Victoria Lease1e546812013-06-25 14:25:17 -0700494}
495
496void FontRenderer::issueDrawCommand() {
497 issueDrawCommand(mACacheTextures);
498 issueDrawCommand(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700499}
500
John Reck1bcacfd2017-11-03 10:12:19 -0700501void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1, float x2, float y2,
502 float u2, float v2, float x3, float y3, float u3, float v3,
503 float x4, float y4, float u4, float v4,
504 CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800505 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800506 // Now use the new texture id
507 mCurrentCacheTexture = texture;
508 }
Romain Guy09147fb2010-07-22 13:08:20 -0700509
John Reck1bcacfd2017-11-03 10:12:19 -0700510 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800511}
512
John Reck1bcacfd2017-11-03 10:12:19 -0700513void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1, float x2, float y2,
514 float u2, float v2, float x3, float y3, float u3, float v3,
515 float x4, float y4, float u4, float v4, CacheTexture* texture) {
516 if (mClip && (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
Romain Guy97771732012-02-28 18:17:02 -0800517 return;
518 }
519
520 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 -0700521
Romain Guy5b3b3522010-10-27 18:57:51 -0700522 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700523 mBounds->left = std::min(mBounds->left, x1);
524 mBounds->top = std::min(mBounds->top, y3);
525 mBounds->right = std::max(mBounds->right, x3);
526 mBounds->bottom = std::max(mBounds->bottom, y1);
Romain Guy5b3b3522010-10-27 18:57:51 -0700527 }
528
Romain Guy661a87e2013-03-19 15:24:36 -0700529 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700530 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700531 }
532}
533
John Reck1bcacfd2017-11-03 10:12:19 -0700534void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1, float x2, float y2,
535 float u2, float v2, float x3, float y3, float u3, float v3,
536 float x4, float y4, float u4, float v4,
537 CacheTexture* texture) {
Romain Guy97771732012-02-28 18:17:02 -0800538 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
539
540 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700541 mBounds->left = std::min(mBounds->left, std::min(x1, std::min(x2, std::min(x3, x4))));
542 mBounds->top = std::min(mBounds->top, std::min(y1, std::min(y2, std::min(y3, y4))));
543 mBounds->right = std::max(mBounds->right, std::max(x1, std::max(x2, std::max(x3, x4))));
544 mBounds->bottom = std::max(mBounds->bottom, std::max(y1, std::max(y2, std::max(y3, y4))));
Romain Guy97771732012-02-28 18:17:02 -0800545 }
546
Romain Guy661a87e2013-03-19 15:24:36 -0700547 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800548 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800549 }
550}
551
Chris Craik59744b72014-07-01 17:56:52 -0700552void FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800553 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700554}
Romain Guy7975fb62010-10-01 16:36:14 -0700555
John Reck1bcacfd2017-11-03 10:12:19 -0700556FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const glyph_t* glyphs,
557 int numGlyphs, float radius,
558 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);
John Reck1bcacfd2017-11-03 10:12:19 -0700580 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
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800588 // Align buffers for renderscript usage
589 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
590 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700591 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800592 int size = paddedWidth * paddedHeight;
John Reck1bcacfd2017-11-03 10:12:19 -0700593 uint8_t* dataBuffer = (uint8_t*)memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700594
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800595 memset(dataBuffer, 0, size);
596
Derek Sollenbergere392c812014-05-21 11:25:22 -0400597 int penX = intRadius - bounds.left;
598 int penY = intRadius - bounds.bottom;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700599
Chris Craikdd8697c2013-02-22 10:41:36 -0800600 if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
601 // text has non-whitespace, so draw and blur to create the shadow
602 // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
603 // TODO: don't draw pure whitespace in the first place, and avoid needing this check
John Reck1bcacfd2017-11-03 10:12:19 -0700604 mCurrentFont->render(paint, glyphs, numGlyphs, penX, penY, Font::BITMAP, dataBuffer,
605 paddedWidth, paddedHeight, nullptr, positions);
Chris Craikdd8697c2013-02-22 10:41:36 -0800606
Romain Guycf51a412013-04-08 19:40:31 -0700607 // Unbind any PBO we might have used
Chris Craik44eb2c02015-01-29 09:45:09 -0800608 Caches::getInstance().pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700609
Chris Craikdd8697c2013-02-22 10:41:36 -0800610 blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
611 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700612
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700613 image.width = paddedWidth;
614 image.height = paddedHeight;
615 image.image = dataBuffer;
616 image.penX = penX;
617 image.penY = penY;
Romain Guy2d4fd362011-12-13 22:00:19 -0800618
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700619 return image;
620}
Romain Guy694b5192010-07-21 21:33:20 -0700621
Chris Craik82840732015-04-03 09:37:49 -0700622void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextDrawFunctor* functor) {
Romain Guy694b5192010-07-21 21:33:20 -0700623 checkInit();
624
Romain Guy5b3b3522010-10-27 18:57:51 -0700625 mDrawn = false;
626 mBounds = bounds;
Romain Guy257ae352013-03-20 16:31:12 -0700627 mFunctor = functor;
Romain Guy09147fb2010-07-22 13:08:20 -0700628 mClip = clip;
Romain Guy671d6cf2012-01-18 12:39:17 -0800629}
Romain Guyff98fa52011-11-28 09:35:09 -0800630
Romain Guy671d6cf2012-01-18 12:39:17 -0800631void FontRenderer::finishRender() {
Chris Craikd41c4d82015-01-05 15:51:13 -0800632 mBounds = nullptr;
633 mClip = nullptr;
Romain Guy694b5192010-07-21 21:33:20 -0700634
Romain Guy661a87e2013-03-19 15:24:36 -0700635 issueDrawCommand();
Romain Guy671d6cf2012-01-18 12:39:17 -0800636}
637
Chris Craike8c3c812016-02-05 20:10:50 -0800638void FontRenderer::precache(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs,
John Reck1bcacfd2017-11-03 10:12:19 -0700639 const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800640 Font* font = Font::create(this, paint, matrix);
Chris Craike8c3c812016-02-05 20:10:50 -0800641 font->precache(paint, glyphs, numGlyphs);
Chet Haasee816bae2012-08-09 13:39:02 -0700642}
643
Romain Guycf51a412013-04-08 19:40:31 -0700644void FontRenderer::endPrecaching() {
645 checkTextureUpdate();
646}
647
Chris Craike8c3c812016-02-05 20:10:50 -0800648bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
John Reck1bcacfd2017-11-03 10:12:19 -0700649 int numGlyphs, int x, int y, const float* positions, Rect* bounds,
650 TextDrawFunctor* functor, bool forceFinish) {
Romain Guy671d6cf2012-01-18 12:39:17 -0800651 if (!mCurrentFont) {
652 ALOGE("No font set");
653 return false;
654 }
655
Romain Guy257ae352013-03-20 16:31:12 -0700656 initRender(clip, bounds, functor);
Chris Craike8c3c812016-02-05 20:10:50 -0800657 mCurrentFont->render(paint, glyphs, numGlyphs, x, y, positions);
Chris Craik527a3aa2013-03-04 10:19:31 -0800658
659 if (forceFinish) {
660 finishRender();
661 }
Romain Guy5b3b3522010-10-27 18:57:51 -0700662
663 return mDrawn;
Romain Guy694b5192010-07-21 21:33:20 -0700664}
665
Chris Craike8c3c812016-02-05 20:10:50 -0800666bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
John Reck1bcacfd2017-11-03 10:12:19 -0700667 int numGlyphs, const SkPath* path, float hOffset, float vOffset,
668 Rect* bounds, TextDrawFunctor* functor) {
Romain Guy97771732012-02-28 18:17:02 -0800669 if (!mCurrentFont) {
670 ALOGE("No font set");
671 return false;
672 }
673
Victoria Lease1e546812013-06-25 14:25:17 -0700674 initRender(clip, bounds, functor);
Chris Craike8c3c812016-02-05 20:10:50 -0800675 mCurrentFont->render(paint, glyphs, numGlyphs, path, hOffset, vOffset);
Romain Guy97771732012-02-28 18:17:02 -0800676 finishRender();
677
678 return mDrawn;
679}
680
Derek Sollenbergere392c812014-05-21 11:25:22 -0400681void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
682 uint32_t intRadius = Blur::convertRadiusToInt(radius);
Chris Craikf3754a82016-04-19 18:13:21 -0700683 if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF && radius <= 25.0f) {
John Reck1bcacfd2017-11-03 10:12:19 -0700684 uint8_t* outImage = (uint8_t*)memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700685
Chris Craikd41c4d82015-01-05 15:51:13 -0800686 if (mRs == nullptr) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700687 mRs = new RSC::RS();
Tim Murrayabe55e92013-12-13 12:57:36 -0800688 // a null path is OK because there are no custom kernels used
689 // hence nothing gets cached by RS
690 if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800691 mRs.clear();
Dan Morrille4d9a012013-03-28 18:10:43 -0700692 ALOGE("blur RS failed to init");
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800693 } else {
694 mRsElement = RSC::Element::A_8(mRs);
695 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Dan Morrille4d9a012013-03-28 18:10:43 -0700696 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800697 }
Chris Craikd41c4d82015-01-05 15:51:13 -0800698 if (mRs != nullptr) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800699 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
John Reck1bcacfd2017-11-03 10:12:19 -0700700 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(
701 mRs, t, RS_ALLOCATION_MIPMAP_NONE,
702 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, *image);
703 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(
704 mRs, t, RS_ALLOCATION_MIPMAP_NONE,
705 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, outImage);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800706
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800707 mRsScript->setRadius(radius);
708 mRsScript->setInput(ain);
709 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700710
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800711 // replace the original image's pointer, avoiding a copy back to the original buffer
712 free(*image);
713 *image = outImage;
Dan Morrille4d9a012013-03-28 18:10:43 -0700714
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800715 return;
716 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800717 }
718
Chris Craik51d6a3d2014-12-22 17:16:56 -0800719 std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
huanhuan.x.wanga46ca5e2015-04-14 16:23:15 +0200720 Blur::generateGaussianWeights(gaussian.get(), radius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800721
Chris Craik51d6a3d2014-12-22 17:16:56 -0800722 std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
723 Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
724 Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700725}
726
John Reck272a6852015-07-29 16:48:58 -0700727static uint32_t calculateCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700728 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700729 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
730 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700731 if (cacheTexture && cacheTexture->getPixelBuffer()) {
732 size += cacheTexture->getPixelBuffer()->getSize();
733 }
734 }
735 return size;
736}
737
sergeyvbaf29e72016-09-08 11:09:34 -0700738static uint32_t calculateFreeCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
739 uint32_t size = 0;
740 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
741 CacheTexture* cacheTexture = cacheTextures[i];
742 if (cacheTexture && cacheTexture->getPixelBuffer()) {
743 size += cacheTexture->calculateFreeMemory();
Victoria Lease1e546812013-06-25 14:25:17 -0700744 }
745 }
sergeyvbaf29e72016-09-08 11:09:34 -0700746 return size;
747}
748
749const std::vector<CacheTexture*>& FontRenderer::cacheTexturesForFormat(GLenum format) const {
750 switch (format) {
751 case GL_ALPHA: {
752 return mACacheTextures;
753 }
754 case GL_RGBA: {
755 return mRGBACacheTextures;
756 }
757 default: {
758 LOG_ALWAYS_FATAL("Unsupported format: %d", format);
759 // Impossible to hit this, but the compiler doesn't know that
760 return *(new std::vector<CacheTexture*>());
761 }
762 }
763}
764
765static void dumpTextures(String8& log, const char* tag,
John Reck1bcacfd2017-11-03 10:12:19 -0700766 const std::vector<CacheTexture*>& cacheTextures) {
sergeyvbaf29e72016-09-08 11:09:34 -0700767 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
768 CacheTexture* cacheTexture = cacheTextures[i];
769 if (cacheTexture && cacheTexture->getPixelBuffer()) {
770 uint32_t free = cacheTexture->calculateFreeMemory();
771 uint32_t total = cacheTexture->getPixelBuffer()->getSize();
772 log.appendFormat(" %-4s texture %d %8d / %8d\n", tag, i, total - free, total);
773 }
774 }
775}
776
777void FontRenderer::dumpMemoryUsage(String8& log) const {
778 const uint32_t sizeA8 = getCacheSize(GL_ALPHA);
779 const uint32_t usedA8 = sizeA8 - getFreeCacheSize(GL_ALPHA);
780 const uint32_t sizeRGBA = getCacheSize(GL_RGBA);
781 const uint32_t usedRGBA = sizeRGBA - getFreeCacheSize(GL_RGBA);
782 log.appendFormat(" FontRenderer A8 %8d / %8d\n", usedA8, sizeA8);
783 dumpTextures(log, "A8", cacheTexturesForFormat(GL_ALPHA));
784 log.appendFormat(" FontRenderer RGBA %8d / %8d\n", usedRGBA, sizeRGBA);
785 dumpTextures(log, "RGBA", cacheTexturesForFormat(GL_RGBA));
786 log.appendFormat(" FontRenderer total %8d / %8d\n", usedA8 + usedRGBA, sizeA8 + sizeRGBA);
787}
788
789uint32_t FontRenderer::getCacheSize(GLenum format) const {
790 return calculateCacheSize(cacheTexturesForFormat(format));
791}
792
793uint32_t FontRenderer::getFreeCacheSize(GLenum format) const {
794 return calculateFreeCacheSize(cacheTexturesForFormat(format));
795}
796
797uint32_t FontRenderer::getSize() const {
798 return getCacheSize(GL_ALPHA) + getCacheSize(GL_RGBA);
Victoria Lease1e546812013-06-25 14:25:17 -0700799}
800
John Reck1bcacfd2017-11-03 10:12:19 -0700801}; // namespace uirenderer
802}; // namespace android