blob: 56380db03602fb3f5e333a30f6fa1b4d5c1d8234 [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
19#include "Caches.h"
20#include "Debug.h"
21#include "Extensions.h"
Chris Craike2bb3802015-03-13 15:07:52 -070022#include "Glop.h"
23#include "GlopBuilder.h"
Chris Craik96a5c4c2015-01-27 15:46:35 -080024#include "OpenGLRenderer.h"
25#include "PixelBuffer.h"
26#include "Rect.h"
27#include "renderstate/RenderState.h"
28#include "utils/Blur.h"
Chris Craik083e7332015-02-27 17:04:20 -080029#include "utils/MathUtils.h"
Chris Craik96a5c4c2015-01-27 15:46:35 -080030#include "utils/Timing.h"
Romain Guy694b5192010-07-21 21:33:20 -070031
Derek Sollenbergerca79cf62012-08-14 16:44:52 -040032#include <SkGlyph.h>
Romain Guy694b5192010-07-21 21:33:20 -070033#include <SkUtils.h>
34
Romain Guy51769a62010-07-23 00:28:00 -070035#include <cutils/properties.h>
Romain Guye2d345e2010-09-24 18:39:22 -070036
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 Craike2bb3802015-03-13 15:07:52 -070054 int textureFillFlags = static_cast<int>(texture.getFormat() == GL_ALPHA
55 ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone);
56 if (linearFiltering) {
57 textureFillFlags |= TextureFillFlags::kForceFilter;
58 }
59 const Matrix4& transform = pureTranslate ? Matrix4::identity() : *(renderer->currentTransform());
60 Glop glop;
61 GlopBuilder(renderer->mRenderState, renderer->mCaches, &glop)
62 .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
63 .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, renderer->currentSnapshot()->alpha)
64 .setTransform(renderer->currentSnapshot()->getOrthoMatrix(), transform, false)
65 .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
66 .setRoundRectClipState(renderer->currentSnapshot()->roundRectClipState)
67 .build();
68 renderer->renderGlop(glop);
Victoria Lease1e546812013-06-25 14:25:17 -070069}
70
71///////////////////////////////////////////////////////////////////////////////
Romain Guy694b5192010-07-21 21:33:20 -070072// FontRenderer
73///////////////////////////////////////////////////////////////////////////////
74
Romain Guy514fb182011-01-19 14:38:29 -080075static bool sLogFontRendererCreate = true;
76
Chris Craik083e7332015-02-27 17:04:20 -080077FontRenderer::FontRenderer()
78 : mGammaTable(nullptr)
79 , mCurrentFont(nullptr)
80 , mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity)
81 , mCurrentCacheTexture(nullptr)
82 , mUploadTexture(false)
83 , mFunctor(nullptr)
84 , mClip(nullptr)
85 , mBounds(nullptr)
86 , mDrawn(false)
87 , mInitialized(false)
88 , mLinearFiltering(false) {
Romain Guye3a9b242013-01-08 11:15:30 -080089
Romain Guyc9855a52011-01-21 21:14:15 -080090 if (sLogFontRendererCreate) {
91 INIT_LOGD("Creating FontRenderer");
92 }
Romain Guy51769a62010-07-23 00:28:00 -070093
Chet Haaseeb32a492012-08-31 13:54:03 -070094 mSmallCacheWidth = DEFAULT_TEXT_SMALL_CACHE_WIDTH;
95 mSmallCacheHeight = DEFAULT_TEXT_SMALL_CACHE_HEIGHT;
96 mLargeCacheWidth = DEFAULT_TEXT_LARGE_CACHE_WIDTH;
97 mLargeCacheHeight = DEFAULT_TEXT_LARGE_CACHE_HEIGHT;
Romain Guy51769a62010-07-23 00:28:00 -070098
99 char property[PROPERTY_VALUE_MAX];
Chris Craikd41c4d82015-01-05 15:51:13 -0800100 if (property_get(PROPERTY_TEXT_SMALL_CACHE_WIDTH, property, nullptr) > 0) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800101 mSmallCacheWidth = atoi(property);
Romain Guy51769a62010-07-23 00:28:00 -0700102 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700103
Chris Craikd41c4d82015-01-05 15:51:13 -0800104 if (property_get(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, property, nullptr) > 0) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800105 mSmallCacheHeight = atoi(property);
Chet Haaseeb32a492012-08-31 13:54:03 -0700106 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700107
Chris Craikd41c4d82015-01-05 15:51:13 -0800108 if (property_get(PROPERTY_TEXT_LARGE_CACHE_WIDTH, property, nullptr) > 0) {
Chet Haaseeb32a492012-08-31 13:54:03 -0700109 mLargeCacheWidth = atoi(property);
110 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700111
Chris Craikd41c4d82015-01-05 15:51:13 -0800112 if (property_get(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, property, nullptr) > 0) {
Chet Haaseeb32a492012-08-31 13:54:03 -0700113 mLargeCacheHeight = atoi(property);
114 }
Romain Guy9f5dab32012-09-04 12:55:44 -0700115
116 uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
Chris Craik083e7332015-02-27 17:04:20 -0800117
118 mSmallCacheWidth = MathUtils::min(mSmallCacheWidth, maxTextureSize);
119 mSmallCacheHeight = MathUtils::min(mSmallCacheHeight, maxTextureSize);
120 mLargeCacheWidth = MathUtils::min(mLargeCacheWidth, maxTextureSize);
121 mLargeCacheHeight = MathUtils::min(mLargeCacheHeight, maxTextureSize);
Romain Guy9f5dab32012-09-04 12:55:44 -0700122
Chet Haaseeb32a492012-08-31 13:54:03 -0700123 if (sLogFontRendererCreate) {
124 INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
125 mSmallCacheWidth, mSmallCacheHeight,
126 mLargeCacheWidth, mLargeCacheHeight >> 1,
127 mLargeCacheWidth, mLargeCacheHeight >> 1,
128 mLargeCacheWidth, mLargeCacheHeight);
Romain Guy51769a62010-07-23 00:28:00 -0700129 }
Romain Guy514fb182011-01-19 14:38:29 -0800130
131 sLogFontRendererCreate = false;
Romain Guy694b5192010-07-21 21:33:20 -0700132}
133
Victoria Lease1e546812013-06-25 14:25:17 -0700134void clearCacheTextures(Vector<CacheTexture*>& cacheTextures) {
135 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
136 delete cacheTextures[i];
Romain Guy694b5192010-07-21 21:33:20 -0700137 }
Victoria Lease1e546812013-06-25 14:25:17 -0700138 cacheTextures.clear();
139}
140
141FontRenderer::~FontRenderer() {
142 clearCacheTextures(mACacheTextures);
143 clearCacheTextures(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700144
Romain Guye3a9b242013-01-08 11:15:30 -0800145 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
146 while (it.next()) {
147 delete it.value();
Romain Guy694b5192010-07-21 21:33:20 -0700148 }
Romain Guye3a9b242013-01-08 11:15:30 -0800149 mActiveFonts.clear();
Romain Guy694b5192010-07-21 21:33:20 -0700150}
151
152void FontRenderer::flushAllAndInvalidate() {
Romain Guy661a87e2013-03-19 15:24:36 -0700153 issueDrawCommand();
Romain Guy9d9758a2012-05-14 15:19:58 -0700154
Romain Guye3a9b242013-01-08 11:15:30 -0800155 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
156 while (it.next()) {
157 it.value()->invalidateTextureCache();
Romain Guy694b5192010-07-21 21:33:20 -0700158 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700159
Victoria Lease1e546812013-06-25 14:25:17 -0700160 for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
161 mACacheTextures[i]->init();
162 }
163
164 for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
165 mRGBACacheTextures[i]->init();
Romain Guy694b5192010-07-21 21:33:20 -0700166 }
167}
168
Victoria Lease1e546812013-06-25 14:25:17 -0700169void FontRenderer::flushLargeCaches(Vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700170 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700171 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
172 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700173 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700174 cacheTexture->init();
Romain Guye3a9b242013-01-08 11:15:30 -0800175 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
176 while (it.next()) {
177 it.value()->invalidateTextureCache(cacheTexture);
Chet Haasee816bae2012-08-09 13:39:02 -0700178 }
Chris Craike2bb3802015-03-13 15:07:52 -0700179 cacheTexture->releasePixelBuffer();
Chet Haase9a824562011-12-16 15:44:59 -0800180 }
181 }
Chet Haase9a824562011-12-16 15:44:59 -0800182}
183
Victoria Lease1e546812013-06-25 14:25:17 -0700184void FontRenderer::flushLargeCaches() {
185 flushLargeCaches(mACacheTextures);
186 flushLargeCaches(mRGBACacheTextures);
187}
188
189CacheTexture* FontRenderer::cacheBitmapInTexture(Vector<CacheTexture*>& cacheTextures,
190 const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
191 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
192 if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
193 return cacheTextures[i];
Chet Haase378e9192012-08-15 15:54:54 -0700194 }
195 }
196 // Could not fit glyph into current cache textures
Chris Craikd41c4d82015-01-05 15:51:13 -0800197 return nullptr;
Chet Haase378e9192012-08-15 15:54:54 -0700198}
199
Chet Haase7de0cb12011-12-05 16:35:38 -0800200void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
Chet Haasef942cf12012-08-30 09:06:46 -0700201 uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700202 checkInit();
Romain Guya4adcf02013-02-28 12:15:35 -0800203
204 // If the glyph bitmap is empty let's assum the glyph is valid
205 // so we can avoid doing extra work later on
206 if (glyph.fWidth == 0 || glyph.fHeight == 0) {
207 cachedGlyph->mIsValid = true;
Chris Craikd41c4d82015-01-05 15:51:13 -0800208 cachedGlyph->mCacheTexture = nullptr;
Romain Guya4adcf02013-02-28 12:15:35 -0800209 return;
210 }
211
Chet Haase7de0cb12011-12-05 16:35:38 -0800212 cachedGlyph->mIsValid = false;
Romain Guya4adcf02013-02-28 12:15:35 -0800213
Victoria Lease1e546812013-06-25 14:25:17 -0700214 // choose an appropriate cache texture list for this glyph format
215 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
Chris Craikd41c4d82015-01-05 15:51:13 -0800216 Vector<CacheTexture*>* cacheTextures = nullptr;
Victoria Lease1e546812013-06-25 14:25:17 -0700217 switch (format) {
218 case SkMask::kA8_Format:
Victoria Lease723b2fe2013-08-12 14:38:44 -0700219 case SkMask::kBW_Format:
Victoria Lease1e546812013-06-25 14:25:17 -0700220 cacheTextures = &mACacheTextures;
221 break;
222 case SkMask::kARGB32_Format:
223 cacheTextures = &mRGBACacheTextures;
224 break;
225 default:
226#if DEBUG_FONT_RENDERER
227 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
228#endif
229 return;
230 }
231
Romain Guy694b5192010-07-21 21:33:20 -0700232 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700233 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
Victoria Lease1e546812013-06-25 14:25:17 -0700234 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700235 ALOGE("Font size too large to fit in cache. width, height = %i, %i",
236 (int) glyph.fWidth, (int) glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800237 return;
Romain Guy694b5192010-07-21 21:33:20 -0700238 }
239
240 // Now copy the bitmap into the cache texture
241 uint32_t startX = 0;
242 uint32_t startY = 0;
243
Victoria Lease1e546812013-06-25 14:25:17 -0700244 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700245
Chet Haase378e9192012-08-15 15:54:54 -0700246 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700247 if (!precaching) {
248 // If the new glyph didn't fit and we are not just trying to precache it,
249 // clear out the cache and try again
250 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700251 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700252 }
Romain Guy694b5192010-07-21 21:33:20 -0700253
Chet Haase378e9192012-08-15 15:54:54 -0700254 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700255 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800256 return;
Romain Guy694b5192010-07-21 21:33:20 -0700257 }
258 }
259
Chet Haase378e9192012-08-15 15:54:54 -0700260 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800261
Romain Guy694b5192010-07-21 21:33:20 -0700262 *retOriginX = startX;
263 *retOriginY = startY;
264
265 uint32_t endX = startX + glyph.fWidth;
266 uint32_t endY = startY + glyph.fHeight;
267
Romain Guy80872462012-09-04 16:42:01 -0700268 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700269
Romain Guycf51a412013-04-08 19:40:31 -0700270 if (!cacheTexture->getPixelBuffer()) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800271 Caches::getInstance().textureState().activateTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800272 // Large-glyph texture memory is allocated only as needed
Chris Craike2bb3802015-03-13 15:07:52 -0700273 cacheTexture->allocatePixelBuffer();
Chet Haase7de0cb12011-12-05 16:35:38 -0800274 }
Romain Guy661a87e2013-03-19 15:24:36 -0700275 if (!cacheTexture->mesh()) {
276 cacheTexture->allocateMesh();
277 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700278
Romain Guycf51a412013-04-08 19:40:31 -0700279 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
Victoria Lease1e546812013-06-25 14:25:17 -0700280 uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
281 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700282
Romain Guyb969a0d2013-02-05 14:38:40 -0800283 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800284 switch (format) {
285 case SkMask::kA8_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700286 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
287 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
288 - TEXTURE_BORDER_SIZE;
289 // write leading border line
290 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
291 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800292 if (mGammaTable) {
Victoria Lease1e546812013-06-25 14:25:17 -0700293 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800294 row = cacheY * cacheWidth;
295 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800296 for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
297 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800298 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800299 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800300 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800301 }
302 } else {
Victoria Lease1e546812013-06-25 14:25:17 -0700303 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800304 row = cacheY * cacheWidth;
305 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
306 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
307 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800308 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700309 }
Victoria Lease1e546812013-06-25 14:25:17 -0700310 // write trailing border line
311 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
312 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
313 break;
314 }
315 case SkMask::kARGB32_Format: {
316 // prep data lengths
317 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
318 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
319 size_t rowSize = formatSize * glyph.fWidth;
320 // prep advances
321 size_t dstStride = formatSize * cacheWidth;
322 // prep indices
323 // - we actually start one row early, and then increment before first copy
324 uint8_t* src = &bitmapBuffer[0 - srcStride];
325 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
326 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
327 uint8_t* dstL = dst - borderSize;
328 uint8_t* dstR = dst + rowSize;
329 // write leading border line
330 memset(dstL, 0, rowSize + 2 * borderSize);
331 // write glyph data
332 while (dst < dstEnd) {
333 memset(dstL += dstStride, 0, borderSize); // leading border column
334 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
335 memset(dstR += dstStride, 0, borderSize); // trailing border column
336 }
337 // write trailing border line
Victoria Lease16c84062013-09-19 15:38:21 -0700338 memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800339 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700340 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800341 case SkMask::kBW_Format: {
Andreas Gampe1e196742014-11-10 15:23:43 -0800342 uint32_t cacheX = 0, cacheY = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700343 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
344 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800345 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700346 // write leading border line
347 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
348 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800349 for (cacheY = startY; cacheY < endY; cacheY++) {
350 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700351 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800352 uint8_t* buffer = bitmapBuffer;
353
Romain Guy0b58a3d2013-03-05 12:16:27 -0800354 row = cacheY * cacheWidth;
355 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800356 while (--rowBytes >= 0) {
357 uint8_t b = *buffer++;
358 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
359 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
360 }
361 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800362 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800363
Victoria Lease1e546812013-06-25 14:25:17 -0700364 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700365 }
Victoria Lease1e546812013-06-25 14:25:17 -0700366 // write trailing border line
367 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
368 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800369 break;
Romain Guy694b5192010-07-21 21:33:20 -0700370 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800371 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700372 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800373 break;
Romain Guy694b5192010-07-21 21:33:20 -0700374 }
Romain Guy97771732012-02-28 18:17:02 -0800375
Chet Haase7de0cb12011-12-05 16:35:38 -0800376 cachedGlyph->mIsValid = true;
Romain Guy694b5192010-07-21 21:33:20 -0700377}
378
Victoria Lease1e546812013-06-25 14:25:17 -0700379CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
380 bool allocate) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800381 CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700382
Chet Haase2a47c142011-12-14 15:22:56 -0800383 if (allocate) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800384 Caches::getInstance().textureState().activateTexture(0);
Chris Craike2bb3802015-03-13 15:07:52 -0700385 cacheTexture->allocatePixelBuffer();
Romain Guy661a87e2013-03-19 15:24:36 -0700386 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800387 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700388
Chet Haase2a47c142011-12-14 15:22:56 -0800389 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800390}
391
392void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700393 clearCacheTextures(mACacheTextures);
394 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700395
Chet Haase7de0cb12011-12-05 16:35:38 -0800396 mUploadTexture = false;
Victoria Lease1e546812013-06-25 14:25:17 -0700397 mACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
398 GL_ALPHA, true));
399 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
400 GL_ALPHA, false));
401 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
402 GL_ALPHA, false));
403 mACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
404 GL_ALPHA, false));
405 mRGBACacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
406 GL_RGBA, false));
407 mRGBACacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
408 GL_RGBA, false));
409 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700410}
411
Romain Guy694b5192010-07-21 21:33:20 -0700412// We don't want to allocate anything unless we actually draw text
413void FontRenderer::checkInit() {
414 if (mInitialized) {
415 return;
416 }
417
418 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700419
420 mInitialized = true;
421}
422
Victoria Lease1e546812013-06-25 14:25:17 -0700423void checkTextureUpdateForCache(Caches& caches, Vector<CacheTexture*>& cacheTextures,
424 bool& resetPixelStore, GLuint& lastTextureId) {
425 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
426 CacheTexture* cacheTexture = cacheTextures[i];
427 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
428 if (cacheTexture->getTextureId() != lastTextureId) {
429 lastTextureId = cacheTexture->getTextureId();
Chris Craik44eb2c02015-01-29 09:45:09 -0800430 caches.textureState().activateTexture(0);
431 caches.textureState().bindTexture(lastTextureId);
Victoria Lease1e546812013-06-25 14:25:17 -0700432 }
433
434 if (cacheTexture->upload()) {
435 resetPixelStore = true;
436 }
437 }
438 }
439}
440
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700441void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900442 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700443 return;
Romain Guy694b5192010-07-21 21:33:20 -0700444 }
445
Romain Guy2d4fd362011-12-13 22:00:19 -0800446 Caches& caches = Caches::getInstance();
447 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700448
Romain Guycf51a412013-04-08 19:40:31 -0700449 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700450 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
451
Chet Haase378e9192012-08-15 15:54:54 -0700452 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700453 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
454 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700455
Romain Guycf51a412013-04-08 19:40:31 -0700456 // Unbind any PBO we might have used to update textures
Chris Craik44eb2c02015-01-29 09:45:09 -0800457 caches.pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700458
Romain Guy09087642013-04-04 12:27:54 -0700459 // Reset to default unpack row length to avoid affecting texture
460 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700461 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700462 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
463 }
464
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700465 mUploadTexture = false;
466}
467
Victoria Lease1e546812013-06-25 14:25:17 -0700468void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800469 if (!mFunctor) return;
470
Romain Guy661a87e2013-03-19 15:24:36 -0700471 bool first = true;
Chris Craik96a5c4c2015-01-27 15:46:35 -0800472 bool forceRebind = false;
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();
Chris Craik96a5c4c2015-01-27 15:46:35 -0800485 forceRebind = false;
Romain Guy115096f2013-03-19 11:32:41 -0700486 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900487 }
Victoria Lease1e546812013-06-25 14:25:17 -0700488}
489
490void FontRenderer::issueDrawCommand() {
491 issueDrawCommand(mACacheTextures);
492 issueDrawCommand(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700493}
494
Romain Guy97771732012-02-28 18:17:02 -0800495void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
496 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
Chet Haase7de0cb12011-12-05 16:35:38 -0800497 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800498 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800499 // Now use the new texture id
500 mCurrentCacheTexture = texture;
501 }
Romain Guy09147fb2010-07-22 13:08:20 -0700502
Romain Guy661a87e2013-03-19 15:24:36 -0700503 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
504 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800505}
506
507void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
508 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
509 float x4, float y4, float u4, float v4, CacheTexture* texture) {
510
511 if (mClip &&
512 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
513 return;
514 }
515
516 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 -0700517
Romain Guy5b3b3522010-10-27 18:57:51 -0700518 if (mBounds) {
519 mBounds->left = fmin(mBounds->left, x1);
520 mBounds->top = fmin(mBounds->top, y3);
521 mBounds->right = fmax(mBounds->right, x3);
522 mBounds->bottom = fmax(mBounds->bottom, y1);
523 }
524
Romain Guy661a87e2013-03-19 15:24:36 -0700525 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700526 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700527 }
528}
529
Romain Guy97771732012-02-28 18:17:02 -0800530void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
531 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
532 float x4, float y4, float u4, float v4, CacheTexture* texture) {
533
534 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
535
536 if (mBounds) {
537 mBounds->left = fmin(mBounds->left, fmin(x1, fmin(x2, fmin(x3, x4))));
538 mBounds->top = fmin(mBounds->top, fmin(y1, fmin(y2, fmin(y3, y4))));
539 mBounds->right = fmax(mBounds->right, fmax(x1, fmax(x2, fmax(x3, x4))));
540 mBounds->bottom = fmax(mBounds->bottom, fmax(y1, fmax(y2, fmax(y3, y4))));
541 }
542
Romain Guy661a87e2013-03-19 15:24:36 -0700543 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800544 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800545 }
546}
547
Chris Craik59744b72014-07-01 17:56:52 -0700548void FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800549 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700550}
Romain Guy7975fb62010-10-01 16:36:14 -0700551
Chris Craikd218a922014-01-02 17:13:34 -0800552FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const char *text,
Derek Sollenbergere392c812014-05-21 11:25:22 -0400553 uint32_t startIndex, uint32_t len, int numGlyphs, float radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700554 checkInit();
555
Romain Guycf51a412013-04-08 19:40:31 -0700556 DropShadow image;
557 image.width = 0;
558 image.height = 0;
Chris Craikd41c4d82015-01-05 15:51:13 -0800559 image.image = nullptr;
Romain Guycf51a412013-04-08 19:40:31 -0700560 image.penX = 0;
561 image.penY = 0;
562
Romain Guy1e45aae2010-08-13 19:39:53 -0700563 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700564 return image;
565 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700566
Romain Guy2d4fd362011-12-13 22:00:19 -0800567 mDrawn = false;
Chris Craikd41c4d82015-01-05 15:51:13 -0800568 mClip = nullptr;
569 mBounds = nullptr;
Romain Guyff98fa52011-11-28 09:35:09 -0800570
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700571 Rect bounds;
Raph Levien416a8472012-07-19 22:48:17 -0700572 mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800573
Derek Sollenbergere392c812014-05-21 11:25:22 -0400574 uint32_t intRadius = Blur::convertRadiusToInt(radius);
575 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
576 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
Romain Guyff98fa52011-11-28 09:35:09 -0800577
Romain Guycf51a412013-04-08 19:40:31 -0700578 uint32_t maxSize = Caches::getInstance().maxTextureSize;
579 if (paddedWidth > maxSize || paddedHeight > maxSize) {
580 return image;
581 }
582
Dan Morrille4d9a012013-03-28 18:10:43 -0700583#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800584 // Align buffers for renderscript usage
585 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
586 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700587 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800588 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800589 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700590#else
591 int size = paddedWidth * paddedHeight;
592 uint8_t* dataBuffer = (uint8_t*) malloc(size);
593#endif
594
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
604 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
Chris Craikd41c4d82015-01-05 15:51:13 -0800605 Font::BITMAP, dataBuffer, 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 Craikd218a922014-01-02 17:13:34 -0800638void FontRenderer::precache(const SkPaint* paint, const char* text, int numGlyphs,
Chris Craik59744b72014-07-01 17:56:52 -0700639 const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800640 Font* font = Font::create(this, paint, matrix);
Chet Haasee816bae2012-08-09 13:39:02 -0700641 font->precache(paint, text, numGlyphs);
642}
643
Romain Guycf51a412013-04-08 19:40:31 -0700644void FontRenderer::endPrecaching() {
645 checkTextureUpdate();
646}
647
Chris Craikd218a922014-01-02 17:13:34 -0800648bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
Romain Guy671d6cf2012-01-18 12:39:17 -0800649 uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
Chris Craik82840732015-04-03 09:37:49 -0700650 const float* positions, Rect* bounds, 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);
Romain Guy671d6cf2012-01-18 12:39:17 -0800657 mCurrentFont->render(paint, text, startIndex, len, 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 Craikd218a922014-01-02 17:13:34 -0800666bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
667 uint32_t startIndex, uint32_t len, int numGlyphs, const SkPath* path,
Chris Craik82840732015-04-03 09:37:49 -0700668 float hOffset, float vOffset, 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);
Romain Guy97771732012-02-28 18:17:02 -0800675 mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset);
676 finishRender();
677
678 return mDrawn;
679}
680
Romain Guy9b1204b2012-09-04 15:22:57 -0700681void FontRenderer::removeFont(const Font* font) {
Romain Guye3a9b242013-01-08 11:15:30 -0800682 mActiveFonts.remove(font->getDescription());
Romain Guy9b1204b2012-09-04 15:22:57 -0700683
684 if (mCurrentFont == font) {
Chris Craikd41c4d82015-01-05 15:51:13 -0800685 mCurrentFont = nullptr;
Romain Guy9b1204b2012-09-04 15:22:57 -0700686 }
687}
688
Derek Sollenbergere392c812014-05-21 11:25:22 -0400689void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
690 uint32_t intRadius = Blur::convertRadiusToInt(radius);
Dan Morrille4d9a012013-03-28 18:10:43 -0700691#ifdef ANDROID_ENABLE_RENDERSCRIPT
Derek Sollenbergere392c812014-05-21 11:25:22 -0400692 if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700693 uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700694
Chris Craikd41c4d82015-01-05 15:51:13 -0800695 if (mRs == nullptr) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700696 mRs = new RSC::RS();
Tim Murrayabe55e92013-12-13 12:57:36 -0800697 // a null path is OK because there are no custom kernels used
698 // hence nothing gets cached by RS
699 if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800700 mRs.clear();
Dan Morrille4d9a012013-03-28 18:10:43 -0700701 ALOGE("blur RS failed to init");
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800702 } else {
703 mRsElement = RSC::Element::A_8(mRs);
704 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Dan Morrille4d9a012013-03-28 18:10:43 -0700705 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800706 }
Chris Craikd41c4d82015-01-05 15:51:13 -0800707 if (mRs != nullptr) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800708 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
709 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
710 RS_ALLOCATION_MIPMAP_NONE,
711 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
712 *image);
713 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
714 RS_ALLOCATION_MIPMAP_NONE,
715 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
716 outImage);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800717
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800718 mRsScript->setRadius(radius);
719 mRsScript->setInput(ain);
720 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700721
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800722 // replace the original image's pointer, avoiding a copy back to the original buffer
723 free(*image);
724 *image = outImage;
Dan Morrille4d9a012013-03-28 18:10:43 -0700725
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800726 return;
727 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800728 }
Dan Morrille4d9a012013-03-28 18:10:43 -0700729#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800730
Chris Craik51d6a3d2014-12-22 17:16:56 -0800731 std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
732 Blur::generateGaussianWeights(gaussian.get(), intRadius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800733
Chris Craik51d6a3d2014-12-22 17:16:56 -0800734 std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
735 Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
736 Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700737}
738
Victoria Lease1e546812013-06-25 14:25:17 -0700739static uint32_t calculateCacheSize(const Vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700740 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700741 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
742 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700743 if (cacheTexture && cacheTexture->getPixelBuffer()) {
744 size += cacheTexture->getPixelBuffer()->getSize();
745 }
746 }
747 return size;
748}
749
Victoria Lease1e546812013-06-25 14:25:17 -0700750uint32_t FontRenderer::getCacheSize(GLenum format) const {
751 switch (format) {
752 case GL_ALPHA: {
753 return calculateCacheSize(mACacheTextures);
754 }
755 case GL_RGBA: {
756 return calculateCacheSize(mRGBACacheTextures);
757 }
758 default: {
759 return 0;
760 }
761 }
762}
763
Romain Guy694b5192010-07-21 21:33:20 -0700764}; // namespace uirenderer
765}; // namespace android