blob: bc4181075319494606232f3ff11eab521bc23221 [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>
Po-Chien Hsuehc5ae5952017-02-09 10:38:34 +080035#include <RenderScript.h>
Derek Sollenbergerca79cf62012-08-14 16:44:52 -040036#include <SkGlyph.h>
Romain Guy694b5192010-07-21 21:33:20 -070037#include <SkUtils.h>
Romain Guy51769a62010-07-23 00:28:00 -070038#include <utils/Log.h>
39
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 }
58 int transformFlags = pureTranslate
59 ? 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 Guye3a9b242013-01-08 11:15:30 -080096
Romain Guyc9855a52011-01-21 21:14:15 -080097 if (sLogFontRendererCreate) {
98 INIT_LOGD("Creating FontRenderer");
99 }
Romain Guy51769a62010-07-23 00:28:00 -0700100
John Reck8dc02f92017-07-17 09:55:02 -0700101 auto deviceInfo = DeviceInfo::get();
102 int maxTextureSize = deviceInfo->maxTextureSize();
Romain Guy51769a62010-07-23 00:28:00 -0700103
John Reck8dc02f92017-07-17 09:55:02 -0700104 // TODO: Most devices are hardcoded with this configuration, does it need to be dynamic?
105 mSmallCacheWidth = std::min(1024, maxTextureSize);
106 mSmallCacheHeight = std::min(1024, maxTextureSize);
107 mLargeCacheWidth = std::min(2048, maxTextureSize);
108 mLargeCacheHeight = std::min(1024, maxTextureSize);
Romain Guy9f5dab32012-09-04 12:55:44 -0700109
Chet Haaseeb32a492012-08-31 13:54:03 -0700110 if (sLogFontRendererCreate) {
111 INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
112 mSmallCacheWidth, mSmallCacheHeight,
113 mLargeCacheWidth, mLargeCacheHeight >> 1,
114 mLargeCacheWidth, mLargeCacheHeight >> 1,
115 mLargeCacheWidth, mLargeCacheHeight);
Romain Guy51769a62010-07-23 00:28:00 -0700116 }
Romain Guy514fb182011-01-19 14:38:29 -0800117
118 sLogFontRendererCreate = false;
Romain Guy694b5192010-07-21 21:33:20 -0700119}
120
John Reck272a6852015-07-29 16:48:58 -0700121void clearCacheTextures(std::vector<CacheTexture*>& cacheTextures) {
Victoria Lease1e546812013-06-25 14:25:17 -0700122 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
123 delete cacheTextures[i];
Romain Guy694b5192010-07-21 21:33:20 -0700124 }
Victoria Lease1e546812013-06-25 14:25:17 -0700125 cacheTextures.clear();
126}
127
128FontRenderer::~FontRenderer() {
129 clearCacheTextures(mACacheTextures);
130 clearCacheTextures(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700131
Romain Guye3a9b242013-01-08 11:15:30 -0800132 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
133 while (it.next()) {
134 delete it.value();
Romain Guy694b5192010-07-21 21:33:20 -0700135 }
Romain Guye3a9b242013-01-08 11:15:30 -0800136 mActiveFonts.clear();
Romain Guy694b5192010-07-21 21:33:20 -0700137}
138
139void FontRenderer::flushAllAndInvalidate() {
Romain Guy661a87e2013-03-19 15:24:36 -0700140 issueDrawCommand();
Romain Guy9d9758a2012-05-14 15:19:58 -0700141
Romain Guye3a9b242013-01-08 11:15:30 -0800142 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
143 while (it.next()) {
144 it.value()->invalidateTextureCache();
Romain Guy694b5192010-07-21 21:33:20 -0700145 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700146
Victoria Lease1e546812013-06-25 14:25:17 -0700147 for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
148 mACacheTextures[i]->init();
sergeyvaf102be2016-09-09 18:02:07 -0700149
150#ifdef BUGREPORT_FONT_CACHE_USAGE
151 mHistoryTracker.glyphsCleared(mACacheTextures[i]);
152#endif
Victoria Lease1e546812013-06-25 14:25:17 -0700153 }
154
155 for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
156 mRGBACacheTextures[i]->init();
sergeyvaf102be2016-09-09 18:02:07 -0700157#ifdef BUGREPORT_FONT_CACHE_USAGE
158 mHistoryTracker.glyphsCleared(mRGBACacheTextures[i]);
159#endif
Romain Guy694b5192010-07-21 21:33:20 -0700160 }
chaochen1f61b192014-08-28 18:45:27 -0700161
162 mDrawn = false;
Romain Guy694b5192010-07-21 21:33:20 -0700163}
164
John Reck272a6852015-07-29 16:48:58 -0700165void FontRenderer::flushLargeCaches(std::vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700166 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700167 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
168 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700169 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700170 cacheTexture->init();
sergeyvaf102be2016-09-09 18:02:07 -0700171#ifdef BUGREPORT_FONT_CACHE_USAGE
172 mHistoryTracker.glyphsCleared(cacheTexture);
173#endif
Romain Guye3a9b242013-01-08 11:15:30 -0800174 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
175 while (it.next()) {
176 it.value()->invalidateTextureCache(cacheTexture);
Chet Haasee816bae2012-08-09 13:39:02 -0700177 }
Chris Craike2bb3802015-03-13 15:07:52 -0700178 cacheTexture->releasePixelBuffer();
Chet Haase9a824562011-12-16 15:44:59 -0800179 }
180 }
Chet Haase9a824562011-12-16 15:44:59 -0800181}
182
Victoria Lease1e546812013-06-25 14:25:17 -0700183void FontRenderer::flushLargeCaches() {
184 flushLargeCaches(mACacheTextures);
185 flushLargeCaches(mRGBACacheTextures);
186}
187
John Reck272a6852015-07-29 16:48:58 -0700188CacheTexture* FontRenderer::cacheBitmapInTexture(std::vector<CacheTexture*>& cacheTextures,
Victoria Lease1e546812013-06-25 14:25:17 -0700189 const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
190 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
191 if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
192 return cacheTextures[i];
Chet Haase378e9192012-08-15 15:54:54 -0700193 }
194 }
195 // Could not fit glyph into current cache textures
Chris Craikd41c4d82015-01-05 15:51:13 -0800196 return nullptr;
Chet Haase378e9192012-08-15 15:54:54 -0700197}
198
Chet Haase7de0cb12011-12-05 16:35:38 -0800199void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
Chet Haasef942cf12012-08-30 09:06:46 -0700200 uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700201 checkInit();
Romain Guya4adcf02013-02-28 12:15:35 -0800202
203 // If the glyph bitmap is empty let's assum the glyph is valid
204 // so we can avoid doing extra work later on
205 if (glyph.fWidth == 0 || glyph.fHeight == 0) {
206 cachedGlyph->mIsValid = true;
Chris Craikd41c4d82015-01-05 15:51:13 -0800207 cachedGlyph->mCacheTexture = nullptr;
Romain Guya4adcf02013-02-28 12:15:35 -0800208 return;
209 }
210
Chet Haase7de0cb12011-12-05 16:35:38 -0800211 cachedGlyph->mIsValid = false;
Romain Guya4adcf02013-02-28 12:15:35 -0800212
Victoria Lease1e546812013-06-25 14:25:17 -0700213 // choose an appropriate cache texture list for this glyph format
214 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
John Reck272a6852015-07-29 16:48:58 -0700215 std::vector<CacheTexture*>* cacheTextures = nullptr;
Victoria Lease1e546812013-06-25 14:25:17 -0700216 switch (format) {
217 case SkMask::kA8_Format:
Victoria Lease723b2fe2013-08-12 14:38:44 -0700218 case SkMask::kBW_Format:
Victoria Lease1e546812013-06-25 14:25:17 -0700219 cacheTextures = &mACacheTextures;
220 break;
221 case SkMask::kARGB32_Format:
222 cacheTextures = &mRGBACacheTextures;
223 break;
224 default:
225#if DEBUG_FONT_RENDERER
226 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
227#endif
228 return;
229 }
230
Romain Guy694b5192010-07-21 21:33:20 -0700231 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700232 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
Victoria Lease1e546812013-06-25 14:25:17 -0700233 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700234 ALOGE("Font size too large to fit in cache. width, height = %i, %i",
235 (int) glyph.fWidth, (int) glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800236 return;
Romain Guy694b5192010-07-21 21:33:20 -0700237 }
238
239 // Now copy the bitmap into the cache texture
240 uint32_t startX = 0;
241 uint32_t startY = 0;
242
Victoria Lease1e546812013-06-25 14:25:17 -0700243 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700244
Chet Haase378e9192012-08-15 15:54:54 -0700245 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700246 if (!precaching) {
247 // If the new glyph didn't fit and we are not just trying to precache it,
248 // clear out the cache and try again
249 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700250 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700251 }
Romain Guy694b5192010-07-21 21:33:20 -0700252
Chet Haase378e9192012-08-15 15:54:54 -0700253 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700254 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800255 return;
Romain Guy694b5192010-07-21 21:33:20 -0700256 }
257 }
258
Chet Haase378e9192012-08-15 15:54:54 -0700259 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800260
Romain Guy694b5192010-07-21 21:33:20 -0700261 *retOriginX = startX;
262 *retOriginY = startY;
263
264 uint32_t endX = startX + glyph.fWidth;
265 uint32_t endY = startY + glyph.fHeight;
266
Romain Guy80872462012-09-04 16:42:01 -0700267 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700268
Romain Guycf51a412013-04-08 19:40:31 -0700269 if (!cacheTexture->getPixelBuffer()) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800270 Caches::getInstance().textureState().activateTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800271 // Large-glyph texture memory is allocated only as needed
Chris Craike2bb3802015-03-13 15:07:52 -0700272 cacheTexture->allocatePixelBuffer();
Chet Haase7de0cb12011-12-05 16:35:38 -0800273 }
Romain Guy661a87e2013-03-19 15:24:36 -0700274 if (!cacheTexture->mesh()) {
275 cacheTexture->allocateMesh();
276 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700277
Romain Guycf51a412013-04-08 19:40:31 -0700278 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
Victoria Lease1e546812013-06-25 14:25:17 -0700279 uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
280 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700281
Romain Guyb969a0d2013-02-05 14:38:40 -0800282 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800283 switch (format) {
284 case SkMask::kA8_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700285 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
286 - TEXTURE_BORDER_SIZE;
287 // write leading border line
288 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
289 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800290 if (mGammaTable) {
Romain Guy253f2c22016-09-28 17:34:42 -0700291 for (uint32_t cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800292 row = cacheY * cacheWidth;
293 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guy253f2c22016-09-28 17:34:42 -0700294 for (uint32_t cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
Romain Guyb969a0d2013-02-05 14:38:40 -0800295 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800296 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800297 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800298 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800299 }
300 } else {
Romain Guy253f2c22016-09-28 17:34:42 -0700301 for (uint32_t cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800302 row = cacheY * cacheWidth;
303 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
304 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
305 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800306 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700307 }
Victoria Lease1e546812013-06-25 14:25:17 -0700308 // write trailing border line
309 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
310 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
311 break;
312 }
313 case SkMask::kARGB32_Format: {
314 // prep data lengths
315 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
316 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
317 size_t rowSize = formatSize * glyph.fWidth;
318 // prep advances
319 size_t dstStride = formatSize * cacheWidth;
320 // prep indices
321 // - we actually start one row early, and then increment before first copy
322 uint8_t* src = &bitmapBuffer[0 - srcStride];
323 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
324 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
325 uint8_t* dstL = dst - borderSize;
326 uint8_t* dstR = dst + rowSize;
327 // write leading border line
328 memset(dstL, 0, rowSize + 2 * borderSize);
329 // write glyph data
330 while (dst < dstEnd) {
331 memset(dstL += dstStride, 0, borderSize); // leading border column
332 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
333 memset(dstR += dstStride, 0, borderSize); // trailing border column
334 }
335 // write trailing border line
Victoria Lease16c84062013-09-19 15:38:21 -0700336 memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800337 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700338 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800339 case SkMask::kBW_Format: {
Andreas Gampe1e196742014-11-10 15:23:43 -0800340 uint32_t cacheX = 0, cacheY = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700341 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
342 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800343 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700344 // write leading border line
345 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
346 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800347 for (cacheY = startY; cacheY < endY; cacheY++) {
348 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700349 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800350 uint8_t* buffer = bitmapBuffer;
351
Romain Guy0b58a3d2013-03-05 12:16:27 -0800352 row = cacheY * cacheWidth;
353 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800354 while (--rowBytes >= 0) {
355 uint8_t b = *buffer++;
356 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
357 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
358 }
359 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800360 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800361
Victoria Lease1e546812013-06-25 14:25:17 -0700362 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700363 }
Victoria Lease1e546812013-06-25 14:25:17 -0700364 // write trailing border line
365 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
366 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800367 break;
Romain Guy694b5192010-07-21 21:33:20 -0700368 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800369 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700370 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800371 break;
Romain Guy694b5192010-07-21 21:33:20 -0700372 }
Romain Guy97771732012-02-28 18:17:02 -0800373
Chet Haase7de0cb12011-12-05 16:35:38 -0800374 cachedGlyph->mIsValid = true;
sergeyvaf102be2016-09-09 18:02:07 -0700375
376#ifdef BUGREPORT_FONT_CACHE_USAGE
377 mHistoryTracker.glyphUploaded(cacheTexture, startX, startY, glyph.fWidth, glyph.fHeight);
378#endif
Romain Guy694b5192010-07-21 21:33:20 -0700379}
380
Victoria Lease1e546812013-06-25 14:25:17 -0700381CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
382 bool allocate) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800383 CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700384
Chet Haase2a47c142011-12-14 15:22:56 -0800385 if (allocate) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800386 Caches::getInstance().textureState().activateTexture(0);
Chris Craike2bb3802015-03-13 15:07:52 -0700387 cacheTexture->allocatePixelBuffer();
Romain Guy661a87e2013-03-19 15:24:36 -0700388 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800389 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700390
Chet Haase2a47c142011-12-14 15:22:56 -0800391 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800392}
393
394void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700395 clearCacheTextures(mACacheTextures);
396 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700397
Chet Haase7de0cb12011-12-05 16:35:38 -0800398 mUploadTexture = false;
John Reck272a6852015-07-29 16:48:58 -0700399 mACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700400 GL_ALPHA, true));
John Reck272a6852015-07-29 16:48:58 -0700401 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700402 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700403 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700404 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700405 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700406 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700407 mRGBACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700408 GL_RGBA, false));
John Reck272a6852015-07-29 16:48:58 -0700409 mRGBACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700410 GL_RGBA, false));
411 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700412}
413
Romain Guy694b5192010-07-21 21:33:20 -0700414// We don't want to allocate anything unless we actually draw text
415void FontRenderer::checkInit() {
416 if (mInitialized) {
417 return;
418 }
419
420 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700421
422 mInitialized = true;
423}
424
John Reck272a6852015-07-29 16:48:58 -0700425void checkTextureUpdateForCache(Caches& caches, std::vector<CacheTexture*>& cacheTextures,
Victoria Lease1e546812013-06-25 14:25:17 -0700426 bool& resetPixelStore, GLuint& lastTextureId) {
427 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
428 CacheTexture* cacheTexture = cacheTextures[i];
429 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
430 if (cacheTexture->getTextureId() != lastTextureId) {
431 lastTextureId = cacheTexture->getTextureId();
Chris Craik44eb2c02015-01-29 09:45:09 -0800432 caches.textureState().activateTexture(0);
433 caches.textureState().bindTexture(lastTextureId);
Victoria Lease1e546812013-06-25 14:25:17 -0700434 }
435
436 if (cacheTexture->upload()) {
437 resetPixelStore = true;
438 }
439 }
440 }
441}
442
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700443void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900444 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700445 return;
Romain Guy694b5192010-07-21 21:33:20 -0700446 }
447
Romain Guy2d4fd362011-12-13 22:00:19 -0800448 Caches& caches = Caches::getInstance();
449 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700450
Romain Guycf51a412013-04-08 19:40:31 -0700451 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700452
Chet Haase378e9192012-08-15 15:54:54 -0700453 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700454 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
455 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700456
Romain Guycf51a412013-04-08 19:40:31 -0700457 // Unbind any PBO we might have used to update textures
Chris Craik44eb2c02015-01-29 09:45:09 -0800458 caches.pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700459
Romain Guy09087642013-04-04 12:27:54 -0700460 // Reset to default unpack row length to avoid affecting texture
461 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700462 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700463 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
464 }
465
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700466 mUploadTexture = false;
467}
468
John Reck272a6852015-07-29 16:48:58 -0700469void FontRenderer::issueDrawCommand(std::vector<CacheTexture*>& cacheTextures) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800470 if (!mFunctor) return;
471
Romain Guy661a87e2013-03-19 15:24:36 -0700472 bool first = true;
Victoria Lease1e546812013-06-25 14:25:17 -0700473 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
474 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700475 if (texture->canDraw()) {
476 if (first) {
Chris Craike2bb3802015-03-13 15:07:52 -0700477 checkTextureUpdate();
Romain Guy661a87e2013-03-19 15:24:36 -0700478 first = false;
Chris Craik083e7332015-02-27 17:04:20 -0800479 mDrawn = true;
Romain Guy661a87e2013-03-19 15:24:36 -0700480 }
Chris Craik82840732015-04-03 09:37:49 -0700481
Chris Craike2bb3802015-03-13 15:07:52 -0700482 mFunctor->draw(*texture, mLinearFiltering);
Romain Guy661a87e2013-03-19 15:24:36 -0700483
Romain Guy661a87e2013-03-19 15:24:36 -0700484 texture->resetMesh();
Romain Guy115096f2013-03-19 11:32:41 -0700485 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900486 }
Victoria Lease1e546812013-06-25 14:25:17 -0700487}
488
489void FontRenderer::issueDrawCommand() {
490 issueDrawCommand(mACacheTextures);
491 issueDrawCommand(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700492}
493
Romain Guy97771732012-02-28 18:17:02 -0800494void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
495 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
Chet Haase7de0cb12011-12-05 16:35:38 -0800496 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800497 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800498 // Now use the new texture id
499 mCurrentCacheTexture = texture;
500 }
Romain Guy09147fb2010-07-22 13:08:20 -0700501
Romain Guy661a87e2013-03-19 15:24:36 -0700502 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
503 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800504}
505
506void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
507 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
508 float x4, float y4, float u4, float v4, CacheTexture* texture) {
509
510 if (mClip &&
511 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
512 return;
513 }
514
515 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 -0700516
Romain Guy5b3b3522010-10-27 18:57:51 -0700517 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700518 mBounds->left = std::min(mBounds->left, x1);
519 mBounds->top = std::min(mBounds->top, y3);
520 mBounds->right = std::max(mBounds->right, x3);
521 mBounds->bottom = std::max(mBounds->bottom, y1);
Romain Guy5b3b3522010-10-27 18:57:51 -0700522 }
523
Romain Guy661a87e2013-03-19 15:24:36 -0700524 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700525 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700526 }
527}
528
Romain Guy97771732012-02-28 18:17:02 -0800529void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
530 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
531 float x4, float y4, float u4, float v4, CacheTexture* texture) {
532
533 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
534
535 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700536 mBounds->left = std::min(mBounds->left, std::min(x1, std::min(x2, std::min(x3, x4))));
537 mBounds->top = std::min(mBounds->top, std::min(y1, std::min(y2, std::min(y3, y4))));
538 mBounds->right = std::max(mBounds->right, std::max(x1, std::max(x2, std::max(x3, x4))));
539 mBounds->bottom = std::max(mBounds->bottom, std::max(y1, std::max(y2, std::max(y3, y4))));
Romain Guy97771732012-02-28 18:17:02 -0800540 }
541
Romain Guy661a87e2013-03-19 15:24:36 -0700542 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800543 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800544 }
545}
546
Chris Craik59744b72014-07-01 17:56:52 -0700547void FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800548 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700549}
Romain Guy7975fb62010-10-01 16:36:14 -0700550
Chris Craike8c3c812016-02-05 20:10:50 -0800551FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const glyph_t *glyphs,
Chris Craika1717272015-11-19 13:02:43 -0800552 int numGlyphs, float radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700553 checkInit();
554
Romain Guycf51a412013-04-08 19:40:31 -0700555 DropShadow image;
556 image.width = 0;
557 image.height = 0;
Chris Craikd41c4d82015-01-05 15:51:13 -0800558 image.image = nullptr;
Romain Guycf51a412013-04-08 19:40:31 -0700559 image.penX = 0;
560 image.penY = 0;
561
Romain Guy1e45aae2010-08-13 19:39:53 -0700562 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700563 return image;
564 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700565
Romain Guy2d4fd362011-12-13 22:00:19 -0800566 mDrawn = false;
Chris Craikd41c4d82015-01-05 15:51:13 -0800567 mClip = nullptr;
568 mBounds = nullptr;
Romain Guyff98fa52011-11-28 09:35:09 -0800569
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700570 Rect bounds;
Chris Craike8c3c812016-02-05 20:10:50 -0800571 mCurrentFont->measure(paint, glyphs, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800572
Derek Sollenbergere392c812014-05-21 11:25:22 -0400573 uint32_t intRadius = Blur::convertRadiusToInt(radius);
574 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
575 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
Romain Guyff98fa52011-11-28 09:35:09 -0800576
Romain Guycf51a412013-04-08 19:40:31 -0700577 uint32_t maxSize = Caches::getInstance().maxTextureSize;
578 if (paddedWidth > maxSize || paddedHeight > maxSize) {
579 return image;
580 }
581
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800582 // Align buffers for renderscript usage
583 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
584 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700585 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800586 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800587 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700588
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800589 memset(dataBuffer, 0, size);
590
Derek Sollenbergere392c812014-05-21 11:25:22 -0400591 int penX = intRadius - bounds.left;
592 int penY = intRadius - bounds.bottom;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700593
Chris Craikdd8697c2013-02-22 10:41:36 -0800594 if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
595 // text has non-whitespace, so draw and blur to create the shadow
596 // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
597 // TODO: don't draw pure whitespace in the first place, and avoid needing this check
Chris Craike8c3c812016-02-05 20:10:50 -0800598 mCurrentFont->render(paint, glyphs, numGlyphs, penX, penY,
Chris Craikd41c4d82015-01-05 15:51:13 -0800599 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
Chris Craikdd8697c2013-02-22 10:41:36 -0800600
Romain Guycf51a412013-04-08 19:40:31 -0700601 // Unbind any PBO we might have used
Chris Craik44eb2c02015-01-29 09:45:09 -0800602 Caches::getInstance().pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700603
Chris Craikdd8697c2013-02-22 10:41:36 -0800604 blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
605 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700606
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700607 image.width = paddedWidth;
608 image.height = paddedHeight;
609 image.image = dataBuffer;
610 image.penX = penX;
611 image.penY = penY;
Romain Guy2d4fd362011-12-13 22:00:19 -0800612
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700613 return image;
614}
Romain Guy694b5192010-07-21 21:33:20 -0700615
Chris Craik82840732015-04-03 09:37:49 -0700616void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextDrawFunctor* functor) {
Romain Guy694b5192010-07-21 21:33:20 -0700617 checkInit();
618
Romain Guy5b3b3522010-10-27 18:57:51 -0700619 mDrawn = false;
620 mBounds = bounds;
Romain Guy257ae352013-03-20 16:31:12 -0700621 mFunctor = functor;
Romain Guy09147fb2010-07-22 13:08:20 -0700622 mClip = clip;
Romain Guy671d6cf2012-01-18 12:39:17 -0800623}
Romain Guyff98fa52011-11-28 09:35:09 -0800624
Romain Guy671d6cf2012-01-18 12:39:17 -0800625void FontRenderer::finishRender() {
Chris Craikd41c4d82015-01-05 15:51:13 -0800626 mBounds = nullptr;
627 mClip = nullptr;
Romain Guy694b5192010-07-21 21:33:20 -0700628
Romain Guy661a87e2013-03-19 15:24:36 -0700629 issueDrawCommand();
Romain Guy671d6cf2012-01-18 12:39:17 -0800630}
631
Chris Craike8c3c812016-02-05 20:10:50 -0800632void FontRenderer::precache(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs,
Chris Craik59744b72014-07-01 17:56:52 -0700633 const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800634 Font* font = Font::create(this, paint, matrix);
Chris Craike8c3c812016-02-05 20:10:50 -0800635 font->precache(paint, glyphs, numGlyphs);
Chet Haasee816bae2012-08-09 13:39:02 -0700636}
637
Romain Guycf51a412013-04-08 19:40:31 -0700638void FontRenderer::endPrecaching() {
639 checkTextureUpdate();
640}
641
Chris Craike8c3c812016-02-05 20:10:50 -0800642bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
Chris Craika1717272015-11-19 13:02:43 -0800643 int numGlyphs, int x, int y, const float* positions,
644 Rect* bounds, TextDrawFunctor* functor, bool forceFinish) {
Romain Guy671d6cf2012-01-18 12:39:17 -0800645 if (!mCurrentFont) {
646 ALOGE("No font set");
647 return false;
648 }
649
Romain Guy257ae352013-03-20 16:31:12 -0700650 initRender(clip, bounds, functor);
Chris Craike8c3c812016-02-05 20:10:50 -0800651 mCurrentFont->render(paint, glyphs, numGlyphs, x, y, positions);
Chris Craik527a3aa2013-03-04 10:19:31 -0800652
653 if (forceFinish) {
654 finishRender();
655 }
Romain Guy5b3b3522010-10-27 18:57:51 -0700656
657 return mDrawn;
Romain Guy694b5192010-07-21 21:33:20 -0700658}
659
Chris Craike8c3c812016-02-05 20:10:50 -0800660bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
Chris Craika1717272015-11-19 13:02:43 -0800661 int numGlyphs, const SkPath* path, float hOffset, float vOffset,
662 Rect* bounds, TextDrawFunctor* functor) {
Romain Guy97771732012-02-28 18:17:02 -0800663 if (!mCurrentFont) {
664 ALOGE("No font set");
665 return false;
666 }
667
Victoria Lease1e546812013-06-25 14:25:17 -0700668 initRender(clip, bounds, functor);
Chris Craike8c3c812016-02-05 20:10:50 -0800669 mCurrentFont->render(paint, glyphs, numGlyphs, path, hOffset, vOffset);
Romain Guy97771732012-02-28 18:17:02 -0800670 finishRender();
671
672 return mDrawn;
673}
674
Derek Sollenbergere392c812014-05-21 11:25:22 -0400675void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
676 uint32_t intRadius = Blur::convertRadiusToInt(radius);
Chris Craikf3754a82016-04-19 18:13:21 -0700677 if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF && radius <= 25.0f) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700678 uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700679
Chris Craikd41c4d82015-01-05 15:51:13 -0800680 if (mRs == nullptr) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700681 mRs = new RSC::RS();
Tim Murrayabe55e92013-12-13 12:57:36 -0800682 // a null path is OK because there are no custom kernels used
683 // hence nothing gets cached by RS
684 if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800685 mRs.clear();
Dan Morrille4d9a012013-03-28 18:10:43 -0700686 ALOGE("blur RS failed to init");
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800687 } else {
688 mRsElement = RSC::Element::A_8(mRs);
689 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Dan Morrille4d9a012013-03-28 18:10:43 -0700690 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800691 }
Chris Craikd41c4d82015-01-05 15:51:13 -0800692 if (mRs != nullptr) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800693 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
694 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
695 RS_ALLOCATION_MIPMAP_NONE,
696 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
697 *image);
698 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
699 RS_ALLOCATION_MIPMAP_NONE,
700 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
701 outImage);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800702
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800703 mRsScript->setRadius(radius);
704 mRsScript->setInput(ain);
705 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700706
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800707 // replace the original image's pointer, avoiding a copy back to the original buffer
708 free(*image);
709 *image = outImage;
Dan Morrille4d9a012013-03-28 18:10:43 -0700710
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800711 return;
712 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800713 }
714
Chris Craik51d6a3d2014-12-22 17:16:56 -0800715 std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
huanhuan.x.wanga46ca5e2015-04-14 16:23:15 +0200716 Blur::generateGaussianWeights(gaussian.get(), radius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800717
Chris Craik51d6a3d2014-12-22 17:16:56 -0800718 std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
719 Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
720 Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700721}
722
John Reck272a6852015-07-29 16:48:58 -0700723static uint32_t calculateCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700724 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700725 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
726 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700727 if (cacheTexture && cacheTexture->getPixelBuffer()) {
728 size += cacheTexture->getPixelBuffer()->getSize();
729 }
730 }
731 return size;
732}
733
sergeyvbaf29e72016-09-08 11:09:34 -0700734static uint32_t calculateFreeCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
735 uint32_t size = 0;
736 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
737 CacheTexture* cacheTexture = cacheTextures[i];
738 if (cacheTexture && cacheTexture->getPixelBuffer()) {
739 size += cacheTexture->calculateFreeMemory();
Victoria Lease1e546812013-06-25 14:25:17 -0700740 }
741 }
sergeyvbaf29e72016-09-08 11:09:34 -0700742 return size;
743}
744
745const std::vector<CacheTexture*>& FontRenderer::cacheTexturesForFormat(GLenum format) const {
746 switch (format) {
747 case GL_ALPHA: {
748 return mACacheTextures;
749 }
750 case GL_RGBA: {
751 return mRGBACacheTextures;
752 }
753 default: {
754 LOG_ALWAYS_FATAL("Unsupported format: %d", format);
755 // Impossible to hit this, but the compiler doesn't know that
756 return *(new std::vector<CacheTexture*>());
757 }
758 }
759}
760
761static void dumpTextures(String8& log, const char* tag,
762 const std::vector<CacheTexture*>& cacheTextures) {
763 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
764 CacheTexture* cacheTexture = cacheTextures[i];
765 if (cacheTexture && cacheTexture->getPixelBuffer()) {
766 uint32_t free = cacheTexture->calculateFreeMemory();
767 uint32_t total = cacheTexture->getPixelBuffer()->getSize();
768 log.appendFormat(" %-4s texture %d %8d / %8d\n", tag, i, total - free, total);
769 }
770 }
771}
772
773void FontRenderer::dumpMemoryUsage(String8& log) const {
774 const uint32_t sizeA8 = getCacheSize(GL_ALPHA);
775 const uint32_t usedA8 = sizeA8 - getFreeCacheSize(GL_ALPHA);
776 const uint32_t sizeRGBA = getCacheSize(GL_RGBA);
777 const uint32_t usedRGBA = sizeRGBA - getFreeCacheSize(GL_RGBA);
778 log.appendFormat(" FontRenderer A8 %8d / %8d\n", usedA8, sizeA8);
779 dumpTextures(log, "A8", cacheTexturesForFormat(GL_ALPHA));
780 log.appendFormat(" FontRenderer RGBA %8d / %8d\n", usedRGBA, sizeRGBA);
781 dumpTextures(log, "RGBA", cacheTexturesForFormat(GL_RGBA));
782 log.appendFormat(" FontRenderer total %8d / %8d\n", usedA8 + usedRGBA, sizeA8 + sizeRGBA);
783}
784
785uint32_t FontRenderer::getCacheSize(GLenum format) const {
786 return calculateCacheSize(cacheTexturesForFormat(format));
787}
788
789uint32_t FontRenderer::getFreeCacheSize(GLenum format) const {
790 return calculateFreeCacheSize(cacheTexturesForFormat(format));
791}
792
793uint32_t FontRenderer::getSize() const {
794 return getCacheSize(GL_ALPHA) + getCacheSize(GL_RGBA);
Victoria Lease1e546812013-06-25 14:25:17 -0700795}
796
Romain Guy694b5192010-07-21 21:33:20 -0700797}; // namespace uirenderer
798}; // namespace android