diff options
author | Romain Guy <romainguy@google.com> | 2011-12-12 20:35:21 -0800 |
---|---|---|
committer | Romain Guy <romainguy@google.com> | 2011-12-12 20:35:21 -0800 |
commit | f3a910b423db7ad79cf61518bdd9278c048ad0d8 (patch) | |
tree | a0ae14d597ee14202ec6ca60cedfb446ff470379 | |
parent | d71dd367af604571c7d00ca473184a1b9240eca2 (diff) | |
download | frameworks_base-f3a910b423db7ad79cf61518bdd9278c048ad0d8.zip frameworks_base-f3a910b423db7ad79cf61518bdd9278c048ad0d8.tar.gz frameworks_base-f3a910b423db7ad79cf61518bdd9278c048ad0d8.tar.bz2 |
Optimize state changes
Change-Id: Iae59bc8dfd6427d0967472462cc1994987092827
-rw-r--r-- | libs/hwui/Caches.cpp | 38 | ||||
-rw-r--r-- | libs/hwui/Caches.h | 45 | ||||
-rw-r--r-- | libs/hwui/FontRenderer.cpp | 13 | ||||
-rw-r--r-- | libs/hwui/FontRenderer.h | 13 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 49 | ||||
-rw-r--r-- | libs/hwui/Patch.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/Program.cpp | 8 | ||||
-rw-r--r-- | libs/hwui/Program.h | 257 | ||||
-rw-r--r-- | libs/hwui/ProgramCache.cpp | 2 | ||||
-rw-r--r-- | libs/hwui/ProgramCache.h | 232 |
10 files changed, 365 insertions, 296 deletions
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index f293cba..4da576d 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -73,6 +73,9 @@ void Caches::init() { glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW); mCurrentBuffer = meshBuffer; + mCurrentPositionPointer = this; + mCurrentTexCoordsPointer = this; + mRegionMesh = NULL; blend = false; @@ -218,24 +221,51 @@ 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; +} + +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; +} + TextureVertex* Caches::getRegionMesh() { // Create the mesh, 2 triangles and 4 vertices per rectangle in the region if (!mRegionMesh) { diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index 5e58a9e..7ca198a 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -91,15 +91,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 +138,36 @@ 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(); + + /** + * 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(); /** * Returns the mesh used to draw regions. Calling this method will @@ -203,6 +213,17 @@ public: ResourceCache resourceCache; private: + GLuint mCurrentBuffer; + void* mCurrentPositionPointer; + void* mCurrentTexCoordsPointer; + + // 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 6e80d15..f04ea6f 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -325,8 +325,6 @@ FontRenderer::FontRenderer() { mTextTexture = NULL; mIndexBufferID = 0; - mPositionAttrSlot = -1; - mTexcoordAttrSlot = -1; mCacheWidth = DEFAULT_TEXT_CACHE_WIDTH; mCacheHeight = DEFAULT_TEXT_CACHE_HEIGHT; @@ -599,12 +597,6 @@ void FontRenderer::checkTextureUpdate() { void FontRenderer::issueDrawCommand() { checkTextureUpdate(); - float* vtx = mTextMeshPtr; - float* tex = vtx + 2; - - glVertexAttribPointer(mPositionAttrSlot, 2, GL_FLOAT, GL_FALSE, 16, vtx); - glVertexAttribPointer(mTexcoordAttrSlot, 2, GL_FLOAT, GL_FALSE, 16, tex); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferID); glDrawElements(GL_TRIANGLES, mCurrentQuadIndex * 6, GL_UNSIGNED_SHORT, NULL); @@ -760,11 +752,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; diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h index 71695a8..f945873 100644 --- a/libs/hwui/FontRenderer.h +++ b/libs/hwui/FontRenderer.h @@ -178,9 +178,13 @@ public: mGammaTable = gammaTable; } - void setAttributeBindingSlots(int positionSlot, int texCoordSlot) { - mPositionAttrSlot = positionSlot; - mTexcoordAttrSlot = texCoordSlot; + inline float* getMeshBuffer() { + checkInit(); + return mTextMeshPtr; + } + + inline int getMeshTexCoordsOffset() const { + return 2; } void setFont(SkPaint* paint, uint32_t fontId, float fontSize); @@ -309,9 +313,6 @@ protected: uint32_t mIndexBufferID; - int32_t mPositionAttrSlot; - int32_t mTexcoordAttrSlot; - const Rect* mClip; Rect* mBounds; bool mDrawn; diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 6e2f1c3..fcac053 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -199,13 +199,13 @@ void OpenGLRenderer::interrupt() { } } mCaches.unbindMeshBuffer(); + mCaches.resetVertexPointers(); } 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); @@ -1201,16 +1201,15 @@ 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); } void OpenGLRenderer::setupDrawTexture(GLuint texture) { bindTexture(texture); glUniform1i(mCaches.currentProgram->getUniform("sampler"), mTextureUnit++); - mTexCoordsSlot = mCaches.currentProgram->getAttrib("texCoords"); + mTexCoordsSlot = mCaches.currentProgram->texCoords; glEnableVertexAttribArray(mTexCoordsSlot); } @@ -1218,7 +1217,7 @@ void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) { bindExternalTexture(texture); glUniform1i(mCaches.currentProgram->getUniform("sampler"), mTextureUnit++); - mTexCoordsSlot = mCaches.currentProgram->getAttrib("texCoords"); + mTexCoordsSlot = mCaches.currentProgram->texCoords; glEnableVertexAttribArray(mTexCoordsSlot); } @@ -1232,23 +1231,23 @@ 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); + mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, vertices); if (mTexCoordsSlot >= 0) { - glVertexAttribPointer(mTexCoordsSlot, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords); + mCaches.bindTexCoordsVertexPointer(force, mTexCoordsSlot, 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); } /** @@ -1264,10 +1263,10 @@ 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(); int widthSlot = mCaches.currentProgram->getAttrib("vtxWidth"); glEnableVertexAttribArray(widthSlot); @@ -2186,12 +2185,14 @@ 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); + float* buffer = fontRenderer.getMeshBuffer(); + int offset = fontRenderer.getMeshTexCoordsOffset(); + + bool force = mCaches.unbindMeshBuffer(); + mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, buffer); + mCaches.bindTexCoordsVertexPointer(force, mTexCoordsSlot, buffer + offset); + if (fontRenderer.renderText(paint, clip, text, 0, bytesCount, count, x, y, hasActiveLayer ? &bounds : NULL)) { #if RENDER_LAYERS_AS_REGIONS @@ -2205,7 +2206,7 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords")); + glDisableVertexAttribArray(mCaches.currentProgram->texCoords); drawTextDecorations(text, bytesCount, length, oldX, oldY, paint); } 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 cb2a5fd..cbea843 100644 --- a/libs/hwui/Program.cpp +++ b/libs/hwui/Program.cpp @@ -26,7 +26,7 @@ namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// // TODO: Program instance should be created from a factory method -Program::Program(const char* vertex, const char* fragment) { +Program::Program(const ProgramDescription& description, const char* vertex, const char* fragment) { mInitialized = false; mHasColorUniform = false; mUse = false; @@ -43,6 +43,12 @@ Program::Program(const char* vertex, const char* fragment) { glAttachShader(mProgramId, mFragmentShader); position = bindAttrib("position", kBindingPosition); + if (description.hasTexture || description.hasExternalTexture) { + texCoords = bindAttrib("texCoords", kBindingTexCoords); + } else { + texCoords = -1; + } + glLinkProgram(mProgramId); GLint status; diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h index 9e59621..559c717 100644 --- a/libs/hwui/Program.h +++ b/libs/hwui/Program.h @@ -17,16 +17,264 @@ #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. @@ -42,7 +290,7 @@ public: * 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(); /** @@ -99,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; 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 441db8c..e3ed79e 100644 --- a/libs/hwui/ProgramCache.h +++ b/libs/hwui/ProgramCache.h @@ -23,8 +23,6 @@ #include <GLES2/gl2.h> -#include <SkXfermode.h> - #include "Debug.h" #include "Program.h" #include "Properties.h" @@ -43,241 +41,11 @@ namespace uirenderer { #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; - /////////////////////////////////////////////////////////////////////////////// // 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. */ |