diff options
Diffstat (limited to 'libs/hwui/OpenGLRenderer.cpp')
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 463 |
1 files changed, 297 insertions, 166 deletions
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 5089c5c..afae70f 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -47,6 +47,8 @@ namespace uirenderer { // TODO: This should be set in properties #define ALPHA_THRESHOLD (0x7f / PANEL_BIT_DEPTH) +#define FILTER(paint) (paint && paint->isFilterBitmap() ? GL_LINEAR : GL_NEAREST) + /////////////////////////////////////////////////////////////////////////////// // Globals /////////////////////////////////////////////////////////////////////////////// @@ -101,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 /////////////////////////////////////////////////////////////////////////////// @@ -115,6 +111,7 @@ OpenGLRenderer::OpenGLRenderer(): mCaches(Caches::getInstance()) { mShader = NULL; mColorFilter = NULL; mHasShadow = false; + mHasDrawFilter = false; memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices)); @@ -127,12 +124,26 @@ OpenGLRenderer::~OpenGLRenderer() { } /////////////////////////////////////////////////////////////////////////////// +// Debug +/////////////////////////////////////////////////////////////////////////////// + +void OpenGLRenderer::startMark(const char* name) const { + mCaches.startMark(0, name); +} + +void OpenGLRenderer::endMark() const { + mCaches.endMark(); +} + +/////////////////////////////////////////////////////////////////////////////// // Setup /////////////////////////////////////////////////////////////////////////////// +uint32_t OpenGLRenderer::getStencilSize() { + return STENCIL_BUFFER_SIZE; +} + 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; @@ -141,7 +152,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) { @@ -154,17 +169,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); + mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top); - 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); } } @@ -198,20 +211,23 @@ 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); + mCaches.resetScissor(); dirtyClip(); - glDisable(GL_DITHER); - + mCaches.activeTexture(0); glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); mCaches.blend = true; glEnable(GL_BLEND); @@ -451,7 +467,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; @@ -552,9 +568,8 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> sna #endif // 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, + mCaches.setScissor(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(); @@ -594,7 +609,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 @@ -613,6 +628,11 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { } if (fboLayer) { + // Note: No need to use glDiscardFramebufferEXT() since we never + // create/compose layers that are not on screen with this + // code path + // See LayerRenderer::destroyLayer(Layer*) + // Detach the texture from the FBO glBindFramebuffer(GL_FRAMEBUFFER, current->fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); @@ -665,10 +685,10 @@ void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) { const float x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f); const float y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f); - layer->setFilter(GL_NEAREST, GL_NEAREST); + layer->setFilter(GL_NEAREST); setupDrawModelView(x, y, x + rect.getWidth(), y + rect.getHeight(), true); } else { - layer->setFilter(GL_LINEAR, GL_LINEAR); + layer->setFilter(GL_LINEAR); setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom); } setupDrawTextureTransformUniforms(layer->getTexTransform()); @@ -702,9 +722,9 @@ void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f); } - layer->setFilter(GL_NEAREST, GL_NEAREST, true); + layer->setFilter(GL_NEAREST, true); } else { - layer->setFilter(GL_LINEAR, GL_LINEAR, true); + layer->setFilter(GL_LINEAR, true); } drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(), @@ -734,7 +754,7 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { // TODO: See LayerRenderer.cpp::generateMesh() for important // information about this implementation - if (!layer->region.isEmpty()) { + if (CC_LIKELY(!layer->region.isEmpty())) { size_t count; const android::Rect* rects = layer->region.getArray(&count); @@ -760,13 +780,13 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { const float x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f); const float y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f); - layer->setFilter(GL_NEAREST, GL_NEAREST); + layer->setFilter(GL_NEAREST); setupDrawModelViewTranslate(x, y, x + rect.getWidth(), y + rect.getHeight(), true); } else { - layer->setFilter(GL_LINEAR, GL_LINEAR); + 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]; @@ -795,7 +815,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 @@ -904,10 +923,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); @@ -941,7 +958,11 @@ void OpenGLRenderer::skew(float sx, float sy) { } void OpenGLRenderer::setMatrix(SkMatrix* matrix) { - mSnapshot->transform->load(*matrix); + if (matrix) { + mSnapshot->transform->load(*matrix); + } else { + mSnapshot->transform->loadIdentity(); + } } void OpenGLRenderer::getMatrix(SkMatrix* matrix) { @@ -962,7 +983,10 @@ void OpenGLRenderer::concatMatrix(SkMatrix* matrix) { void OpenGLRenderer::setScissorFromClip() { Rect clip(*mSnapshot->clipRect); clip.snapToPixelBoundaries(); - glScissor(clip.left, mSnapshot->height - clip.bottom, clip.getWidth(), clip.getHeight()); + + mCaches.setScissor(clip.left, mSnapshot->height - clip.bottom, + clip.getWidth(), clip.getHeight()); + mDirtyClip = false; } @@ -1008,7 +1032,6 @@ void OpenGLRenderer::setupDraw(bool clear) { mColorA = mColorR = mColorG = mColorB = 0.0f; mTextureUnit = 0; mTrackDirtyRegions = true; - mTexCoordsSlot = -1; } void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) { @@ -1020,6 +1043,10 @@ void OpenGLRenderer::setupDrawWithExternalTexture() { mDescription.hasExternalTexture = true; } +void OpenGLRenderer::setupDrawNoTexture() { + mCaches.disbaleTexCoordsVertexArray(); +} + void OpenGLRenderer::setupDrawAALine() { mDescription.isAA = true; } @@ -1194,25 +1221,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() { @@ -1225,22 +1248,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(); } /** @@ -1256,24 +1291,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); } /////////////////////////////////////////////////////////////////////////////// @@ -1316,6 +1356,8 @@ void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, Sk y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f); ignoreTransform = true; filter = GL_NEAREST; + } else { + filter = FILTER(paint); } setupDraw(); @@ -1330,8 +1372,8 @@ void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, Sk setupDrawModelView(x, y, x + texture->width, y + texture->height, ignoreTransform); setupDrawTexture(texture->id); - texture->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); - texture->setFilter(filter, filter); + texture->setWrap(GL_CLAMP_TO_EDGE); + texture->setFilter(filter); setupDrawPureColorUniforms(); setupDrawColorFilterUniforms(); @@ -1351,12 +1393,12 @@ 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); - if (bitmap->getConfig() == SkBitmap::kA8_Config) { + if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) { drawAlphaBitmap(texture, left, top, paint); } else { drawTextureRect(left, top, right, bottom, texture, paint); @@ -1372,7 +1414,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); @@ -1392,13 +1434,13 @@ 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); - texture->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, true); - texture->setFilter(GL_LINEAR, GL_LINEAR, true); + texture->setWrap(GL_CLAMP_TO_EDGE, true); + texture->setFilter(FILTER(paint), true); int alpha; SkXfermode::Mode mode; @@ -1412,9 +1454,9 @@ void OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHei float bottom = FLT_MIN; #if RENDER_LAYERS_AS_REGIONS - bool hasActiveLayer = hasLayer(); + const bool hasActiveLayer = hasLayer(); #else - bool hasActiveLayer = false; + const bool hasActiveLayer = false; #endif // TODO: Support the colors array @@ -1477,11 +1519,10 @@ 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); - texture->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, true); const float width = texture->width; const float height = texture->height; @@ -1498,24 +1539,25 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); - if (mSnapshot->transform->isPureTranslate()) { + texture->setWrap(GL_CLAMP_TO_EDGE, true); + + if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) { const float x = (int) floorf(dstLeft + mSnapshot->transform->getTranslateX() + 0.5f); const float y = (int) floorf(dstTop + mSnapshot->transform->getTranslateY() + 0.5f); GLenum filter = GL_NEAREST; // Enable linear filtering if the source rectangle is scaled if (srcRight - srcLeft != dstRight - dstLeft || srcBottom - srcTop != dstBottom - dstTop) { - filter = GL_LINEAR; + filter = FILTER(paint); } - texture->setFilter(filter, filter, true); + texture->setFilter(filter, true); drawTextureMesh(x, y, x + (dstRight - dstLeft), y + (dstBottom - dstTop), texture->id, alpha / 255.0f, mode, texture->blend, &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, false, true); } else { - texture->setFilter(GL_LINEAR, GL_LINEAR, true); - + texture->setFilter(FILTER(paint), true); drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom, texture->id, alpha / 255.0f, mode, texture->blend, &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount); @@ -1531,12 +1573,12 @@ 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); - texture->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, true); - texture->setFilter(GL_LINEAR, GL_LINEAR, true); + texture->setWrap(GL_CLAMP_TO_EDGE, true); + texture->setFilter(GL_LINEAR, true); int alpha; SkXfermode::Mode mode; @@ -1545,7 +1587,7 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int const Patch* mesh = mCaches.patchCache.get(bitmap->width(), bitmap->height(), right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors); - if (mesh && mesh->verticesCount > 0) { + if (CC_LIKELY(mesh && mesh->verticesCount > 0)) { const bool pureTranslate = mSnapshot->transform->isPureTranslate(); #if RENDER_LAYERS_AS_REGIONS // Mark the current layer dirty where we are going to draw the patch @@ -1555,7 +1597,7 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int const size_t count = mesh->quads.size(); for (size_t i = 0; i < count; i++) { const Rect& bounds = mesh->quads.itemAt(i); - if (pureTranslate) { + if (CC_LIKELY(pureTranslate)) { const float x = (int) floorf(bounds.left + offsetX + 0.5f); const float y = (int) floorf(bounds.top + offsetY + 0.5f); dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight()); @@ -1567,7 +1609,7 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int } #endif - if (pureTranslate) { + if (CC_LIKELY(pureTranslate)) { const float x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f); const float y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f); @@ -1595,7 +1637,7 @@ void OpenGLRenderer::drawAARect(float left, float top, float right, float bottom float inverseScaleX = 1.0f; float inverseScaleY = 1.0f; // The quad that we use needs to account for scaling. - if (!mSnapshot->transform->isPureTranslate()) { + if (CC_UNLIKELY(!mSnapshot->transform->isPureTranslate())) { Matrix4 *mat = mSnapshot->transform; float m00 = mat->data[Matrix4::kScaleX]; float m01 = mat->data[Matrix4::kSkewY]; @@ -1610,6 +1652,7 @@ void OpenGLRenderer::drawAARect(float left, float top, float right, float bottom } setupDraw(); + setupDrawNoTexture(); setupDrawAALine(); setupDrawColor(color); setupDrawColorFilter(); @@ -1700,7 +1743,7 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { // The quad that we use for AA and hairlines needs to account for scaling. For hairlines // the line on the screen should always be one pixel wide regardless of scale. For // AA lines, we only want one pixel of translucent boundary around the quad. - if (!mSnapshot->transform->isPureTranslate()) { + if (CC_UNLIKELY(!mSnapshot->transform->isPureTranslate())) { Matrix4 *mat = mSnapshot->transform; float m00 = mat->data[Matrix4::kScaleX]; float m01 = mat->data[Matrix4::kSkewY]; @@ -1708,8 +1751,8 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { float m10 = mat->data[Matrix4::kSkewX]; float m11 = mat->data[Matrix4::kScaleX]; float m12 = mat->data[6]; - float scaleX = sqrt(m00*m00 + m01*m01); - float scaleY = sqrt(m10*m10 + m11*m11); + float scaleX = sqrtf(m00 * m00 + m01 * m01); + float scaleY = sqrtf(m10 * m10 + m11 * m11); inverseScaleX = (scaleX != 0) ? (inverseScaleX / scaleX) : 0; inverseScaleY = (scaleY != 0) ? (inverseScaleY / scaleY) : 0; if (inverseScaleX != 1.0f || inverseScaleY != 1.0f) { @@ -1720,17 +1763,14 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { getAlphaAndMode(paint, &alpha, &mode); setupDraw(); + setupDrawNoTexture(); if (isAA) { setupDrawAALine(); } setupDrawColor(paint->getColor(), alpha); setupDrawColorFilter(); setupDrawShader(); - if (isAA) { - setupDrawBlending(true, mode); - } else { - setupDrawBlending(mode); - } + setupDrawBlending(isAA, mode); setupDrawProgram(); setupDrawModelViewIdentity(true); setupDrawColorUniforms(); @@ -1748,7 +1788,7 @@ void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { Vertex* vertices = &lines[0]; AAVertex wLines[verticesCount]; AAVertex* aaVertices = &wLines[0]; - if (!isAA) { + if (CC_UNLIKELY(!isAA)) { setupDrawVertices(vertices); } else { void* widthCoords = ((GLbyte*) aaVertices) + gVertexAAWidthOffset; @@ -1929,6 +1969,7 @@ void OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) { TextureVertex* vertex = &pointsData[0]; setupDraw(); + setupDrawNoTexture(); setupDrawPoint(strokeWidth); setupDrawColor(paint->getColor(), alpha); setupDrawColorFilter(); @@ -1979,7 +2020,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); @@ -1988,7 +2029,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); } @@ -1996,7 +2037,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); } @@ -2010,7 +2051,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); @@ -2020,7 +2061,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); } @@ -2054,46 +2095,117 @@ void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, } } -void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, - float x, float y, SkPaint* paint) { - if (text == NULL || count == 0) { +void OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count, + const float* positions, SkPaint* paint) { + if (text == NULL || count == 0 || mSnapshot->isIgnored() || + (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) { + return; + } + + // NOTE: Skia does not support perspective transform on drawPosText yet + if (!mSnapshot->transform->isSimple()) { return; } - if (mSnapshot->isIgnored()) return; - // TODO: We should probably make a copy of the paint instead of modifying - // it; modifying the paint will change its generationID the first - // time, which might impact caches. More investigation needed to - // see if it matters. - // If we make a copy, then drawTextDecorations() should *not* make - // its own copy as it does right now. - paint->setAntiAlias(true); -#if RENDER_TEXT_AS_GLYPHS - paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); + float x = 0.0f; + float y = 0.0f; + const bool pureTranslate = mSnapshot->transform->isPureTranslate(); + if (pureTranslate) { + x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f); + y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f); + } + + FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(paint); + fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()), + paint->getTextSize()); + + int alpha; + SkXfermode::Mode mode; + getAlphaAndMode(paint, &alpha, &mode); + + // Pick the appropriate texture filtering + bool linearFilter = mSnapshot->transform->changesBounds(); + if (pureTranslate && !linearFilter) { + linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f; + } + + mCaches.activeTexture(0); + setupDraw(); + setupDrawDirtyRegionsDisabled(); + setupDrawWithTexture(true); + setupDrawAlpha8Color(paint->getColor(), alpha); + setupDrawColorFilter(); + setupDrawShader(); + setupDrawBlending(true, mode); + setupDrawProgram(); + setupDrawModelView(x, y, x, y, pureTranslate, true); + setupDrawTexture(fontRenderer.getTexture(linearFilter)); + setupDrawPureColorUniforms(); + setupDrawColorFilterUniforms(); + setupDrawShaderUniforms(pureTranslate); + + const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip(); + Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); + +#if RENDER_LAYERS_AS_REGIONS + const bool hasActiveLayer = hasLayer(); +#else + const bool hasActiveLayer = false; #endif - float length = -1.0f; + if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y, + positions, hasActiveLayer ? &bounds : NULL)) { +#if RENDER_LAYERS_AS_REGIONS + if (hasActiveLayer) { + if (!pureTranslate) { + mSnapshot->transform->mapRect(bounds); + } + dirtyLayerUnchecked(bounds, getRegion()); + } +#endif + } +} + +void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, + float x, float y, SkPaint* paint, float length) { + if (text == NULL || count == 0 || mSnapshot->isIgnored() || + (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) { + return; + } + switch (paint->getTextAlign()) { case SkPaint::kCenter_Align: - length = paint->measureText(text, bytesCount); + if (length < 0.0f) length = paint->measureText(text, bytesCount); x -= length / 2.0f; break; case SkPaint::kRight_Align: - length = paint->measureText(text, bytesCount); + if (length < 0.0f) length = paint->measureText(text, bytesCount); x -= length; break; default: break; } + SkPaint::FontMetrics metrics; + paint->getFontMetrics(&metrics, 0.0f); + // If no length was specified, just perform the hit test on the Y axis + if (quickReject(x, y + metrics.fTop, + x + (length >= 0.0f ? length : INT_MAX / 2), y + metrics.fBottom)) { + return; + } + const float oldX = x; const float oldY = y; const bool pureTranslate = mSnapshot->transform->isPureTranslate(); - if (pureTranslate) { + if (CC_LIKELY(pureTranslate)) { x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f); y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f); } +#if DEBUG_GLYPHS + ALOGD("OpenGLRenderer drawText() with FontID=%d", SkTypeface::UniqueID(paint->getTypeface())); +#endif + FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(paint); fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()), paint->getTextSize()); @@ -2102,7 +2214,9 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); - if (mHasShadow) { + if (CC_UNLIKELY(mHasShadow)) { + mCaches.activeTexture(0); + mCaches.dropShadowCache.setFontRenderer(fontRenderer); const ShadowTexture* shadow = mCaches.dropShadowCache.get( paint, text, bytesCount, count, mShadowRadius); @@ -2117,7 +2231,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); @@ -2133,12 +2246,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) { - return; } // Pick the appropriate texture filtering @@ -2147,7 +2254,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); @@ -2166,16 +2273,11 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); #if RENDER_LAYERS_AS_REGIONS - bool hasActiveLayer = hasLayer(); + const bool hasActiveLayer = hasLayer(); #else - bool hasActiveLayer = false; + const 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 @@ -2188,16 +2290,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; @@ -2214,7 +2313,7 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) { return; } - glActiveTexture(gTextureUnits[0]); + mCaches.activeTexture(0); int alpha; SkXfermode::Mode mode; @@ -2223,7 +2322,7 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) { layer->setAlpha(alpha, mode); #if RENDER_LAYERS_AS_REGIONS - if (!layer->region.isEmpty()) { + if (CC_LIKELY(!layer->region.isEmpty())) { if (layer->region.isRect()) { composeLayerRect(layer, layer->regionRect); } else if (layer->mesh) { @@ -2239,15 +2338,15 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) { setupDrawPureColorUniforms(); setupDrawColorFilterUniforms(); setupDrawTexture(layer->getTexture()); - if (mSnapshot->transform->isPureTranslate()) { + if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) { x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f); y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f); - layer->setFilter(GL_NEAREST, GL_NEAREST); + layer->setFilter(GL_NEAREST); setupDrawModelViewTranslate(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(), true); } else { - layer->setFilter(GL_LINEAR, GL_LINEAR); + layer->setFilter(GL_LINEAR); setupDrawModelViewTranslate(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight()); } @@ -2313,6 +2412,31 @@ void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) { } /////////////////////////////////////////////////////////////////////////////// +// Draw filters +/////////////////////////////////////////////////////////////////////////////// + +void OpenGLRenderer::resetPaintFilter() { + mHasDrawFilter = false; +} + +void OpenGLRenderer::setupPaintFilter(int clearBits, int setBits) { + mHasDrawFilter = true; + mPaintFilterClearBits = clearBits & SkPaint::kAllFlags; + mPaintFilterSetBits = setBits & SkPaint::kAllFlags; +} + +SkPaint* OpenGLRenderer::filterPaint(SkPaint* paint) { + if (!mHasDrawFilter || !paint) return paint; + + uint32_t flags = paint->getFlags(); + + mFilteredPaint = *paint; + mFilteredPaint.setFlags((flags & ~mPaintFilterClearBits) | mPaintFilterSetBits); + + return &mFilteredPaint; +} + +/////////////////////////////////////////////////////////////////////////////// // Drawing implementation /////////////////////////////////////////////////////////////////////////////// @@ -2374,7 +2498,7 @@ void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float break; } - if (underlineWidth > 0.0f) { + if (CC_LIKELY(underlineWidth > 0.0f)) { const float textSize = paintCopy.getTextSize(); const float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f); @@ -2420,6 +2544,7 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot } setupDraw(); + setupDrawNoTexture(); setupDrawColor(color); setupDrawShader(); setupDrawColorFilter(); @@ -2440,18 +2565,18 @@ void OpenGLRenderer::drawTextureRect(float left, float top, float right, float b SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); - texture->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, true); + texture->setWrap(GL_CLAMP_TO_EDGE, true); - if (mSnapshot->transform->isPureTranslate()) { + if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) { const float x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f); const float y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f); - texture->setFilter(GL_NEAREST, GL_NEAREST, true); + texture->setFilter(GL_NEAREST, true); drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id, alpha / 255.0f, mode, texture->blend, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount, false, true); } else { - texture->setFilter(GL_LINEAR, GL_LINEAR, true); + texture->setFilter(FILTER(paint), true); drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode, texture->blend, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount); @@ -2497,32 +2622,38 @@ void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, ProgramDescription& description, bool swapSrcDst) { blend = blend || mode != SkXfermode::kSrcOver_Mode; if (blend) { - if (mode <= SkXfermode::kScreen_Mode) { - if (!mCaches.blend) { - glEnable(GL_BLEND); - } - - GLenum sourceMode = swapSrcDst ? gBlendsSwap[mode].src : gBlends[mode].src; - GLenum destMode = swapSrcDst ? gBlendsSwap[mode].dst : gBlends[mode].dst; - - if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) { - glBlendFunc(sourceMode, destMode); - mCaches.lastSrcMode = sourceMode; - mCaches.lastDstMode = destMode; - } - } else { - // These blend modes are not supported by OpenGL directly and have - // to be implemented using shaders. Since the shader will perform - // the blending, turn blending off here - if (mCaches.extensions.hasFramebufferFetch()) { + // These blend modes are not supported by OpenGL directly and have + // to be implemented using shaders. Since the shader will perform + // the blending, turn blending off here + // If the blend mode cannot be implemented using shaders, fall + // back to the default SrcOver blend mode instead + if CC_UNLIKELY((mode > SkXfermode::kScreen_Mode)) { + if (CC_UNLIKELY(mCaches.extensions.hasFramebufferFetch())) { description.framebufferMode = mode; description.swapSrcDst = swapSrcDst; - } - if (mCaches.blend) { - glDisable(GL_BLEND); + if (mCaches.blend) { + glDisable(GL_BLEND); + mCaches.blend = false; + } + + return; + } else { + mode = SkXfermode::kSrcOver_Mode; } - blend = false; + } + + if (!mCaches.blend) { + glEnable(GL_BLEND); + } + + GLenum sourceMode = swapSrcDst ? gBlendsSwap[mode].src : gBlends[mode].src; + GLenum destMode = swapSrcDst ? gBlendsSwap[mode].dst : gBlends[mode].dst; + + if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) { + glBlendFunc(sourceMode, destMode); + mCaches.lastSrcMode = sourceMode; + mCaches.lastDstMode = destMode; } } else if (mCaches.blend) { glDisable(GL_BLEND); |