blob: 5f33cae2f91af45a74327c9226f9a77b40a576f4 [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 "PixelBuffer.h"
25#include "Rect.h"
26#include "renderstate/RenderState.h"
27#include "utils/Blur.h"
28#include "utils/Timing.h"
Romain Guy694b5192010-07-21 21:33:20 -070029
Chris Craika1717272015-11-19 13:02:43 -080030
31#if HWUI_NEW_OPS
32#include "BakedOpState.h"
33#include "BakedOpRenderer.h"
34#else
35#include "OpenGLRenderer.h"
36#endif
37
Chris Craik9db58c02015-08-19 15:19:18 -070038#include <algorithm>
39#include <cutils/properties.h>
Derek Sollenbergerca79cf62012-08-14 16:44:52 -040040#include <SkGlyph.h>
Romain Guy694b5192010-07-21 21:33:20 -070041#include <SkUtils.h>
Romain Guy51769a62010-07-23 00:28:00 -070042#include <utils/Log.h>
43
Dan Morrille4d9a012013-03-28 18:10:43 -070044#ifdef ANDROID_ENABLE_RENDERSCRIPT
Romain Guy6e200402013-03-08 11:28:22 -080045#include <RenderScript.h>
Dan Morrille4d9a012013-03-28 18:10:43 -070046#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -080047
Romain Guy694b5192010-07-21 21:33:20 -070048namespace android {
49namespace uirenderer {
50
Chris Craikf2d8ccc2013-02-13 16:14:17 -080051// blur inputs smaller than this constant will bypass renderscript
52#define RS_MIN_INPUT_CUTOFF 10000
53
Romain Guy694b5192010-07-21 21:33:20 -070054///////////////////////////////////////////////////////////////////////////////
Victoria Lease1e546812013-06-25 14:25:17 -070055// TextSetupFunctor
56///////////////////////////////////////////////////////////////////////////////
Victoria Lease1e546812013-06-25 14:25:17 -070057
Chris Craik82840732015-04-03 09:37:49 -070058void TextDrawFunctor::draw(CacheTexture& texture, bool linearFiltering) {
Chris Craik53e51e42015-06-01 10:35:35 -070059 int textureFillFlags = TextureFillFlags::None;
60 if (texture.getFormat() == GL_ALPHA) {
61 textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture;
Chris Craike2bb3802015-03-13 15:07:52 -070062 }
Chris Craik53e51e42015-06-01 10:35:35 -070063 if (linearFiltering) {
64 textureFillFlags |= TextureFillFlags::ForceFilter;
65 }
66 int transformFlags = pureTranslate
67 ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
Chris Craike2bb3802015-03-13 15:07:52 -070068 Glop glop;
Chris Craika1717272015-11-19 13:02:43 -080069#if HWUI_NEW_OPS
70 GlopBuilder(renderer->renderState(), renderer->caches(), &glop)
71 .setRoundRectClipState(bakedState->roundRectClipState)
72 .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
73 .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, bakedState->alpha)
74 .setTransform(bakedState->computedState.transform, transformFlags)
75 .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
76 .build();
77 renderer->renderGlop(*bakedState, glop);
78#else
Chris Craike2bb3802015-03-13 15:07:52 -070079 GlopBuilder(renderer->mRenderState, renderer->mCaches, &glop)
Chris Craika1717272015-11-19 13:02:43 -080080 .setRoundRectClipState(renderer->currentSnapshot()->roundRectClipState)
Chris Craike2bb3802015-03-13 15:07:52 -070081 .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
82 .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, renderer->currentSnapshot()->alpha)
Chris Craik53e51e42015-06-01 10:35:35 -070083 .setTransform(*(renderer->currentSnapshot()), transformFlags)
Chris Craike2bb3802015-03-13 15:07:52 -070084 .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
Chris Craike2bb3802015-03-13 15:07:52 -070085 .build();
86 renderer->renderGlop(glop);
Chris Craika1717272015-11-19 13:02:43 -080087#endif
Victoria Lease1e546812013-06-25 14:25:17 -070088}
89
90///////////////////////////////////////////////////////////////////////////////
Romain Guy694b5192010-07-21 21:33:20 -070091// FontRenderer
92///////////////////////////////////////////////////////////////////////////////
93
Romain Guy514fb182011-01-19 14:38:29 -080094static bool sLogFontRendererCreate = true;
95
Chris Craikc08820f2015-09-22 14:22:29 -070096FontRenderer::FontRenderer(const uint8_t* gammaTable)
97 : mGammaTable(gammaTable)
Chris Craik083e7332015-02-27 17:04:20 -080098 , mCurrentFont(nullptr)
99 , mActiveFonts(LruCache<Font::FontDescription, Font*>::kUnlimitedCapacity)
100 , mCurrentCacheTexture(nullptr)
101 , mUploadTexture(false)
102 , mFunctor(nullptr)
103 , mClip(nullptr)
104 , mBounds(nullptr)
105 , mDrawn(false)
106 , mInitialized(false)
107 , mLinearFiltering(false) {
Romain Guye3a9b242013-01-08 11:15:30 -0800108
Romain Guyc9855a52011-01-21 21:14:15 -0800109 if (sLogFontRendererCreate) {
110 INIT_LOGD("Creating FontRenderer");
111 }
Romain Guy51769a62010-07-23 00:28:00 -0700112
Chris Craikc08820f2015-09-22 14:22:29 -0700113 mSmallCacheWidth = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_WIDTH,
114 DEFAULT_TEXT_SMALL_CACHE_WIDTH);
115 mSmallCacheHeight = property_get_int32(PROPERTY_TEXT_SMALL_CACHE_HEIGHT,
116 DEFAULT_TEXT_SMALL_CACHE_HEIGHT);
Romain Guy51769a62010-07-23 00:28:00 -0700117
Chris Craikc08820f2015-09-22 14:22:29 -0700118 mLargeCacheWidth = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_WIDTH,
119 DEFAULT_TEXT_LARGE_CACHE_WIDTH);
120 mLargeCacheHeight = property_get_int32(PROPERTY_TEXT_LARGE_CACHE_HEIGHT,
121 DEFAULT_TEXT_LARGE_CACHE_HEIGHT);
Romain Guy9f5dab32012-09-04 12:55:44 -0700122
123 uint32_t maxTextureSize = (uint32_t) Caches::getInstance().maxTextureSize;
Chris Craik083e7332015-02-27 17:04:20 -0800124
Chris Craik9db58c02015-08-19 15:19:18 -0700125 mSmallCacheWidth = std::min(mSmallCacheWidth, maxTextureSize);
126 mSmallCacheHeight = std::min(mSmallCacheHeight, maxTextureSize);
127 mLargeCacheWidth = std::min(mLargeCacheWidth, maxTextureSize);
128 mLargeCacheHeight = std::min(mLargeCacheHeight, maxTextureSize);
Romain Guy9f5dab32012-09-04 12:55:44 -0700129
Chet Haaseeb32a492012-08-31 13:54:03 -0700130 if (sLogFontRendererCreate) {
131 INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
132 mSmallCacheWidth, mSmallCacheHeight,
133 mLargeCacheWidth, mLargeCacheHeight >> 1,
134 mLargeCacheWidth, mLargeCacheHeight >> 1,
135 mLargeCacheWidth, mLargeCacheHeight);
Romain Guy51769a62010-07-23 00:28:00 -0700136 }
Romain Guy514fb182011-01-19 14:38:29 -0800137
138 sLogFontRendererCreate = false;
Romain Guy694b5192010-07-21 21:33:20 -0700139}
140
John Reck272a6852015-07-29 16:48:58 -0700141void clearCacheTextures(std::vector<CacheTexture*>& cacheTextures) {
Victoria Lease1e546812013-06-25 14:25:17 -0700142 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
143 delete cacheTextures[i];
Romain Guy694b5192010-07-21 21:33:20 -0700144 }
Victoria Lease1e546812013-06-25 14:25:17 -0700145 cacheTextures.clear();
146}
147
148FontRenderer::~FontRenderer() {
149 clearCacheTextures(mACacheTextures);
150 clearCacheTextures(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700151
Romain Guye3a9b242013-01-08 11:15:30 -0800152 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
153 while (it.next()) {
154 delete it.value();
Romain Guy694b5192010-07-21 21:33:20 -0700155 }
Romain Guye3a9b242013-01-08 11:15:30 -0800156 mActiveFonts.clear();
Romain Guy694b5192010-07-21 21:33:20 -0700157}
158
159void FontRenderer::flushAllAndInvalidate() {
Romain Guy661a87e2013-03-19 15:24:36 -0700160 issueDrawCommand();
Romain Guy9d9758a2012-05-14 15:19:58 -0700161
Romain Guye3a9b242013-01-08 11:15:30 -0800162 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
163 while (it.next()) {
164 it.value()->invalidateTextureCache();
Romain Guy694b5192010-07-21 21:33:20 -0700165 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700166
Victoria Lease1e546812013-06-25 14:25:17 -0700167 for (uint32_t i = 0; i < mACacheTextures.size(); i++) {
168 mACacheTextures[i]->init();
169 }
170
171 for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
172 mRGBACacheTextures[i]->init();
Romain Guy694b5192010-07-21 21:33:20 -0700173 }
chaochen1f61b192014-08-28 18:45:27 -0700174
175 mDrawn = false;
Romain Guy694b5192010-07-21 21:33:20 -0700176}
177
John Reck272a6852015-07-29 16:48:58 -0700178void FontRenderer::flushLargeCaches(std::vector<CacheTexture*>& cacheTextures) {
Chet Haase378e9192012-08-15 15:54:54 -0700179 // Start from 1; don't deallocate smallest/default texture
Victoria Lease1e546812013-06-25 14:25:17 -0700180 for (uint32_t i = 1; i < cacheTextures.size(); i++) {
181 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700182 if (cacheTexture->getPixelBuffer()) {
Chet Haase378e9192012-08-15 15:54:54 -0700183 cacheTexture->init();
Romain Guye3a9b242013-01-08 11:15:30 -0800184 LruCache<Font::FontDescription, Font*>::Iterator it(mActiveFonts);
185 while (it.next()) {
186 it.value()->invalidateTextureCache(cacheTexture);
Chet Haasee816bae2012-08-09 13:39:02 -0700187 }
Chris Craike2bb3802015-03-13 15:07:52 -0700188 cacheTexture->releasePixelBuffer();
Chet Haase9a824562011-12-16 15:44:59 -0800189 }
190 }
Chet Haase9a824562011-12-16 15:44:59 -0800191}
192
Victoria Lease1e546812013-06-25 14:25:17 -0700193void FontRenderer::flushLargeCaches() {
194 flushLargeCaches(mACacheTextures);
195 flushLargeCaches(mRGBACacheTextures);
196}
197
John Reck272a6852015-07-29 16:48:58 -0700198CacheTexture* FontRenderer::cacheBitmapInTexture(std::vector<CacheTexture*>& cacheTextures,
Victoria Lease1e546812013-06-25 14:25:17 -0700199 const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
200 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
201 if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
202 return cacheTextures[i];
Chet Haase378e9192012-08-15 15:54:54 -0700203 }
204 }
205 // Could not fit glyph into current cache textures
Chris Craikd41c4d82015-01-05 15:51:13 -0800206 return nullptr;
Chet Haase378e9192012-08-15 15:54:54 -0700207}
208
Chet Haase7de0cb12011-12-05 16:35:38 -0800209void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
Chet Haasef942cf12012-08-30 09:06:46 -0700210 uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700211 checkInit();
Romain Guya4adcf02013-02-28 12:15:35 -0800212
213 // If the glyph bitmap is empty let's assum the glyph is valid
214 // so we can avoid doing extra work later on
215 if (glyph.fWidth == 0 || glyph.fHeight == 0) {
216 cachedGlyph->mIsValid = true;
Chris Craikd41c4d82015-01-05 15:51:13 -0800217 cachedGlyph->mCacheTexture = nullptr;
Romain Guya4adcf02013-02-28 12:15:35 -0800218 return;
219 }
220
Chet Haase7de0cb12011-12-05 16:35:38 -0800221 cachedGlyph->mIsValid = false;
Romain Guya4adcf02013-02-28 12:15:35 -0800222
Victoria Lease1e546812013-06-25 14:25:17 -0700223 // choose an appropriate cache texture list for this glyph format
224 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
John Reck272a6852015-07-29 16:48:58 -0700225 std::vector<CacheTexture*>* cacheTextures = nullptr;
Victoria Lease1e546812013-06-25 14:25:17 -0700226 switch (format) {
227 case SkMask::kA8_Format:
Victoria Lease723b2fe2013-08-12 14:38:44 -0700228 case SkMask::kBW_Format:
Victoria Lease1e546812013-06-25 14:25:17 -0700229 cacheTextures = &mACacheTextures;
230 break;
231 case SkMask::kARGB32_Format:
232 cacheTextures = &mRGBACacheTextures;
233 break;
234 default:
235#if DEBUG_FONT_RENDERER
236 ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
237#endif
238 return;
239 }
240
Romain Guy694b5192010-07-21 21:33:20 -0700241 // If the glyph is too tall, don't cache it
Chet Haase378e9192012-08-15 15:54:54 -0700242 if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
Victoria Lease1e546812013-06-25 14:25:17 -0700243 (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
Chet Haase2efd5c52012-08-15 13:15:16 -0700244 ALOGE("Font size too large to fit in cache. width, height = %i, %i",
245 (int) glyph.fWidth, (int) glyph.fHeight);
Chet Haase7de0cb12011-12-05 16:35:38 -0800246 return;
Romain Guy694b5192010-07-21 21:33:20 -0700247 }
248
249 // Now copy the bitmap into the cache texture
250 uint32_t startX = 0;
251 uint32_t startY = 0;
252
Victoria Lease1e546812013-06-25 14:25:17 -0700253 CacheTexture* cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Romain Guy694b5192010-07-21 21:33:20 -0700254
Chet Haase378e9192012-08-15 15:54:54 -0700255 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700256 if (!precaching) {
257 // If the new glyph didn't fit and we are not just trying to precache it,
258 // clear out the cache and try again
259 flushAllAndInvalidate();
Victoria Lease1e546812013-06-25 14:25:17 -0700260 cacheTexture = cacheBitmapInTexture(*cacheTextures, glyph, &startX, &startY);
Chet Haasef942cf12012-08-30 09:06:46 -0700261 }
Romain Guy694b5192010-07-21 21:33:20 -0700262
Chet Haase378e9192012-08-15 15:54:54 -0700263 if (!cacheTexture) {
Chet Haasef942cf12012-08-30 09:06:46 -0700264 // either the glyph didn't fit or we're precaching and will cache it when we draw
Chet Haase7de0cb12011-12-05 16:35:38 -0800265 return;
Romain Guy694b5192010-07-21 21:33:20 -0700266 }
267 }
268
Chet Haase378e9192012-08-15 15:54:54 -0700269 cachedGlyph->mCacheTexture = cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800270
Romain Guy694b5192010-07-21 21:33:20 -0700271 *retOriginX = startX;
272 *retOriginY = startY;
273
274 uint32_t endX = startX + glyph.fWidth;
275 uint32_t endY = startY + glyph.fHeight;
276
Romain Guy80872462012-09-04 16:42:01 -0700277 uint32_t cacheWidth = cacheTexture->getWidth();
Romain Guy694b5192010-07-21 21:33:20 -0700278
Romain Guycf51a412013-04-08 19:40:31 -0700279 if (!cacheTexture->getPixelBuffer()) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800280 Caches::getInstance().textureState().activateTexture(0);
Chet Haase7de0cb12011-12-05 16:35:38 -0800281 // Large-glyph texture memory is allocated only as needed
Chris Craike2bb3802015-03-13 15:07:52 -0700282 cacheTexture->allocatePixelBuffer();
Chet Haase7de0cb12011-12-05 16:35:38 -0800283 }
Romain Guy661a87e2013-03-19 15:24:36 -0700284 if (!cacheTexture->mesh()) {
285 cacheTexture->allocateMesh();
286 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700287
Romain Guycf51a412013-04-08 19:40:31 -0700288 uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
Victoria Lease1e546812013-06-25 14:25:17 -0700289 uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
290 int srcStride = glyph.rowBytes();
Romain Guy33fa1f72012-08-07 19:09:57 -0700291
Romain Guyb969a0d2013-02-05 14:38:40 -0800292 // Copy the glyph image, taking the mask format into account
Romain Guyb969a0d2013-02-05 14:38:40 -0800293 switch (format) {
294 case SkMask::kA8_Format: {
Victoria Lease1e546812013-06-25 14:25:17 -0700295 uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
296 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
297 - TEXTURE_BORDER_SIZE;
298 // write leading border line
299 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
300 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800301 if (mGammaTable) {
Victoria Lease1e546812013-06-25 14:25:17 -0700302 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800303 row = cacheY * cacheWidth;
304 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800305 for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
306 uint8_t tempCol = bitmapBuffer[bY + bX];
Romain Guy0b58a3d2013-03-05 12:16:27 -0800307 cacheBuffer[row + cacheX] = mGammaTable[tempCol];
Romain Guyb969a0d2013-02-05 14:38:40 -0800308 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800309 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800310 }
311 } else {
Victoria Lease1e546812013-06-25 14:25:17 -0700312 for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
Romain Guy0b58a3d2013-03-05 12:16:27 -0800313 row = cacheY * cacheWidth;
314 memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
315 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
316 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800317 }
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700318 }
Victoria Lease1e546812013-06-25 14:25:17 -0700319 // write trailing border line
320 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
321 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
322 break;
323 }
324 case SkMask::kARGB32_Format: {
325 // prep data lengths
326 const size_t formatSize = PixelBuffer::formatSize(GL_RGBA);
327 const size_t borderSize = formatSize * TEXTURE_BORDER_SIZE;
328 size_t rowSize = formatSize * glyph.fWidth;
329 // prep advances
330 size_t dstStride = formatSize * cacheWidth;
331 // prep indices
332 // - we actually start one row early, and then increment before first copy
333 uint8_t* src = &bitmapBuffer[0 - srcStride];
334 uint8_t* dst = &cacheBuffer[cacheTexture->getOffset(startX, startY - 1)];
335 uint8_t* dstEnd = &cacheBuffer[cacheTexture->getOffset(startX, endY - 1)];
336 uint8_t* dstL = dst - borderSize;
337 uint8_t* dstR = dst + rowSize;
338 // write leading border line
339 memset(dstL, 0, rowSize + 2 * borderSize);
340 // write glyph data
341 while (dst < dstEnd) {
342 memset(dstL += dstStride, 0, borderSize); // leading border column
343 memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
344 memset(dstR += dstStride, 0, borderSize); // trailing border column
345 }
346 // write trailing border line
Victoria Lease16c84062013-09-19 15:38:21 -0700347 memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
Romain Guyb969a0d2013-02-05 14:38:40 -0800348 break;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700349 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800350 case SkMask::kBW_Format: {
Andreas Gampe1e196742014-11-10 15:23:43 -0800351 uint32_t cacheX = 0, cacheY = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700352 uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
353 - TEXTURE_BORDER_SIZE;
Romain Guyb969a0d2013-02-05 14:38:40 -0800354 static const uint8_t COLORS[2] = { 0, 255 };
Victoria Lease1e546812013-06-25 14:25:17 -0700355 // write leading border line
356 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
357 // write glyph data
Romain Guyb969a0d2013-02-05 14:38:40 -0800358 for (cacheY = startY; cacheY < endY; cacheY++) {
359 cacheX = startX;
Victoria Lease1e546812013-06-25 14:25:17 -0700360 int rowBytes = srcStride;
Romain Guyb969a0d2013-02-05 14:38:40 -0800361 uint8_t* buffer = bitmapBuffer;
362
Romain Guy0b58a3d2013-03-05 12:16:27 -0800363 row = cacheY * cacheWidth;
364 cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800365 while (--rowBytes >= 0) {
366 uint8_t b = *buffer++;
367 for (int8_t mask = 7; mask >= 0 && cacheX < endX; mask--) {
368 cacheBuffer[cacheY * cacheWidth + cacheX++] = COLORS[(b >> mask) & 0x1];
369 }
370 }
Romain Guy0b58a3d2013-03-05 12:16:27 -0800371 cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
Romain Guyb969a0d2013-02-05 14:38:40 -0800372
Victoria Lease1e546812013-06-25 14:25:17 -0700373 bitmapBuffer += srcStride;
Romain Guyb1d0a4e2012-07-13 18:25:35 -0700374 }
Victoria Lease1e546812013-06-25 14:25:17 -0700375 // write trailing border line
376 row = (endY + TEXTURE_BORDER_SIZE - 1) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
377 memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
Romain Guyb969a0d2013-02-05 14:38:40 -0800378 break;
Romain Guy694b5192010-07-21 21:33:20 -0700379 }
Romain Guyb969a0d2013-02-05 14:38:40 -0800380 default:
Victoria Lease1e546812013-06-25 14:25:17 -0700381 ALOGW("Unknown glyph format: 0x%x", format);
Romain Guyb969a0d2013-02-05 14:38:40 -0800382 break;
Romain Guy694b5192010-07-21 21:33:20 -0700383 }
Romain Guy97771732012-02-28 18:17:02 -0800384
Chet Haase7de0cb12011-12-05 16:35:38 -0800385 cachedGlyph->mIsValid = true;
Romain Guy694b5192010-07-21 21:33:20 -0700386}
387
Victoria Lease1e546812013-06-25 14:25:17 -0700388CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
389 bool allocate) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800390 CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
Romain Guy9d9758a2012-05-14 15:19:58 -0700391
Chet Haase2a47c142011-12-14 15:22:56 -0800392 if (allocate) {
Chris Craik44eb2c02015-01-29 09:45:09 -0800393 Caches::getInstance().textureState().activateTexture(0);
Chris Craike2bb3802015-03-13 15:07:52 -0700394 cacheTexture->allocatePixelBuffer();
Romain Guy661a87e2013-03-19 15:24:36 -0700395 cacheTexture->allocateMesh();
Chet Haase2a47c142011-12-14 15:22:56 -0800396 }
Romain Guy9d9758a2012-05-14 15:19:58 -0700397
Chet Haase2a47c142011-12-14 15:22:56 -0800398 return cacheTexture;
Chet Haase7de0cb12011-12-05 16:35:38 -0800399}
400
401void FontRenderer::initTextTexture() {
Victoria Lease1e546812013-06-25 14:25:17 -0700402 clearCacheTextures(mACacheTextures);
403 clearCacheTextures(mRGBACacheTextures);
Romain Guy9d9758a2012-05-14 15:19:58 -0700404
Chet Haase7de0cb12011-12-05 16:35:38 -0800405 mUploadTexture = false;
John Reck272a6852015-07-29 16:48:58 -0700406 mACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700407 GL_ALPHA, true));
John Reck272a6852015-07-29 16:48:58 -0700408 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700409 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700410 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700411 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700412 mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700413 GL_ALPHA, false));
John Reck272a6852015-07-29 16:48:58 -0700414 mRGBACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
Victoria Lease1e546812013-06-25 14:25:17 -0700415 GL_RGBA, false));
John Reck272a6852015-07-29 16:48:58 -0700416 mRGBACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
Victoria Lease1e546812013-06-25 14:25:17 -0700417 GL_RGBA, false));
418 mCurrentCacheTexture = mACacheTextures[0];
Romain Guy694b5192010-07-21 21:33:20 -0700419}
420
Romain Guy694b5192010-07-21 21:33:20 -0700421// We don't want to allocate anything unless we actually draw text
422void FontRenderer::checkInit() {
423 if (mInitialized) {
424 return;
425 }
426
427 initTextTexture();
Romain Guy694b5192010-07-21 21:33:20 -0700428
429 mInitialized = true;
430}
431
John Reck272a6852015-07-29 16:48:58 -0700432void checkTextureUpdateForCache(Caches& caches, std::vector<CacheTexture*>& cacheTextures,
Victoria Lease1e546812013-06-25 14:25:17 -0700433 bool& resetPixelStore, GLuint& lastTextureId) {
434 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
435 CacheTexture* cacheTexture = cacheTextures[i];
436 if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
437 if (cacheTexture->getTextureId() != lastTextureId) {
438 lastTextureId = cacheTexture->getTextureId();
Chris Craik44eb2c02015-01-29 09:45:09 -0800439 caches.textureState().activateTexture(0);
440 caches.textureState().bindTexture(lastTextureId);
Victoria Lease1e546812013-06-25 14:25:17 -0700441 }
442
443 if (cacheTexture->upload()) {
444 resetPixelStore = true;
445 }
446 }
447 }
448}
449
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700450void FontRenderer::checkTextureUpdate() {
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900451 if (!mUploadTexture) {
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700452 return;
Romain Guy694b5192010-07-21 21:33:20 -0700453 }
454
Romain Guy2d4fd362011-12-13 22:00:19 -0800455 Caches& caches = Caches::getInstance();
456 GLuint lastTextureId = 0;
Romain Guy09087642013-04-04 12:27:54 -0700457
Romain Guycf51a412013-04-08 19:40:31 -0700458 bool resetPixelStore = false;
Romain Guy09087642013-04-04 12:27:54 -0700459 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
460
Chet Haase378e9192012-08-15 15:54:54 -0700461 // Iterate over all the cache textures and see which ones need to be updated
Victoria Lease1e546812013-06-25 14:25:17 -0700462 checkTextureUpdateForCache(caches, mACacheTextures, resetPixelStore, lastTextureId);
463 checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700464
Romain Guycf51a412013-04-08 19:40:31 -0700465 // Unbind any PBO we might have used to update textures
Chris Craik44eb2c02015-01-29 09:45:09 -0800466 caches.pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700467
Romain Guy09087642013-04-04 12:27:54 -0700468 // Reset to default unpack row length to avoid affecting texture
469 // uploads in other parts of the renderer
Romain Guycf51a412013-04-08 19:40:31 -0700470 if (resetPixelStore) {
Romain Guy09087642013-04-04 12:27:54 -0700471 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
472 }
473
Alex Sakhartchouk9b9902d2010-07-23 14:45:49 -0700474 mUploadTexture = false;
475}
476
John Reck272a6852015-07-29 16:48:58 -0700477void FontRenderer::issueDrawCommand(std::vector<CacheTexture*>& cacheTextures) {
Chris Craik96a5c4c2015-01-27 15:46:35 -0800478 if (!mFunctor) return;
479
Romain Guy661a87e2013-03-19 15:24:36 -0700480 bool first = true;
Victoria Lease1e546812013-06-25 14:25:17 -0700481 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
482 CacheTexture* texture = cacheTextures[i];
Romain Guy661a87e2013-03-19 15:24:36 -0700483 if (texture->canDraw()) {
484 if (first) {
Chris Craike2bb3802015-03-13 15:07:52 -0700485 checkTextureUpdate();
Romain Guy661a87e2013-03-19 15:24:36 -0700486 first = false;
Chris Craik083e7332015-02-27 17:04:20 -0800487 mDrawn = true;
Romain Guy661a87e2013-03-19 15:24:36 -0700488 }
Chris Craik82840732015-04-03 09:37:49 -0700489
Chris Craike2bb3802015-03-13 15:07:52 -0700490 mFunctor->draw(*texture, mLinearFiltering);
Romain Guy661a87e2013-03-19 15:24:36 -0700491
Romain Guy661a87e2013-03-19 15:24:36 -0700492 texture->resetMesh();
Romain Guy115096f2013-03-19 11:32:41 -0700493 }
Sangkyu Lee7bb3cfe2012-11-16 00:03:17 +0900494 }
Victoria Lease1e546812013-06-25 14:25:17 -0700495}
496
497void FontRenderer::issueDrawCommand() {
498 issueDrawCommand(mACacheTextures);
499 issueDrawCommand(mRGBACacheTextures);
Romain Guy694b5192010-07-21 21:33:20 -0700500}
501
Romain Guy97771732012-02-28 18:17:02 -0800502void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
503 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
Chet Haase7de0cb12011-12-05 16:35:38 -0800504 float x4, float y4, float u4, float v4, CacheTexture* texture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800505 if (texture != mCurrentCacheTexture) {
Chet Haase7de0cb12011-12-05 16:35:38 -0800506 // Now use the new texture id
507 mCurrentCacheTexture = texture;
508 }
Romain Guy09147fb2010-07-22 13:08:20 -0700509
Romain Guy661a87e2013-03-19 15:24:36 -0700510 mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
511 x3, y3, u3, v3, x4, y4, u4, v4);
Romain Guy97771732012-02-28 18:17:02 -0800512}
513
514void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
515 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
516 float x4, float y4, float u4, float v4, CacheTexture* texture) {
517
518 if (mClip &&
519 (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
520 return;
521 }
522
523 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 -0700524
Romain Guy5b3b3522010-10-27 18:57:51 -0700525 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700526 mBounds->left = std::min(mBounds->left, x1);
527 mBounds->top = std::min(mBounds->top, y3);
528 mBounds->right = std::max(mBounds->right, x3);
529 mBounds->bottom = std::max(mBounds->bottom, y1);
Romain Guy5b3b3522010-10-27 18:57:51 -0700530 }
531
Romain Guy661a87e2013-03-19 15:24:36 -0700532 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy694b5192010-07-21 21:33:20 -0700533 issueDrawCommand();
Romain Guy694b5192010-07-21 21:33:20 -0700534 }
535}
536
Romain Guy97771732012-02-28 18:17:02 -0800537void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
538 float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
539 float x4, float y4, float u4, float v4, CacheTexture* texture) {
540
541 appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
542
543 if (mBounds) {
Chris Craike6a15ee2015-07-07 18:42:17 -0700544 mBounds->left = std::min(mBounds->left, std::min(x1, std::min(x2, std::min(x3, x4))));
545 mBounds->top = std::min(mBounds->top, std::min(y1, std::min(y2, std::min(y3, y4))));
546 mBounds->right = std::max(mBounds->right, std::max(x1, std::max(x2, std::max(x3, x4))));
547 mBounds->bottom = std::max(mBounds->bottom, std::max(y1, std::max(y2, std::max(y3, y4))));
Romain Guy97771732012-02-28 18:17:02 -0800548 }
549
Romain Guy661a87e2013-03-19 15:24:36 -0700550 if (mCurrentCacheTexture->endOfMesh()) {
Romain Guy97771732012-02-28 18:17:02 -0800551 issueDrawCommand();
Romain Guy97771732012-02-28 18:17:02 -0800552 }
553}
554
Chris Craik59744b72014-07-01 17:56:52 -0700555void FontRenderer::setFont(const SkPaint* paint, const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800556 mCurrentFont = Font::create(this, paint, matrix);
Romain Guy694b5192010-07-21 21:33:20 -0700557}
Romain Guy7975fb62010-10-01 16:36:14 -0700558
Chris Craikd218a922014-01-02 17:13:34 -0800559FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const char *text,
Chris Craika1717272015-11-19 13:02:43 -0800560 int numGlyphs, float radius, const float* positions) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700561 checkInit();
562
Romain Guycf51a412013-04-08 19:40:31 -0700563 DropShadow image;
564 image.width = 0;
565 image.height = 0;
Chris Craikd41c4d82015-01-05 15:51:13 -0800566 image.image = nullptr;
Romain Guycf51a412013-04-08 19:40:31 -0700567 image.penX = 0;
568 image.penY = 0;
569
Romain Guy1e45aae2010-08-13 19:39:53 -0700570 if (!mCurrentFont) {
Romain Guy1e45aae2010-08-13 19:39:53 -0700571 return image;
572 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700573
Romain Guy2d4fd362011-12-13 22:00:19 -0800574 mDrawn = false;
Chris Craikd41c4d82015-01-05 15:51:13 -0800575 mClip = nullptr;
576 mBounds = nullptr;
Romain Guyff98fa52011-11-28 09:35:09 -0800577
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700578 Rect bounds;
Chris Craika1717272015-11-19 13:02:43 -0800579 mCurrentFont->measure(paint, text, numGlyphs, &bounds, positions);
Romain Guyff98fa52011-11-28 09:35:09 -0800580
Derek Sollenbergere392c812014-05-21 11:25:22 -0400581 uint32_t intRadius = Blur::convertRadiusToInt(radius);
582 uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
583 uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
Romain Guyff98fa52011-11-28 09:35:09 -0800584
Romain Guycf51a412013-04-08 19:40:31 -0700585 uint32_t maxSize = Caches::getInstance().maxTextureSize;
586 if (paddedWidth > maxSize || paddedHeight > maxSize) {
587 return image;
588 }
589
Dan Morrille4d9a012013-03-28 18:10:43 -0700590#ifdef ANDROID_ENABLE_RENDERSCRIPT
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800591 // Align buffers for renderscript usage
592 if (paddedWidth & (RS_CPU_ALLOCATION_ALIGNMENT - 1)) {
593 paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700594 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800595 int size = paddedWidth * paddedHeight;
Romain Guy6e200402013-03-08 11:28:22 -0800596 uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
Dan Morrille4d9a012013-03-28 18:10:43 -0700597#else
598 int size = paddedWidth * paddedHeight;
599 uint8_t* dataBuffer = (uint8_t*) malloc(size);
600#endif
601
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800602 memset(dataBuffer, 0, size);
603
Derek Sollenbergere392c812014-05-21 11:25:22 -0400604 int penX = intRadius - bounds.left;
605 int penY = intRadius - bounds.bottom;
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700606
Chris Craikdd8697c2013-02-22 10:41:36 -0800607 if ((bounds.right > bounds.left) && (bounds.top > bounds.bottom)) {
608 // text has non-whitespace, so draw and blur to create the shadow
609 // NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
610 // TODO: don't draw pure whitespace in the first place, and avoid needing this check
Chris Craika1717272015-11-19 13:02:43 -0800611 mCurrentFont->render(paint, text, numGlyphs, penX, penY,
Chris Craikd41c4d82015-01-05 15:51:13 -0800612 Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
Chris Craikdd8697c2013-02-22 10:41:36 -0800613
Romain Guycf51a412013-04-08 19:40:31 -0700614 // Unbind any PBO we might have used
Chris Craik44eb2c02015-01-29 09:45:09 -0800615 Caches::getInstance().pixelBufferState().unbind();
Romain Guycf51a412013-04-08 19:40:31 -0700616
Chris Craikdd8697c2013-02-22 10:41:36 -0800617 blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
618 }
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700619
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700620 image.width = paddedWidth;
621 image.height = paddedHeight;
622 image.image = dataBuffer;
623 image.penX = penX;
624 image.penY = penY;
Romain Guy2d4fd362011-12-13 22:00:19 -0800625
Alex Sakhartchoukf18136c2010-08-06 14:49:04 -0700626 return image;
627}
Romain Guy694b5192010-07-21 21:33:20 -0700628
Chris Craik82840732015-04-03 09:37:49 -0700629void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextDrawFunctor* functor) {
Romain Guy694b5192010-07-21 21:33:20 -0700630 checkInit();
631
Romain Guy5b3b3522010-10-27 18:57:51 -0700632 mDrawn = false;
633 mBounds = bounds;
Romain Guy257ae352013-03-20 16:31:12 -0700634 mFunctor = functor;
Romain Guy09147fb2010-07-22 13:08:20 -0700635 mClip = clip;
Romain Guy671d6cf2012-01-18 12:39:17 -0800636}
Romain Guyff98fa52011-11-28 09:35:09 -0800637
Romain Guy671d6cf2012-01-18 12:39:17 -0800638void FontRenderer::finishRender() {
Chris Craikd41c4d82015-01-05 15:51:13 -0800639 mBounds = nullptr;
640 mClip = nullptr;
Romain Guy694b5192010-07-21 21:33:20 -0700641
Romain Guy661a87e2013-03-19 15:24:36 -0700642 issueDrawCommand();
Romain Guy671d6cf2012-01-18 12:39:17 -0800643}
644
Chris Craikd218a922014-01-02 17:13:34 -0800645void FontRenderer::precache(const SkPaint* paint, const char* text, int numGlyphs,
Chris Craik59744b72014-07-01 17:56:52 -0700646 const SkMatrix& matrix) {
Romain Guye3a9b242013-01-08 11:15:30 -0800647 Font* font = Font::create(this, paint, matrix);
Chet Haasee816bae2012-08-09 13:39:02 -0700648 font->precache(paint, text, numGlyphs);
649}
650
Romain Guycf51a412013-04-08 19:40:31 -0700651void FontRenderer::endPrecaching() {
652 checkTextureUpdate();
653}
654
Chris Craikd218a922014-01-02 17:13:34 -0800655bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
Chris Craika1717272015-11-19 13:02:43 -0800656 int numGlyphs, int x, int y, const float* positions,
657 Rect* bounds, TextDrawFunctor* functor, bool forceFinish) {
Romain Guy671d6cf2012-01-18 12:39:17 -0800658 if (!mCurrentFont) {
659 ALOGE("No font set");
660 return false;
661 }
662
Romain Guy257ae352013-03-20 16:31:12 -0700663 initRender(clip, bounds, functor);
Chris Craika1717272015-11-19 13:02:43 -0800664 mCurrentFont->render(paint, text, numGlyphs, x, y, positions);
Chris Craik527a3aa2013-03-04 10:19:31 -0800665
666 if (forceFinish) {
667 finishRender();
668 }
Romain Guy5b3b3522010-10-27 18:57:51 -0700669
670 return mDrawn;
Romain Guy694b5192010-07-21 21:33:20 -0700671}
672
Chris Craikd218a922014-01-02 17:13:34 -0800673bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
Chris Craika1717272015-11-19 13:02:43 -0800674 int numGlyphs, const SkPath* path, float hOffset, float vOffset,
675 Rect* bounds, TextDrawFunctor* functor) {
Romain Guy97771732012-02-28 18:17:02 -0800676 if (!mCurrentFont) {
677 ALOGE("No font set");
678 return false;
679 }
680
Victoria Lease1e546812013-06-25 14:25:17 -0700681 initRender(clip, bounds, functor);
Chris Craika1717272015-11-19 13:02:43 -0800682 mCurrentFont->render(paint, text, numGlyphs, path, hOffset, vOffset);
Romain Guy97771732012-02-28 18:17:02 -0800683 finishRender();
684
685 return mDrawn;
686}
687
Derek Sollenbergere392c812014-05-21 11:25:22 -0400688void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
689 uint32_t intRadius = Blur::convertRadiusToInt(radius);
Dan Morrille4d9a012013-03-28 18:10:43 -0700690#ifdef ANDROID_ENABLE_RENDERSCRIPT
Derek Sollenbergere392c812014-05-21 11:25:22 -0400691 if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700692 uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700693
Chris Craikd41c4d82015-01-05 15:51:13 -0800694 if (mRs == nullptr) {
Dan Morrille4d9a012013-03-28 18:10:43 -0700695 mRs = new RSC::RS();
Tim Murrayabe55e92013-12-13 12:57:36 -0800696 // a null path is OK because there are no custom kernels used
697 // hence nothing gets cached by RS
698 if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800699 mRs.clear();
Dan Morrille4d9a012013-03-28 18:10:43 -0700700 ALOGE("blur RS failed to init");
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800701 } else {
702 mRsElement = RSC::Element::A_8(mRs);
703 mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
Dan Morrille4d9a012013-03-28 18:10:43 -0700704 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800705 }
Chris Craikd41c4d82015-01-05 15:51:13 -0800706 if (mRs != nullptr) {
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800707 RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
708 RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
709 RS_ALLOCATION_MIPMAP_NONE,
710 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
711 *image);
712 RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
713 RS_ALLOCATION_MIPMAP_NONE,
714 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
715 outImage);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800716
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800717 mRsScript->setRadius(radius);
718 mRsScript->setInput(ain);
719 mRsScript->forEach(aout);
Dan Morrille4d9a012013-03-28 18:10:43 -0700720
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800721 // replace the original image's pointer, avoiding a copy back to the original buffer
722 free(*image);
723 *image = outImage;
Dan Morrille4d9a012013-03-28 18:10:43 -0700724
Lu, Shenghuaea42e012013-11-14 15:52:22 +0800725 return;
726 }
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800727 }
Dan Morrille4d9a012013-03-28 18:10:43 -0700728#endif
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800729
Chris Craik51d6a3d2014-12-22 17:16:56 -0800730 std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
huanhuan.x.wanga46ca5e2015-04-14 16:23:15 +0200731 Blur::generateGaussianWeights(gaussian.get(), radius);
Chris Craikf2d8ccc2013-02-13 16:14:17 -0800732
Chris Craik51d6a3d2014-12-22 17:16:56 -0800733 std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
734 Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
735 Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
Alex Sakhartchouk89a524a2010-08-02 17:52:30 -0700736}
737
John Reck272a6852015-07-29 16:48:58 -0700738static uint32_t calculateCacheSize(const std::vector<CacheTexture*>& cacheTextures) {
Romain Guycf51a412013-04-08 19:40:31 -0700739 uint32_t size = 0;
Victoria Lease1e546812013-06-25 14:25:17 -0700740 for (uint32_t i = 0; i < cacheTextures.size(); i++) {
741 CacheTexture* cacheTexture = cacheTextures[i];
Romain Guycf51a412013-04-08 19:40:31 -0700742 if (cacheTexture && cacheTexture->getPixelBuffer()) {
743 size += cacheTexture->getPixelBuffer()->getSize();
744 }
745 }
746 return size;
747}
748
Victoria Lease1e546812013-06-25 14:25:17 -0700749uint32_t FontRenderer::getCacheSize(GLenum format) const {
750 switch (format) {
751 case GL_ALPHA: {
752 return calculateCacheSize(mACacheTextures);
753 }
754 case GL_RGBA: {
755 return calculateCacheSize(mRGBACacheTextures);
756 }
757 default: {
758 return 0;
759 }
760 }
761}
762
Romain Guy694b5192010-07-21 21:33:20 -0700763}; // namespace uirenderer
764}; // namespace android