diff options
Diffstat (limited to 'libs/hwui')
-rw-r--r-- | libs/hwui/AssetAtlas.cpp | 15 | ||||
-rw-r--r-- | libs/hwui/AssetAtlas.h | 4 | ||||
-rw-r--r-- | libs/hwui/Caches.cpp | 15 | ||||
-rw-r--r-- | libs/hwui/Caches.h | 5 | ||||
-rw-r--r-- | libs/hwui/DisplayListOp.h | 2 | ||||
-rw-r--r-- | libs/hwui/FontRenderer.cpp | 44 | ||||
-rw-r--r-- | libs/hwui/Layer.cpp | 1 | ||||
-rw-r--r-- | libs/hwui/LayerRenderer.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/Patch.cpp | 7 | ||||
-rw-r--r-- | libs/hwui/Patch.h | 2 | ||||
-rw-r--r-- | libs/hwui/PatchCache.cpp | 23 | ||||
-rw-r--r-- | libs/hwui/PathCache.cpp | 8 | ||||
-rw-r--r-- | libs/hwui/PathCache.h | 5 | ||||
-rw-r--r-- | libs/hwui/PixelBuffer.cpp | 2 | ||||
-rw-r--r-- | libs/hwui/PixelBuffer.h | 19 | ||||
-rw-r--r-- | libs/hwui/ResourceCache.cpp | 34 | ||||
-rw-r--r-- | libs/hwui/Snapshot.h | 2 | ||||
-rw-r--r-- | libs/hwui/TextureCache.cpp | 60 | ||||
-rw-r--r-- | libs/hwui/TextureCache.h | 2 | ||||
-rw-r--r-- | libs/hwui/font/Font.cpp | 27 | ||||
-rw-r--r-- | libs/hwui/utils/TinyHashMap.h | 6 |
21 files changed, 194 insertions, 93 deletions
diff --git a/libs/hwui/AssetAtlas.cpp b/libs/hwui/AssetAtlas.cpp index eb8bb9f..e8c3d3c 100644 --- a/libs/hwui/AssetAtlas.cpp +++ b/libs/hwui/AssetAtlas.cpp @@ -28,7 +28,7 @@ namespace uirenderer { // Lifecycle /////////////////////////////////////////////////////////////////////////////// -void AssetAtlas::init(sp<GraphicBuffer> buffer, int* map, int count) { +void AssetAtlas::init(sp<GraphicBuffer> buffer, int64_t* map, int count) { if (mImage) { return; } @@ -108,14 +108,19 @@ private: /** * TODO: This method does not take the rotation flag into account */ -void AssetAtlas::createEntries(Caches& caches, int* map, int count) { +void AssetAtlas::createEntries(Caches& caches, int64_t* map, int count) { const float width = float(mTexture->width); const float height = float(mTexture->height); for (int i = 0; i < count; ) { - SkBitmap* bitmap = (SkBitmap*) map[i++]; - int x = map[i++]; - int y = map[i++]; + SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(map[i++]); + // NOTE: We're converting from 64 bit signed values to 32 bit + // signed values. This is guaranteed to be safe because the "x" + // and "y" coordinate values are guaranteed to be representable + // with 32 bits. The array is 64 bits wide so that it can carry + // pointers on 64 bit architectures. + const int x = static_cast<int>(map[i++]); + const int y = static_cast<int>(map[i++]); bool rotated = map[i++] > 0; // Bitmaps should never be null, we're just extra paranoid diff --git a/libs/hwui/AssetAtlas.h b/libs/hwui/AssetAtlas.h index a28efc6..163bdbc 100644 --- a/libs/hwui/AssetAtlas.h +++ b/libs/hwui/AssetAtlas.h @@ -121,7 +121,7 @@ public: * initialized. To re-initialize the atlas, you must * first call terminate(). */ - ANDROID_API void init(sp<GraphicBuffer> buffer, int* map, int count); + ANDROID_API void init(sp<GraphicBuffer> buffer, int64_t* map, int count); /** * Destroys the atlas texture. This object can be @@ -176,7 +176,7 @@ public: } private: - void createEntries(Caches& caches, int* map, int count); + void createEntries(Caches& caches, int64_t* map, int count); Texture* mTexture; Image* mImage; diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index f8d3589..b0f4c2c 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -554,11 +554,8 @@ void Caches::deleteTexture(GLuint texture) { // call, any texture operation will be performed on the default // texture (name=0) - for (int i = 0; i < REQUIRED_TEXTURE_UNITS_COUNT; i++) { - if (mBoundTextures[i] == texture) { - mBoundTextures[i] = 0; - } - } + unbindTexture(texture); + glDeleteTextures(1, &texture); } @@ -566,6 +563,14 @@ void Caches::resetBoundTextures() { memset(mBoundTextures, 0, REQUIRED_TEXTURE_UNITS_COUNT * sizeof(GLuint)); } +void Caches::unbindTexture(GLuint texture) { + for (int i = 0; i < REQUIRED_TEXTURE_UNITS_COUNT; i++) { + if (mBoundTextures[i] == texture) { + mBoundTextures[i] = 0; + } + } +} + /////////////////////////////////////////////////////////////////////////////// // Scissor /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index 282aee9..544757a 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -264,6 +264,11 @@ public: void resetBoundTextures(); /** + * Clear the cache of bound textures. + */ + void unbindTexture(GLuint texture); + + /** * Sets the scissor for the current surface. */ bool setScissor(GLint x, GLint y, GLint width, GLint height); diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h index 326805a..842e028 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -1444,7 +1444,7 @@ public: DeferredDisplayList::kOpBatch_Text : DeferredDisplayList::kOpBatch_ColorText; - deferInfo.mergeId = (mergeid_t)mPaint->getColor(); + deferInfo.mergeId = reinterpret_cast<mergeid_t>(mPaint->getColor()); // don't merge decorated text - the decorations won't draw in order bool noDecorations = !(mPaint->getFlags() & (SkPaint::kUnderlineText_Flag | diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index 0be17ff..8d19ca2 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -735,30 +735,34 @@ void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, int // a null path is OK because there are no custom kernels used // hence nothing gets cached by RS if (!mRs->init("", RSC::RS_INIT_LOW_LATENCY | RSC::RS_INIT_SYNCHRONOUS)) { + mRs.clear(); ALOGE("blur RS failed to init"); + } else { + mRsElement = RSC::Element::A_8(mRs); + mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement); } - - mRsElement = RSC::Element::A_8(mRs); - mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement); } + if (mRs != 0) { + RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0); + RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t, + RS_ALLOCATION_MIPMAP_NONE, + RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, + *image); + RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t, + RS_ALLOCATION_MIPMAP_NONE, + RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, + outImage); + + mRsScript->setRadius(radius); + mRsScript->setInput(ain); + mRsScript->forEach(aout); + + // replace the original image's pointer, avoiding a copy back to the original buffer + free(*image); + *image = outImage; - RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0); - RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t, - RS_ALLOCATION_MIPMAP_NONE, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, - *image); - RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t, - RS_ALLOCATION_MIPMAP_NONE, RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, - outImage); - - mRsScript->setRadius(radius); - mRsScript->setInput(ain); - mRsScript->forEach(aout); - - // replace the original image's pointer, avoiding a copy back to the original buffer - free(*image); - *image = outImage; - - return; + return; + } } #endif diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index bd371a3..987bf03 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -171,6 +171,7 @@ void Layer::deleteTexture() { } void Layer::clearTexture() { + caches.unbindTexture(texture.id); texture.id = 0; } diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index f8076cc..006d145 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -339,8 +339,10 @@ void LayerRenderer::destroyLayerDeferred(Layer* layer) { void LayerRenderer::flushLayer(Layer* layer) { #ifdef GL_EXT_discard_framebuffer + if (!layer) return; + GLuint fbo = layer->getFbo(); - if (layer && fbo) { + if (fbo) { // If possible, discard any enqueud operations on deferred // rendering architectures if (Extensions::getInstance().hasDiscardFramebuffer()) { diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp index 9b023f9..442e9ba 100644 --- a/libs/hwui/Patch.cpp +++ b/libs/hwui/Patch.cpp @@ -36,6 +36,7 @@ Patch::Patch(): vertices(NULL), verticesCount(0), indexCount(0), hasEmptyQuads(f } Patch::~Patch() { + delete[] vertices; } /////////////////////////////////////////////////////////////////////////////// @@ -57,7 +58,7 @@ TextureVertex* Patch::createMesh(const float bitmapWidth, const float bitmapHeig if (vertices) return vertices; int8_t emptyQuads = 0; - mColors = patch->colors; + mColors = patch->getColors(); const int8_t numColors = patch->numColors; if (uint8_t(numColors) < sizeof(uint32_t) * 4) { @@ -79,8 +80,8 @@ TextureVertex* Patch::createMesh(const float bitmapWidth, const float bitmapHeig TextureVertex* tempVertices = new TextureVertex[maxVertices]; TextureVertex* vertex = tempVertices; - const int32_t* xDivs = patch->xDivs; - const int32_t* yDivs = patch->yDivs; + const int32_t* xDivs = patch->getXDivs(); + const int32_t* yDivs = patch->getYDivs(); const uint32_t xStretchCount = (xCount + 1) >> 1; const uint32_t yStretchCount = (yCount + 1) >> 1; diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h index 763a785..b5e8838 100644 --- a/libs/hwui/Patch.h +++ b/libs/hwui/Patch.h @@ -66,7 +66,7 @@ private: void generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2, float u1, float v1, float u2, float v2, uint32_t& quadCount); - uint32_t* mColors; + const uint32_t* mColors; UvMapper mUvMapper; }; // struct Patch diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp index dc0d98c..2f2debc 100644 --- a/libs/hwui/PatchCache.cpp +++ b/libs/hwui/PatchCache.cpp @@ -119,6 +119,17 @@ void PatchCache::remove(Vector<patch_pair_t>& patchesToRemove, Res_png_9patch* p void PatchCache::removeDeferred(Res_png_9patch* patch) { Mutex::Autolock _l(mLock); + + // Assert that patch is not already garbage + size_t count = mGarbage.size(); + for (size_t i = 0; i < count; i++) { + if (patch == mGarbage[i]) { + patch = NULL; + break; + } + } + LOG_ALWAYS_FATAL_IF(patch == NULL); + mGarbage.push(patch); } @@ -129,7 +140,11 @@ void PatchCache::clearGarbage() { Mutex::Autolock _l(mLock); size_t count = mGarbage.size(); for (size_t i = 0; i < count; i++) { - remove(patchesToRemove, mGarbage[i]); + Res_png_9patch* patch = mGarbage[i]; + remove(patchesToRemove, patch); + // A Res_png_9patch is actually an array of byte that's larger + // than sizeof(Res_png_9patch). It must be freed as an array. + delete[] (int8_t*) patch; } mGarbage.clear(); } @@ -139,8 +154,8 @@ void PatchCache::clearGarbage() { for (size_t i = 0; i < patchesToRemove.size(); i++) { const patch_pair_t& pair = patchesToRemove[i]; - // Add a new free block to the list - const Patch* patch = pair.getSecond(); + // Release the patch and mark the space in the free list + Patch* patch = pair.getSecond(); BufferBlock* block = new BufferBlock(patch->offset, patch->getSize()); block->next = mFreeBlocks; mFreeBlocks = block; @@ -148,6 +163,7 @@ void PatchCache::clearGarbage() { mSize -= patch->getSize(); mCache.remove(*pair.getFirst()); + delete patch; } #if DEBUG_PATCHES @@ -212,6 +228,7 @@ void PatchCache::setupMesh(Patch* newMesh, TextureVertex* vertices) { } else { mFreeBlocks = block->next; } + delete block; } else { // Resize the block now that it's occupied block->offset += size; diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp index 5df6408..0794aec 100644 --- a/libs/hwui/PathCache.cpp +++ b/libs/hwui/PathCache.cpp @@ -346,7 +346,7 @@ void PathCache::PathProcessor::onProcess(const sp<Task<SkBitmap*> >& task) { float left, top, offset; uint32_t width, height; - PathCache::computePathBounds(t->path, t->paint, left, top, offset, width, height); + PathCache::computePathBounds(t->path, &t->paint, left, top, offset, width, height); PathTexture* texture = t->texture; texture->left = left; @@ -357,7 +357,7 @@ void PathCache::PathProcessor::onProcess(const sp<Task<SkBitmap*> >& task) { if (width <= mMaxTextureSize && height <= mMaxTextureSize) { SkBitmap* bitmap = new SkBitmap(); - drawPath(t->path, t->paint, *bitmap, left, top, offset, width, height); + drawPath(t->path, &t->paint, *bitmap, left, top, offset, width, height); t->setResult(bitmap); } else { texture->width = 0; @@ -395,7 +395,9 @@ void PathCache::clearGarbage() { Mutex::Autolock l(mLock); size_t count = mGarbage.size(); for (size_t i = 0; i < count; i++) { - remove(pathsToRemove, mGarbage.itemAt(i)); + const path_pair_t& pair = mGarbage.itemAt(i); + remove(pathsToRemove, pair); + delete pair.getFirst(); } mGarbage.clear(); } diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h index 16d20a8..24f88f1 100644 --- a/libs/hwui/PathCache.h +++ b/libs/hwui/PathCache.h @@ -293,7 +293,7 @@ private: class PathTask: public Task<SkBitmap*> { public: PathTask(SkPath* path, SkPaint* paint, PathTexture* texture): - path(path), paint(paint), texture(texture) { + path(path), paint(*paint), texture(texture) { } ~PathTask() { @@ -301,7 +301,8 @@ private: } SkPath* path; - SkPaint* paint; + //copied, since input paint may not be immutable + SkPaint paint; PathTexture* texture; }; diff --git a/libs/hwui/PixelBuffer.cpp b/libs/hwui/PixelBuffer.cpp index 36e89c6..5b642b9 100644 --- a/libs/hwui/PixelBuffer.cpp +++ b/libs/hwui/PixelBuffer.cpp @@ -151,7 +151,7 @@ void GpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t hei mCaches.bindPixelBuffer(mBuffer); unmap(); glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat, - GL_UNSIGNED_BYTE, (void*) offset); + GL_UNSIGNED_BYTE, reinterpret_cast<void*>(offset)); } /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/PixelBuffer.h b/libs/hwui/PixelBuffer.h index 9725a61..04225a2 100644 --- a/libs/hwui/PixelBuffer.h +++ b/libs/hwui/PixelBuffer.h @@ -175,6 +175,25 @@ public: return 0; } + /** + * Returns the alpha channel offset in the specified format. + * + * Supported formats: + * GL_ALPHA + * GL_RGBA + */ + static uint32_t formatAlphaOffset(GLenum format) { + switch (format) { + case GL_ALPHA: + return 0; + case GL_RGBA: + return 3; + } + + ALOGE("unsupported format: %d",format); + return 0; + } + protected: /** * Creates a new render buffer in the specified format and dimensions. diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp index 3f77021..77292bf 100644 --- a/libs/hwui/ResourceCache.cpp +++ b/libs/hwui/ResourceCache.cpp @@ -31,9 +31,9 @@ void ResourceCache::logCache() { ALOGD("ResourceCache: cacheReport:"); for (size_t i = 0; i < mCache->size(); ++i) { ResourceReference* ref = mCache->valueAt(i); - ALOGD(" ResourceCache: mCache(%d): resource, ref = 0x%p, 0x%p", + ALOGD(" ResourceCache: mCache(%zu): resource, ref = 0x%p, 0x%p", i, mCache->keyAt(i), mCache->valueAt(i)); - ALOGD(" ResourceCache: mCache(%d): refCount, recycled, destroyed, type = %d, %d, %d, %d", + ALOGD(" ResourceCache: mCache(%zu): refCount, recycled, destroyed, type = %d, %d, %d, %d", i, ref->refCount, ref->recycled, ref->destroyed, ref->resourceType); } } @@ -213,8 +213,9 @@ void ResourceCache::destructorLocked(SkPath* resource) { // If we're not tracking this resource, just delete it if (Caches::hasInstance()) { Caches::getInstance().pathCache.removeDeferred(resource); + } else { + delete resource; } - delete resource; return; } ref->destroyed = true; @@ -235,8 +236,9 @@ void ResourceCache::destructorLocked(SkBitmap* resource) { // If we're not tracking this resource, just delete it if (Caches::hasInstance()) { Caches::getInstance().textureCache.removeDeferred(resource); + } else { + delete resource; } - delete resource; return; } ref->destroyed = true; @@ -292,13 +294,14 @@ void ResourceCache::destructorLocked(Res_png_9patch* resource) { ssize_t index = mCache->indexOfKey(resource); ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL; if (ref == NULL) { + // If we're not tracking this resource, just delete it if (Caches::hasInstance()) { Caches::getInstance().patchCache.removeDeferred(resource); + } else { + // A Res_png_9patch is actually an array of byte that's larger + // than sizeof(Res_png_9patch). It must be freed as an array. + delete[] (int8_t*) resource; } - // If we're not tracking this resource, just delete it - // A Res_png_9patch is actually an array of byte that's larger - // than sizeof(Res_png_9patch). It must be freed as an array. - delete[] (int8_t*) resource; return; } ref->destroyed = true; @@ -355,16 +358,18 @@ void ResourceCache::deleteResourceReferenceLocked(void* resource, ResourceRefere SkBitmap* bitmap = (SkBitmap*) resource; if (Caches::hasInstance()) { Caches::getInstance().textureCache.removeDeferred(bitmap); + } else { + delete bitmap; } - delete bitmap; } break; case kPath: { SkPath* path = (SkPath*) resource; if (Caches::hasInstance()) { Caches::getInstance().pathCache.removeDeferred(path); + } else { + delete path; } - delete path; } break; case kShader: { @@ -380,11 +385,12 @@ void ResourceCache::deleteResourceReferenceLocked(void* resource, ResourceRefere case kNinePatch: { if (Caches::hasInstance()) { Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*) resource); + } else { + // A Res_png_9patch is actually an array of byte that's larger + // than sizeof(Res_png_9patch). It must be freed as an array. + int8_t* patch = (int8_t*) resource; + delete[] patch; } - // A Res_png_9patch is actually an array of byte that's larger - // than sizeof(Res_png_9patch). It must be freed as an array. - int8_t* patch = (int8_t*) resource; - delete[] patch; } break; case kLayer: { diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h index cc6d0cd..5bdb18a 100644 --- a/libs/hwui/Snapshot.h +++ b/libs/hwui/Snapshot.h @@ -108,7 +108,7 @@ public: * Returns the current clip in local coordinates. The clip rect is * transformed by the inverse transform matrix. */ - const Rect& getLocalClip(); + ANDROID_API const Rect& getLocalClip(); /** * Resets the clip to the specified rect. diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp index 8d0874f..6f68666 100644 --- a/libs/hwui/TextureCache.cpp +++ b/libs/hwui/TextureCache.cpp @@ -184,7 +184,9 @@ void TextureCache::clearGarbage() { Mutex::Autolock _l(mLock); size_t count = mGarbage.size(); for (size_t i = 0; i < count; i++) { - mCache.remove(mGarbage.itemAt(i)); + const SkBitmap* bitmap = mGarbage.itemAt(i); + mCache.remove(bitmap); + delete bitmap; } mGarbage.clear(); } @@ -240,19 +242,19 @@ void TextureCache::generateTexture(SkBitmap* bitmap, Texture* texture, bool rege switch (bitmap->getConfig()) { case SkBitmap::kA8_Config: glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(), + uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(), texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels()); texture->blend = true; break; case SkBitmap::kRGB_565_Config: glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel()); - uploadToTexture(resize, GL_RGB, bitmap->rowBytesAsPixels(), + uploadToTexture(resize, GL_RGB, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(), texture->width, texture->height, GL_UNSIGNED_SHORT_5_6_5, bitmap->getPixels()); texture->blend = false; break; case SkBitmap::kARGB_8888_Config: glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel()); - uploadToTexture(resize, GL_RGBA, bitmap->rowBytesAsPixels(), + uploadToTexture(resize, GL_RGBA, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(), texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels()); // Do this after calling getPixels() to make sure Skia's deferred // decoding happened @@ -292,27 +294,49 @@ void TextureCache::uploadLoFiTexture(bool resize, SkBitmap* bitmap, SkCanvas canvas(rgbaBitmap); canvas.drawBitmap(*bitmap, 0.0f, 0.0f, NULL); - uploadToTexture(resize, GL_RGBA, rgbaBitmap.rowBytesAsPixels(), width, height, - GL_UNSIGNED_BYTE, rgbaBitmap.getPixels()); + uploadToTexture(resize, GL_RGBA, rgbaBitmap.rowBytesAsPixels(), rgbaBitmap.bytesPerPixel(), + width, height, GL_UNSIGNED_BYTE, rgbaBitmap.getPixels()); } -void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei stride, +void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp, GLsizei width, GLsizei height, GLenum type, const GLvoid * data) { - // TODO: With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer - // if the stride doesn't match the width const bool useStride = stride != width && Extensions::getInstance().hasUnpackRowLength(); - if (useStride) { - glPixelStorei(GL_UNPACK_ROW_LENGTH, stride); - } + if ((stride == width) || useStride) { + if (useStride) { + glPixelStorei(GL_UNPACK_ROW_LENGTH, stride); + } + + if (resize) { + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data); + } else { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data); + } - if (resize) { - glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data); + if (useStride) { + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + } } else { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data); - } + // With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer + // if the stride doesn't match the width + + GLvoid * temp = (GLvoid *) malloc(width * height * bpp); + if (!temp) return; + + uint8_t * pDst = (uint8_t *)temp; + uint8_t * pSrc = (uint8_t *)data; + for (GLsizei i = 0; i < height; i++) { + memcpy(pDst, pSrc, width * bpp); + pDst += width * bpp; + pSrc += stride * bpp; + } + + if (resize) { + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, temp); + } else { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, temp); + } - if (useStride) { - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + free(temp); } } diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h index 57fc19a..909d762 100644 --- a/libs/hwui/TextureCache.h +++ b/libs/hwui/TextureCache.h @@ -125,7 +125,7 @@ private: void generateTexture(SkBitmap* bitmap, Texture* texture, bool regenerate = false); void uploadLoFiTexture(bool resize, SkBitmap* bitmap, uint32_t width, uint32_t height); - void uploadToTexture(bool resize, GLenum format, GLsizei stride, + void uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp, GLsizei width, GLsizei height, GLenum type, const GLvoid * data); void init(); diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp index e54c61e..e69b0cc 100644 --- a/libs/hwui/font/Font.cpp +++ b/libs/hwui/font/Font.cpp @@ -214,18 +214,29 @@ void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y, uint8_t* int dstY = y + glyph->mBitmapTop; CacheTexture* cacheTexture = glyph->mCacheTexture; + PixelBuffer* pixelBuffer = cacheTexture->getPixelBuffer(); + uint32_t formatSize = PixelBuffer::formatSize(pixelBuffer->getFormat()); + uint32_t alpha_channel_offset = PixelBuffer::formatAlphaOffset(pixelBuffer->getFormat()); uint32_t cacheWidth = cacheTexture->getWidth(); - uint32_t startY = glyph->mStartY * cacheWidth; - uint32_t endY = startY + (glyph->mBitmapHeight * cacheWidth); + uint32_t srcStride = formatSize * cacheWidth; + uint32_t startY = glyph->mStartY * srcStride; + uint32_t endY = startY + (glyph->mBitmapHeight * srcStride); - PixelBuffer* pixelBuffer = cacheTexture->getPixelBuffer(); const uint8_t* cacheBuffer = pixelBuffer->map(); for (uint32_t cacheY = startY, bitmapY = dstY * bitmapWidth; cacheY < endY; - cacheY += cacheWidth, bitmapY += bitmapWidth) { - memcpy(&bitmap[bitmapY + dstX], &cacheBuffer[cacheY + glyph->mStartX], glyph->mBitmapWidth); + cacheY += srcStride, bitmapY += bitmapWidth) { + + if (formatSize == 1) { + memcpy(&bitmap[bitmapY + dstX], &cacheBuffer[cacheY + glyph->mStartX], glyph->mBitmapWidth); + } else { + for (uint32_t i = 0; i < glyph->mBitmapWidth; ++i) { + bitmap[bitmapY + dstX + i] = cacheBuffer[cacheY + (glyph->mStartX + i)*formatSize + alpha_channel_offset]; + } + } } + } void Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset, @@ -406,10 +417,10 @@ void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len // If it's still not valid, we couldn't cache it, so we shouldn't // draw garbage; also skip empty glyphs (spaces) if (cachedGlyph->mIsValid && cachedGlyph->mCacheTexture) { - float penX = x + positions[(glyphsCount << 1)]; - float penY = y + positions[(glyphsCount << 1) + 1]; + int penX = x + (int) roundf(positions[(glyphsCount << 1)]); + int penY = y + (int) roundf(positions[(glyphsCount << 1) + 1]); - (*this.*render)(cachedGlyph, roundf(penX), roundf(penY), + (*this.*render)(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH, bounds, positions); } diff --git a/libs/hwui/utils/TinyHashMap.h b/libs/hwui/utils/TinyHashMap.h index 8855140..4ff9a42 100644 --- a/libs/hwui/utils/TinyHashMap.h +++ b/libs/hwui/utils/TinyHashMap.h @@ -24,8 +24,6 @@ namespace uirenderer { /** * A very simple hash map that doesn't allow duplicate keys, overwriting the older entry. - * - * Currently, expects simple keys that are handled by hash_t() */ template <typename TKey, typename TValue> class TinyHashMap { @@ -36,7 +34,7 @@ public: * Puts an entry in the hash, removing any existing entry with the same key */ void put(TKey key, TValue value) { - hash_t hash = hash_t(key); + hash_t hash = android::hash_type(key); ssize_t index = mTable.find(-1, hash, key); if (index != -1) { @@ -51,7 +49,7 @@ public: * Return true if key is in the map, in which case stores the value in the output ref */ bool get(TKey key, TValue& outValue) { - hash_t hash = hash_t(key); + hash_t hash = android::hash_type(key); ssize_t index = mTable.find(-1, hash, key); if (index == -1) { return false; |