blob: 25dc92c8a8dc3d530a2998dbcfe0333f2326e1ab [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();
154 }
155
156 for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
157 mRGBACacheTextures[i]->init();
Romain Guy694b5192010-07-21 21:33:20 -0700158 }
chaochen1f61b192014-08-28 18:45:27 -0700159
160 mDrawn = false;
Romain Guy694b5192010-07-21 21:33:20 -0700161}
162
John Reck272a6852015-07-29 16:48:58 -0700163void FontRenderer::flushLargeCaches(std::vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700164 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700165 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
166 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700167 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700168 cacheTexture->init();
Romain Guye3a9b242013-01-08 11:15:30 -0800169 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
170 while (it.next()) {
171 it.value()->invalidateTextureCache(cacheTexture);
Chet Haasee816bae2012-08-09 13:39:02 -0700172 }
Chris Craike2bb3802015-03-13 15:07:52 -0700173 cacheTexture->releasePixelBuffer();
Chet Haase9a824562011-12-16 15:44:59 -0800174 }
175 }
Chet Haase9a824562011-12-16 15:44:59 -0800176}
177
Victoria Lease1e546812013-06-25 14:25:17 -0700178void FontRenderer::flushLargeCaches() {
179 flushLargeCaches(mACacheTextures);
180 flushLargeCaches(mRGBACacheTextures);
181}
182
John Reck272a6852015-07-29 16:48:58 -0700183CacheTexture* FontRenderer::cacheBitmapInTexture(std::vector<CacheTexture*>& cacheTextures,
Victoria Lease1e546812013-06-25 14:25:17 -0700184 const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
185 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
186 if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
187 return cacheTextures[i];
Chet Haase378e9192012-08-15 15:54:54 -0700188 }
189 }
190 // Could not fit glyph into current cache textures
Chris Craikd41c4d82015-01-05 15:51:13 -0800191 return nullptr;
Chet Haase378e9192012-08-15 15:54:54 -0700192}
193
Chet Haase7de0cb12011-12-05 16:35:38 -0800194void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
Chet Haasef942cf12012-08-30 09:06:46 -0700195 uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700196 checkInit();
Romain Guya4adcf02013-02-28 12:15:35 -0800197
198 // If the glyph bitmap is empty let's assum the glyph is valid
199 // so we can avoid doing extra work later on
200 if (glyph.fWidth == 0 || glyph.fHeight == 0) {
201 cachedGlyph->mIsValid = true;
Chris Craikd41c4d82015-01-05 15:51:13 -0800202 cachedGlyph->mCacheTexture = nullptr;
Romain Guya4adcf02013-02-28 12:15:35 -0800203 return;
204 }
205
Chet Haase7de0cb12011-12-05 16:35:38 -0800206 cachedGlyph->mIsValid = false;
Romain Guya4adcf02013-02-28 12:15:35 -0800207
Victoria Lease1e546812013-06-25 14:25:17 -0700208 // choose an appropriate cache texture list for this glyph format
209 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
John Reck272a6852015-07-29 16:48:58 -0700210 std::vector<CacheTexture*>* cacheTextures = nullptr;
Victoria Lease1e546812013-06-25 14:25:17 -0700211 switch (format) {
212 case SkMask::kA8_Format:
Victoria Lease723b2fe2013-08-12 14:38:44 -0700213 case SkMask::kBW_Format:
Victoria Lease1e546812013-06-25 14:25:17 -0700214 cacheTextures = &mACacheTextures;
215 break;
216 case SkMask::kARGB32_Format:
217 cacheTextures = &mRGBACacheTextures;
218 break;
219 default:
220#if DEBUG_FONT_RENDERER
221 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
222#endif
223 return;
224 }
225
Romain Guy694b5192010-07-21 21:33:20 -0700226 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700227 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
Victoria Lease1e546812013-06-25 14:25:17 -0700228 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700229 ALOGE("Font size too large to fit in cache. width, height = %i, %i",
230 (int) glyph.fWidth, (int) glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800231 return;
Romain Guy694b5192010-07-21 21:33:20 -0700232 }
233
234 // Now copy the bitmap into the cache texture
235 uint32_t startX = 0;
236 uint32_t startY = 0;
237
Victoria Lease1e546812013-06-25 14:25:17 -0700238 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700239
Chet Haase378e9192012-08-15 15:54:54 -0700240 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700241 if (!precaching) {
242 // If the new glyph didn't fit and we are not just trying to precache it,
243 // clear out the cache and try again
244 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700245 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700246 }
Romain Guy694b5192010-07-21 21:33:20 -0700247
Chet Haase378e9192012-08-15 15:54:54 -0700248 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700249 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800250 return;
Romain Guy694b5192010-07-21 21:33:20 -0700251 }
252 }
253
Chet Haase378e9192012-08-15 15:54:54 -0700254 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800255
Romain Guy694b5192010-07-21 21:33:20 -0700256 *retOriginX = startX;
257 *retOriginY = startY;
258
259 uint32_t endX = startX + glyph.fWidth;
260 uint32_t endY = startY + glyph.fHeight;
261
Romain Guy80872462012-09-04 16:42:01 -0700262 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700263
Romain Guycf51a412013-04-08 19:40:31 -0700264 if (!cacheTexture->getPixelBuffer()) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800265 Caches::getInstance().textureState().activateTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800266 // Large-glyph texture memory is allocated only as needed
Chris Craike2bb3802015-03-13 15:07:52 -0700267 cacheTexture->allocatePixelBuffer();
Chet Haase7de0cb12011-12-05 16:35:38 -0800268 }
Romain Guy661a87e2013-03-19 15:24:36 -0700269 if (!cacheTexture->mesh()) {
270 cacheTexture->allocateMesh();
271 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700272
Romain Guycf51a412013-04-08 19:40:31 -0700273 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
Victoria Lease1e546812013-06-25 14:25:17 -0700274 uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
275 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700276
Romain Guyb969a0d2013-02-05 14:38:40 -0800277 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800278 switch (format) {
279 case SkMask::kA8_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700280 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
281 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
282 - TEXTURE_BORDER_SIZE;
283 // write leading border line
284 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
285 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800286 if (mGammaTable) {
Victoria Lease1e546812013-06-25 14:25:17 -0700287 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800288 row = cacheY * cacheWidth;
289 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800290 for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
291 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800292 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800293 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800294 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800295 }
296 } else {
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 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
300 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
301 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800302 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700303 }
Victoria Lease1e546812013-06-25 14:25:17 -0700304 // write trailing border line
305 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
306 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
307 break;
308 }
309 case SkMask::kARGB32_Format: {
310 // prep data lengths
311 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
312 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
313 size_t rowSize = formatSize * glyph.fWidth;
314 // prep advances
315 size_t dstStride = formatSize * cacheWidth;
316 // prep indices
317 // - we actually start one row early, and then increment before first copy
318 uint8_t* src = &bitmapBuffer[0 - srcStride];
319 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
320 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
321 uint8_t* dstL = dst - borderSize;
322 uint8_t* dstR = dst + rowSize;
323 // write leading border line
324 memset(dstL, 0, rowSize + 2 * borderSize);
325 // write glyph data
326 while (dst < dstEnd) {
327 memset(dstL += dstStride, 0, borderSize); // leading border column
328 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
329 memset(dstR += dstStride, 0, borderSize); // trailing border column
330 }
331 // write trailing border line
Victoria Lease16c84062013-09-19 15:38:21 -0700332 memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800333 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700334 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800335 case SkMask::kBW_Format: {
Andreas Gampe1e196742014-11-10 15:23:43 -0800336 uint32_t cacheX = 0, cacheY = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700337 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
338 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800339 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700340 // write leading border line
341 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
342 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800343 for (cacheY = startY; cacheY < endY; cacheY++) {
344 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700345 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800346 uint8_t* buffer = bitmapBuffer;
347
Romain Guy0b58a3d2013-03-05 12:16:27 -0800348 row = cacheY * cacheWidth;
349 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800350 while (--rowBytes >= 0) {
351 uint8_t b = *buffer++;
352 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
353 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
354 }
355 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800356 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800357
Victoria Lease1e546812013-06-25 14:25:17 -0700358 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700359 }
Victoria Lease1e546812013-06-25 14:25:17 -0700360 // write trailing border line
361 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
362 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800363 break;
Romain Guy694b5192010-07-21 21:33:20 -0700364 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800365 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700366 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800367 break;
Romain Guy694b5192010-07-21 21:33:20 -0700368 }
Romain Guy97771732012-02-28 18:17:02 -0800369
Chet Haase7de0cb12011-12-05 16:35:38 -0800370 cachedGlyph->mIsValid = true;
Romain Guy694b5192010-07-21 21:33:20 -0700371}
372
Victoria Lease1e546812013-06-25 14:25:17 -0700373CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
374 bool allocate) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800375 CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700376
Chet Haase2a47c142011-12-14 15:22:56 -0800377 if (allocate) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800378 Caches::getInstance().textureState().activateTexture(0);
Chris Craike2bb3802015-03-13 15:07:52 -0700379 cacheTexture->allocatePixelBuffer();
Romain Guy661a87e2013-03-19 15:24:36 -0700380 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800381 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700382
Chet Haase2a47c142011-12-14 15:22:56 -0800383 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800384}
385
386void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700387 clearCacheTextures(mACacheTextures);
388 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700389
Chet Haase7de0cb12011-12-05 16:35:38 -0800390 mUploadTexture = false;
John Reck272a6852015-07-29 16:48:58 -0700391 mACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700392 GL_ALPHA, true));
John Reck272a6852015-07-29 16:48:58 -0700393 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700394 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700395 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700396 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700397 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700398 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700399 mRGBACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700400 GL_RGBA, false));
John Reck272a6852015-07-29 16:48:58 -0700401 mRGBACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700402 GL_RGBA, false));
403 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700404}
405
Romain Guy694b5192010-07-21 21:33:20 -0700406// We don't want to allocate anything unless we actually draw text
407void FontRenderer::checkInit() {
408 if (mInitialized) {
409 return;
410 }
411
412 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700413
414 mInitialized = true;
415}
416
John Reck272a6852015-07-29 16:48:58 -0700417void checkTextureUpdateForCache(Caches& caches, std::vector<CacheTexture*>& cacheTextures,
Victoria Lease1e546812013-06-25 14:25:17 -0700418 bool& resetPixelStore, GLuint& lastTextureId) {
419 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
420 CacheTexture* cacheTexture = cacheTextures[i];
421 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
422 if (cacheTexture->getTextureId() != lastTextureId) {
423 lastTextureId = cacheTexture->getTextureId();
Chris Craik44eb2c02015-01-29 09:45:09 -0800424 caches.textureState().activateTexture(0);
425 caches.textureState().bindTexture(lastTextureId);
Victoria Lease1e546812013-06-25 14:25:17 -0700426 }
427
428 if (cacheTexture->upload()) {
429 resetPixelStore = true;
430 }
431 }
432 }
433}
434
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700435void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900436 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700437 return;
Romain Guy694b5192010-07-21 21:33:20 -0700438 }
439
Romain Guy2d4fd362011-12-13 22:00:19 -0800440 Caches& caches = Caches::getInstance();
441 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700442
Romain Guycf51a412013-04-08 19:40:31 -0700443 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700444
Chet Haase378e9192012-08-15 15:54:54 -0700445 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700446 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
447 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700448
Romain Guycf51a412013-04-08 19:40:31 -0700449 // Unbind any PBO we might have used to update textures
Chris Craik44eb2c02015-01-29 09:45:09 -0800450 caches.pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700451
Romain Guy09087642013-04-04 12:27:54 -0700452 // Reset to default unpack row length to avoid affecting texture
453 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700454 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700455 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
456 }
457
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700458 mUploadTexture = false;
459}
460
John Reck272a6852015-07-29 16:48:58 -0700461void FontRenderer::issueDrawCommand(std::vector<CacheTexture*>& cacheTextures) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800462 if (!mFunctor) return;
463
Romain Guy661a87e2013-03-19 15:24:36 -0700464 bool first = true;
Victoria Lease1e546812013-06-25 14:25:17 -0700465 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
466 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700467 if (texture->canDraw()) {
468 if (first) {
Chris Craike2bb3802015-03-13 15:07:52 -0700469 checkTextureUpdate();
Romain Guy661a87e2013-03-19 15:24:36 -0700470 first = false;
Chris Craik083e7332015-02-27 17:04:20 -0800471 mDrawn = true;
Romain Guy661a87e2013-03-19 15:24:36 -0700472 }
Chris Craik82840732015-04-03 09:37:49 -0700473
Chris Craike2bb3802015-03-13 15:07:52 -0700474 mFunctor->draw(*texture, mLinearFiltering);
Romain Guy661a87e2013-03-19 15:24:36 -0700475
Romain Guy661a87e2013-03-19 15:24:36 -0700476 texture->resetMesh();
Romain Guy115096f2013-03-19 11:32:41 -0700477 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900478 }
Victoria Lease1e546812013-06-25 14:25:17 -0700479}
480
481void FontRenderer::issueDrawCommand() {
482 issueDrawCommand(mACacheTextures);
483 issueDrawCommand(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700484}
485
Romain Guy97771732012-02-28 18:17:02 -0800486void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
487 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
Chet Haase7de0cb12011-12-05 16:35:38 -0800488 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800489 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800490 // Now use the new texture id
491 mCurrentCacheTexture = texture;
492 }
Romain Guy09147fb2010-07-22 13:08:20 -0700493
Romain Guy661a87e2013-03-19 15:24:36 -0700494 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
495 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800496}
497
498void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
499 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
500 float x4, float y4, float u4, float v4, CacheTexture* texture) {
501
502 if (mClip &&
503 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
504 return;
505 }
506
507 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 -0700508
Romain Guy5b3b3522010-10-27 18:57:51 -0700509 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700510 mBounds->left = std::min(mBounds->left, x1);
511 mBounds->top = std::min(mBounds->top, y3);
512 mBounds->right = std::max(mBounds->right, x3);
513 mBounds->bottom = std::max(mBounds->bottom, y1);
Romain Guy5b3b3522010-10-27 18:57:51 -0700514 }
515
Romain Guy661a87e2013-03-19 15:24:36 -0700516 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700517 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700518 }
519}
520
Romain Guy97771732012-02-28 18:17:02 -0800521void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
522 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
523 float x4, float y4, float u4, float v4, CacheTexture* texture) {
524
525 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
526
527 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700528 mBounds->left = std::min(mBounds->left, std::min(x1, std::min(x2, std::min(x3, x4))));
529 mBounds->top = std::min(mBounds->top, std::min(y1, std::min(y2, std::min(y3, y4))));
530 mBounds->right = std::max(mBounds->right, std::max(x1, std::max(x2, std::max(x3, x4))));
531 mBounds->bottom = std::max(mBounds->bottom, std::max(y1, std::max(y2, std::max(y3, y4))));
Romain Guy97771732012-02-28 18:17:02 -0800532 }
533
Romain Guy661a87e2013-03-19 15:24:36 -0700534 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800535 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800536 }
537}
538
Chris Craik59744b72014-07-01 17:56:52 -0700539void FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800540 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700541}
Romain Guy7975fb62010-10-01 16:36:14 -0700542
Chris Craike8c3c812016-02-05 20:10:50 -0800543FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const glyph_t *glyphs,
Chris Craika1717272015-11-19 13:02:43 -0800544 int numGlyphs, float radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700545 checkInit();
546
Romain Guycf51a412013-04-08 19:40:31 -0700547 DropShadow image;
548 image.width = 0;
549 image.height = 0;
Chris Craikd41c4d82015-01-05 15:51:13 -0800550 image.image = nullptr;
Romain Guycf51a412013-04-08 19:40:31 -0700551 image.penX = 0;
552 image.penY = 0;
553
Romain Guy1e45aae2010-08-13 19:39:53 -0700554 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700555 return image;
556 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700557
Romain Guy2d4fd362011-12-13 22:00:19 -0800558 mDrawn = false;
Chris Craikd41c4d82015-01-05 15:51:13 -0800559 mClip = nullptr;
560 mBounds = nullptr;
Romain Guyff98fa52011-11-28 09:35:09 -0800561
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700562 Rect bounds;
Chris Craike8c3c812016-02-05 20:10:50 -0800563 mCurrentFont->measure(paint, glyphs, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800564
Derek Sollenbergere392c812014-05-21 11:25:22 -0400565 uint32_t intRadius = Blur::convertRadiusToInt(radius);
566 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
567 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
Romain Guyff98fa52011-11-28 09:35:09 -0800568
Romain Guycf51a412013-04-08 19:40:31 -0700569 uint32_t maxSize = Caches::getInstance().maxTextureSize;
570 if (paddedWidth > maxSize || paddedHeight > maxSize) {
571 return image;
572 }
573
Dan Morrille4d9a012013-03-28 18:10:43 -0700574#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800575 // Align buffers for renderscript usage
576 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
577 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700578 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800579 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800580 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700581#else
582 int size = paddedWidth * paddedHeight;
583 uint8_t* dataBuffer = (uint8_t*) malloc(size);
584#endif
585
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800586 memset(dataBuffer, 0, size);
587
Derek Sollenbergere392c812014-05-21 11:25:22 -0400588 int penX = intRadius - bounds.left;
589 int penY = intRadius - bounds.bottom;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700590
Chris Craikdd8697c2013-02-22 10:41:36 -0800591 if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
592 // text has non-whitespace, so draw and blur to create the shadow
593 // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
594 // TODO: don't draw pure whitespace in the first place, and avoid needing this check
Chris Craike8c3c812016-02-05 20:10:50 -0800595 mCurrentFont->render(paint, glyphs, numGlyphs, penX, penY,
Chris Craikd41c4d82015-01-05 15:51:13 -0800596 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
Chris Craikdd8697c2013-02-22 10:41:36 -0800597
Romain Guycf51a412013-04-08 19:40:31 -0700598 // Unbind any PBO we might have used
Chris Craik44eb2c02015-01-29 09:45:09 -0800599 Caches::getInstance().pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700600
Chris Craikdd8697c2013-02-22 10:41:36 -0800601 blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
602 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700603
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700604 image.width = paddedWidth;
605 image.height = paddedHeight;
606 image.image = dataBuffer;
607 image.penX = penX;
608 image.penY = penY;
Romain Guy2d4fd362011-12-13 22:00:19 -0800609
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700610 return image;
611}
Romain Guy694b5192010-07-21 21:33:20 -0700612
Chris Craik82840732015-04-03 09:37:49 -0700613void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextDrawFunctor* functor) {
Romain Guy694b5192010-07-21 21:33:20 -0700614 checkInit();
615
Romain Guy5b3b3522010-10-27 18:57:51 -0700616 mDrawn = false;
617 mBounds = bounds;
Romain Guy257ae352013-03-20 16:31:12 -0700618 mFunctor = functor;
Romain Guy09147fb2010-07-22 13:08:20 -0700619 mClip = clip;
Romain Guy671d6cf2012-01-18 12:39:17 -0800620}
Romain Guyff98fa52011-11-28 09:35:09 -0800621
Romain Guy671d6cf2012-01-18 12:39:17 -0800622void FontRenderer::finishRender() {
Chris Craikd41c4d82015-01-05 15:51:13 -0800623 mBounds = nullptr;
624 mClip = nullptr;
Romain Guy694b5192010-07-21 21:33:20 -0700625
Romain Guy661a87e2013-03-19 15:24:36 -0700626 issueDrawCommand();
Romain Guy671d6cf2012-01-18 12:39:17 -0800627}
628
Chris Craike8c3c812016-02-05 20:10:50 -0800629void FontRenderer::precache(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs,
Chris Craik59744b72014-07-01 17:56:52 -0700630 const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800631 Font* font = Font::create(this, paint, matrix);
Chris Craike8c3c812016-02-05 20:10:50 -0800632 font->precache(paint, glyphs, numGlyphs);
Chet Haasee816bae2012-08-09 13:39:02 -0700633}
634
Romain Guycf51a412013-04-08 19:40:31 -0700635void FontRenderer::endPrecaching() {
636 checkTextureUpdate();
637}
638
Chris Craike8c3c812016-02-05 20:10:50 -0800639bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
Chris Craika1717272015-11-19 13:02:43 -0800640 int numGlyphs, int x, int y, const float* positions,
641 Rect* bounds, TextDrawFunctor* functor, bool forceFinish) {
Romain Guy671d6cf2012-01-18 12:39:17 -0800642 if (!mCurrentFont) {
643 ALOGE("No font set");
644 return false;
645 }
646
Romain Guy257ae352013-03-20 16:31:12 -0700647 initRender(clip, bounds, functor);
Chris Craike8c3c812016-02-05 20:10:50 -0800648 mCurrentFont->render(paint, glyphs, numGlyphs, x, y, positions);
Chris Craik527a3aa2013-03-04 10:19:31 -0800649
650 if (forceFinish) {
651 finishRender();
652 }
Romain Guy5b3b3522010-10-27 18:57:51 -0700653
654 return mDrawn;
Romain Guy694b5192010-07-21 21:33:20 -0700655}
656
Chris Craike8c3c812016-02-05 20:10:50 -0800657bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
Chris Craika1717272015-11-19 13:02:43 -0800658 int numGlyphs, const SkPath* path, float hOffset, float vOffset,
659 Rect* bounds, TextDrawFunctor* functor) {
Romain Guy97771732012-02-28 18:17:02 -0800660 if (!mCurrentFont) {
661 ALOGE("No font set");
662 return false;
663 }
664
Victoria Lease1e546812013-06-25 14:25:17 -0700665 initRender(clip, bounds, functor);
Chris Craike8c3c812016-02-05 20:10:50 -0800666 mCurrentFont->render(paint, glyphs, numGlyphs, path, hOffset, vOffset);
Romain Guy97771732012-02-28 18:17:02 -0800667 finishRender();
668
669 return mDrawn;
670}
671
Derek Sollenbergere392c812014-05-21 11:25:22 -0400672void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
673 uint32_t intRadius = Blur::convertRadiusToInt(radius);
Dan Morrille4d9a012013-03-28 18:10:43 -0700674#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf3754a82016-04-19 18:13:21 -0700675 if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF && radius <= 25.0f) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700676 uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700677
Chris Craikd41c4d82015-01-05 15:51:13 -0800678 if (mRs == nullptr) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700679 mRs = new RSC::RS();
Tim Murrayabe55e92013-12-13 12:57:36 -0800680 // a null path is OK because there are no custom kernels used
681 // hence nothing gets cached by RS
682 if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800683 mRs.clear();
Dan Morrille4d9a012013-03-28 18:10:43 -0700684 ALOGE("blur RS failed to init");
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800685 } else {
686 mRsElement = RSC::Element::A_8(mRs);
687 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Dan Morrille4d9a012013-03-28 18:10:43 -0700688 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800689 }
Chris Craikd41c4d82015-01-05 15:51:13 -0800690 if (mRs != nullptr) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800691 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
692 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
693 RS_ALLOCATION_MIPMAP_NONE,
694 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
695 *image);
696 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
697 RS_ALLOCATION_MIPMAP_NONE,
698 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
699 outImage);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800700
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800701 mRsScript->setRadius(radius);
702 mRsScript->setInput(ain);
703 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700704
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800705 // replace the original image's pointer, avoiding a copy back to the original buffer
706 free(*image);
707 *image = outImage;
Dan Morrille4d9a012013-03-28 18:10:43 -0700708
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800709 return;
710 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800711 }
Dan Morrille4d9a012013-03-28 18:10:43 -0700712#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800713
Chris Craik51d6a3d2014-12-22 17:16:56 -0800714 std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
huanhuan.x.wanga46ca5e2015-04-14 16:23:15 +0200715 Blur::generateGaussianWeights(gaussian.get(), radius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800716
Chris Craik51d6a3d2014-12-22 17:16:56 -0800717 std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
718 Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
719 Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700720}
721
John Reck272a6852015-07-29 16:48:58 -0700722static uint32_t calculateCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700723 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700724 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
725 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700726 if (cacheTexture && cacheTexture->getPixelBuffer()) {
727 size += cacheTexture->getPixelBuffer()->getSize();
728 }
729 }
730 return size;
731}
732
Victoria Lease1e546812013-06-25 14:25:17 -0700733uint32_t FontRenderer::getCacheSize(GLenum format) const {
734 switch (format) {
735 case GL_ALPHA: {
736 return calculateCacheSize(mACacheTextures);
737 }
738 case GL_RGBA: {
739 return calculateCacheSize(mRGBACacheTextures);
740 }
741 default: {
742 return 0;
743 }
744 }
745}
746
Romain Guy694b5192010-07-21 21:33:20 -0700747}; // namespace uirenderer
748}; // namespace android