diff options
Diffstat (limited to 'libs')
-rw-r--r-- | libs/gui/SurfaceTexture.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/Caches.cpp | 88 | ||||
-rw-r--r-- | libs/hwui/Caches.h | 68 | ||||
-rw-r--r-- | libs/hwui/FontRenderer.cpp | 290 | ||||
-rw-r--r-- | libs/hwui/FontRenderer.h | 196 | ||||
-rw-r--r-- | libs/hwui/GammaFontRenderer.h | 2 | ||||
-rw-r--r-- | libs/hwui/GradientCache.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/LayerCache.cpp | 7 | ||||
-rw-r--r-- | libs/hwui/LayerRenderer.cpp | 16 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 149 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 4 | ||||
-rw-r--r-- | libs/hwui/Patch.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/Program.cpp | 110 | ||||
-rw-r--r-- | libs/hwui/Program.h | 286 | ||||
-rw-r--r-- | libs/hwui/ProgramCache.cpp | 2 | ||||
-rw-r--r-- | libs/hwui/ProgramCache.h | 235 | ||||
-rw-r--r-- | libs/hwui/Properties.h | 3 | ||||
-rw-r--r-- | libs/hwui/Rect.h | 36 | ||||
-rw-r--r-- | libs/hwui/SkiaShader.cpp | 13 | ||||
-rw-r--r-- | libs/hwui/TextDropShadowCache.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/Texture.h | 2 |
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; |