summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/hwui/Android.mk1
-rw-r--r--libs/hwui/Caches.h7
-rw-r--r--libs/hwui/FontRenderer.cpp98
-rw-r--r--libs/hwui/FontRenderer.h11
-rw-r--r--libs/hwui/GradientCache.cpp10
-rw-r--r--libs/hwui/OpenGLRenderer.cpp127
-rw-r--r--libs/hwui/OpenGLRenderer.h11
-rw-r--r--libs/hwui/ProgramCache.cpp17
-rw-r--r--libs/hwui/Properties.h6
-rw-r--r--libs/hwui/SkiaShader.cpp35
-rw-r--r--libs/hwui/SkiaShader.h7
-rw-r--r--libs/hwui/Snapshot.cpp76
-rw-r--r--libs/hwui/Snapshot.h9
-rw-r--r--libs/hwui/Stencil.cpp71
-rw-r--r--libs/hwui/Stencil.h89
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