summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/gui/SurfaceTexture.cpp4
-rw-r--r--libs/hwui/Caches.cpp88
-rw-r--r--libs/hwui/Caches.h68
-rw-r--r--libs/hwui/FontRenderer.cpp290
-rw-r--r--libs/hwui/FontRenderer.h196
-rw-r--r--libs/hwui/GammaFontRenderer.h2
-rw-r--r--libs/hwui/GradientCache.cpp4
-rw-r--r--libs/hwui/LayerCache.cpp7
-rw-r--r--libs/hwui/LayerRenderer.cpp16
-rw-r--r--libs/hwui/OpenGLRenderer.cpp149
-rw-r--r--libs/hwui/OpenGLRenderer.h4
-rw-r--r--libs/hwui/Patch.cpp4
-rw-r--r--libs/hwui/Program.cpp110
-rw-r--r--libs/hwui/Program.h286
-rw-r--r--libs/hwui/ProgramCache.cpp2
-rw-r--r--libs/hwui/ProgramCache.h235
-rw-r--r--libs/hwui/Properties.h3
-rw-r--r--libs/hwui/Rect.h36
-rw-r--r--libs/hwui/SkiaShader.cpp13
-rw-r--r--libs/hwui/TextDropShadowCache.cpp4
-rw-r--r--libs/hwui/Texture.h2
21 files changed, 902 insertions, 621 deletions
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 6f3051a..4310bed 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -500,8 +500,8 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
eglDestroySyncKHR(dpy, fence);
}
- ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", buf,
- mSlots[buf].mGraphicBuffer->handle, returnFlags);
+ ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf,
+ mSlots[*outBuf].mGraphicBuffer->handle, returnFlags);
return returnFlags;
}
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index f293cba..c3bac5d 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -73,6 +73,15 @@ void Caches::init() {
glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW);
mCurrentBuffer = meshBuffer;
+ mCurrentIndicesBuffer = 0;
+ mCurrentPositionPointer = this;
+ mCurrentTexCoordsPointer = this;
+
+ mTexCoordsArrayEnabled = false;
+
+ glActiveTexture(gTextureUnits[0]);
+ mTextureUnit = 0;
+
mRegionMesh = NULL;
blend = false;
@@ -218,21 +227,88 @@ void Caches::flush(FlushMode mode) {
// VBO
///////////////////////////////////////////////////////////////////////////////
-void Caches::bindMeshBuffer() {
- bindMeshBuffer(meshBuffer);
+bool Caches::bindMeshBuffer() {
+ return bindMeshBuffer(meshBuffer);
}
-void Caches::bindMeshBuffer(const GLuint buffer) {
+bool Caches::bindMeshBuffer(const GLuint buffer) {
if (mCurrentBuffer != buffer) {
glBindBuffer(GL_ARRAY_BUFFER, buffer);
mCurrentBuffer = buffer;
+ return true;
}
+ return false;
}
-void Caches::unbindMeshBuffer() {
+bool Caches::unbindMeshBuffer() {
if (mCurrentBuffer) {
glBindBuffer(GL_ARRAY_BUFFER, 0);
mCurrentBuffer = 0;
+ return true;
+ }
+ return false;
+}
+
+bool Caches::bindIndicesBuffer(const GLuint buffer) {
+ if (mCurrentIndicesBuffer != buffer) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
+ mCurrentIndicesBuffer = buffer;
+ return true;
+ }
+ return false;
+}
+
+bool Caches::unbindIndicesBuffer() {
+ if (mCurrentIndicesBuffer) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ mCurrentIndicesBuffer = 0;
+ return true;
+ }
+ return false;
+}
+
+void Caches::bindPositionVertexPointer(bool force, GLuint slot, GLvoid* vertices, GLsizei stride) {
+ if (force || vertices != mCurrentPositionPointer) {
+ glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
+ mCurrentPositionPointer = vertices;
+ }
+}
+
+void Caches::bindTexCoordsVertexPointer(bool force, GLuint slot, GLvoid* vertices) {
+ if (force || vertices != mCurrentTexCoordsPointer) {
+ glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, gMeshStride, vertices);
+ mCurrentTexCoordsPointer = vertices;
+ }
+}
+
+void Caches::resetVertexPointers() {
+ mCurrentPositionPointer = this;
+ mCurrentTexCoordsPointer = this;
+}
+
+void Caches::resetTexCoordsVertexPointer() {
+ mCurrentTexCoordsPointer = this;
+}
+
+void Caches::enableTexCoordsVertexArray() {
+ if (!mTexCoordsArrayEnabled) {
+ glEnableVertexAttribArray(Program::kBindingTexCoords);
+ mCurrentTexCoordsPointer = this;
+ mTexCoordsArrayEnabled = true;
+ }
+}
+
+void Caches::disbaleTexCoordsVertexArray() {
+ if (mTexCoordsArrayEnabled) {
+ glDisableVertexAttribArray(Program::kBindingTexCoords);
+ mTexCoordsArrayEnabled = false;
+ }
+}
+
+void Caches::activeTexture(GLuint textureUnit) {
+ if (mTextureUnit != textureUnit) {
+ glActiveTexture(gTextureUnits[textureUnit]);
+ mTextureUnit = textureUnit;
}
}
@@ -254,13 +330,13 @@ TextureVertex* Caches::getRegionMesh() {
}
glGenBuffers(1, &mRegionMeshIndices);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mRegionMeshIndices);
+ bindIndicesBuffer(mRegionMeshIndices);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, REGION_MESH_QUAD_COUNT * 6 * sizeof(uint16_t),
regionIndices, GL_STATIC_DRAW);
delete[] regionIndices;
} else {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mRegionMeshIndices);
+ bindIndicesBuffer(mRegionMeshIndices);
}
return mRegionMesh;
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 5e58a9e..edf3a47 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -70,6 +70,12 @@ static const GLsizei gVertexAAWidthOffset = 2 * sizeof(float);
static const GLsizei gVertexAALengthOffset = 3 * sizeof(float);
static const GLsizei gMeshCount = 4;
+static const GLenum gTextureUnits[] = {
+ GL_TEXTURE0,
+ GL_TEXTURE1,
+ GL_TEXTURE2
+};
+
///////////////////////////////////////////////////////////////////////////////
// Debug
///////////////////////////////////////////////////////////////////////////////
@@ -91,15 +97,6 @@ class ANDROID_API Caches: public Singleton<Caches> {
CacheLogger mLogger;
- GLuint mCurrentBuffer;
-
- // Used to render layers
- TextureVertex* mRegionMesh;
- GLuint mRegionMeshIndices;
-
- mutable Mutex mGarbageLock;
- Vector<Layer*> mLayerGarbage;
-
public:
enum FlushMode {
kFlushMode_Layers = 0,
@@ -147,17 +144,48 @@ public:
/**
* Binds the VBO used to render simple textured quads.
*/
- void bindMeshBuffer();
+ bool bindMeshBuffer();
/**
* Binds the specified VBO if needed.
*/
- void bindMeshBuffer(const GLuint buffer);
+ bool bindMeshBuffer(const GLuint buffer);
/**
* Unbinds the VBO used to render simple textured quads.
*/
- void unbindMeshBuffer();
+ bool unbindMeshBuffer();
+
+ bool bindIndicesBuffer(const GLuint buffer);
+ bool unbindIndicesBuffer();
+
+ /**
+ * Binds an attrib to the specified float vertex pointer.
+ * Assumes a stride of gMeshStride and a size of 2.
+ */
+ void bindPositionVertexPointer(bool force, GLuint slot, GLvoid* vertices,
+ GLsizei stride = gMeshStride);
+
+ /**
+ * Binds an attrib to the specified float vertex pointer.
+ * Assumes a stride of gMeshStride and a size of 2.
+ */
+ void bindTexCoordsVertexPointer(bool force, GLuint slot, GLvoid* vertices);
+
+ /**
+ * Resets the vertex pointers.
+ */
+ void resetVertexPointers();
+ void resetTexCoordsVertexPointer();
+
+ void enableTexCoordsVertexArray();
+ void disbaleTexCoordsVertexArray();
+
+ /**
+ * Activate the specified texture unit. The texture unit must
+ * be specified using an integer number (0 for GL_TEXTURE0 etc.)
+ */
+ void activeTexture(GLuint textureUnit);
/**
* Returns the mesh used to draw regions. Calling this method will
@@ -203,6 +231,22 @@ public:
ResourceCache resourceCache;
private:
+ GLuint mCurrentBuffer;
+ GLuint mCurrentIndicesBuffer;
+ void* mCurrentPositionPointer;
+ void* mCurrentTexCoordsPointer;
+
+ bool mTexCoordsArrayEnabled;
+
+ GLuint mTextureUnit;
+
+ // Used to render layers
+ TextureVertex* mRegionMesh;
+ GLuint mRegionMeshIndices;
+
+ mutable Mutex mGarbageLock;
+ Vector<Layer*> mLayerGarbage;
+
DebugLevel mDebugLevel;
bool mInitialized;
}; // class Caches
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 158f785..3c6a952 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -22,8 +22,10 @@
#include <utils/Log.h>
+#include "Caches.h"
#include "Debug.h"
#include "FontRenderer.h"
+#include "Caches.h"
namespace android {
namespace uirenderer {
@@ -34,10 +36,28 @@ namespace uirenderer {
#define DEFAULT_TEXT_CACHE_WIDTH 1024
#define DEFAULT_TEXT_CACHE_HEIGHT 256
-
-// We should query these values from the GL context
#define MAX_TEXT_CACHE_WIDTH 2048
-#define MAX_TEXT_CACHE_HEIGHT 2048
+#define TEXTURE_BORDER_SIZE 2
+
+///////////////////////////////////////////////////////////////////////////////
+// CacheTextureLine
+///////////////////////////////////////////////////////////////////////////////
+
+bool CacheTextureLine::fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY) {
+ if (glyph.fHeight + TEXTURE_BORDER_SIZE > mMaxHeight) {
+ return false;
+ }
+
+ if (mCurrentCol + glyph.fWidth + TEXTURE_BORDER_SIZE < mMaxWidth) {
+ *retOriginX = mCurrentCol + 1;
+ *retOriginY = mCurrentRow + 1;
+ mCurrentCol += glyph.fWidth + TEXTURE_BORDER_SIZE;
+ mDirty = true;
+ return true;
+ }
+
+ return false;
+}
///////////////////////////////////////////////////////////////////////////////
// Font
@@ -104,10 +124,10 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y) {
int width = (int) glyph->mBitmapWidth;
int height = (int) glyph->mBitmapHeight;
- mState->appendMeshQuad(nPenX, nPenY, 0, u1, v2,
- nPenX + width, nPenY, 0, u2, v2,
- nPenX + width, nPenY - height, 0, u2, v1,
- nPenX, nPenY - height, 0, u1, v1);
+ mState->appendMeshQuad(nPenX, nPenY, u1, v2,
+ nPenX + width, nPenY, u2, v2,
+ nPenX + width, nPenY - height, u2, v1,
+ nPenX, nPenY - height, u1, v1, glyph->mCachedTextureLine->mCacheTexture);
}
void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
@@ -118,8 +138,9 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
uint32_t endX = glyph->mStartX + glyph->mBitmapWidth;
uint32_t endY = glyph->mStartY + glyph->mBitmapHeight;
- uint32_t cacheWidth = mState->getCacheWidth();
- const uint8_t* cacheBuffer = mState->getTextTextureData();
+ CacheTexture *cacheTexture = glyph->mCachedTextureLine->mCacheTexture;
+ uint32_t cacheWidth = cacheTexture->mWidth;
+ const uint8_t* cacheBuffer = cacheTexture->mTexture;
uint32_t cacheX = 0, cacheY = 0;
int32_t bX = 0, bY = 0;
@@ -133,10 +154,9 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
bitmap[bY * bitmapW + bX] = tempCol;
}
}
-
}
-Font::CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) {
+CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) {
CachedGlyphInfo* cachedGlyph = NULL;
ssize_t index = mCachedGlyphs.indexOfKey(textUnit);
if (index >= 0) {
@@ -245,7 +265,7 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp
// Get the bitmap for the glyph
paint->findImage(skiaGlyph);
- glyph->mIsValid = mState->cacheBitmap(skiaGlyph, &startX, &startY);
+ mState->cacheBitmap(skiaGlyph, glyph, &startX, &startY);
if (!glyph->mIsValid) {
return;
@@ -259,8 +279,8 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp
glyph->mBitmapWidth = skiaGlyph.fWidth;
glyph->mBitmapHeight = skiaGlyph.fHeight;
- uint32_t cacheWidth = mState->getCacheWidth();
- uint32_t cacheHeight = mState->getCacheHeight();
+ uint32_t cacheWidth = glyph->mCachedTextureLine->mCacheTexture->mWidth;
+ uint32_t cacheHeight = glyph->mCachedTextureLine->mCacheTexture->mHeight;
glyph->mBitmapMinU = (float) startX / (float) cacheWidth;
glyph->mBitmapMinV = (float) startY / (float) cacheHeight;
@@ -270,7 +290,7 @@ void Font::updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyp
mState->mUploadTexture = true;
}
-Font::CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph) {
+CachedGlyphInfo* Font::cacheGlyph(SkPaint* paint, glyph_t glyph) {
CachedGlyphInfo* newGlyph = new CachedGlyphInfo();
mCachedGlyphs.add(glyph, newGlyph);
@@ -319,27 +339,29 @@ FontRenderer::FontRenderer() {
mInitialized = false;
mMaxNumberOfQuads = 1024;
mCurrentQuadIndex = 0;
- mTextureId = 0;
mTextMeshPtr = NULL;
- mTextTexture = NULL;
+ mCurrentCacheTexture = NULL;
+ mLastCacheTexture = NULL;
+ mCacheTextureSmall = NULL;
+ mCacheTexture128 = NULL;
+ mCacheTexture256 = NULL;
+ mCacheTexture512 = NULL;
mIndexBufferID = 0;
- mPositionAttrSlot = -1;
- mTexcoordAttrSlot = -1;
- mCacheWidth = DEFAULT_TEXT_CACHE_WIDTH;
- mCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT;
+ mSmallCacheWidth = DEFAULT_TEXT_CACHE_WIDTH;
+ mSmallCacheHeight = DEFAULT_TEXT_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);
}
- mCacheWidth = atoi(property);
+ mSmallCacheWidth = atoi(property);
} else {
if (sLogFontRendererCreate) {
- INIT_LOGD(" Using default text cache width of %i pixels", mCacheWidth);
+ INIT_LOGD(" Using default text cache width of %i pixels", mSmallCacheWidth);
}
}
@@ -347,10 +369,10 @@ FontRenderer::FontRenderer() {
if (sLogFontRendererCreate) {
INIT_LOGD(" Setting text cache width to %s pixels", property);
}
- mCacheHeight = atoi(property);
+ mSmallCacheHeight = atoi(property);
} else {
if (sLogFontRendererCreate) {
- INIT_LOGD(" Using default text cache height of %i pixels", mCacheHeight);
+ INIT_LOGD(" Using default text cache height of %i pixels", mSmallCacheHeight);
}
}
@@ -365,11 +387,10 @@ FontRenderer::~FontRenderer() {
if (mInitialized) {
delete[] mTextMeshPtr;
- delete[] mTextTexture;
- }
-
- if (mTextureId) {
- glDeleteTextures(1, &mTextureId);
+ delete mCacheTextureSmall;
+ delete mCacheTexture128;
+ delete mCacheTexture256;
+ delete mCacheTexture512;
}
Vector<Font*> fontsToDereference = mActiveFonts;
@@ -391,20 +412,21 @@ void FontRenderer::flushAllAndInvalidate() {
}
}
-bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY) {
+uint8_t* FontRenderer::allocateTextureMemory(int width, int height) {
+ uint8_t* textureMemory = new uint8_t[width * height];
+ memset(textureMemory, 0, width * height * sizeof(uint8_t));
+
+ return textureMemory;
+}
+
+void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
+ uint32_t* retOriginX, uint32_t* retOriginY) {
+ cachedGlyph->mIsValid = false;
// If the glyph is too tall, don't cache it
- if (glyph.fHeight + 2 > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) {
- if (mCacheHeight < MAX_TEXT_CACHE_HEIGHT) {
- // Default cache not large enough for large glyphs - resize cache to
- // max size and try again
- flushAllAndInvalidate();
- initTextTexture(true);
- }
- if (glyph.fHeight + 2 > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) {
- LOGE("Font size to large to fit in cache. width, height = %i, %i",
- (int) glyph.fWidth, (int) glyph.fHeight);
- return false;
- }
+ if (glyph.fHeight + TEXTURE_BORDER_SIZE > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) {
+ LOGE("Font size to large to fit in cache. width, height = %i, %i",
+ (int) glyph.fWidth, (int) glyph.fHeight);
+ return;
}
// Now copy the bitmap into the cache texture
@@ -412,9 +434,11 @@ bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint3
uint32_t startY = 0;
bool bitmapFit = false;
+ CacheTextureLine *cacheLine;
for (uint32_t i = 0; i < mCacheLines.size(); i++) {
bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
if (bitmapFit) {
+ cacheLine = mCacheLines[i];
break;
}
}
@@ -427,27 +451,33 @@ bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint3
for (uint32_t i = 0; i < mCacheLines.size(); i++) {
bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
if (bitmapFit) {
+ cacheLine = mCacheLines[i];
break;
}
}
// if we still don't fit, something is wrong and we shouldn't draw
if (!bitmapFit) {
- LOGE("Bitmap doesn't fit in cache. width, height = %i, %i",
- (int) glyph.fWidth, (int) glyph.fHeight);
- return false;
+ return;
}
}
+ cachedGlyph->mCachedTextureLine = cacheLine;
+
*retOriginX = startX;
*retOriginY = startY;
uint32_t endX = startX + glyph.fWidth;
uint32_t endY = startY + glyph.fHeight;
- uint32_t cacheWidth = mCacheWidth;
+ uint32_t cacheWidth = cacheLine->mMaxWidth;
- uint8_t* cacheBuffer = mTextTexture;
+ CacheTexture *cacheTexture = cacheLine->mCacheTexture;
+ if (cacheTexture->mTexture == NULL) {
+ // Large-glyph texture memory is allocated only as needed
+ cacheTexture->mTexture = allocateTextureMemory(cacheTexture->mWidth, cacheTexture->mHeight);
+ }
+ uint8_t* cacheBuffer = cacheTexture->mTexture;
uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
unsigned int stride = glyph.rowBytes();
@@ -458,30 +488,17 @@ bool FontRenderer::cacheBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint3
cacheBuffer[cacheY * cacheWidth + cacheX] = mGammaTable[tempCol];
}
}
-
- return true;
+ cachedGlyph->mIsValid = true;
}
-void FontRenderer::initTextTexture(bool largeFonts) {
- mCacheLines.clear();
- if (largeFonts) {
- mCacheWidth = MAX_TEXT_CACHE_WIDTH;
- mCacheHeight = MAX_TEXT_CACHE_HEIGHT;
- }
-
- mTextTexture = new uint8_t[mCacheWidth * mCacheHeight];
- memset(mTextTexture, 0, mCacheWidth * mCacheHeight * sizeof(uint8_t));
-
- mUploadTexture = false;
-
- if (mTextureId != 0) {
- glDeleteTextures(1, &mTextureId);
- }
- glGenTextures(1, &mTextureId);
- glBindTexture(GL_TEXTURE_2D, mTextureId);
+CacheTexture* FontRenderer::createCacheTexture(int width, int height, bool allocate) {
+ uint8_t* textureMemory = allocate ? allocateTextureMemory(width, height) : NULL;
+ GLuint textureId;
+ glGenTextures(1, &textureId);
+ glBindTexture(GL_TEXTURE_2D, textureId);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Initialize texture dimensions
- glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, mCacheWidth, mCacheHeight, 0,
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0,
GL_ALPHA, GL_UNSIGNED_BYTE, 0);
mLinearFiltering = false;
@@ -491,36 +508,61 @@ void FontRenderer::initTextTexture(bool largeFonts) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- // Split up our cache texture into lines of certain widths
+ return new CacheTexture(textureMemory, textureId, width, height);
+}
+
+void FontRenderer::initTextTexture() {
+ mCacheLines.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;
+ }
+ if (mCacheTextureSmall != NULL) {
+ delete mCacheTextureSmall;
+ delete mCacheTexture128;
+ delete mCacheTexture256;
+ delete mCacheTexture512;
+ }
+ mCacheTextureSmall = createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true);
+ mCacheTexture128 = createCacheTexture(maxWidth, 256, false);
+ mCacheTexture256 = createCacheTexture(maxWidth, 256, false);
+ mCacheTexture512 = createCacheTexture(maxWidth, 512, false);
+ mCurrentCacheTexture = mCacheTextureSmall;
+
+ mUploadTexture = false;
+ // Split up our default cache texture into lines of certain widths
int nextLine = 0;
- mCacheLines.push(new CacheTextureLine(mCacheWidth, 18, nextLine, 0));
+ mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 18, nextLine, 0, mCacheTextureSmall));
nextLine += mCacheLines.top()->mMaxHeight;
- mCacheLines.push(new CacheTextureLine(mCacheWidth, 26, nextLine, 0));
+ mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, 0, mCacheTextureSmall));
nextLine += mCacheLines.top()->mMaxHeight;
- mCacheLines.push(new CacheTextureLine(mCacheWidth, 26, nextLine, 0));
+ mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, 0, mCacheTextureSmall));
nextLine += mCacheLines.top()->mMaxHeight;
- mCacheLines.push(new CacheTextureLine(mCacheWidth, 34, nextLine, 0));
+ mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, 0, mCacheTextureSmall));
nextLine += mCacheLines.top()->mMaxHeight;
- mCacheLines.push(new CacheTextureLine(mCacheWidth, 34, nextLine, 0));
+ mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, 0, mCacheTextureSmall));
nextLine += mCacheLines.top()->mMaxHeight;
- mCacheLines.push(new CacheTextureLine(mCacheWidth, 42, nextLine, 0));
+ mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 42, nextLine, 0, mCacheTextureSmall));
nextLine += mCacheLines.top()->mMaxHeight;
- if (largeFonts) {
- int nextSize = 76;
- // Make several new lines with increasing font sizes
- while (nextSize < (int)(mCacheHeight - nextLine - (2 * nextSize))) {
- mCacheLines.push(new CacheTextureLine(mCacheWidth, nextSize, nextLine, 0));
- nextLine += mCacheLines.top()->mMaxHeight;
- nextSize += 50;
- }
- }
- mCacheLines.push(new CacheTextureLine(mCacheWidth, mCacheHeight - nextLine, nextLine, 0));
+ mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, mSmallCacheHeight - nextLine,
+ nextLine, 0, mCacheTextureSmall));
+
+ // The first cache is split into 2 lines of height 128, the rest have just one cache line.
+ mCacheLines.push(new CacheTextureLine(maxWidth, 128, 0, 0, mCacheTexture128));
+ mCacheLines.push(new CacheTextureLine(maxWidth, 128, 128, 0, mCacheTexture128));
+ mCacheLines.push(new CacheTextureLine(maxWidth, 256, 0, 0, mCacheTexture256));
+ mCacheLines.push(new CacheTextureLine(maxWidth, 512, 0, 0, mCacheTexture512));
}
// Avoid having to reallocate memory and render quad by quad
void FontRenderer::initVertexArrayBuffers() {
- uint32_t numIndicies = mMaxNumberOfQuads * 6;
- uint32_t indexBufferSizeBytes = numIndicies * sizeof(uint16_t);
+ uint32_t numIndices = mMaxNumberOfQuads * 6;
+ uint32_t indexBufferSizeBytes = numIndices * sizeof(uint16_t);
uint16_t* indexBufferData = (uint16_t*) malloc(indexBufferSizeBytes);
// Four verts, two triangles , six indices per quad
@@ -538,13 +580,12 @@ void FontRenderer::initVertexArrayBuffers() {
}
glGenBuffers(1, &mIndexBufferID);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID);
+ Caches::getInstance().bindIndicesBuffer(mIndexBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSizeBytes, indexBufferData, GL_STATIC_DRAW);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
free(indexBufferData);
- uint32_t coordSize = 3;
+ uint32_t coordSize = 2;
uint32_t uvSize = 2;
uint32_t vertsPerQuad = 4;
uint32_t vertexBufferSize = mMaxNumberOfQuads * vertsPerQuad * coordSize * uvSize;
@@ -570,22 +611,28 @@ void FontRenderer::checkInit() {
}
void FontRenderer::checkTextureUpdate() {
- if (!mUploadTexture) {
+ if (!mUploadTexture && mLastCacheTexture == mCurrentCacheTexture) {
return;
}
- glBindTexture(GL_TEXTURE_2D, mTextureId);
-
+ Caches& caches = Caches::getInstance();
+ GLuint lastTextureId = 0;
// Iterate over all the cache lines and see which ones need to be updated
for (uint32_t i = 0; i < mCacheLines.size(); i++) {
CacheTextureLine* cl = mCacheLines[i];
- if(cl->mDirty) {
+ if (cl->mDirty && cl->mCacheTexture->mTexture != NULL) {
+ CacheTexture* cacheTexture = cl->mCacheTexture;
uint32_t xOffset = 0;
uint32_t yOffset = cl->mCurrentRow;
- uint32_t width = mCacheWidth;
+ uint32_t width = cl->mMaxWidth;
uint32_t height = cl->mMaxHeight;
- void* textureData = mTextTexture + yOffset*width;
+ void* textureData = cacheTexture->mTexture + (yOffset * width);
+ if (cacheTexture->mTextureId != lastTextureId) {
+ caches.activeTexture(0);
+ glBindTexture(GL_TEXTURE_2D, cacheTexture->mTextureId);
+ lastTextureId = cacheTexture->mTextureId;
+ }
glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height,
GL_ALPHA, GL_UNSIGNED_BYTE, textureData);
@@ -593,57 +640,72 @@ void FontRenderer::checkTextureUpdate() {
}
}
+ glBindTexture(GL_TEXTURE_2D, mCurrentCacheTexture->mTextureId);
+ mLastCacheTexture = mCurrentCacheTexture;
+
mUploadTexture = false;
}
void FontRenderer::issueDrawCommand() {
checkTextureUpdate();
- float* vtx = mTextMeshPtr;
- float* tex = vtx + 3;
+ Caches& caches = Caches::getInstance();
+ caches.bindIndicesBuffer(mIndexBufferID);
+ if (!mDrawn) {
+ float* buffer = mTextMeshPtr;
+ int offset = 2;
- glVertexAttribPointer(mPositionAttrSlot, 3, GL_FLOAT, false, 20, vtx);
- glVertexAttribPointer(mTexcoordAttrSlot, 2, GL_FLOAT, false, 20, tex);
+ bool force = caches.unbindMeshBuffer();
+ caches.bindPositionVertexPointer(force, caches.currentProgram->position, buffer);
+ caches.bindTexCoordsVertexPointer(force, caches.currentProgram->texCoords,
+ buffer + offset);
+ }
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID);
glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL);
mDrawn = true;
}
-void FontRenderer::appendMeshQuad(float x1, float y1, float z1, float u1, float v1, float x2,
- float y2, float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3,
- float x4, float y4, float z4, float u4, float v4) {
+void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
+ float x2, float y2, float u2, float v2,
+ float x3, float y3, float u3, float v3,
+ float x4, float y4, float u4, float v4, CacheTexture* texture) {
+
if (mClip &&
(x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
return;
}
+ if (texture != mCurrentCacheTexture) {
+ if (mCurrentQuadIndex != 0) {
+ // First, draw everything stored already which uses the previous texture
+ issueDrawCommand();
+ mCurrentQuadIndex = 0;
+ }
+ // Now use the new texture id
+ mCurrentCacheTexture = texture;
+ }
const uint32_t vertsPerQuad = 4;
- const uint32_t floatsPerVert = 5;
+ const uint32_t floatsPerVert = 4;
float* currentPos = mTextMeshPtr + mCurrentQuadIndex * vertsPerQuad * floatsPerVert;
(*currentPos++) = x1;
(*currentPos++) = y1;
- (*currentPos++) = z1;
(*currentPos++) = u1;
(*currentPos++) = v1;
(*currentPos++) = x2;
(*currentPos++) = y2;
- (*currentPos++) = z2;
(*currentPos++) = u2;
(*currentPos++) = v2;
(*currentPos++) = x3;
(*currentPos++) = y3;
- (*currentPos++) = z3;
(*currentPos++) = u3;
(*currentPos++) = v3;
(*currentPos++) = x4;
(*currentPos++) = y4;
- (*currentPos++) = z4;
(*currentPos++) = u4;
(*currentPos++) = v4;
@@ -723,6 +785,7 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const ch
return image;
}
+ mDrawn = false;
mClip = NULL;
mBounds = NULL;
@@ -750,6 +813,7 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const ch
image.image = dataBuffer;
image.penX = penX;
image.penY = penY;
+
return image;
}
@@ -762,11 +826,6 @@ bool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text
return false;
}
- if (mPositionAttrSlot < 0 || mTexcoordAttrSlot < 0) {
- LOGE("Font renderer unable to draw, attribute slots undefined");
- return false;
- }
-
mDrawn = false;
mBounds = bounds;
mClip = clip;
@@ -914,9 +973,12 @@ void FontRenderer::verticalBlur(float* weights, int32_t radius,
void FontRenderer::blurImage(uint8_t *image, int32_t width, int32_t height, int32_t radius) {
float *gaussian = new float[2 * radius + 1];
computeGaussianWeights(gaussian, radius);
+
uint8_t* scratch = new uint8_t[width * height];
+
horizontalBlur(gaussian, radius, image, scratch, width, height);
verticalBlur(gaussian, radius, scratch, image, width, height);
+
delete[] gaussian;
delete[] scratch;
}
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 1922812..b34fdfa 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -55,6 +55,77 @@ namespace uirenderer {
class FontRenderer;
+class CacheTexture {
+public:
+ CacheTexture(){}
+ CacheTexture(uint8_t* texture, GLuint textureId, uint16_t width, uint16_t height) :
+ mTexture(texture), mTextureId(textureId), mWidth(width), mHeight(height) {}
+ ~CacheTexture() {
+ if (mTexture != NULL) {
+ delete[] mTexture;
+ }
+ if (mTextureId != 0) {
+ glDeleteTextures(1, &mTextureId);
+ }
+ }
+
+ uint8_t* mTexture;
+ GLuint mTextureId;
+ uint16_t mWidth;
+ uint16_t mHeight;
+};
+
+class CacheTextureLine {
+public:
+ CacheTextureLine(uint16_t maxWidth, uint16_t maxHeight, uint32_t currentRow,
+ uint32_t currentCol, CacheTexture* cacheTexture):
+ mMaxHeight(maxHeight),
+ mMaxWidth(maxWidth),
+ mCurrentRow(currentRow),
+ mCurrentCol(currentCol),
+ mDirty(false),
+ mCacheTexture(cacheTexture){
+ }
+
+ bool fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY);
+
+ uint16_t mMaxHeight;
+ uint16_t mMaxWidth;
+ uint32_t mCurrentRow;
+ uint32_t mCurrentCol;
+ bool mDirty;
+ CacheTexture *mCacheTexture;
+};
+
+struct CachedGlyphInfo {
+ // Has the cache been invalidated?
+ bool mIsValid;
+ // Location of the cached glyph in the bitmap
+ // in case we need to resize the texture or
+ // render to bitmap
+ uint32_t mStartX;
+ uint32_t mStartY;
+ uint32_t mBitmapWidth;
+ uint32_t mBitmapHeight;
+ // Also cache texture coords for the quad
+ float mBitmapMinU;
+ float mBitmapMinV;
+ float mBitmapMaxU;
+ float mBitmapMaxV;
+ // Minimize how much we call freetype
+ uint32_t mGlyphIndex;
+ uint32_t mAdvanceX;
+ uint32_t mAdvanceY;
+ // Values below contain a glyph's origin in the bitmap
+ int32_t mBitmapLeft;
+ int32_t mBitmapTop;
+ // Auto-kerning
+ SkFixed mLsbDelta;
+ SkFixed mRsbDelta;
+ CacheTextureLine* mCachedTextureLine;
+};
+
+
///////////////////////////////////////////////////////////////////////////////
// Font
///////////////////////////////////////////////////////////////////////////////
@@ -101,33 +172,6 @@ protected:
void measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
int numGlyphs, Rect *bounds);
- struct CachedGlyphInfo {
- // Has the cache been invalidated?
- bool mIsValid;
- // Location of the cached glyph in the bitmap
- // in case we need to resize the texture or
- // render to bitmap
- uint32_t mStartX;
- uint32_t mStartY;
- uint32_t mBitmapWidth;
- uint32_t mBitmapHeight;
- // Also cache texture coords for the quad
- float mBitmapMinU;
- float mBitmapMinV;
- float mBitmapMaxU;
- float mBitmapMaxV;
- // Minimize how much we call freetype
- uint32_t mGlyphIndex;
- uint32_t mAdvanceX;
- uint32_t mAdvanceY;
- // Values below contain a glyph's origin in the bitmap
- int32_t mBitmapLeft;
- int32_t mBitmapTop;
- // Auto-kerning
- SkFixed mLsbDelta;
- SkFixed mRsbDelta;
- };
-
Font(FontRenderer* state, uint32_t fontId, float fontSize, int flags, uint32_t italicStyle,
uint32_t scaleX, SkPaint::Style style, uint32_t strokeWidth);
@@ -178,11 +222,6 @@ public:
mGammaTable = gammaTable;
}
- void setAttributeBindingSlots(int positionSlot, int texCoordSlot) {
- mPositionAttrSlot = positionSlot;
- mTexcoordAttrSlot = texCoordSlot;
- }
-
void setFont(SkPaint* paint, uint32_t fontId, float fontSize);
bool renderText(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex,
uint32_t len, int numGlyphs, int x, int y, Rect* bounds);
@@ -214,19 +253,28 @@ public:
mLinearFiltering = linearFiltering;
const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST;
- glBindTexture(GL_TEXTURE_2D, mTextureId);
+ glBindTexture(GL_TEXTURE_2D, mCurrentCacheTexture->mTextureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
}
- return mTextureId;
- }
-
- uint32_t getCacheWidth() const {
- return mCacheWidth;
+ return mCurrentCacheTexture->mTextureId;
}
- uint32_t getCacheHeight() const {
- return mCacheHeight;
+ uint32_t getCacheSize() const {
+ uint32_t size = 0;
+ if (mCacheTextureSmall != NULL && mCacheTextureSmall->mTexture != NULL) {
+ size += mCacheTextureSmall->mWidth * mCacheTextureSmall->mHeight;
+ }
+ if (mCacheTexture128 != NULL && mCacheTexture128->mTexture != NULL) {
+ size += mCacheTexture128->mWidth * mCacheTexture128->mHeight;
+ }
+ if (mCacheTexture256 != NULL && mCacheTexture256->mTexture != NULL) {
+ size += mCacheTexture256->mWidth * mCacheTexture256->mHeight;
+ }
+ if (mCacheTexture512 != NULL && mCacheTexture512->mTexture != NULL) {
+ size += mCacheTexture512->mWidth * mCacheTexture512->mHeight;
+ }
+ return size;
}
protected:
@@ -234,41 +282,11 @@ protected:
const uint8_t* mGammaTable;
- struct CacheTextureLine {
- uint16_t mMaxHeight;
- uint16_t mMaxWidth;
- uint32_t mCurrentRow;
- uint32_t mCurrentCol;
- bool mDirty;
-
- CacheTextureLine(uint16_t maxWidth, uint16_t maxHeight, uint32_t currentRow,
- uint32_t currentCol):
- mMaxHeight(maxHeight),
- mMaxWidth(maxWidth),
- mCurrentRow(currentRow),
- mCurrentCol(currentCol),
- mDirty(false) {
- }
-
- bool fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY) {
- if (glyph.fHeight + 2 > mMaxHeight) {
- return false;
- }
-
- if (mCurrentCol + glyph.fWidth + 2 < mMaxWidth) {
- *retOriginX = mCurrentCol + 1;
- *retOriginY = mCurrentRow + 1;
- mCurrentCol += glyph.fWidth + 2;
- mDirty = true;
- return true;
- }
-
- return false;
- }
- };
-
- void initTextTexture(bool largeFonts = false);
- bool cacheBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY);
+ uint8_t* allocateTextureMemory(int width, int height);
+ void initTextTexture();
+ CacheTexture *createCacheTexture(int width, int height, bool allocate);
+ void cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
+ uint32_t *retOriginX, uint32_t *retOriginY);
void flushAllAndInvalidate();
void initVertexArrayBuffers();
@@ -279,12 +297,13 @@ protected:
void precacheLatin(SkPaint* paint);
void issueDrawCommand();
- void appendMeshQuad(float x1, float y1, float z1, float u1, float v1, float x2, float y2,
- float z2, float u2, float v2, float x3, float y3, float z3, float u3, float v3,
- float x4, float y4, float z4, float u4, float v4);
+ void appendMeshQuad(float x1, float y1, float u1, float v1,
+ float x2, float y2, float u2, float v2,
+ float x3, float y3, float u3, float v3,
+ float x4, float y4, float u4, float v4, CacheTexture* texture);
- uint32_t mCacheWidth;
- uint32_t mCacheHeight;
+ uint32_t mSmallCacheWidth;
+ uint32_t mSmallCacheHeight;
Vector<CacheTextureLine*> mCacheLines;
uint32_t getRemainingCacheCapacity();
@@ -292,12 +311,14 @@ protected:
Font* mCurrentFont;
Vector<Font*> mActiveFonts;
- // Texture to cache glyph bitmaps
- uint8_t* mTextTexture;
- const uint8_t* getTextTextureData() const {
- return mTextTexture;
- }
- GLuint mTextureId;
+ CacheTexture* mCurrentCacheTexture;
+ CacheTexture* mLastCacheTexture;
+ CacheTexture* mCacheTextureSmall;
+ CacheTexture* mCacheTexture128;
+ CacheTexture* mCacheTexture256;
+ CacheTexture* mCacheTexture512;
+
+
void checkTextureUpdate();
bool mUploadTexture;
@@ -308,9 +329,6 @@ protected:
uint32_t mIndexBufferID;
- int32_t mPositionAttrSlot;
- int32_t mTexcoordAttrSlot;
-
const Rect* mClip;
Rect* mBounds;
bool mDrawn;
diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h
index 54c208e..99f08f0 100644
--- a/libs/hwui/GammaFontRenderer.h
+++ b/libs/hwui/GammaFontRenderer.h
@@ -50,7 +50,7 @@ struct GammaFontRenderer {
FontRenderer* renderer = mRenderers[fontRenderer];
if (!renderer) return 0;
- return renderer->getCacheHeight() * renderer->getCacheWidth();
+ return renderer->getCacheSize();
}
private:
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index aacf22a..a88a59a 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -171,8 +171,8 @@ void GradientCache::generateTexture(SkBitmap* bitmap, Texture* texture) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap->rowBytesAsPixels(), texture->height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, bitmap->getPixels());
- texture->setFilter(GL_LINEAR, GL_LINEAR);
- texture->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
+ texture->setFilter(GL_LINEAR);
+ texture->setWrap(GL_CLAMP_TO_EDGE);
}
}; // namespace uirenderer
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index 5298125..d304b37 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -20,6 +20,7 @@
#include <utils/Log.h>
+#include "Caches.h"
#include "Debug.h"
#include "LayerCache.h"
#include "Properties.h"
@@ -108,8 +109,8 @@ Layer* LayerCache::get(const uint32_t width, const uint32_t height) {
layer->generateTexture();
layer->bindTexture();
- layer->setFilter(GL_NEAREST, GL_NEAREST);
- layer->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, false);
+ layer->setFilter(GL_NEAREST);
+ layer->setWrap(GL_CLAMP_TO_EDGE, false);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
#if DEBUG_LAYERS
@@ -140,7 +141,7 @@ bool LayerCache::resize(Layer* layer, const uint32_t width, const uint32_t heigh
uint32_t oldWidth = layer->getWidth();
uint32_t oldHeight = layer->getHeight();
- glActiveTexture(GL_TEXTURE0);
+ Caches::getInstance().activeTexture(0);
layer->bindTexture();
layer->setSize(entry.mWidth, entry.mHeight);
layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE);
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index e2d9ea3..38630b8 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -182,14 +182,15 @@ void LayerRenderer::generateMesh() {
Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque) {
LAYER_RENDERER_LOGD("Requesting new render layer %dx%d", width, height);
- GLuint fbo = Caches::getInstance().fboCache.get();
+ Caches& caches = Caches::getInstance();
+ GLuint fbo = caches.fboCache.get();
if (!fbo) {
LOGW("Could not obtain an FBO");
return NULL;
}
- glActiveTexture(GL_TEXTURE0);
- Layer* layer = Caches::getInstance().layerCache.get(width, height);
+ caches.activeTexture(0);
+ Layer* layer = caches.layerCache.get(width, height);
if (!layer) {
LOGW("Could not obtain a layer");
return NULL;
@@ -220,7 +221,7 @@ Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque
fbo, width, height);
glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
- Caches::getInstance().fboCache.put(fbo);
+ caches.fboCache.put(fbo);
layer->deleteTexture();
delete layer;
@@ -233,7 +234,6 @@ Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque
layer->getTexture(), 0);
glDisable(GL_SCISSOR_TEST);
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_SCISSOR_TEST);
@@ -275,7 +275,7 @@ Layer* LayerRenderer::createTextureLayer(bool isOpaque) {
layer->region.clear();
layer->setRenderTarget(GL_NONE); // see ::updateTextureLayer()
- glActiveTexture(GL_TEXTURE0);
+ Caches::getInstance().activeTexture(0);
layer->generateTexture();
return layer;
@@ -407,7 +407,7 @@ bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) {
glGenTextures(1, &texture);
if ((error = glGetError()) != GL_NO_ERROR) goto error;
- glActiveTexture(GL_TEXTURE0);
+ caches.activeTexture(0);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -459,6 +459,8 @@ bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) {
}
error:
+ glEnable(GL_SCISSOR_TEST);
+
#if DEBUG_OPENGL
if (error != GL_NO_ERROR) {
LOGD("GL error while copying layer into bitmap = 0x%x", error);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 1d7b99d..cbfd778 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -103,12 +103,6 @@ static const Blender gBlendsSwap[] = {
{ SkXfermode::kScreen_Mode, GL_ONE_MINUS_DST_COLOR, GL_ONE }
};
-static const GLenum gTextureUnits[] = {
- GL_TEXTURE0,
- GL_TEXTURE1,
- GL_TEXTURE2
-};
-
///////////////////////////////////////////////////////////////////////////////
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
@@ -133,8 +127,6 @@ OpenGLRenderer::~OpenGLRenderer() {
///////////////////////////////////////////////////////////////////////////////
void OpenGLRenderer::setViewport(int width, int height) {
- glDisable(GL_DITHER);
- glViewport(0, 0, width, height);
mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
mWidth = width;
@@ -143,7 +135,11 @@ void OpenGLRenderer::setViewport(int width, int height) {
mFirstSnapshot->height = height;
mFirstSnapshot->viewport.set(0, 0, width, height);
- mDirtyClip = false;
+ glDisable(GL_DITHER);
+ glEnable(GL_SCISSOR_TEST);
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+ glEnableVertexAttribArray(Program::kBindingPosition);
}
void OpenGLRenderer::prepare(bool opaque) {
@@ -156,17 +152,15 @@ void OpenGLRenderer::prepareDirty(float left, float top, float right, float bott
mSnapshot = new Snapshot(mFirstSnapshot,
SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
mSnapshot->fbo = getTargetFbo();
-
mSaveCount = 1;
glViewport(0, 0, mWidth, mHeight);
-
- glEnable(GL_SCISSOR_TEST);
glScissor(left, mSnapshot->height - bottom, right - left, bottom - top);
+
mSnapshot->setClip(left, top, right, bottom);
+ mDirtyClip = false;
if (!opaque) {
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
}
@@ -200,20 +194,22 @@ void OpenGLRenderer::interrupt() {
}
}
mCaches.unbindMeshBuffer();
+ mCaches.unbindIndicesBuffer();
+ mCaches.resetVertexPointers();
+ mCaches.disbaleTexCoordsVertexArray();
}
void OpenGLRenderer::resume() {
sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot;
glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glEnable(GL_SCISSOR_TEST);
dirtyClip();
- glDisable(GL_DITHER);
-
+ mCaches.activeTexture(0);
glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
mCaches.blend = true;
glEnable(GL_BLEND);
@@ -453,7 +449,7 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
return false;
}
- glActiveTexture(gTextureUnits[0]);
+ mCaches.activeTexture(0);
Layer* layer = mCaches.layerCache.get(bounds.getWidth(), bounds.getHeight());
if (!layer) {
return false;
@@ -556,7 +552,6 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> sna
// Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
glScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
clip.getWidth() + 2.0f, clip.getHeight() + 2.0f);
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
dirtyClip();
@@ -596,7 +591,7 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
mCaches.unbindMeshBuffer();
- glActiveTexture(gTextureUnits[0]);
+ mCaches.activeTexture(0);
// When the layer is stored in an FBO, we can save a bit of fillrate by
// drawing only the dirty region
@@ -773,7 +768,7 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
layer->setFilter(GL_LINEAR);
setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom);
}
- setupDrawMesh(&mesh[0].position[0], &mesh[0].texture[0]);
+ setupDrawMeshIndices(&mesh[0].position[0], &mesh[0].texture[0]);
for (size_t i = 0; i < count; i++) {
const android::Rect* r = &rects[i];
@@ -802,7 +797,6 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, NULL);
}
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
finishDrawTexture();
#if DEBUG_LAYERS_AS_REGIONS
@@ -911,10 +905,8 @@ void OpenGLRenderer::clearLayerRegions() {
setupDrawProgram();
setupDrawPureColorUniforms();
setupDrawModelViewTranslate(0.0f, 0.0f, 0.0f, 0.0f, true);
+ setupDrawVertices(&mesh[0].position[0]);
- mCaches.unbindMeshBuffer();
- glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
- gVertexStride, &mesh[0].position[0]);
glDrawArrays(GL_TRIANGLES, 0, count * 6);
glEnable(GL_SCISSOR_TEST);
@@ -1019,7 +1011,6 @@ void OpenGLRenderer::setupDraw(bool clear) {
mColorA = mColorR = mColorG = mColorB = 0.0f;
mTextureUnit = 0;
mTrackDirtyRegions = true;
- mTexCoordsSlot = -1;
}
void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
@@ -1031,6 +1022,10 @@ void OpenGLRenderer::setupDrawWithExternalTexture() {
mDescription.hasExternalTexture = true;
}
+void OpenGLRenderer::setupDrawNoTexture() {
+ mCaches.disbaleTexCoordsVertexArray();
+}
+
void OpenGLRenderer::setupDrawAALine() {
mDescription.isAA = true;
}
@@ -1205,25 +1200,21 @@ void OpenGLRenderer::setupDrawColorFilterUniforms() {
}
void OpenGLRenderer::setupDrawSimpleMesh() {
- mCaches.bindMeshBuffer();
- glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
- gMeshStride, 0);
+ bool force = mCaches.bindMeshBuffer();
+ mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, 0);
+ mCaches.unbindIndicesBuffer();
}
void OpenGLRenderer::setupDrawTexture(GLuint texture) {
bindTexture(texture);
- glUniform1i(mCaches.currentProgram->getUniform("sampler"), mTextureUnit++);
-
- mTexCoordsSlot = mCaches.currentProgram->getAttrib("texCoords");
- glEnableVertexAttribArray(mTexCoordsSlot);
+ mTextureUnit++;
+ mCaches.enableTexCoordsVertexArray();
}
void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) {
bindExternalTexture(texture);
- glUniform1i(mCaches.currentProgram->getUniform("sampler"), mTextureUnit++);
-
- mTexCoordsSlot = mCaches.currentProgram->getAttrib("texCoords");
- glEnableVertexAttribArray(mTexCoordsSlot);
+ mTextureUnit++;
+ mCaches.enableTexCoordsVertexArray();
}
void OpenGLRenderer::setupDrawTextureTransform() {
@@ -1236,22 +1227,34 @@ void OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) {
}
void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLuint vbo) {
+ bool force = false;
if (!vertices) {
- mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
+ force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
} else {
- mCaches.unbindMeshBuffer();
+ force = mCaches.unbindMeshBuffer();
}
- glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
- gMeshStride, vertices);
- if (mTexCoordsSlot >= 0) {
- glVertexAttribPointer(mTexCoordsSlot, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords);
+
+ mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, vertices);
+ if (mCaches.currentProgram->texCoords >= 0) {
+ mCaches.bindTexCoordsVertexPointer(force, mCaches.currentProgram->texCoords, texCoords);
+ }
+
+ mCaches.unbindIndicesBuffer();
+}
+
+void OpenGLRenderer::setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords) {
+ bool force = mCaches.unbindMeshBuffer();
+ mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, vertices);
+ if (mCaches.currentProgram->texCoords >= 0) {
+ mCaches.bindTexCoordsVertexPointer(force, mCaches.currentProgram->texCoords, texCoords);
}
}
void OpenGLRenderer::setupDrawVertices(GLvoid* vertices) {
- mCaches.unbindMeshBuffer();
- glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
- gVertexStride, vertices);
+ bool force = mCaches.unbindMeshBuffer();
+ mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position,
+ vertices, gVertexStride);
+ mCaches.unbindIndicesBuffer();
}
/**
@@ -1267,24 +1270,29 @@ void OpenGLRenderer::setupDrawVertices(GLvoid* vertices) {
*/
void OpenGLRenderer::setupDrawAALine(GLvoid* vertices, GLvoid* widthCoords,
GLvoid* lengthCoords, float boundaryWidthProportion) {
- mCaches.unbindMeshBuffer();
- glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
- gAAVertexStride, vertices);
+ bool force = mCaches.unbindMeshBuffer();
+ mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position,
+ vertices, gAAVertexStride);
+ mCaches.resetTexCoordsVertexPointer();
+ mCaches.unbindIndicesBuffer();
+
int widthSlot = mCaches.currentProgram->getAttrib("vtxWidth");
glEnableVertexAttribArray(widthSlot);
glVertexAttribPointer(widthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, widthCoords);
+
int lengthSlot = mCaches.currentProgram->getAttrib("vtxLength");
glEnableVertexAttribArray(lengthSlot);
glVertexAttribPointer(lengthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, lengthCoords);
+
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 / boundaryWidthProportion));
}
void OpenGLRenderer::finishDrawTexture() {
- glDisableVertexAttribArray(mTexCoordsSlot);
}
///////////////////////////////////////////////////////////////////////////////
@@ -1364,7 +1372,7 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint
return;
}
- glActiveTexture(gTextureUnits[0]);
+ mCaches.activeTexture(0);
Texture* texture = mCaches.textureCache.get(bitmap);
if (!texture) return;
const AutoTexture autoCleanup(texture);
@@ -1385,7 +1393,7 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* pai
return;
}
- glActiveTexture(gTextureUnits[0]);
+ mCaches.activeTexture(0);
Texture* texture = mCaches.textureCache.get(bitmap);
if (!texture) return;
const AutoTexture autoCleanup(texture);
@@ -1405,7 +1413,7 @@ void OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHei
return;
}
- glActiveTexture(gTextureUnits[0]);
+ mCaches.activeTexture(0);
Texture* texture = mCaches.textureCache.get(bitmap);
if (!texture) return;
const AutoTexture autoCleanup(texture);
@@ -1490,7 +1498,7 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
return;
}
- glActiveTexture(gTextureUnits[0]);
+ mCaches.activeTexture(0);
Texture* texture = mCaches.textureCache.get(bitmap);
if (!texture) return;
const AutoTexture autoCleanup(texture);
@@ -1544,7 +1552,7 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int
return;
}
- glActiveTexture(gTextureUnits[0]);
+ mCaches.activeTexture(0);
Texture* texture = mCaches.textureCache.get(bitmap);
if (!texture) return;
const AutoTexture autoCleanup(texture);
@@ -1623,6 +1631,7 @@ void OpenGLRenderer::drawAARect(float left, float top, float right, float bottom
}
setupDraw();
+ setupDrawNoTexture();
setupDrawAALine();
setupDrawColor(color);
setupDrawColorFilter();
@@ -1733,6 +1742,7 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
getAlphaAndMode(paint, &alpha, &mode);
setupDraw();
+ setupDrawNoTexture();
if (isAA) {
setupDrawAALine();
}
@@ -1942,6 +1952,7 @@ void OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) {
TextureVertex* vertex = &pointsData[0];
setupDraw();
+ setupDrawNoTexture();
setupDrawPoint(strokeWidth);
setupDrawColor(paint->getColor(), alpha);
setupDrawColorFilter();
@@ -1992,7 +2003,7 @@ void OpenGLRenderer::drawRoundRect(float left, float top, float right, float bot
float rx, float ry, SkPaint* paint) {
if (mSnapshot->isIgnored()) return;
- glActiveTexture(gTextureUnits[0]);
+ mCaches.activeTexture(0);
const PathTexture* texture = mCaches.roundRectShapeCache.getRoundRect(
right - left, bottom - top, rx, ry, paint);
drawShape(left, top, texture, paint);
@@ -2001,7 +2012,7 @@ void OpenGLRenderer::drawRoundRect(float left, float top, float right, float bot
void OpenGLRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) {
if (mSnapshot->isIgnored()) return;
- glActiveTexture(gTextureUnits[0]);
+ mCaches.activeTexture(0);
const PathTexture* texture = mCaches.circleShapeCache.getCircle(radius, paint);
drawShape(x - radius, y - radius, texture, paint);
}
@@ -2009,7 +2020,7 @@ void OpenGLRenderer::drawCircle(float x, float y, float radius, SkPaint* paint)
void OpenGLRenderer::drawOval(float left, float top, float right, float bottom, SkPaint* paint) {
if (mSnapshot->isIgnored()) return;
- glActiveTexture(gTextureUnits[0]);
+ mCaches.activeTexture(0);
const PathTexture* texture = mCaches.ovalShapeCache.getOval(right - left, bottom - top, paint);
drawShape(left, top, texture, paint);
}
@@ -2023,7 +2034,7 @@ void OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
return;
}
- glActiveTexture(gTextureUnits[0]);
+ mCaches.activeTexture(0);
const PathTexture* texture = mCaches.arcShapeCache.getArc(right - left, bottom - top,
startAngle, sweepAngle, useCenter, paint);
drawShape(left, top, texture, paint);
@@ -2033,7 +2044,7 @@ void OpenGLRenderer::drawRectAsShape(float left, float top, float right, float b
SkPaint* paint) {
if (mSnapshot->isIgnored()) return;
- glActiveTexture(gTextureUnits[0]);
+ mCaches.activeTexture(0);
const PathTexture* texture = mCaches.rectShapeCache.getRect(right - left, bottom - top, paint);
drawShape(left, top, texture, paint);
}
@@ -2117,6 +2128,8 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
getAlphaAndMode(paint, &alpha, &mode);
if (mHasShadow) {
+ mCaches.activeTexture(0);
+
mCaches.dropShadowCache.setFontRenderer(fontRenderer);
const ShadowTexture* shadow = mCaches.dropShadowCache.get(
paint, text, bytesCount, count, mShadowRadius);
@@ -2131,7 +2144,6 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
shadowColor = 0xffffffff;
}
- glActiveTexture(gTextureUnits[0]);
setupDraw();
setupDrawWithTexture(true);
setupDrawAlpha8Color(shadowColor, shadowAlpha < 255 ? shadowAlpha : alpha);
@@ -2147,8 +2159,6 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
-
- finishDrawTexture();
}
if (paint->getAlpha() == 0 && paint->getXfermode() == NULL) {
@@ -2161,7 +2171,7 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f;
}
- glActiveTexture(gTextureUnits[0]);
+ mCaches.activeTexture(0);
setupDraw();
setupDrawDirtyRegionsDisabled();
setupDrawWithTexture(true);
@@ -2184,12 +2194,7 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
#else
bool hasActiveLayer = false;
#endif
- mCaches.unbindMeshBuffer();
- // Tell font renderer the locations of position and texture coord
- // attributes so it can bind its data properly
- int positionSlot = mCaches.currentProgram->position;
- fontRenderer.setAttributeBindingSlots(positionSlot, mTexCoordsSlot);
if (fontRenderer.renderText(paint, clip, text, 0, bytesCount, count, x, y,
hasActiveLayer ? &bounds : NULL)) {
#if RENDER_LAYERS_AS_REGIONS
@@ -2202,16 +2207,13 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
#endif
}
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords"));
-
drawTextDecorations(text, bytesCount, length, oldX, oldY, paint);
}
void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) {
if (mSnapshot->isIgnored()) return;
- glActiveTexture(gTextureUnits[0]);
+ mCaches.activeTexture(0);
const PathTexture* texture = mCaches.pathCache.get(path, paint);
if (!texture) return;
@@ -2228,7 +2230,7 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) {
return;
}
- glActiveTexture(gTextureUnits[0]);
+ mCaches.activeTexture(0);
int alpha;
SkXfermode::Mode mode;
@@ -2434,6 +2436,7 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot
}
setupDraw();
+ setupDrawNoTexture();
setupDrawColor(color);
setupDrawShader();
setupDrawColorFilter();
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index cd9ff93..019e9b2 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -498,6 +498,7 @@ private:
*/
void setupDrawWithTexture(bool isAlpha8 = false);
void setupDrawWithExternalTexture();
+ void setupDrawNoTexture();
void setupDrawAALine();
void setupDrawPoint(float pointSize);
void setupDrawColor(int color);
@@ -530,6 +531,7 @@ private:
void setupDrawTextureTransform();
void setupDrawTextureTransformUniforms(mat4& transform);
void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords = NULL, GLuint vbo = 0);
+ void setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords);
void setupDrawVertices(GLvoid* vertices);
void setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, GLvoid* lengthCoords,
float strokeWidth);
@@ -601,8 +603,6 @@ private:
GLuint mTextureUnit;
// Track dirty regions, true by default
bool mTrackDirtyRegions;
- // Texture coordinates slot
- int mTexCoordsSlot;
friend class DisplayListRenderer;
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index 47a2c99..27f530c 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -197,7 +197,8 @@ void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight,
}
if (verticesCount > 0) {
- Caches::getInstance().bindMeshBuffer(meshBuffer);
+ Caches& caches = Caches::getInstance();
+ caches.bindMeshBuffer(meshBuffer);
if (!mUploaded) {
glBufferData(GL_ARRAY_BUFFER, sizeof(TextureVertex) * verticesCount,
mVertices, GL_DYNAMIC_DRAW);
@@ -206,6 +207,7 @@ void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight,
glBufferSubData(GL_ARRAY_BUFFER, 0,
sizeof(TextureVertex) * verticesCount, mVertices);
}
+ caches.resetVertexPointers();
}
PATCH_LOGD(" patch: new vertices count = %d", verticesCount);
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index 972dd87..701314d 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -25,80 +25,107 @@ namespace uirenderer {
// Base program
///////////////////////////////////////////////////////////////////////////////
-Program::Program(const char* vertex, const char* fragment) {
+// TODO: Program instance should be created from a factory method
+Program::Program(const ProgramDescription& description, const char* vertex, const char* fragment) {
mInitialized = false;
+ mHasColorUniform = false;
+ mHasSampler = false;
+ mUse = false;
- vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
- if (vertexShader) {
+ // No need to cache compiled shaders, rely instead on Android's
+ // persistent shaders cache
+ mVertexShader = buildShader(vertex, GL_VERTEX_SHADER);
+ if (mVertexShader) {
+ mFragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
+ if (mFragmentShader) {
+ mProgramId = glCreateProgram();
- fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
- if (fragmentShader) {
+ glAttachShader(mProgramId, mVertexShader);
+ glAttachShader(mProgramId, mFragmentShader);
- id = glCreateProgram();
- glAttachShader(id, vertexShader);
- glAttachShader(id, fragmentShader);
- glLinkProgram(id);
+ position = bindAttrib("position", kBindingPosition);
+ if (description.hasTexture || description.hasExternalTexture) {
+ texCoords = bindAttrib("texCoords", kBindingTexCoords);
+ } else {
+ texCoords = -1;
+ }
+
+ glLinkProgram(mProgramId);
GLint status;
- glGetProgramiv(id, GL_LINK_STATUS, &status);
+ glGetProgramiv(mProgramId, GL_LINK_STATUS, &status);
if (status != GL_TRUE) {
LOGE("Error while linking shaders:");
GLint infoLen = 0;
- glGetProgramiv(id, GL_INFO_LOG_LENGTH, &infoLen);
+ glGetProgramiv(mProgramId, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
GLchar log[infoLen];
- glGetProgramInfoLog(id, infoLen, 0, &log[0]);
+ glGetProgramInfoLog(mProgramId, infoLen, 0, &log[0]);
LOGE("%s", log);
}
- glDeleteShader(vertexShader);
- glDeleteShader(fragmentShader);
- glDeleteProgram(id);
+
+ glDetachShader(mProgramId, mVertexShader);
+ glDetachShader(mProgramId, mFragmentShader);
+
+ glDeleteShader(mVertexShader);
+ glDeleteShader(mFragmentShader);
+
+ glDeleteProgram(mProgramId);
} else {
mInitialized = true;
}
+ } else {
+ glDeleteShader(mVertexShader);
}
}
- mUse = false;
-
if (mInitialized) {
- position = addAttrib("position");
transform = addUniform("transform");
}
}
Program::~Program() {
if (mInitialized) {
- glDeleteShader(vertexShader);
- glDeleteShader(fragmentShader);
- glDeleteProgram(id);
+ glDetachShader(mProgramId, mVertexShader);
+ glDetachShader(mProgramId, mFragmentShader);
+
+ glDeleteShader(mVertexShader);
+ glDeleteShader(mFragmentShader);
+
+ glDeleteProgram(mProgramId);
}
}
int Program::addAttrib(const char* name) {
- int slot = glGetAttribLocation(id, name);
- attributes.add(name, slot);
+ int slot = glGetAttribLocation(mProgramId, name);
+ mAttributes.add(name, slot);
return slot;
}
+int Program::bindAttrib(const char* name, ShaderBindings bindingSlot) {
+ glBindAttribLocation(mProgramId, bindingSlot, name);
+ mAttributes.add(name, bindingSlot);
+ return bindingSlot;
+}
+
int Program::getAttrib(const char* name) {
- ssize_t index = attributes.indexOfKey(name);
+ ssize_t index = mAttributes.indexOfKey(name);
if (index >= 0) {
- return attributes.valueAt(index);
+ return mAttributes.valueAt(index);
}
return addAttrib(name);
}
int Program::addUniform(const char* name) {
- int slot = glGetUniformLocation(id, name);
- uniforms.add(name, slot);
+ int slot = glGetUniformLocation(mProgramId, name);
+ mUniforms.add(name, slot);
return slot;
}
int Program::getUniform(const char* name) {
- ssize_t index = uniforms.indexOfKey(name);
+ ssize_t index = mUniforms.indexOfKey(name);
if (index >= 0) {
- return uniforms.valueAt(index);
+ return mUniforms.valueAt(index);
}
return addUniform(name);
}
@@ -127,10 +154,11 @@ void Program::set(const mat4& projectionMatrix, const mat4& modelViewMatrix,
const mat4& transformMatrix, bool offset) {
mat4 t(projectionMatrix);
if (offset) {
- // offset screenspace xy by an amount that compensates for typical precision issues
- // in GPU hardware that tends to paint hor/vert lines in pixels shifted up and to the left.
- // This offset value is based on an assumption that some hardware may use as little
- // as 12.4 precision, so we offset by slightly more than 1/16.
+ // offset screenspace xy by an amount that compensates for typical precision
+ // issues in GPU hardware that tends to paint hor/vert lines in pixels shifted
+ // up and to the left.
+ // This offset value is based on an assumption that some hardware may use as
+ // little as 12.4 precision, so we offset by slightly more than 1/16.
t.translate(.375, .375, 0);
}
t.multiply(transformMatrix);
@@ -140,20 +168,24 @@ void Program::set(const mat4& projectionMatrix, const mat4& modelViewMatrix,
}
void Program::setColor(const float r, const float g, const float b, const float a) {
- glUniform4f(getUniform("color"), r, g, b, a);
+ if (!mHasColorUniform) {
+ mColorUniform = getUniform("color");
+ mHasColorUniform = true;
+ }
+ glUniform4f(mColorUniform, r, g, b, a);
}
void Program::use() {
- glUseProgram(id);
+ glUseProgram(mProgramId);
+ if (texCoords >= 0 && !mHasSampler) {
+ glUniform1i(getUniform("sampler"), 0);
+ mHasSampler = true;
+ }
mUse = true;
-
- glEnableVertexAttribArray(position);
}
void Program::remove() {
mUse = false;
-
- glDisableVertexAttribArray(position);
}
}; // namespace uirenderer
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index 764cb05..eed909d 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -17,27 +17,280 @@
#ifndef ANDROID_HWUI_PROGRAM_H
#define ANDROID_HWUI_PROGRAM_H
+#include <utils/KeyedVector.h>
+
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
-#include <utils/KeyedVector.h>
+#include <SkXfermode.h>
#include "Matrix.h"
+#include "Properties.h"
namespace android {
namespace uirenderer {
+///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
+// Debug
+#if DEBUG_PROGRAMS
+ #define PROGRAM_LOGD(...) LOGD(__VA_ARGS__)
+#else
+ #define PROGRAM_LOGD(...)
+#endif
+
+#define COLOR_COMPONENT_THRESHOLD (1.0f - (0.5f / PANEL_BIT_DEPTH))
+#define COLOR_COMPONENT_INV_THRESHOLD (0.5f / PANEL_BIT_DEPTH)
+
+#define PROGRAM_KEY_TEXTURE 0x1
+#define PROGRAM_KEY_A8_TEXTURE 0x2
+#define PROGRAM_KEY_BITMAP 0x4
+#define PROGRAM_KEY_GRADIENT 0x8
+#define PROGRAM_KEY_BITMAP_FIRST 0x10
+#define PROGRAM_KEY_COLOR_MATRIX 0x20
+#define PROGRAM_KEY_COLOR_LIGHTING 0x40
+#define PROGRAM_KEY_COLOR_BLEND 0x80
+#define PROGRAM_KEY_BITMAP_NPOT 0x100
+#define PROGRAM_KEY_SWAP_SRC_DST 0x2000
+
+#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600
+#define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800
+
+// Encode the xfermodes on 6 bits
+#define PROGRAM_MAX_XFERMODE 0x1f
+#define PROGRAM_XFERMODE_SHADER_SHIFT 26
+#define PROGRAM_XFERMODE_COLOR_OP_SHIFT 20
+#define PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT 14
+
+#define PROGRAM_BITMAP_WRAPS_SHIFT 9
+#define PROGRAM_BITMAP_WRAPT_SHIFT 11
+
+#define PROGRAM_GRADIENT_TYPE_SHIFT 33
+#define PROGRAM_MODULATE_SHIFT 35
+
+#define PROGRAM_IS_POINT_SHIFT 36
+
+#define PROGRAM_HAS_AA_SHIFT 37
+
+#define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38
+#define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 39
+
+///////////////////////////////////////////////////////////////////////////////
+// Types
+///////////////////////////////////////////////////////////////////////////////
+
+typedef uint64_t programid;
+
+///////////////////////////////////////////////////////////////////////////////
+// Program description
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Describe the features required for a given program. The features
+ * determine the generation of both the vertex and fragment shaders.
+ * A ProgramDescription must be used in conjunction with a ProgramCache.
+ */
+struct ProgramDescription {
+ enum ColorModifier {
+ kColorNone,
+ kColorMatrix,
+ kColorLighting,
+ kColorBlend
+ };
+
+ enum Gradient {
+ kGradientLinear,
+ kGradientCircular,
+ kGradientSweep
+ };
+
+ ProgramDescription() {
+ reset();
+ }
+
+ // Texturing
+ bool hasTexture;
+ bool hasAlpha8Texture;
+ bool hasExternalTexture;
+ bool hasTextureTransform;
+
+ // Modulate, this should only be set when setColor() return true
+ bool modulate;
+
+ // Shaders
+ bool hasBitmap;
+ bool isBitmapNpot;
+
+ bool isAA;
+
+ bool hasGradient;
+ Gradient gradientType;
+
+ SkXfermode::Mode shadersMode;
+
+ bool isBitmapFirst;
+ GLenum bitmapWrapS;
+ GLenum bitmapWrapT;
+
+ // Color operations
+ ColorModifier colorOp;
+ SkXfermode::Mode colorMode;
+
+ // Framebuffer blending (requires Extensions.hasFramebufferFetch())
+ // Ignored for all values < SkXfermode::kPlus_Mode
+ SkXfermode::Mode framebufferMode;
+ bool swapSrcDst;
+
+ bool isPoint;
+ float pointSize;
+
+ /**
+ * Resets this description. All fields are reset back to the default
+ * values they hold after building a new instance.
+ */
+ void reset() {
+ hasTexture = false;
+ hasAlpha8Texture = false;
+ hasExternalTexture = false;
+ hasTextureTransform = false;
+
+ isAA = false;
+
+ modulate = false;
+
+ hasBitmap = false;
+ isBitmapNpot = false;
+
+ hasGradient = false;
+ gradientType = kGradientLinear;
+
+ shadersMode = SkXfermode::kClear_Mode;
+
+ isBitmapFirst = false;
+ bitmapWrapS = GL_CLAMP_TO_EDGE;
+ bitmapWrapT = GL_CLAMP_TO_EDGE;
+
+ colorOp = kColorNone;
+ colorMode = SkXfermode::kClear_Mode;
+
+ framebufferMode = SkXfermode::kClear_Mode;
+ swapSrcDst = false;
+
+ isPoint = false;
+ pointSize = 0.0f;
+ }
+
+ /**
+ * Indicates, for a given color, whether color modulation is required in
+ * the fragment shader. When this method returns true, the program should
+ * be provided with a modulation color.
+ */
+ bool setColor(const float r, const float g, const float b, const float a) {
+ modulate = a < COLOR_COMPONENT_THRESHOLD || r < COLOR_COMPONENT_THRESHOLD ||
+ g < COLOR_COMPONENT_THRESHOLD || b < COLOR_COMPONENT_THRESHOLD;
+ return modulate;
+ }
+
+ /**
+ * Indicates, for a given color, whether color modulation is required in
+ * the fragment shader. When this method returns true, the program should
+ * be provided with a modulation color.
+ */
+ bool setAlpha8Color(const float r, const float g, const float b, const float a) {
+ modulate = a < COLOR_COMPONENT_THRESHOLD || r > COLOR_COMPONENT_INV_THRESHOLD ||
+ g > COLOR_COMPONENT_INV_THRESHOLD || b > COLOR_COMPONENT_INV_THRESHOLD;
+ return modulate;
+ }
+
+ /**
+ * Computes the unique key identifying this program.
+ */
+ programid key() const {
+ programid key = 0;
+ if (hasTexture) key |= PROGRAM_KEY_TEXTURE;
+ if (hasAlpha8Texture) key |= PROGRAM_KEY_A8_TEXTURE;
+ if (hasBitmap) {
+ key |= PROGRAM_KEY_BITMAP;
+ if (isBitmapNpot) {
+ key |= PROGRAM_KEY_BITMAP_NPOT;
+ key |= getEnumForWrap(bitmapWrapS) << PROGRAM_BITMAP_WRAPS_SHIFT;
+ key |= getEnumForWrap(bitmapWrapT) << PROGRAM_BITMAP_WRAPT_SHIFT;
+ }
+ }
+ if (hasGradient) key |= PROGRAM_KEY_GRADIENT;
+ key |= programid(gradientType) << PROGRAM_GRADIENT_TYPE_SHIFT;
+ if (isBitmapFirst) key |= PROGRAM_KEY_BITMAP_FIRST;
+ if (hasBitmap && hasGradient) {
+ key |= (shadersMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_SHADER_SHIFT;
+ }
+ switch (colorOp) {
+ case kColorMatrix:
+ key |= PROGRAM_KEY_COLOR_MATRIX;
+ break;
+ case kColorLighting:
+ key |= PROGRAM_KEY_COLOR_LIGHTING;
+ break;
+ case kColorBlend:
+ key |= PROGRAM_KEY_COLOR_BLEND;
+ key |= (colorMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_COLOR_OP_SHIFT;
+ break;
+ case kColorNone:
+ break;
+ }
+ key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT;
+ if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST;
+ if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT;
+ if (isPoint) key |= programid(0x1) << PROGRAM_IS_POINT_SHIFT;
+ if (isAA) key |= programid(0x1) << PROGRAM_HAS_AA_SHIFT;
+ if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT;
+ if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT;
+ return key;
+ }
+
+ /**
+ * Logs the specified message followed by the key identifying this program.
+ */
+ void log(const char* message) const {
+#if DEBUG_PROGRAMS
+ programid k = key();
+ PROGRAM_LOGD("%s (key = 0x%.8x%.8x)", message, uint32_t(k >> 32),
+ uint32_t(k & 0xffffffff));
+#endif
+ }
+
+private:
+ inline uint32_t getEnumForWrap(GLenum wrap) const {
+ switch (wrap) {
+ case GL_CLAMP_TO_EDGE:
+ return 0;
+ case GL_REPEAT:
+ return 1;
+ case GL_MIRRORED_REPEAT:
+ return 2;
+ }
+ return 0;
+ }
+
+}; // struct ProgramDescription
+
/**
* A program holds a vertex and a fragment shader. It offers several utility
* methods to query attributes and uniforms.
*/
class Program {
public:
+ enum ShaderBindings {
+ kBindingPosition,
+ kBindingTexCoords
+ };
+
/**
* Creates a new program with the specified vertex and fragment
* shaders sources.
*/
- Program(const char* vertex, const char* fragment);
+ Program(const ProgramDescription& description, const char* vertex, const char* fragment);
virtual ~Program();
/**
@@ -94,6 +347,11 @@ public:
int position;
/**
+ * Name of the texCoords attribute if it exists, -1 otherwise.
+ */
+ int texCoords;
+
+ /**
* Name of the transform uniform.
*/
int transform;
@@ -107,6 +365,11 @@ protected:
int addAttrib(const char* name);
/**
+ * Binds the specified attribute name to the specified slot.
+ */
+ int bindAttrib(const char* name, ShaderBindings bindingSlot);
+
+ /**
* Adds a uniform with the specified name.
*
* @return The OpenGL name of the uniform.
@@ -121,19 +384,22 @@ private:
*/
GLuint buildShader(const char* source, GLenum type);
- // Name of the OpenGL program
- GLuint id;
-
- // Name of the shaders
- GLuint vertexShader;
- GLuint fragmentShader;
+ // Name of the OpenGL program and shaders
+ GLuint mProgramId;
+ GLuint mVertexShader;
+ GLuint mFragmentShader;
// Keeps track of attributes and uniforms slots
- KeyedVector<const char*, int> attributes;
- KeyedVector<const char*, int> uniforms;
+ KeyedVector<const char*, int> mAttributes;
+ KeyedVector<const char*, int> mUniforms;
bool mUse;
bool mInitialized;
+
+ bool mHasColorUniform;
+ int mColorUniform;
+
+ bool mHasSampler;
}; // class Program
}; // namespace uirenderer
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index c2383f4..a7f1277 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -388,7 +388,7 @@ Program* ProgramCache::generateProgram(const ProgramDescription& description, pr
String8 vertexShader = generateVertexShader(description);
String8 fragmentShader = generateFragmentShader(description);
- Program* program = new Program(vertexShader.string(), fragmentShader.string());
+ Program* program = new Program(description, vertexShader.string(), fragmentShader.string());
return program;
}
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index 5c7197b..e3ed79e 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -23,10 +23,9 @@
#include <GLES2/gl2.h>
-#include <SkXfermode.h>
-
#include "Debug.h"
#include "Program.h"
+#include "Properties.h"
namespace android {
namespace uirenderer {
@@ -42,243 +41,11 @@ namespace uirenderer {
#define PROGRAM_LOGD(...)
#endif
-// TODO: This should be set in properties
-#define PANEL_BIT_DEPTH 20
-#define COLOR_COMPONENT_THRESHOLD (1.0f - (0.5f / PANEL_BIT_DEPTH))
-#define COLOR_COMPONENT_INV_THRESHOLD (0.5f / PANEL_BIT_DEPTH)
-
-#define PROGRAM_KEY_TEXTURE 0x1
-#define PROGRAM_KEY_A8_TEXTURE 0x2
-#define PROGRAM_KEY_BITMAP 0x4
-#define PROGRAM_KEY_GRADIENT 0x8
-#define PROGRAM_KEY_BITMAP_FIRST 0x10
-#define PROGRAM_KEY_COLOR_MATRIX 0x20
-#define PROGRAM_KEY_COLOR_LIGHTING 0x40
-#define PROGRAM_KEY_COLOR_BLEND 0x80
-#define PROGRAM_KEY_BITMAP_NPOT 0x100
-#define PROGRAM_KEY_SWAP_SRC_DST 0x2000
-
-#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600
-#define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800
-
-// Encode the xfermodes on 6 bits
-#define PROGRAM_MAX_XFERMODE 0x1f
-#define PROGRAM_XFERMODE_SHADER_SHIFT 26
-#define PROGRAM_XFERMODE_COLOR_OP_SHIFT 20
-#define PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT 14
-
-#define PROGRAM_BITMAP_WRAPS_SHIFT 9
-#define PROGRAM_BITMAP_WRAPT_SHIFT 11
-
-#define PROGRAM_GRADIENT_TYPE_SHIFT 33
-#define PROGRAM_MODULATE_SHIFT 35
-
-#define PROGRAM_IS_POINT_SHIFT 36
-
-#define PROGRAM_HAS_AA_SHIFT 37
-
-#define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38
-#define PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT 39
-
-///////////////////////////////////////////////////////////////////////////////
-// Types
-///////////////////////////////////////////////////////////////////////////////
-
-typedef uint64_t programid;
-
///////////////////////////////////////////////////////////////////////////////
// Cache
///////////////////////////////////////////////////////////////////////////////
/**
- * Describe the features required for a given program. The features
- * determine the generation of both the vertex and fragment shaders.
- * A ProgramDescription must be used in conjunction with a ProgramCache.
- */
-struct ProgramDescription {
- enum ColorModifier {
- kColorNone,
- kColorMatrix,
- kColorLighting,
- kColorBlend
- };
-
- enum Gradient {
- kGradientLinear,
- kGradientCircular,
- kGradientSweep
- };
-
- ProgramDescription() {
- reset();
- }
-
- // Texturing
- bool hasTexture;
- bool hasAlpha8Texture;
- bool hasExternalTexture;
- bool hasTextureTransform;
-
- // Modulate, this should only be set when setColor() return true
- bool modulate;
-
- // Shaders
- bool hasBitmap;
- bool isBitmapNpot;
-
- bool isAA;
-
- bool hasGradient;
- Gradient gradientType;
-
- SkXfermode::Mode shadersMode;
-
- bool isBitmapFirst;
- GLenum bitmapWrapS;
- GLenum bitmapWrapT;
-
- // Color operations
- ColorModifier colorOp;
- SkXfermode::Mode colorMode;
-
- // Framebuffer blending (requires Extensions.hasFramebufferFetch())
- // Ignored for all values < SkXfermode::kPlus_Mode
- SkXfermode::Mode framebufferMode;
- bool swapSrcDst;
-
- bool isPoint;
- float pointSize;
-
- /**
- * Resets this description. All fields are reset back to the default
- * values they hold after building a new instance.
- */
- void reset() {
- hasTexture = false;
- hasAlpha8Texture = false;
- hasExternalTexture = false;
- hasTextureTransform = false;
-
- isAA = false;
-
- modulate = false;
-
- hasBitmap = false;
- isBitmapNpot = false;
-
- hasGradient = false;
- gradientType = kGradientLinear;
-
- shadersMode = SkXfermode::kClear_Mode;
-
- isBitmapFirst = false;
- bitmapWrapS = GL_CLAMP_TO_EDGE;
- bitmapWrapT = GL_CLAMP_TO_EDGE;
-
- colorOp = kColorNone;
- colorMode = SkXfermode::kClear_Mode;
-
- framebufferMode = SkXfermode::kClear_Mode;
- swapSrcDst = false;
-
- isPoint = false;
- pointSize = 0.0f;
- }
-
- /**
- * Indicates, for a given color, whether color modulation is required in
- * the fragment shader. When this method returns true, the program should
- * be provided with a modulation color.
- */
- bool setColor(const float r, const float g, const float b, const float a) {
- modulate = a < COLOR_COMPONENT_THRESHOLD || r < COLOR_COMPONENT_THRESHOLD ||
- g < COLOR_COMPONENT_THRESHOLD || b < COLOR_COMPONENT_THRESHOLD;
- return modulate;
- }
-
- /**
- * Indicates, for a given color, whether color modulation is required in
- * the fragment shader. When this method returns true, the program should
- * be provided with a modulation color.
- */
- bool setAlpha8Color(const float r, const float g, const float b, const float a) {
- modulate = a < COLOR_COMPONENT_THRESHOLD || r > COLOR_COMPONENT_INV_THRESHOLD ||
- g > COLOR_COMPONENT_INV_THRESHOLD || b > COLOR_COMPONENT_INV_THRESHOLD;
- return modulate;
- }
-
- /**
- * Computes the unique key identifying this program.
- */
- programid key() const {
- programid key = 0;
- if (hasTexture) key |= PROGRAM_KEY_TEXTURE;
- if (hasAlpha8Texture) key |= PROGRAM_KEY_A8_TEXTURE;
- if (hasBitmap) {
- key |= PROGRAM_KEY_BITMAP;
- if (isBitmapNpot) {
- key |= PROGRAM_KEY_BITMAP_NPOT;
- key |= getEnumForWrap(bitmapWrapS) << PROGRAM_BITMAP_WRAPS_SHIFT;
- key |= getEnumForWrap(bitmapWrapT) << PROGRAM_BITMAP_WRAPT_SHIFT;
- }
- }
- if (hasGradient) key |= PROGRAM_KEY_GRADIENT;
- key |= programid(gradientType) << PROGRAM_GRADIENT_TYPE_SHIFT;
- if (isBitmapFirst) key |= PROGRAM_KEY_BITMAP_FIRST;
- if (hasBitmap && hasGradient) {
- key |= (shadersMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_SHADER_SHIFT;
- }
- switch (colorOp) {
- case kColorMatrix:
- key |= PROGRAM_KEY_COLOR_MATRIX;
- break;
- case kColorLighting:
- key |= PROGRAM_KEY_COLOR_LIGHTING;
- break;
- case kColorBlend:
- key |= PROGRAM_KEY_COLOR_BLEND;
- key |= (colorMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_COLOR_OP_SHIFT;
- break;
- case kColorNone:
- break;
- }
- key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT;
- if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST;
- if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT;
- if (isPoint) key |= programid(0x1) << PROGRAM_IS_POINT_SHIFT;
- if (isAA) key |= programid(0x1) << PROGRAM_HAS_AA_SHIFT;
- if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT;
- if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT;
- return key;
- }
-
- /**
- * Logs the specified message followed by the key identifying this program.
- */
- void log(const char* message) const {
-#if DEBUG_PROGRAMS
- programid k = key();
- PROGRAM_LOGD("%s (key = 0x%.8x%.8x)", message, uint32_t(k >> 32),
- uint32_t(k & 0xffffffff));
-#endif
- }
-
-private:
- inline uint32_t getEnumForWrap(GLenum wrap) const {
- switch (wrap) {
- case GL_CLAMP_TO_EDGE:
- return 0;
- case GL_REPEAT:
- return 1;
- case GL_MIRRORED_REPEAT:
- return 2;
- }
- return 0;
- }
-
-}; // struct ProgramDescription
-
-/**
* Generates and caches program. Programs are generated based on
* ProgramDescriptions.
*/
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 8c01e3a..2eae0f1 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -73,6 +73,9 @@ enum DebugLevel {
#define PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD "ro.text_gamma.black_threshold"
#define PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD "ro.text_gamma.white_threshold"
+// TODO: This should be set by a system property
+#define PANEL_BIT_DEPTH 20
+
// Converts a number of mega-bytes into bytes
#define MB(s) s * 1024 * 1024
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index edc90e1..fb76717 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -29,17 +29,6 @@ namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
class Rect {
- static inline float min(float a, float b) { return (a<b) ? a : b; }
- static inline float max(float a, float b) { return (a>b) ? a : b; }
- Rect intersectWith(float l, float t, float r, float b) const {
- Rect tmp;
- tmp.left = max(left, l);
- tmp.top = max(top, t);
- tmp.right = min(right, r);
- tmp.bottom = min(bottom, b);
- return tmp;
- }
-
public:
float left;
float top;
@@ -115,7 +104,7 @@ public:
}
bool intersects(float l, float t, float r, float b) const {
- return !intersectWith(l,t,r,b).isEmpty();
+ return !intersectWith(l, t, r, b).isEmpty();
}
bool intersects(const Rect& r) const {
@@ -123,7 +112,7 @@ public:
}
bool intersect(float l, float t, float r, float b) {
- Rect tmp(intersectWith(l,t,r,b));
+ Rect tmp(intersectWith(l, t, r, b));
if (!tmp.isEmpty()) {
set(tmp);
return true;
@@ -135,6 +124,14 @@ public:
return intersect(r.left, r.top, r.right, r.bottom);
}
+ bool contains(float l, float t, float r, float b) {
+ return l >= left && t >= top && r <= right && b <= bottom;
+ }
+
+ bool contains(const Rect& r) {
+ return contains(r.left, r.top, r.right, r.bottom);
+ }
+
bool unionWith(const Rect& r) {
if (r.left < r.right && r.top < r.bottom) {
if (left < right && top < bottom) {
@@ -172,6 +169,19 @@ public:
LOGD("Rect[l=%f t=%f r=%f b=%f]", left, top, right, bottom);
}
+private:
+ static inline float min(float a, float b) { return (a < b) ? a : b; }
+ static inline float max(float a, float b) { return (a > b) ? a : b; }
+
+ Rect intersectWith(float l, float t, float r, float b) const {
+ Rect tmp;
+ tmp.left = max(left, l);
+ tmp.top = max(top, t);
+ tmp.right = min(right, r);
+ tmp.bottom = min(bottom, b);
+ return tmp;
+ }
+
}; // class Rect
}; // namespace uirenderer
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 32e7533..66993a4 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -20,6 +20,7 @@
#include <SkMatrix.h>
+#include "Caches.h"
#include "SkiaShader.h"
#include "Texture.h"
#include "Matrix.h"
@@ -31,12 +32,6 @@ namespace uirenderer {
// Support
///////////////////////////////////////////////////////////////////////////////
-static const GLenum gTextureUnitsMap[] = {
- GL_TEXTURE0,
- GL_TEXTURE1,
- GL_TEXTURE2
-};
-
static const GLint gTileModes[] = {
GL_CLAMP_TO_EDGE, // == SkShader::kClamp_TileMode
GL_REPEAT, // == SkShader::kRepeat_Mode
@@ -129,7 +124,7 @@ void SkiaBitmapShader::describe(ProgramDescription& description, const Extension
void SkiaBitmapShader::setupProgram(Program* program, const mat4& modelView,
const Snapshot& snapshot, GLuint* textureUnit) {
GLuint textureSlot = (*textureUnit)++;
- glActiveTexture(gTextureUnitsMap[textureSlot]);
+ Caches::getInstance().activeTexture(textureSlot);
Texture* texture = mTexture;
mTexture = NULL;
@@ -223,7 +218,7 @@ void SkiaLinearGradientShader::describe(ProgramDescription& description,
void SkiaLinearGradientShader::setupProgram(Program* program, const mat4& modelView,
const Snapshot& snapshot, GLuint* textureUnit) {
GLuint textureSlot = (*textureUnit)++;
- glActiveTexture(gTextureUnitsMap[textureSlot]);
+ Caches::getInstance().activeTexture(textureSlot);
Texture* texture = mGradientCache->get(mColors, mPositions, mCount, mTileX);
@@ -335,7 +330,7 @@ void SkiaSweepGradientShader::describe(ProgramDescription& description,
void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelView,
const Snapshot& snapshot, GLuint* textureUnit) {
GLuint textureSlot = (*textureUnit)++;
- glActiveTexture(gTextureUnitsMap[textureSlot]);
+ Caches::getInstance().activeTexture(textureSlot);
Texture* texture = mGradientCache->get(mColors, mPositions, mCount);
diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp
index a3ee63b..bbefec6 100644
--- a/libs/hwui/TextDropShadowCache.cpp
+++ b/libs/hwui/TextDropShadowCache.cpp
@@ -137,8 +137,8 @@ ShadowTexture* TextDropShadowCache::get(SkPaint* paint, const char* text, uint32
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texture->width, texture->height, 0,
GL_ALPHA, GL_UNSIGNED_BYTE, shadow.image);
- texture->setFilter(GL_LINEAR, GL_LINEAR);
- texture->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
+ texture->setFilter(GL_LINEAR);
+ texture->setWrap(GL_CLAMP_TO_EDGE);
if (size < mMaxSize) {
if (mDebugEnabled) {
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index a4aed07..1adf2c7 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -49,7 +49,7 @@ struct Texture {
GLenum renderTarget = GL_TEXTURE_2D) {
if (firstWrap || force || wrapS != this->wrapS || wrapT != this->wrapT) {
- firstWrap = true;
+ firstWrap = false;
this->wrapS = wrapS;
this->wrapT = wrapT;