diff options
Diffstat (limited to 'libs')
-rw-r--r-- | libs/hwui/Android.mk | 1 | ||||
-rw-r--r-- | libs/hwui/Caches.h | 7 | ||||
-rw-r--r-- | libs/hwui/FontRenderer.cpp | 98 | ||||
-rw-r--r-- | libs/hwui/FontRenderer.h | 11 | ||||
-rw-r--r-- | libs/hwui/GradientCache.cpp | 10 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 127 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 11 | ||||
-rw-r--r-- | libs/hwui/ProgramCache.cpp | 17 | ||||
-rw-r--r-- | libs/hwui/Properties.h | 6 | ||||
-rw-r--r-- | libs/hwui/SkiaShader.cpp | 35 | ||||
-rw-r--r-- | libs/hwui/SkiaShader.h | 7 | ||||
-rw-r--r-- | libs/hwui/Snapshot.cpp | 76 | ||||
-rw-r--r-- | libs/hwui/Snapshot.h | 9 | ||||
-rw-r--r-- | libs/hwui/Stencil.cpp | 71 | ||||
-rw-r--r-- | libs/hwui/Stencil.h | 89 |
15 files changed, 316 insertions, 259 deletions
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 1947c32..c3a07a1 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -28,6 +28,7 @@ ifeq ($(USE_OPENGL_RENDERER),true) SkiaColorFilter.cpp \ SkiaShader.cpp \ Snapshot.cpp \ + Stencil.cpp \ TextureCache.cpp \ TextDropShadowCache.cpp diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index f4f56d6..b9a6336 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -38,6 +38,7 @@ #include "TextDropShadowCache.h" #include "FboCache.h" #include "ResourceCache.h" +#include "Stencil.h" #include "Dither.h" namespace android { @@ -252,10 +253,14 @@ public: TextDropShadowCache dropShadowCache; FboCache fboCache; ResourceCache resourceCache; - Dither dither; GammaFontRenderer* fontRenderer; + Dither dither; +#if STENCIL_BUFFER_SIZE + Stencil stencil; +#endif + // Debug methods PFNGLINSERTEVENTMARKEREXTPROC eventMark; PFNGLPUSHGROUPMARKEREXTPROC startMark; diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index 27e198c..95ccdfc 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -34,9 +34,10 @@ namespace uirenderer { // Defines /////////////////////////////////////////////////////////////////////////////// -#define DEFAULT_TEXT_CACHE_WIDTH 1024 -#define DEFAULT_TEXT_CACHE_HEIGHT 256 -#define MAX_TEXT_CACHE_WIDTH 2048 +#define DEFAULT_TEXT_SMALL_CACHE_WIDTH 1024 +#define DEFAULT_TEXT_SMALL_CACHE_HEIGHT 256 +#define DEFAULT_TEXT_LARGE_CACHE_WIDTH 2048 +#define DEFAULT_TEXT_LARGE_CACHE_HEIGHT 512 #define CACHE_BLOCK_ROUNDING_SIZE 4 #define AUTO_KERN(prev, next) (((next) - (prev) + 32) >> 6 << 16) @@ -328,19 +329,19 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float glyph->mCacheTexture); } -CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) { +CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit, bool precaching) { CachedGlyphInfo* cachedGlyph = NULL; ssize_t index = mCachedGlyphs.indexOfKey(textUnit); if (index >= 0) { cachedGlyph = mCachedGlyphs.valueAt(index); } else { - cachedGlyph = cacheGlyph(paint, textUnit); + cachedGlyph = cacheGlyph(paint, textUnit, precaching); } // Is the glyph still in texture cache? if (!cachedGlyph->mIsValid) { const SkGlyph& skiaGlyph = GET_METRICS(paint, textUnit); - updateGlyphCache(paint, skiaGlyph, cachedGlyph); + updateGlyphCache(paint, skiaGlyph, cachedGlyph, precaching); } return cachedGlyph; @@ -438,7 +439,7 @@ void Font::precache(SkPaint* paint, const char* text, int numGlyphs) { break; } - CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph); + CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph, true); glyphsCount++; } @@ -529,7 +530,8 @@ void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len } } -void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph) { +void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph, + bool precaching) { glyph->mAdvanceX = skiaGlyph.fAdvanceX; glyph->mAdvanceY = skiaGlyph.fAdvanceY; glyph->mBitmapLeft = skiaGlyph.fLeft; @@ -542,7 +544,7 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp // Get the bitmap for the glyph paint->findImage(skiaGlyph); - mState->cacheBitmap(skiaGlyph, glyph, &startX, &startY); + mState->cacheBitmap(skiaGlyph, glyph, &startX, &startY, precaching); if (!glyph->mIsValid) { return; @@ -567,7 +569,7 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp mState->mUploadTexture = true; } -CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph) { +CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph, bool precaching) { CachedGlyphInfo* newGlyph = new CachedGlyphInfo(); mCachedGlyphs.add(glyph, newGlyph); @@ -575,7 +577,7 @@ CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph) { newGlyph->mGlyphIndex = skiaGlyph.fID; newGlyph->mIsValid = false; - updateGlyphCache(paint, skiaGlyph, newGlyph); + updateGlyphCache(paint, skiaGlyph, newGlyph, precaching); return newGlyph; } @@ -625,30 +627,35 @@ FontRenderer::FontRenderer() { mIndexBufferID = 0; - mSmallCacheWidth = DEFAULT_TEXT_CACHE_WIDTH; - mSmallCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT; + mSmallCacheWidth = DEFAULT_TEXT_SMALL_CACHE_WIDTH; + mSmallCacheHeight = DEFAULT_TEXT_SMALL_CACHE_HEIGHT; + mLargeCacheWidth = DEFAULT_TEXT_LARGE_CACHE_WIDTH; + mLargeCacheHeight = DEFAULT_TEXT_LARGE_CACHE_HEIGHT; char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_TEXT_CACHE_WIDTH, property, NULL) > 0) { - if (sLogFontRendererCreate) { - INIT_LOGD(" Setting text cache width to %s pixels", property); - } + if (property_get(PROPERTY_TEXT_SMALL_CACHE_WIDTH, property, NULL) > 0) { mSmallCacheWidth = atoi(property); - } else { - if (sLogFontRendererCreate) { - INIT_LOGD(" Using default text cache width of %i pixels", mSmallCacheWidth); - } } - - if (property_get(PROPERTY_TEXT_CACHE_HEIGHT, property, NULL) > 0) { - if (sLogFontRendererCreate) { - INIT_LOGD(" Setting text cache width to %s pixels", property); - } + if (property_get(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, property, NULL) > 0) { mSmallCacheHeight = atoi(property); - } else { - if (sLogFontRendererCreate) { - INIT_LOGD(" Using default text cache height of %i pixels", mSmallCacheHeight); - } + } + if (property_get(PROPERTY_TEXT_LARGE_CACHE_WIDTH, property, NULL) > 0) { + mLargeCacheWidth = atoi(property); + } + if (property_get(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, property, NULL) > 0) { + mLargeCacheHeight = atoi(property); + } + GLint maxTextureSize = Caches::getInstance().maxTextureSize; + mSmallCacheWidth = (mSmallCacheWidth > maxTextureSize) ? maxTextureSize : mSmallCacheWidth; + mSmallCacheHeight = (mSmallCacheHeight > maxTextureSize) ? maxTextureSize : mSmallCacheHeight; + mLargeCacheWidth = (mLargeCacheWidth > maxTextureSize) ? maxTextureSize : mLargeCacheWidth; + mLargeCacheHeight = (mLargeCacheHeight > maxTextureSize) ? maxTextureSize : mLargeCacheHeight; + if (sLogFontRendererCreate) { + INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i", + mSmallCacheWidth, mSmallCacheHeight, + mLargeCacheWidth, mLargeCacheHeight >> 1, + mLargeCacheWidth, mLargeCacheHeight >> 1, + mLargeCacheWidth, mLargeCacheHeight); } sLogFontRendererCreate = false; @@ -762,7 +769,7 @@ CacheTexture* FontRenderer::cacheBitmapInTexture(const SkGlyph& glyph, } void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph, - uint32_t* retOriginX, uint32_t* retOriginY) { + uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) { checkInit(); cachedGlyph->mIsValid = false; // If the glyph is too tall, don't cache it @@ -779,15 +786,16 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp CacheTexture* cacheTexture = cacheBitmapInTexture(glyph, &startX, &startY); - // If the new glyph didn't fit, flush the state so far and invalidate everything if (!cacheTexture) { - flushAllAndInvalidate(); - - // Try to fit it again - cacheTexture = cacheBitmapInTexture(glyph, &startX, &startY); + if (!precaching) { + // If the new glyph didn't fit and we are not just trying to precache it, + // clear out the cache and try again + flushAllAndInvalidate(); + cacheTexture = cacheBitmapInTexture(glyph, &startX, &startY); + } - // if we still don't fit, something is wrong and we shouldn't draw if (!cacheTexture) { + // either the glyph didn't fit or we're precaching and will cache it when we draw return; } } @@ -859,21 +867,11 @@ void FontRenderer::initTextTexture() { } mCacheTextures.clear(); - // Next, use other, separate caches for large glyphs. - uint16_t maxWidth = 0; - if (Caches::hasInstance()) { - maxWidth = Caches::getInstance().maxTextureSize; - } - - if (maxWidth > MAX_TEXT_CACHE_WIDTH || maxWidth == 0) { - maxWidth = MAX_TEXT_CACHE_WIDTH; - } - mUploadTexture = false; mCacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true)); - mCacheTextures.push(createCacheTexture(maxWidth, 256, false)); - mCacheTextures.push(createCacheTexture(maxWidth, 256, false)); - mCacheTextures.push(createCacheTexture(maxWidth, 512, false)); + mCacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, false)); + mCacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, false)); + mCacheTextures.push(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight, false)); mCurrentCacheTexture = mCacheTextures[0]; } diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h index febae17..241b73e 100644 --- a/libs/hwui/FontRenderer.h +++ b/libs/hwui/FontRenderer.h @@ -243,8 +243,9 @@ protected: void invalidateTextureCache(CacheTexture *cacheTexture = NULL); - CachedGlyphInfo* cacheGlyph(SkPaint* paint, glyph_t glyph); - void updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph); + CachedGlyphInfo* cacheGlyph(SkPaint* paint, glyph_t glyph, bool precaching); + void updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph, + bool precaching); void measureCachedGlyph(CachedGlyphInfo* glyph, int x, int y, uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH, @@ -258,7 +259,7 @@ protected: void drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset, SkPathMeasure& measure, SkPoint* position, SkVector* tangent); - CachedGlyphInfo* getCachedGlyph(SkPaint* paint, glyph_t textUnit); + CachedGlyphInfo* getCachedGlyph(SkPaint* paint, glyph_t textUnit, bool precaching = false); static glyph_t nextGlyph(const uint16_t** srcPtr) { const uint16_t* src = *srcPtr; @@ -364,7 +365,7 @@ protected: void initTextTexture(); CacheTexture* createCacheTexture(int width, int height, bool allocate); void cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph, - uint32_t *retOriginX, uint32_t *retOriginY); + uint32_t *retOriginX, uint32_t *retOriginY, bool precaching); CacheTexture* cacheBitmapInTexture(const SkGlyph& glyph, uint32_t* startX, uint32_t* startY); void flushAllAndInvalidate(); @@ -390,6 +391,8 @@ protected: uint32_t mSmallCacheWidth; uint32_t mSmallCacheHeight; + uint32_t mLargeCacheWidth; + uint32_t mLargeCacheHeight; Vector<CacheTexture*> mCacheTextures; diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index 726b57c7..2e4e349 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -217,10 +217,12 @@ void GradientCache::generateTexture(uint32_t* colors, float* positions, float amount = (pos - start) / distance; float oppAmount = 1.0f - amount; - *p++ = uint8_t(startR * oppAmount + endR * amount); - *p++ = uint8_t(startG * oppAmount + endG * amount); - *p++ = uint8_t(startB * oppAmount + endB * amount); - *p++ = uint8_t(startA * oppAmount + endA * amount); + const float alpha = startA * oppAmount + endA * amount; + const float a = alpha / 255.0f; + *p++ = uint8_t(a * (startR * oppAmount + endR * amount)); + *p++ = uint8_t(a * (startG * oppAmount + endG * amount)); + *p++ = uint8_t(a * (startB * oppAmount + endB * amount)); + *p++ = uint8_t(alpha); } for (int i = 1; i < GRADIENT_TEXTURE_HEIGHT; i++) { diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 849c556..2f43be8 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -139,10 +139,6 @@ void OpenGLRenderer::endMark() const { // Setup /////////////////////////////////////////////////////////////////////////////// -uint32_t OpenGLRenderer::getStencilSize() { - return STENCIL_BUFFER_SIZE; -} - bool OpenGLRenderer::isDeferred() { return false; } @@ -440,7 +436,7 @@ int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom, mode = SkXfermode::kSrcOver_Mode; } - createLayer(mSnapshot, left, top, right, bottom, alpha, mode, flags, previousFbo); + createLayer(left, top, right, bottom, alpha, mode, flags, previousFbo); } return count; @@ -508,44 +504,56 @@ int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bot * buffer is left untouched until the first drawing operation. Only when * something actually gets drawn are the layers regions cleared. */ -bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, - float right, float bottom, int alpha, SkXfermode::Mode mode, - int flags, GLuint previousFbo) { +bool OpenGLRenderer::createLayer(float left, float top, float right, float bottom, + int alpha, SkXfermode::Mode mode, int flags, GLuint previousFbo) { LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top); LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize()); const bool fboLayer = flags & SkCanvas::kClipToLayer_SaveFlag; // Window coordinates of the layer + Rect clip; Rect bounds(left, top, right, bottom); - if (!fboLayer) { - mSnapshot->transform->mapRect(bounds); - - // Layers only make sense if they are in the framebuffer's bounds - if (bounds.intersect(*snapshot->clipRect)) { - // We cannot work with sub-pixels in this case - bounds.snapToPixelBoundaries(); - - // When the layer is not an FBO, we may use glCopyTexImage so we - // need to make sure the layer does not extend outside the bounds - // of the framebuffer - if (!bounds.intersect(snapshot->previous->viewport)) { - bounds.setEmpty(); - } - } else { + Rect untransformedBounds(bounds); + mSnapshot->transform->mapRect(bounds); + + // Layers only make sense if they are in the framebuffer's bounds + if (bounds.intersect(*mSnapshot->clipRect)) { + // We cannot work with sub-pixels in this case + bounds.snapToPixelBoundaries(); + + // When the layer is not an FBO, we may use glCopyTexImage so we + // need to make sure the layer does not extend outside the bounds + // of the framebuffer + if (!bounds.intersect(mSnapshot->previous->viewport)) { bounds.setEmpty(); + } else if (fboLayer) { + clip.set(bounds); + mat4 inverse; + inverse.loadInverse(*mSnapshot->transform); + inverse.mapRect(clip); + clip.snapToPixelBoundaries(); + if (clip.intersect(untransformedBounds)) { + clip.translate(-left, -top); + bounds.set(untransformedBounds); + } else { + clip.setEmpty(); + } } + } else { + bounds.setEmpty(); } if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize || - bounds.getHeight() > mCaches.maxTextureSize) { - snapshot->empty = fboLayer; + bounds.getHeight() > mCaches.maxTextureSize || + (fboLayer && clip.isEmpty())) { + mSnapshot->empty = fboLayer; } else { - snapshot->invisible = snapshot->invisible || (alpha <= ALPHA_THRESHOLD && fboLayer); + mSnapshot->invisible = mSnapshot->invisible || (alpha <= ALPHA_THRESHOLD && fboLayer); } // Bail out if we won't draw in this snapshot - if (snapshot->invisible || snapshot->empty) { + if (mSnapshot->invisible || mSnapshot->empty) { return false; } @@ -563,23 +571,23 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, layer->setBlend(true); // Save the layer in the snapshot - snapshot->flags |= Snapshot::kFlagIsLayer; - snapshot->layer = layer; + mSnapshot->flags |= Snapshot::kFlagIsLayer; + mSnapshot->layer = layer; if (fboLayer) { - return createFboLayer(layer, bounds, snapshot, previousFbo); + return createFboLayer(layer, bounds, clip, previousFbo); } else { // Copy the framebuffer into the layer layer->bindTexture(); if (!bounds.isEmpty()) { if (layer->isEmpty()) { glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, - bounds.left, snapshot->height - bounds.bottom, + bounds.left, mSnapshot->height - bounds.bottom, layer->getWidth(), layer->getHeight(), 0); layer->setEmpty(false); } else { glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left, - snapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight()); + mSnapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight()); } // Enqueue the buffer coordinates to clear the corresponding region later @@ -590,35 +598,20 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, return true; } -bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> snapshot, - GLuint previousFbo) { +bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip, GLuint previousFbo) { layer->setFbo(mCaches.fboCache.get()); - snapshot->region = &snapshot->layer->region; - snapshot->flags |= Snapshot::kFlagFboTarget; - - Rect clip(bounds); - snapshot->transform->mapRect(clip); - clip.intersect(*snapshot->clipRect); - clip.snapToPixelBoundaries(); - clip.intersect(snapshot->previous->viewport); - - mat4 inverse; - inverse.loadInverse(*mSnapshot->transform); + mSnapshot->region = &mSnapshot->layer->region; + mSnapshot->flags |= Snapshot::kFlagFboTarget; - inverse.mapRect(clip); - clip.snapToPixelBoundaries(); - clip.intersect(bounds); - clip.translate(-bounds.left, -bounds.top); - - snapshot->flags |= Snapshot::kFlagIsFboLayer; - snapshot->fbo = layer->getFbo(); - snapshot->resetTransform(-bounds.left, -bounds.top, 0.0f); - snapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom); - snapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight()); - snapshot->height = bounds.getHeight(); - snapshot->flags |= Snapshot::kFlagDirtyOrtho; - snapshot->orthoMatrix.load(mOrthoMatrix); + mSnapshot->flags |= Snapshot::kFlagIsFboLayer; + mSnapshot->fbo = layer->getFbo(); + mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f); + mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom); + mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight()); + mSnapshot->height = bounds.getHeight(); + mSnapshot->flags |= Snapshot::kFlagDirtyOrtho; + mSnapshot->orthoMatrix.load(mOrthoMatrix); // Bind texture to FBO glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo()); @@ -1403,10 +1396,6 @@ void OpenGLRenderer::setupDrawAALine(GLvoid* vertices, GLvoid* widthCoords, int boundaryWidthSlot = mCaches.currentProgram->getUniform("boundaryWidth"); glUniform1f(boundaryWidthSlot, boundaryWidthProportion); - - // Setting the inverse value saves computations per-fragment in the shader - int inverseBoundaryWidthSlot = mCaches.currentProgram->getUniform("inverseBoundaryWidth"); - glUniform1f(inverseBoundaryWidthSlot, 1.0f / boundaryWidthProportion); } void OpenGLRenderer::finishDrawAALine(const int widthSlot, const int lengthSlot) { @@ -1810,15 +1799,13 @@ void OpenGLRenderer::drawAARect(float left, float top, float right, float bottom float width = right - left; float height = bottom - top; - float boundaryWidthProportion = (width != 0) ? (2 * boundarySizeX) / width : 0; - float boundaryHeightProportion = (height != 0) ? (2 * boundarySizeY) / height : 0; + float boundaryWidthProportion = .5 - ((width != 0) ? (2 * boundarySizeX) / width : 0); + float boundaryHeightProportion = .5 - ((height != 0) ? (2 * boundarySizeY) / height : 0); setupDrawAALine((void*) aaVertices, widthCoords, lengthCoords, boundaryWidthProportion, widthSlot, lengthSlot); int boundaryLengthSlot = mCaches.currentProgram->getUniform("boundaryLength"); - int inverseBoundaryLengthSlot = mCaches.currentProgram->getUniform("inverseBoundaryLength"); glUniform1f(boundaryLengthSlot, boundaryHeightProportion); - glUniform1f(inverseBoundaryLengthSlot, (1.0f / boundaryHeightProportion)); AAVertex::set(aaVertices++, left, bottom, 1, 1); AAVertex::set(aaVertices++, left, top, 1, 0); @@ -1955,9 +1942,7 @@ status_t OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { Vertex* prevVertex = NULL; int boundaryLengthSlot = -1; - int inverseBoundaryLengthSlot = -1; int boundaryWidthSlot = -1; - int inverseBoundaryWidthSlot = -1; for (int i = 0; i < count; i += 4) { // a = start point, b = end point @@ -2060,22 +2045,16 @@ status_t OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { if (boundaryWidthSlot < 0) { boundaryWidthSlot = mCaches.currentProgram->getUniform("boundaryWidth"); - inverseBoundaryWidthSlot = - mCaches.currentProgram->getUniform("inverseBoundaryWidth"); } glUniform1f(boundaryWidthSlot, boundaryWidthProportion); - glUniform1f(inverseBoundaryWidthSlot, (1 / boundaryWidthProportion)); } if (boundaryLengthSlot < 0) { boundaryLengthSlot = mCaches.currentProgram->getUniform("boundaryLength"); - inverseBoundaryLengthSlot = - mCaches.currentProgram->getUniform("inverseBoundaryLength"); } glUniform1f(boundaryLengthSlot, boundaryLengthProportion); - glUniform1f(inverseBoundaryLengthSlot, (1 / boundaryLengthProportion)); if (prevAAVertex != NULL) { // Issue two repeat vertices to create degenerate triangles to bridge diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index d3b98a4..4c7cf0a 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -208,12 +208,6 @@ public: SkPaint* filterPaint(SkPaint* paint); /** - * Returns the desired size for the stencil buffer. If the returned value - * is 0, then no stencil buffer is required. - */ - ANDROID_API static uint32_t getStencilSize(); - - /** * Sets the alpha on the current snapshot. This alpha value will be modulated * with other alpha values when drawing primitives. */ @@ -380,7 +374,7 @@ private: * * @return True if the layer was successfully created, false otherwise */ - bool createLayer(sp<Snapshot> snapshot, float left, float top, float right, float bottom, + bool createLayer(float left, float top, float right, float bottom, int alpha, SkXfermode::Mode mode, int flags, GLuint previousFbo); /** @@ -391,8 +385,7 @@ private: * @param bounds The bounds of the layer * @param previousFbo The name of the current framebuffer */ - bool createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> snapshot, - GLuint previousFbo); + bool createFboLayer(Layer* layer, Rect& bounds, Rect& clip, GLuint previousFbo); /** * Compose the specified layer as a region. diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index d67bfbe..8a9a2ac 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -129,9 +129,7 @@ const char* gFS_Uniforms_Color = "uniform vec4 color;\n"; const char* gFS_Uniforms_AA = "uniform float boundaryWidth;\n" - "uniform float inverseBoundaryWidth;\n" - "uniform float boundaryLength;\n" - "uniform float inverseBoundaryLength;\n"; + "uniform float boundaryLength;\n"; const char* gFS_Header_Uniforms_PointHasBitmap = "uniform vec2 textureDimension;\n" "uniform float pointSize;\n"; @@ -242,16 +240,9 @@ const char* gFS_Main_ModulateColor = const char* gFS_Main_ModulateColor_ApplyGamma = " fragColor *= pow(color.a, gamma);\n"; const char* gFS_Main_AccountForAA = - " if (widthProportion < boundaryWidth) {\n" - " fragColor *= (widthProportion * inverseBoundaryWidth);\n" - " } else if (widthProportion > (1.0 - boundaryWidth)) {\n" - " fragColor *= ((1.0 - widthProportion) * inverseBoundaryWidth);\n" - " }\n" - " if (lengthProportion < boundaryLength) {\n" - " fragColor *= (lengthProportion * inverseBoundaryLength);\n" - " } else if (lengthProportion > (1.0 - boundaryLength)) {\n" - " fragColor *= ((1.0 - lengthProportion) * inverseBoundaryLength);\n" - " }\n"; + " fragColor *= (1.0 - smoothstep(boundaryWidth, 0.5, abs(0.5 - widthProportion)))\n" + " * (1.0 - smoothstep(boundaryLength, 0.5, abs(0.5 - lengthProportion)));\n"; + const char* gFS_Main_FetchTexture[2] = { // Don't modulate " fragColor = texture2D(sampler, outTexCoords);\n", diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 6b6dc9e..0e3268e 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -74,8 +74,10 @@ enum DebugLevel { #define PROPERTY_TEXTURE_CACHE_FLUSH_RATE "ro.hwui.texture_cache_flush_rate" // These properties are defined in pixels -#define PROPERTY_TEXT_CACHE_WIDTH "ro.hwui.text_cache_width" -#define PROPERTY_TEXT_CACHE_HEIGHT "ro.hwui.text_cache_height" +#define PROPERTY_TEXT_SMALL_CACHE_WIDTH "ro.hwui.text_small_cache_width" +#define PROPERTY_TEXT_SMALL_CACHE_HEIGHT "ro.hwui.text_small_cache_height" +#define PROPERTY_TEXT_LARGE_CACHE_WIDTH "ro.hwui.text_large_cache_width" +#define PROPERTY_TEXT_LARGE_CACHE_HEIGHT "ro.hwui.text_large_cache_height" // Indicates whether gamma correction should be applied in the shaders // or in lookup tables. Accepted values: diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp index 8916efd..9013fd5 100644 --- a/libs/hwui/SkiaShader.cpp +++ b/libs/hwui/SkiaShader.cpp @@ -46,11 +46,12 @@ static inline bool isPowerOfTwo(unsigned int n) { } static inline void bindUniformColor(int slot, uint32_t color) { + const float a = ((color >> 24) & 0xff) / 255.0f; glUniform4f(slot, - ((color >> 16) & 0xff) / 255.0f, - ((color >> 8) & 0xff) / 255.0f, - ((color ) & 0xff) / 255.0f, - ((color >> 24) & 0xff) / 255.0f); + a * ((color >> 16) & 0xff) / 255.0f, + a * ((color >> 8) & 0xff) / 255.0f, + a * ((color ) & 0xff) / 255.0f, + a); } /////////////////////////////////////////////////////////////////////////////// @@ -154,10 +155,6 @@ void SkiaBitmapShader::setupProgram(Program* program, const mat4& modelView, // Uniforms bindTexture(texture, mWrapS, mWrapT); - // Assume linear here; we should really check the transform in - // ::updateTransforms() but we don't have the texture object - // available at that point. The optimization is not worth the - // effort for now. texture->setFilter(GL_LINEAR); glUniform1i(program->getUniform("bitmapSampler"), textureSlot); @@ -166,14 +163,6 @@ void SkiaBitmapShader::setupProgram(Program* program, const mat4& modelView, glUniform2f(program->getUniform("textureDimension"), 1.0f / width, 1.0f / height); } -void SkiaBitmapShader::updateTransforms(Program* program, const mat4& modelView, - const Snapshot& snapshot) { - mat4 textureTransform; - computeScreenSpaceMatrix(textureTransform, modelView); - glUniformMatrix4fv(program->getUniform("textureTransform"), 1, - GL_FALSE, &textureTransform.data[0]); -} - /////////////////////////////////////////////////////////////////////////////// // Linear gradient shader /////////////////////////////////////////////////////////////////////////////// @@ -257,13 +246,6 @@ void SkiaLinearGradientShader::setupProgram(Program* program, const mat4& modelV glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); } -void SkiaLinearGradientShader::updateTransforms(Program* program, const mat4& modelView, - const Snapshot& snapshot) { - mat4 screenSpace; - computeScreenSpaceMatrix(screenSpace, modelView); - glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); -} - /////////////////////////////////////////////////////////////////////////////// // Circular gradient shader /////////////////////////////////////////////////////////////////////////////// @@ -384,13 +366,6 @@ void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelVi glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); } -void SkiaSweepGradientShader::updateTransforms(Program* program, const mat4& modelView, - const Snapshot& snapshot) { - mat4 screenSpace; - computeScreenSpaceMatrix(screenSpace, modelView); - glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); -} - /////////////////////////////////////////////////////////////////////////////// // Compose shader /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h index a710b86..2687592 100644 --- a/libs/hwui/SkiaShader.h +++ b/libs/hwui/SkiaShader.h @@ -82,10 +82,6 @@ struct SkiaShader { mGradientCache = gradientCache; } - virtual void updateTransforms(Program* program, const mat4& modelView, - const Snapshot& snapshot) { - } - uint32_t getGenerationId() { return mGenerationId; } @@ -148,7 +144,6 @@ struct SkiaBitmapShader: public SkiaShader { void describe(ProgramDescription& description, const Extensions& extensions); void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, GLuint* textureUnit); - void updateTransforms(Program* program, const mat4& modelView, const Snapshot& snapshot); private: SkiaBitmapShader() { @@ -172,7 +167,6 @@ struct SkiaLinearGradientShader: public SkiaShader { void describe(ProgramDescription& description, const Extensions& extensions); void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, GLuint* textureUnit); - void updateTransforms(Program* program, const mat4& modelView, const Snapshot& snapshot); private: SkiaLinearGradientShader() { @@ -197,7 +191,6 @@ struct SkiaSweepGradientShader: public SkiaShader { virtual void describe(ProgramDescription& description, const Extensions& extensions); void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, GLuint* textureUnit); - void updateTransforms(Program* program, const mat4& modelView, const Snapshot& snapshot); protected: SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors, float* positions, diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp index 5d5961a..4484676 100644 --- a/libs/hwui/Snapshot.cpp +++ b/libs/hwui/Snapshot.cpp @@ -57,7 +57,7 @@ Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags): clipRect = &mClipRectRoot; #if STENCIL_BUFFER_SIZE if (s->clipRegion) { - mClipRegionRoot.merge(*s->clipRegion); + mClipRegionRoot.op(*s->clipRegion, SkRegion::kUnion_Op); clipRegion = &mClipRegionRoot; } #endif @@ -84,8 +84,7 @@ void Snapshot::ensureClipRegion() { #if STENCIL_BUFFER_SIZE if (!clipRegion) { clipRegion = &mClipRegionRoot; - android::Rect tmp(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom); - clipRegion->set(tmp); + clipRegion->setRect(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom); } #endif } @@ -93,11 +92,11 @@ void Snapshot::ensureClipRegion() { void Snapshot::copyClipRectFromRegion() { #if STENCIL_BUFFER_SIZE if (!clipRegion->isEmpty()) { - android::Rect bounds(clipRegion->bounds()); - clipRect->set(bounds.left, bounds.top, bounds.right, bounds.bottom); + const SkIRect& bounds = clipRegion->getBounds(); + clipRect->set(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom); if (clipRegion->isRect()) { - clipRegion->clear(); + clipRegion->setEmpty(); clipRegion = NULL; } } else { @@ -107,43 +106,11 @@ void Snapshot::copyClipRectFromRegion() { #endif } -bool Snapshot::clipRegionOr(float left, float top, float right, float bottom) { +bool Snapshot::clipRegionOp(float left, float top, float right, float bottom, SkRegion::Op op) { #if STENCIL_BUFFER_SIZE - android::Rect tmp(left, top, right, bottom); - clipRegion->orSelf(tmp); - copyClipRectFromRegion(); - return true; -#else - return false; -#endif -} - -bool Snapshot::clipRegionXor(float left, float top, float right, float bottom) { -#if STENCIL_BUFFER_SIZE - android::Rect tmp(left, top, right, bottom); - clipRegion->xorSelf(tmp); - copyClipRectFromRegion(); - return true; -#else - return false; -#endif -} - -bool Snapshot::clipRegionAnd(float left, float top, float right, float bottom) { -#if STENCIL_BUFFER_SIZE - android::Rect tmp(left, top, right, bottom); - clipRegion->andSelf(tmp); - copyClipRectFromRegion(); - return true; -#else - return false; -#endif -} - -bool Snapshot::clipRegionNand(float left, float top, float right, float bottom) { -#if STENCIL_BUFFER_SIZE - android::Rect tmp(left, top, right, bottom); - clipRegion->subtractSelf(tmp); + SkIRect tmp; + tmp.set(left, top, right, bottom); + clipRegion->op(tmp, op); copyClipRectFromRegion(); return true; #else @@ -161,14 +128,9 @@ bool Snapshot::clipTransformed(const Rect& r, SkRegion::Op op) { bool clipped = false; switch (op) { - case SkRegion::kDifference_Op: { - ensureClipRegion(); - clipped = clipRegionNand(r.left, r.top, r.right, r.bottom); - break; - } case SkRegion::kIntersect_Op: { if (CC_UNLIKELY(clipRegion)) { - clipped = clipRegionOr(r.left, r.top, r.right, r.bottom); + clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, SkRegion::kIntersect_Op); } else { clipped = clipRect->intersect(r); if (!clipped) { @@ -180,26 +142,22 @@ bool Snapshot::clipTransformed(const Rect& r, SkRegion::Op op) { } case SkRegion::kUnion_Op: { if (CC_UNLIKELY(clipRegion)) { - clipped = clipRegionAnd(r.left, r.top, r.right, r.bottom); + clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, SkRegion::kUnion_Op); } else { clipped = clipRect->unionWith(r); } break; } - case SkRegion::kXOR_Op: { - ensureClipRegion(); - clipped = clipRegionXor(r.left, r.top, r.right, r.bottom); - break; - } - case SkRegion::kReverseDifference_Op: { - // TODO!!!!!!! - break; - } case SkRegion::kReplace_Op: { setClip(r.left, r.top, r.right, r.bottom); clipped = true; break; } + default: { + ensureClipRegion(); + clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, op); + break; + } } if (clipped) { @@ -213,7 +171,7 @@ void Snapshot::setClip(float left, float top, float right, float bottom) { clipRect->set(left, top, right, bottom); #if STENCIL_BUFFER_SIZE if (clipRegion) { - clipRegion->clear(); + clipRegion->setEmpty(); clipRegion = NULL; } #endif diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h index 30b03fc..a89b740 100644 --- a/libs/hwui/Snapshot.h +++ b/libs/hwui/Snapshot.h @@ -198,7 +198,7 @@ public: * * This field is used only if STENCIL_BUFFER_SIZE is > 0. */ - Region* clipRegion; + SkRegion* clipRegion; /** * The ancestor layer's dirty region. @@ -223,17 +223,14 @@ private: void ensureClipRegion(); void copyClipRectFromRegion(); - bool clipRegionOr(float left, float top, float right, float bottom); - bool clipRegionXor(float left, float top, float right, float bottom); - bool clipRegionAnd(float left, float top, float right, float bottom); - bool clipRegionNand(float left, float top, float right, float bottom); + bool clipRegionOp(float left, float top, float right, float bottom, SkRegion::Op op); mat4 mTransformRoot; Rect mClipRectRoot; Rect mLocalClip; #if STENCIL_BUFFER_SIZE - Region mClipRegionRoot; + SkRegion mClipRegionRoot; #endif }; // class Snapshot diff --git a/libs/hwui/Stencil.cpp b/libs/hwui/Stencil.cpp new file mode 100644 index 0000000..9d2c86f --- /dev/null +++ b/libs/hwui/Stencil.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <GLES2/gl2.h> + +#include "Properties.h" +#include "Stencil.h" + +namespace android { +namespace uirenderer { + +Stencil::Stencil(): mState(kDisabled) { +} + +uint32_t Stencil::getStencilSize() { + return STENCIL_BUFFER_SIZE; +} + +void Stencil::clear() { + glClearStencil(0); + glClear(GL_STENCIL_BUFFER_BIT); +} + +void Stencil::enableTest() { + if (mState != kTest) { + enable(); + glStencilFunc(GL_LESS, 0x0, 0x1); + // We only want to test, let's keep everything + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + mState = kTest; + } +} + +void Stencil::enableWrite() { + if (mState != kWrite) { + enable(); + glStencilFunc(GL_ALWAYS, 0x1, 0x1); + // The test always passes so the first two values are meaningless + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + mState = kWrite; + } +} + +void Stencil::enable() { + if (!mState == kDisabled) { + glEnable(GL_STENCIL_TEST); + } +} + +void Stencil::disable() { + if (mState != kDisabled) { + glDisable(GL_STENCIL_TEST); + mState = kDisabled; + } +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/Stencil.h b/libs/hwui/Stencil.h new file mode 100644 index 0000000..67ccc78 --- /dev/null +++ b/libs/hwui/Stencil.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HWUI_STENCIL_H +#define ANDROID_HWUI_STENCIL_H + +#ifndef LOG_TAG + #define LOG_TAG "OpenGLRenderer" +#endif + +#include <cutils/compiler.h> + +namespace android { +namespace uirenderer { + +/////////////////////////////////////////////////////////////////////////////// +// Stencil buffer management +/////////////////////////////////////////////////////////////////////////////// + +class ANDROID_API Stencil { +public: + Stencil(); + + /** + * Returns the desired size for the stencil buffer. If the returned value + * is 0, then no stencil buffer is required. + */ + ANDROID_API static uint32_t getStencilSize(); + + /** + * Clears the stencil buffer. + */ + void clear(); + + /** + * Enables stencil test. When the stencil test is enabled the stencil + * buffer is not written into. + */ + void enableTest(); + + /** + * Enables stencil write. When stencil write is enabled, the stencil + * test always succeeds and the value 0x1 is written in the stencil + * buffer for each fragment. + */ + void enableWrite(); + + /** + * Disables stencil test and write. + */ + void disable(); + + /** + * Indicates whether either test or write is enabled. + */ + bool isEnabled() { + return mState != kDisabled; + } + +private: + void enable(); + + enum StencilState { + kDisabled, + kTest, + kWrite + }; + + StencilState mState; + +}; // class Stencil + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_HWUI_STENCIL_H |