summaryrefslogtreecommitdiffstats
path: root/libs/hwui/OpenGLRenderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui/OpenGLRenderer.cpp')
-rw-r--r--libs/hwui/OpenGLRenderer.cpp463
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);