OpenGLRenderer.cpp revision e5ebcb0107a939395e03592fd44c746cd09e311d
1e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy/*
2e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * Copyright (C) 2010 The Android Open Source Project
3e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy *
4e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * Licensed under the Apache License, Version 2.0 (the "License");
5e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * you may not use this file except in compliance with the License.
6e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * You may obtain a copy of the License at
7e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy *
8e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy *      http://www.apache.org/licenses/LICENSE-2.0
9e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy *
10e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * Unless required by applicable law or agreed to in writing, software
11e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * distributed under the License is distributed on an "AS IS" BASIS,
12e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * See the License for the specific language governing permissions and
14e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy * limitations under the License.
15e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy */
16e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1785bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy#define LOG_TAG "OpenGLRenderer"
18e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
19e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy#include <stdlib.h>
20e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy#include <stdint.h>
21e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy#include <sys/types.h>
22e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
23bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy#include <SkCanvas.h>
24694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy#include <SkTypeface.h>
255cbbce535744b89df5ecea95de21ee3733298260Romain Guy
265cbbce535744b89df5ecea95de21ee3733298260Romain Guy#include <utils/Log.h>
27e2d345ea67e2960b37bfdc0fc8626d1bfa747404Romain Guy#include <utils/StopWatch.h>
2885bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy
2985bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy#include "OpenGLRenderer.h"
30e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
31e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guynamespace android {
329d5316e3f56d138504565ff311145ac01621dff4Romain Guynamespace uirenderer {
339d5316e3f56d138504565ff311145ac01621dff4Romain Guy
349d5316e3f56d138504565ff311145ac01621dff4Romain Guy///////////////////////////////////////////////////////////////////////////////
359d5316e3f56d138504565ff311145ac01621dff4Romain Guy// Defines
369d5316e3f56d138504565ff311145ac01621dff4Romain Guy///////////////////////////////////////////////////////////////////////////////
379d5316e3f56d138504565ff311145ac01621dff4Romain Guy
3806f96e2652e4855b6520ad9dd70583677605b79aRomain Guy#define REQUIRED_TEXTURE_UNITS_COUNT 3
3906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
40dda570201ac851dd85af3861f7e575721d3345daRomain Guy// Generates simple and textured vertices
41bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy#define FV(x, y, u, v) { { x, y }, { u, v } }
429d5316e3f56d138504565ff311145ac01621dff4Romain Guy
43759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy#define RAD_TO_DEG (180.0f / 3.14159265f)
44759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy#define MIN_ANGLE 0.001f
45759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy
46dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy// TODO: This should be set in properties
47dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy#define ALPHA_THRESHOLD (0x7f / PANEL_BIT_DEPTH)
48dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy
499d5316e3f56d138504565ff311145ac01621dff4Romain Guy///////////////////////////////////////////////////////////////////////////////
509d5316e3f56d138504565ff311145ac01621dff4Romain Guy// Globals
519d5316e3f56d138504565ff311145ac01621dff4Romain Guy///////////////////////////////////////////////////////////////////////////////
529d5316e3f56d138504565ff311145ac01621dff4Romain Guy
53026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy// This array is never used directly but used as a memcpy source in the
54026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy// OpenGLRenderer constructor
55ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guystatic const TextureVertex gMeshVertices[] = {
56c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy        FV(0.0f, 0.0f, 0.0f, 0.0f),
57c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy        FV(1.0f, 0.0f, 1.0f, 0.0f),
58c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy        FV(0.0f, 1.0f, 0.0f, 1.0f),
59c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy        FV(1.0f, 1.0f, 1.0f, 1.0f)
60bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy};
61ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guystatic const GLsizei gMeshStride = sizeof(TextureVertex);
62ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guystatic const GLsizei gMeshCount = 4;
63026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy
64889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy/**
65889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy * Structure mapping Skia xfermodes to OpenGL blending factors.
66889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy */
67889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guystruct Blender {
68889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy    SkXfermode::Mode mode;
69889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy    GLenum src;
70889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy    GLenum dst;
71889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy}; // struct Blender
72889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy
73026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy// In this array, the index of each Blender equals the value of the first
74026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
75026c5e16704e817cac7d9c382914c947e34f87e0Romain Guystatic const Blender gBlends[] = {
76026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy        { SkXfermode::kClear_Mode,   GL_ZERO,                 GL_ZERO },
77026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy        { SkXfermode::kSrc_Mode,     GL_ONE,                  GL_ZERO },
78026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy        { SkXfermode::kDst_Mode,     GL_ZERO,                 GL_ONE },
79026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy        { SkXfermode::kSrcOver_Mode, GL_ONE,                  GL_ONE_MINUS_SRC_ALPHA },
80026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy        { SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA,  GL_ONE },
81026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy        { SkXfermode::kSrcIn_Mode,   GL_DST_ALPHA,            GL_ZERO },
82026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy        { SkXfermode::kDstIn_Mode,   GL_ZERO,                 GL_SRC_ALPHA },
83026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy        { SkXfermode::kSrcOut_Mode,  GL_ONE_MINUS_DST_ALPHA,  GL_ZERO },
84026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy        { SkXfermode::kDstOut_Mode,  GL_ZERO,                 GL_ONE_MINUS_SRC_ALPHA },
85026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy        { SkXfermode::kSrcATop_Mode, GL_DST_ALPHA,            GL_ONE_MINUS_SRC_ALPHA },
86026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy        { SkXfermode::kDstATop_Mode, GL_ONE_MINUS_DST_ALPHA,  GL_SRC_ALPHA },
87026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy        { SkXfermode::kXor_Mode,     GL_ONE_MINUS_DST_ALPHA,  GL_ONE_MINUS_SRC_ALPHA }
88026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy};
89e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
9087a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy// This array contains the swapped version of each SkXfermode. For instance
9187a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy// this array's SrcOver blending mode is actually DstOver. You can refer to
9287a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy// createLayer() for more information on the purpose of this array.
93f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guystatic const Blender gBlendsSwap[] = {
94f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy        { SkXfermode::kClear_Mode,   GL_ZERO,                 GL_ZERO },
95f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy        { SkXfermode::kSrc_Mode,     GL_ZERO,                 GL_ONE },
96f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy        { SkXfermode::kDst_Mode,     GL_ONE,                  GL_ZERO },
97f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy        { SkXfermode::kSrcOver_Mode, GL_ONE_MINUS_DST_ALPHA,  GL_ONE },
98f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy        { SkXfermode::kDstOver_Mode, GL_ONE,                  GL_ONE_MINUS_SRC_ALPHA },
99f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy        { SkXfermode::kSrcIn_Mode,   GL_ZERO,                 GL_SRC_ALPHA },
100f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy        { SkXfermode::kDstIn_Mode,   GL_DST_ALPHA,            GL_ZERO },
101f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy        { SkXfermode::kSrcOut_Mode,  GL_ZERO,                 GL_ONE_MINUS_SRC_ALPHA },
102f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy        { SkXfermode::kDstOut_Mode,  GL_ONE_MINUS_DST_ALPHA,  GL_ZERO },
103f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy        { SkXfermode::kSrcATop_Mode, GL_ONE_MINUS_DST_ALPHA,  GL_SRC_ALPHA },
104f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy        { SkXfermode::kDstATop_Mode, GL_DST_ALPHA,            GL_ONE_MINUS_SRC_ALPHA },
105f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy        { SkXfermode::kXor_Mode,     GL_ONE_MINUS_DST_ALPHA,  GL_ONE_MINUS_SRC_ALPHA }
106f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy};
107f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy
108889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guystatic const GLenum gTextureUnits[] = {
10906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        GL_TEXTURE0,
11006f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        GL_TEXTURE1,
11106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        GL_TEXTURE2
112d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy};
113d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy
114f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy///////////////////////////////////////////////////////////////////////////////
115f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy// Constructors/destructor
116f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy///////////////////////////////////////////////////////////////////////////////
117f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
118fb8b763f762ae21923c58d64caa729b012f40e05Romain GuyOpenGLRenderer::OpenGLRenderer(): mCaches(Caches::getInstance()) {
11906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    mShader = NULL;
120db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    mColorFilter = NULL;
1211e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    mHasShadow = false;
122026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy
123ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy    memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
124ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy
125ae5575b3421c8fbe590ab046d7d5f2b36ecfd821Romain Guy    mFirstSnapshot = new Snapshot;
126ae5575b3421c8fbe590ab046d7d5f2b36ecfd821Romain Guy
127ae5575b3421c8fbe590ab046d7d5f2b36ecfd821Romain Guy    GLint maxTextureUnits;
128ae5575b3421c8fbe590ab046d7d5f2b36ecfd821Romain Guy    glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
129ae5575b3421c8fbe590ab046d7d5f2b36ecfd821Romain Guy    if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) {
130889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy        LOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT);
131889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy    }
132b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy
133b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
134e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy}
135e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
13685bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain GuyOpenGLRenderer::~OpenGLRenderer() {
13729d8997bd43b7c4ad37fc3d6f91eaafa74913c88Romain Guy    // The context has already been destroyed at this point, do not call
13829d8997bd43b7c4ad37fc3d6f91eaafa74913c88Romain Guy    // GL APIs. All GL state should be kept in Caches.h
139e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy}
140e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
141f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy///////////////////////////////////////////////////////////////////////////////
142f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy// Setup
143f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy///////////////////////////////////////////////////////////////////////////////
144f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
14585bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guyvoid OpenGLRenderer::setViewport(int width, int height) {
14608ae317c21ec3086b5017672bba87420cc38a407Romain Guy    glViewport(0, 0, width, height);
147260e102162322958cf17dbd895cd6bd30dc87e32Romain Guy    mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
148bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
149bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    mWidth = width;
150bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy    mHeight = height;
151eb99356a0548684a501766e6a524529ab93304c8Romain Guy
152eb99356a0548684a501766e6a524529ab93304c8Romain Guy    mFirstSnapshot->height = height;
153eb99356a0548684a501766e6a524529ab93304c8Romain Guy    mFirstSnapshot->viewport.set(0, 0, width, height);
154e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy}
155e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
1566b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guyvoid OpenGLRenderer::prepare(bool opaque) {
1578aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    mSnapshot = new Snapshot(mFirstSnapshot,
1588aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
1598fb954263dd2f918ad339045cc6d82e346515599Romain Guy    mSaveCount = 1;
160f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
161fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    glViewport(0, 0, mWidth, mHeight);
162fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy
163d90f23e24a4d1768d5a7ed0e7072e67af6330a45Romain Guy    glDisable(GL_DITHER);
16408ae317c21ec3086b5017672bba87420cc38a407Romain Guy    glDisable(GL_SCISSOR_TEST);
165bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
1666b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy    if (!opaque) {
1676b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1686b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy        glClear(GL_COLOR_BUFFER_BIT);
1696b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy    }
170bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
17108ae317c21ec3086b5017672bba87420cc38a407Romain Guy    glEnable(GL_SCISSOR_TEST);
172c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy    glScissor(0, 0, mWidth, mHeight);
173f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
174b82da65cb1601be504241f36778395cd6cb9f87bRomain Guy    mSnapshot->setClip(0.0f, 0.0f, mWidth, mHeight);
175bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy}
176bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
177b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guyvoid OpenGLRenderer::finish() {
178b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy#if DEBUG_OPENGL
179b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy    GLenum status = GL_NO_ERROR;
180b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy    while ((status = glGetError()) != GL_NO_ERROR) {
181b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy        LOGD("GL error from OpenGLRenderer: 0x%x", status);
182b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy    }
183b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy#endif
184b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy}
185b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy
186da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guyvoid OpenGLRenderer::acquireContext() {
187da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    if (mCaches.currentProgram) {
188da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy        if (mCaches.currentProgram->isInUse()) {
189da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy            mCaches.currentProgram->remove();
190da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy            mCaches.currentProgram = NULL;
191da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy        }
192da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    }
193da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy}
194da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy
195da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guyvoid OpenGLRenderer::releaseContext() {
196eb99356a0548684a501766e6a524529ab93304c8Romain Guy    glViewport(0, 0, mSnapshot->viewport.getWidth(), mSnapshot->viewport.getHeight());
197da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy
198da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    glEnable(GL_SCISSOR_TEST);
199da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    setScissorFromClip();
200da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy
201f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy    glDisable(GL_DITHER);
202f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy
203f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy    glBindFramebuffer(GL_FRAMEBUFFER, 0);
204f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy
205da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    if (mCaches.blend) {
206da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy        glEnable(GL_BLEND);
207da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy        glBlendFunc(mCaches.lastSrcMode, mCaches.lastDstMode);
208f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy        glBlendEquation(GL_FUNC_ADD);
209da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    } else {
210da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy        glDisable(GL_BLEND);
211da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy    }
212da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy}
213da8532c6f48b4c10b5e2ccb9e08690341efa1616Romain Guy
214f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy///////////////////////////////////////////////////////////////////////////////
215f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy// State management
216f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy///////////////////////////////////////////////////////////////////////////////
217f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
218bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guyint OpenGLRenderer::getSaveCount() const {
2197ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy    return mSaveCount;
220bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy}
221bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
222bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guyint OpenGLRenderer::save(int flags) {
2238aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    return saveSnapshot(flags);
224bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy}
225bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
226bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guyvoid OpenGLRenderer::restore() {
2272542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy    if (mSaveCount > 1) {
2282542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy        restoreSnapshot();
2297ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy    }
230bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy}
231bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
232bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guyvoid OpenGLRenderer::restoreToCount(int saveCount) {
2338fb954263dd2f918ad339045cc6d82e346515599Romain Guy    if (saveCount < 1) saveCount = 1;
234bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
2358fb954263dd2f918ad339045cc6d82e346515599Romain Guy    while (mSaveCount > saveCount) {
2362542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy        restoreSnapshot();
2377ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy    }
238bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy}
239bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
2408aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guyint OpenGLRenderer::saveSnapshot(int flags) {
2418aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    mSnapshot = new Snapshot(mSnapshot, flags);
2428fb954263dd2f918ad339045cc6d82e346515599Romain Guy    return mSaveCount++;
243bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy}
244bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
245bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guybool OpenGLRenderer::restoreSnapshot() {
2467ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy    bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet;
247bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy    bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer;
248eb99356a0548684a501766e6a524529ab93304c8Romain Guy    bool restoreOrtho = mSnapshot->flags & Snapshot::kFlagDirtyOrtho;
249bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
250bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy    sp<Snapshot> current = mSnapshot;
2517ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy    sp<Snapshot> previous = mSnapshot->previous;
252bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
253eb99356a0548684a501766e6a524529ab93304c8Romain Guy    if (restoreOrtho) {
254eb99356a0548684a501766e6a524529ab93304c8Romain Guy        Rect& r = previous->viewport;
255eb99356a0548684a501766e6a524529ab93304c8Romain Guy        glViewport(r.left, r.top, r.right, r.bottom);
256eb99356a0548684a501766e6a524529ab93304c8Romain Guy        mOrthoMatrix.load(current->orthoMatrix);
257eb99356a0548684a501766e6a524529ab93304c8Romain Guy    }
258eb99356a0548684a501766e6a524529ab93304c8Romain Guy
2598b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy    mSaveCount--;
2608b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy    mSnapshot = previous;
2618b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy
262bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy    if (restoreLayer) {
263d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy        composeLayer(current, previous);
264d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy    }
265bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
2662542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy    if (restoreClip) {
2672542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy        setScissorFromClip();
2688fb954263dd2f918ad339045cc6d82e346515599Romain Guy    }
2692542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy
2702542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy    return restoreClip;
271d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy}
2725cbbce535744b89df5ecea95de21ee3733298260Romain Guy
273f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy///////////////////////////////////////////////////////////////////////////////
274bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy// Layers
275bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy///////////////////////////////////////////////////////////////////////////////
276bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
277bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guyint OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
278bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy        const SkPaint* p, int flags) {
279eb99356a0548684a501766e6a524529ab93304c8Romain Guy    const GLuint previousFbo = mSnapshot->fbo;
280eb99356a0548684a501766e6a524529ab93304c8Romain Guy    const int count = saveSnapshot(flags);
281d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy
282d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy    int alpha = 255;
283d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy    SkXfermode::Mode mode;
284d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy
285d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy    if (p) {
286d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy        alpha = p->getAlpha();
287a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy        if (!mExtensions.hasFramebufferFetch()) {
288a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode);
289a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            if (!isMode) {
290a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy                // Assume SRC_OVER
291a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy                mode = SkXfermode::kSrcOver_Mode;
292a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            }
293a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy        } else {
294a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            mode = getXfermode(p->getXfermode());
295d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy        }
296d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy    } else {
297d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy        mode = SkXfermode::kSrcOver_Mode;
298d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy    }
299d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy
300dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy    if (!mSnapshot->previous->invisible) {
301dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy        createLayer(mSnapshot, left, top, right, bottom, alpha, mode, flags, previousFbo);
302dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy    }
303d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy
304d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy    return count;
305bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy}
306bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
307bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guyint OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom,
308bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy        int alpha, int flags) {
3098aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    if (alpha == 0xff) {
3108aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy        return saveLayer(left, top, right, bottom, NULL, flags);
3118b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy    } else {
3128aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy        SkPaint paint;
3138aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy        paint.setAlpha(alpha);
3148aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy        return saveLayer(left, top, right, bottom, &paint, flags);
3158b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy    }
316d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy}
317bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
3181c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy/**
3191c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * Layers are viewed by Skia are slightly different than layers in image editing
3201c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * programs (for instance.) When a layer is created, previously created layers
3211c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * and the frame buffer still receive every drawing command. For instance, if a
3221c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * layer is created and a shape intersecting the bounds of the layers and the
3231c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * framebuffer is draw, the shape will be drawn on both (unless the layer was
3241c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * created with the SkCanvas::kClipToLayer_SaveFlag flag.)
3251c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy *
3261c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * A way to implement layers is to create an FBO for each layer, backed by an RGBA
3271c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * texture. Unfortunately, this is inefficient as it requires every primitive to
3281c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * be drawn n + 1 times, where n is the number of active layers. In practice this
3291c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * means, for every primitive:
3301c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy *   - Switch active frame buffer
3311c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy *   - Change viewport, clip and projection matrix
3321c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy *   - Issue the drawing
3331c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy *
3341c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * Switching rendering target n + 1 times per drawn primitive is extremely costly.
3356b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy * To avoid this, layers are implemented in a different way here, at least in the
3366b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy * general case. FBOs are used, as an optimization, when the "clip to layer" flag
3376b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy * is set. When this flag is set we can redirect all drawing operations into a
3386b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy * single FBO.
3391c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy *
3401c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * This implementation relies on the frame buffer being at least RGBA 8888. When
3411c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * a layer is created, only a texture is created, not an FBO. The content of the
3421c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * frame buffer contained within the layer's bounds is copied into this texture
34387a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy * using glCopyTexImage2D(). The layer's region is then cleared(1) in the frame
3441c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * buffer and drawing continues as normal. This technique therefore treats the
3451c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * frame buffer as a scratch buffer for the layers.
3461c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy *
3471c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * To compose the layers back onto the frame buffer, each layer texture
3481c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * (containing the original frame buffer data) is drawn as a simple quad over
3491c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * the frame buffer. The trick is that the quad is set as the composition
3501c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * destination in the blending equation, and the frame buffer becomes the source
3511c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * of the composition.
3521c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy *
3531c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * Drawing layers with an alpha value requires an extra step before composition.
3541c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * An empty quad is drawn over the layer's region in the frame buffer. This quad
3551c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * is drawn with the rgba color (0,0,0,alpha). The alpha value offered by the
3561c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * quad is used to multiply the colors in the frame buffer. This is achieved by
3571c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * changing the GL blend functions for the GL_FUNC_ADD blend equation to
3581c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * GL_ZERO, GL_SRC_ALPHA.
3591c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy *
3601c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * Because glCopyTexImage2D() can be slow, an alternative implementation might
3611c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * be use to draw a single clipped layer. The implementation described above
3621c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * is correct in every case.
36387a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy *
36487a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy * (1) The frame buffer is actually not cleared right away. To allow the GPU
36587a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy *     to potentially optimize series of calls to glCopyTexImage2D, the frame
36687a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy *     buffer is left untouched until the first drawing operation. Only when
36787a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy *     something actually gets drawn are the layers regions cleared.
3681c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy */
369d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guybool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
370eb99356a0548684a501766e6a524529ab93304c8Romain Guy        float right, float bottom, int alpha, SkXfermode::Mode mode,
371eb99356a0548684a501766e6a524529ab93304c8Romain Guy        int flags, GLuint previousFbo) {
372eb99356a0548684a501766e6a524529ab93304c8Romain Guy    LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top);
373fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
374dda570201ac851dd85af3861f7e575721d3345daRomain Guy
375eb99356a0548684a501766e6a524529ab93304c8Romain Guy    const bool fboLayer = flags & SkCanvas::kClipToLayer_SaveFlag;
376eb99356a0548684a501766e6a524529ab93304c8Romain Guy
377f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy    // Window coordinates of the layer
3788aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    Rect bounds(left, top, right, bottom);
379eb99356a0548684a501766e6a524529ab93304c8Romain Guy    if (!fboLayer) {
380eb99356a0548684a501766e6a524529ab93304c8Romain Guy        mSnapshot->transform->mapRect(bounds);
381eb99356a0548684a501766e6a524529ab93304c8Romain Guy        // Layers only make sense if they are in the framebuffer's bounds
382eb99356a0548684a501766e6a524529ab93304c8Romain Guy        bounds.intersect(*mSnapshot->clipRect);
383eb99356a0548684a501766e6a524529ab93304c8Romain Guy        bounds.snapToPixelBoundaries();
384eb99356a0548684a501766e6a524529ab93304c8Romain Guy    }
385bf434114cbf55b216fdc76fc8d65a75e84c9dab5Romain Guy
386b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy    if (bounds.isEmpty() || bounds.getWidth() > mMaxTextureSize ||
387b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy            bounds.getHeight() > mMaxTextureSize) {
388dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy        snapshot->invisible = true;
389dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy    } else {
390dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy        // TODO: Should take the mode into account
391d2a1ff003b9b1212c9ab4b5f679b5b097720a359Romain Guy        snapshot->invisible = snapshot->previous->invisible ||
392d2a1ff003b9b1212c9ab4b5f679b5b097720a359Romain Guy                (alpha <= ALPHA_THRESHOLD && fboLayer);
393dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy    }
394dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy
395dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy    // Bail out if we won't draw in this snapshot
396dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy    if (snapshot->invisible) {
397b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy        return false;
398b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy    }
399dda570201ac851dd85af3861f7e575721d3345daRomain Guy
4000bb5667b4ef91fefd0500fae0186789d15d54e0eRomain Guy    glActiveTexture(GL_TEXTURE0);
4010bb5667b4ef91fefd0500fae0186789d15d54e0eRomain Guy
4028550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    Layer* layer = mCaches.layerCache.get(bounds.getWidth(), bounds.getHeight());
403f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy    if (!layer) {
404f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        return false;
405bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy    }
406bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
407dda570201ac851dd85af3861f7e575721d3345daRomain Guy    layer->mode = mode;
408f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy    layer->alpha = alpha;
4098aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    layer->layer.set(bounds);
4108550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->height),
4118550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy            bounds.getWidth() / float(layer->width), 0.0f);
412dda570201ac851dd85af3861f7e575721d3345daRomain Guy
4138fb954263dd2f918ad339045cc6d82e346515599Romain Guy    // Save the layer in the snapshot
4148fb954263dd2f918ad339045cc6d82e346515599Romain Guy    snapshot->flags |= Snapshot::kFlagIsLayer;
415dda570201ac851dd85af3861f7e575721d3345daRomain Guy    snapshot->layer = layer;
4161d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy
417eb99356a0548684a501766e6a524529ab93304c8Romain Guy    if (fboLayer) {
418eb99356a0548684a501766e6a524529ab93304c8Romain Guy        layer->fbo = mCaches.fboCache.get();
41938c85b907a478af96d71b9a5df5a2066b8475311Romain Guy
420eb99356a0548684a501766e6a524529ab93304c8Romain Guy        snapshot->flags |= Snapshot::kFlagIsFboLayer;
421eb99356a0548684a501766e6a524529ab93304c8Romain Guy        snapshot->fbo = layer->fbo;
422eb99356a0548684a501766e6a524529ab93304c8Romain Guy        snapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
423eb99356a0548684a501766e6a524529ab93304c8Romain Guy        snapshot->resetClip(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
424eb99356a0548684a501766e6a524529ab93304c8Romain Guy        snapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
425eb99356a0548684a501766e6a524529ab93304c8Romain Guy        snapshot->height = bounds.getHeight();
426eb99356a0548684a501766e6a524529ab93304c8Romain Guy        snapshot->flags |= Snapshot::kFlagDirtyOrtho;
427eb99356a0548684a501766e6a524529ab93304c8Romain Guy        snapshot->orthoMatrix.load(mOrthoMatrix);
4280bb5667b4ef91fefd0500fae0186789d15d54e0eRomain Guy
429eb99356a0548684a501766e6a524529ab93304c8Romain Guy        // Bind texture to FBO
430eb99356a0548684a501766e6a524529ab93304c8Romain Guy        glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
431eb99356a0548684a501766e6a524529ab93304c8Romain Guy        glBindTexture(GL_TEXTURE_2D, layer->texture);
432eb99356a0548684a501766e6a524529ab93304c8Romain Guy
433eb99356a0548684a501766e6a524529ab93304c8Romain Guy        // Initialize the texture if needed
434eb99356a0548684a501766e6a524529ab93304c8Romain Guy        if (layer->empty) {
435eb99356a0548684a501766e6a524529ab93304c8Romain Guy            layer->empty = false;
4368550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->width, layer->height, 0,
437eb99356a0548684a501766e6a524529ab93304c8Romain Guy                    GL_RGBA, GL_UNSIGNED_BYTE, NULL);
438eb99356a0548684a501766e6a524529ab93304c8Romain Guy        }
439eb99356a0548684a501766e6a524529ab93304c8Romain Guy
440eb99356a0548684a501766e6a524529ab93304c8Romain Guy        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
441eb99356a0548684a501766e6a524529ab93304c8Romain Guy                layer->texture, 0);
442eb99356a0548684a501766e6a524529ab93304c8Romain Guy
443e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy#if DEBUG_LAYERS
444eb99356a0548684a501766e6a524529ab93304c8Romain Guy        GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
445eb99356a0548684a501766e6a524529ab93304c8Romain Guy        if (status != GL_FRAMEBUFFER_COMPLETE) {
446eb99356a0548684a501766e6a524529ab93304c8Romain Guy            LOGE("Framebuffer incomplete (GL error code 0x%x)", status);
447eb99356a0548684a501766e6a524529ab93304c8Romain Guy
448eb99356a0548684a501766e6a524529ab93304c8Romain Guy            glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
449eb99356a0548684a501766e6a524529ab93304c8Romain Guy            glDeleteTextures(1, &layer->texture);
450eb99356a0548684a501766e6a524529ab93304c8Romain Guy            mCaches.fboCache.put(layer->fbo);
451eb99356a0548684a501766e6a524529ab93304c8Romain Guy
452eb99356a0548684a501766e6a524529ab93304c8Romain Guy            delete layer;
453eb99356a0548684a501766e6a524529ab93304c8Romain Guy
454eb99356a0548684a501766e6a524529ab93304c8Romain Guy            return false;
455eb99356a0548684a501766e6a524529ab93304c8Romain Guy        }
456e91080581f467d55913a8c5ab53dedc2dab2e5b6Romain Guy#endif
457eb99356a0548684a501766e6a524529ab93304c8Romain Guy
458eb99356a0548684a501766e6a524529ab93304c8Romain Guy        // Clear the FBO
45993d2361c6d294c390cb5c4a13bd1b88dcd465fd7Romain Guy        glScissor(0.0f, 0.0f, bounds.getWidth() + 1.0f, bounds.getHeight() + 1.0f);
460eb99356a0548684a501766e6a524529ab93304c8Romain Guy        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
461eb99356a0548684a501766e6a524529ab93304c8Romain Guy        glClear(GL_COLOR_BUFFER_BIT);
462eb07af687319a0f52c219c3c0c1b73162fce9d04Romain Guy
463eb07af687319a0f52c219c3c0c1b73162fce9d04Romain Guy        setScissorFromClip();
464eb99356a0548684a501766e6a524529ab93304c8Romain Guy
465eb99356a0548684a501766e6a524529ab93304c8Romain Guy        // Change the ortho projection
466eb99356a0548684a501766e6a524529ab93304c8Romain Guy        glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
467eb99356a0548684a501766e6a524529ab93304c8Romain Guy        mOrthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
468eb99356a0548684a501766e6a524529ab93304c8Romain Guy    } else {
469eb99356a0548684a501766e6a524529ab93304c8Romain Guy        // Copy the framebuffer into the layer
470eb99356a0548684a501766e6a524529ab93304c8Romain Guy        glBindTexture(GL_TEXTURE_2D, layer->texture);
471eb99356a0548684a501766e6a524529ab93304c8Romain Guy
472c00972bb162779e52d1b0d8f662a9f6033bf9182Romain Guy         if (layer->empty) {
473c00972bb162779e52d1b0d8f662a9f6033bf9182Romain Guy             glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left, mHeight - bounds.bottom,
474c00972bb162779e52d1b0d8f662a9f6033bf9182Romain Guy                     layer->width, layer->height, 0);
475c00972bb162779e52d1b0d8f662a9f6033bf9182Romain Guy             layer->empty = false;
476c00972bb162779e52d1b0d8f662a9f6033bf9182Romain Guy         } else {
477c00972bb162779e52d1b0d8f662a9f6033bf9182Romain Guy             glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left, mHeight - bounds.bottom,
478c00972bb162779e52d1b0d8f662a9f6033bf9182Romain Guy                     bounds.getWidth(), bounds.getHeight());
479c00972bb162779e52d1b0d8f662a9f6033bf9182Romain Guy          }
480eb99356a0548684a501766e6a524529ab93304c8Romain Guy
481eb99356a0548684a501766e6a524529ab93304c8Romain Guy        // Enqueue the buffer coordinates to clear the corresponding region later
482eb99356a0548684a501766e6a524529ab93304c8Romain Guy        mLayers.push(new Rect(bounds));
483eb99356a0548684a501766e6a524529ab93304c8Romain Guy    }
484f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy
485d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy    return true;
486bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy}
487bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
4881c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy/**
4891c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * Read the documentation of createLayer() before doing anything in this method.
4901c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy */
4911d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guyvoid OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
4921d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy    if (!current->layer) {
4931d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy        LOGE("Attempting to compose a layer that does not exist");
4941d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy        return;
4951d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy    }
4961d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy
497eb99356a0548684a501766e6a524529ab93304c8Romain Guy    const bool fboLayer = current->flags & SkCanvas::kClipToLayer_SaveFlag;
498eb99356a0548684a501766e6a524529ab93304c8Romain Guy
499eb99356a0548684a501766e6a524529ab93304c8Romain Guy    if (fboLayer) {
500eb99356a0548684a501766e6a524529ab93304c8Romain Guy        // Unbind current FBO and restore previous one
501eb99356a0548684a501766e6a524529ab93304c8Romain Guy        glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);
502eb99356a0548684a501766e6a524529ab93304c8Romain Guy    }
503eb99356a0548684a501766e6a524529ab93304c8Romain Guy
5041d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy    // Restore the clip from the previous snapshot
5058aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    const Rect& clip = *previous->clipRect;
506eb99356a0548684a501766e6a524529ab93304c8Romain Guy    glScissor(clip.left, previous->height - clip.bottom, clip.getWidth(), clip.getHeight());
5071d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy
5081d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy    Layer* layer = current->layer;
5091d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy    const Rect& rect = layer->layer;
5101d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy
511eb99356a0548684a501766e6a524529ab93304c8Romain Guy    if (!fboLayer && layer->alpha < 255) {
512f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy        drawColorRect(rect.left, rect.top, rect.right, rect.bottom,
5131c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy                layer->alpha << 24, SkXfermode::kDstIn_Mode, true);
514f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy    }
515f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy
5168550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    const Rect& texCoords = layer->texCoords;
5178550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    resetDrawTextureTexCoords(texCoords.left, texCoords.top, texCoords.right, texCoords.bottom);
5188b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy
519eb99356a0548684a501766e6a524529ab93304c8Romain Guy    if (fboLayer) {
520eb99356a0548684a501766e6a524529ab93304c8Romain Guy        drawTextureRect(rect.left, rect.top, rect.right, rect.bottom,
521eb99356a0548684a501766e6a524529ab93304c8Romain Guy                layer->texture, layer->alpha / 255.0f, layer->mode, layer->blend);
522eb99356a0548684a501766e6a524529ab93304c8Romain Guy    } else {
523eb99356a0548684a501766e6a524529ab93304c8Romain Guy        drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture,
524eb99356a0548684a501766e6a524529ab93304c8Romain Guy                1.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0],
525eb99356a0548684a501766e6a524529ab93304c8Romain Guy                &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, true, true);
526eb99356a0548684a501766e6a524529ab93304c8Romain Guy    }
5271d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy
5288b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy    resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
5298b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy
530eb99356a0548684a501766e6a524529ab93304c8Romain Guy    if (fboLayer) {
531eb99356a0548684a501766e6a524529ab93304c8Romain Guy        // Detach the texture from the FBO
532eb99356a0548684a501766e6a524529ab93304c8Romain Guy        glBindFramebuffer(GL_FRAMEBUFFER, current->fbo);
533eb99356a0548684a501766e6a524529ab93304c8Romain Guy        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
534eb99356a0548684a501766e6a524529ab93304c8Romain Guy        glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);
535eb99356a0548684a501766e6a524529ab93304c8Romain Guy
536eb99356a0548684a501766e6a524529ab93304c8Romain Guy        // Put the FBO name back in the cache, if it doesn't fit, it will be destroyed
537eb99356a0548684a501766e6a524529ab93304c8Romain Guy        mCaches.fboCache.put(current->fbo);
538eb99356a0548684a501766e6a524529ab93304c8Romain Guy    }
539eb99356a0548684a501766e6a524529ab93304c8Romain Guy
540eb99356a0548684a501766e6a524529ab93304c8Romain Guy    // Failing to add the layer to the cache should happen only if the layer is too large
5418550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    if (!mCaches.layerCache.put(layer)) {
5421d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy        LAYER_LOGD("Deleting layer");
5431d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy        glDeleteTextures(1, &layer->texture);
5441d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy        delete layer;
5451d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy    }
5461d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy}
5471d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy
5488694230ff25fa0a60e480d424843e56b718f0516Romain Guyvoid OpenGLRenderer::clearLayerRegions() {
549dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy    if (mLayers.size() == 0 || mSnapshot->invisible) return;
5508694230ff25fa0a60e480d424843e56b718f0516Romain Guy
5518694230ff25fa0a60e480d424843e56b718f0516Romain Guy    for (uint32_t i = 0; i < mLayers.size(); i++) {
5528694230ff25fa0a60e480d424843e56b718f0516Romain Guy        Rect* bounds = mLayers.itemAt(i);
5538694230ff25fa0a60e480d424843e56b718f0516Romain Guy
5548694230ff25fa0a60e480d424843e56b718f0516Romain Guy        // Clear the framebuffer where the layer will draw
555d2a1ff003b9b1212c9ab4b5f679b5b097720a359Romain Guy        glScissor(bounds->left, mSnapshot->height - bounds->bottom,
5568694230ff25fa0a60e480d424843e56b718f0516Romain Guy                bounds->getWidth(), bounds->getHeight());
5578694230ff25fa0a60e480d424843e56b718f0516Romain Guy        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
5588694230ff25fa0a60e480d424843e56b718f0516Romain Guy        glClear(GL_COLOR_BUFFER_BIT);
5598694230ff25fa0a60e480d424843e56b718f0516Romain Guy
5608694230ff25fa0a60e480d424843e56b718f0516Romain Guy        delete bounds;
5618694230ff25fa0a60e480d424843e56b718f0516Romain Guy    }
5628694230ff25fa0a60e480d424843e56b718f0516Romain Guy    mLayers.clear();
5638694230ff25fa0a60e480d424843e56b718f0516Romain Guy
5648694230ff25fa0a60e480d424843e56b718f0516Romain Guy    // Restore the clip
5658694230ff25fa0a60e480d424843e56b718f0516Romain Guy    setScissorFromClip();
5668694230ff25fa0a60e480d424843e56b718f0516Romain Guy}
5678694230ff25fa0a60e480d424843e56b718f0516Romain Guy
568bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy///////////////////////////////////////////////////////////////////////////////
569f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy// Transforms
570f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy///////////////////////////////////////////////////////////////////////////////
571f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
572f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guyvoid OpenGLRenderer::translate(float dx, float dy) {
5738aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    mSnapshot->transform->translate(dx, dy, 0.0f);
574f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy}
575f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
576f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guyvoid OpenGLRenderer::rotate(float degrees) {
5778aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f);
578f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy}
579f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
580f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guyvoid OpenGLRenderer::scale(float sx, float sy) {
5818aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    mSnapshot->transform->scale(sx, sy, 1.0f);
582f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy}
583f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
584f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guyvoid OpenGLRenderer::setMatrix(SkMatrix* matrix) {
5858aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    mSnapshot->transform->load(*matrix);
586f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy}
587f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
58841030da16856c8869e1e51d4a0405432fa96614eRomain Guyconst float* OpenGLRenderer::getMatrix() const {
58999bcdc52dcb365ed7d8cfa13540fb33fbcbbac9dRomain Guy    if (mSnapshot->fbo != 0) {
59099bcdc52dcb365ed7d8cfa13540fb33fbcbbac9dRomain Guy        return &mSnapshot->transform->data[0];
59199bcdc52dcb365ed7d8cfa13540fb33fbcbbac9dRomain Guy    }
59299bcdc52dcb365ed7d8cfa13540fb33fbcbbac9dRomain Guy    return &mIdentity.data[0];
59341030da16856c8869e1e51d4a0405432fa96614eRomain Guy}
59441030da16856c8869e1e51d4a0405432fa96614eRomain Guy
595f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guyvoid OpenGLRenderer::getMatrix(SkMatrix* matrix) {
5968aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    mSnapshot->transform->copyTo(*matrix);
597f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy}
598f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
599f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guyvoid OpenGLRenderer::concatMatrix(SkMatrix* matrix) {
600e5ebcb0107a939395e03592fd44c746cd09e311dRomain Guy    SkMatrix transform;
601e5ebcb0107a939395e03592fd44c746cd09e311dRomain Guy    mSnapshot->transform->copyTo(transform);
602e5ebcb0107a939395e03592fd44c746cd09e311dRomain Guy    transform.preConcat(*matrix);
603e5ebcb0107a939395e03592fd44c746cd09e311dRomain Guy    mSnapshot->transform->load(transform);
604f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy}
605f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
606f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy///////////////////////////////////////////////////////////////////////////////
607f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy// Clipping
608f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy///////////////////////////////////////////////////////////////////////////////
609f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
610bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guyvoid OpenGLRenderer::setScissorFromClip() {
611e5ebcb0107a939395e03592fd44c746cd09e311dRomain Guy    Rect clip(*mSnapshot->clipRect);
612e5ebcb0107a939395e03592fd44c746cd09e311dRomain Guy    clip.snapToPixelBoundaries();
613eb99356a0548684a501766e6a524529ab93304c8Romain Guy    glScissor(clip.left, mSnapshot->height - clip.bottom, clip.getWidth(), clip.getHeight());
6149d5316e3f56d138504565ff311145ac01621dff4Romain Guy}
6159d5316e3f56d138504565ff311145ac01621dff4Romain Guy
6169d5316e3f56d138504565ff311145ac01621dff4Romain Guyconst Rect& OpenGLRenderer::getClipBounds() {
617079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy    return mSnapshot->getLocalClip();
618bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy}
619bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guy
620c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guybool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) {
621dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy    if (mSnapshot->invisible) {
622dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy        return true;
623dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy    }
624dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy
6251d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy    Rect r(left, top, right, bottom);
6268aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    mSnapshot->transform->mapRect(r);
627d2a1ff003b9b1212c9ab4b5f679b5b097720a359Romain Guy    r.snapToPixelBoundaries();
628d2a1ff003b9b1212c9ab4b5f679b5b097720a359Romain Guy
629d2a1ff003b9b1212c9ab4b5f679b5b097720a359Romain Guy    Rect clipRect(*mSnapshot->clipRect);
630d2a1ff003b9b1212c9ab4b5f679b5b097720a359Romain Guy    clipRect.snapToPixelBoundaries();
631d2a1ff003b9b1212c9ab4b5f679b5b097720a359Romain Guy
632d2a1ff003b9b1212c9ab4b5f679b5b097720a359Romain Guy    return !clipRect.intersects(r);
633c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy}
634c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy
635079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guybool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
636079ba2c85b15e882629b8d188f5fbdb42f7f8eeaRomain Guy    bool clipped = mSnapshot->clip(left, top, right, bottom, op);
6377ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy    if (clipped) {
6387ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy        setScissorFromClip();
6397ae7ac48aa2b53453c9805075171ecd5bcafd7deRomain Guy    }
6408aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    return !mSnapshot->clipRect->isEmpty();
641e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy}
642e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
643f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy///////////////////////////////////////////////////////////////////////////////
644f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy// Drawing
645f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy///////////////////////////////////////////////////////////////////////////////
646f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
647c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guyvoid OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint) {
6486926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    const float right = left + bitmap->width();
6496926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    const float bottom = top + bitmap->height();
6506926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy
6516926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    if (quickReject(left, top, right, bottom)) {
6526926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        return;
6536926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    }
6546926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy
65561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    glActiveTexture(GL_TEXTURE0);
656fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    const Texture* texture = mCaches.textureCache.get(bitmap);
6579cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy    if (!texture) return;
65822158e139a3d6c6a9787ca0de224e9368f643284Romain Guy    const AutoTexture autoCleanup(texture);
65922158e139a3d6c6a9787ca0de224e9368f643284Romain Guy
6606926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    drawTextureRect(left, top, right, bottom, texture, paint);
6618ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy}
6628ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy
663f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guyvoid OpenGLRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint) {
664f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy    Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height());
665f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy    const mat4 transform(*matrix);
666f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy    transform.mapRect(r);
667f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy
6686926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    if (quickReject(r.left, r.top, r.right, r.bottom)) {
6696926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        return;
6706926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    }
6716926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy
67261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    glActiveTexture(GL_TEXTURE0);
673fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    const Texture* texture = mCaches.textureCache.get(bitmap);
6749cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy    if (!texture) return;
67522158e139a3d6c6a9787ca0de224e9368f643284Romain Guy    const AutoTexture autoCleanup(texture);
67622158e139a3d6c6a9787ca0de224e9368f643284Romain Guy
67782ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    drawTextureRect(r.left, r.top, r.right, r.bottom, texture, paint);
678f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy}
679f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy
6808ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guyvoid OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
6818ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy         float srcLeft, float srcTop, float srcRight, float srcBottom,
6828ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy         float dstLeft, float dstTop, float dstRight, float dstBottom,
683f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy         const SkPaint* paint) {
6846926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    if (quickReject(dstLeft, dstTop, dstRight, dstBottom)) {
6856926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        return;
6866926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    }
6876926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy
68861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    glActiveTexture(GL_TEXTURE0);
689fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    const Texture* texture = mCaches.textureCache.get(bitmap);
6909cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy    if (!texture) return;
69122158e139a3d6c6a9787ca0de224e9368f643284Romain Guy    const AutoTexture autoCleanup(texture);
6928ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy
6938ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy    const float width = texture->width;
6948ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy    const float height = texture->height;
695c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy
6968ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy    const float u1 = srcLeft / width;
6978ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy    const float v1 = srcTop / height;
6988ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy    const float u2 = srcRight / width;
6998ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy    const float v2 = srcBottom / height;
700c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy
7018ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy    resetDrawTextureTexCoords(u1, v1, u2, v2);
7028ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy
70382ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    drawTextureRect(dstLeft, dstTop, dstRight, dstBottom, texture, paint);
7048ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy
7058ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy    resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
706ce0537b80087a6225273040a987414b1dd081aa0Romain Guy}
707ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
7084aa90573bbf86db0d33a3a790c5dbd0d93b95cfeRomain Guyvoid OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
7094bb942083a0d4db746adf95349108dd8ef842e32Romain Guy        const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
7104bb942083a0d4db746adf95349108dd8ef842e32Romain Guy        float left, float top, float right, float bottom, const SkPaint* paint) {
7116926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    if (quickReject(left, top, right, bottom)) {
7126926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        return;
7136926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    }
7146926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy
71561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy    glActiveTexture(GL_TEXTURE0);
716fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    const Texture* texture = mCaches.textureCache.get(bitmap);
7179cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy    if (!texture) return;
71822158e139a3d6c6a9787ca0de224e9368f643284Romain Guy    const AutoTexture autoCleanup(texture);
719f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
720f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy    int alpha;
721f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy    SkXfermode::Mode mode;
722f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy    getAlphaAndMode(paint, &alpha, &mode);
723f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
7242728f961614a385df1f056fc24803a9f65c90fabRomain Guy    const Patch* mesh = mCaches.patchCache.get(bitmap->width(), bitmap->height(),
7254bb942083a0d4db746adf95349108dd8ef842e32Romain Guy            right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors);
726f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
727f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy    // Specify right and bottom as +1.0f from left/top to prevent scaling since the
728f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy    // patch mesh already defines the final size
729a979474f15b454c8e2963f239a3770e200bb227cRomain Guy    drawTextureMesh(left, top, left + 1.0f, top + 1.0f, texture->id, alpha / 255.0f,
730a979474f15b454c8e2963f239a3770e200bb227cRomain Guy            mode, texture->blend, &mesh->vertices[0].position[0],
7316820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy            &mesh->vertices[0].texture[0], GL_TRIANGLES, mesh->verticesCount);
732f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy}
733f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
734759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guyvoid OpenGLRenderer::drawLines(float* points, int count, const SkPaint* paint) {
735dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy    if (mSnapshot->invisible) return;
736dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy
737759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy    int alpha;
738759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy    SkXfermode::Mode mode;
739759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy    getAlphaAndMode(paint, &alpha, &mode);
740759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy
741759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy    uint32_t color = paint->getColor();
742759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy    const GLfloat a = alpha / 255.0f;
743759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy    const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f;
744759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy    const GLfloat g = a * ((color >>  8) & 0xFF) / 255.0f;
745759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy    const GLfloat b = a * ((color      ) & 0xFF) / 255.0f;
746759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy
747c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy    const bool isAA = paint->isAntiAlias();
748c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy    if (isAA) {
749c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy        GLuint textureUnit = 0;
75029d8997bd43b7c4ad37fc3d6f91eaafa74913c88Romain Guy        setupTextureAlpha8(mCaches.line.getTexture(), 0, 0, textureUnit, 0.0f, 0.0f, r, g, b, a,
75129d8997bd43b7c4ad37fc3d6f91eaafa74913c88Romain Guy                mode, false, true, mCaches.line.getVertices(), mCaches.line.getTexCoords());
752c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy    } else {
753c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy        setupColorRect(0.0f, 0.0f, 1.0f, 1.0f, r, g, b, a, mode, false);
754c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy    }
755c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy
756c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy    const float strokeWidth = paint->getStrokeWidth();
75729d8997bd43b7c4ad37fc3d6f91eaafa74913c88Romain Guy    const GLsizei elementsCount = isAA ? mCaches.line.getElementsCount() : gMeshCount;
758c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy    const GLenum drawMode = isAA ? GL_TRIANGLES : GL_TRIANGLE_STRIP;
759759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy
760759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy    for (int i = 0; i < count; i += 4) {
761759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy        float tx = 0.0f;
762759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy        float ty = 0.0f;
763759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy
764c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy        if (isAA) {
76529d8997bd43b7c4ad37fc3d6f91eaafa74913c88Romain Guy            mCaches.line.update(points[i], points[i + 1], points[i + 2], points[i + 3],
766c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy                    strokeWidth, tx, ty);
767c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy        } else {
768b5ab4173e0927e4668a45298c9900cd8007584e1Romain Guy            ty = strokeWidth <= 1.0f ? 0.0f : -strokeWidth * 0.5f;
769c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy        }
770759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy
771759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy        const float dx = points[i + 2] - points[i];
772759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy        const float dy = points[i + 3] - points[i + 1];
773759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy        const float mag = sqrtf(dx * dx + dy * dy);
774759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy        const float angle = acos(dx / mag);
775759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy
776759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy        mModelView.loadTranslate(points[i], points[i + 1], 0.0f);
777759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy        if (angle > MIN_ANGLE || angle < -MIN_ANGLE) {
778759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy            mModelView.rotate(angle * RAD_TO_DEG, 0.0f, 0.0f, 1.0f);
779759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy        }
780759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy        mModelView.translate(tx, ty, 0.0f);
781c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy        if (!isAA) {
78229d8997bd43b7c4ad37fc3d6f91eaafa74913c88Romain Guy            float length = mCaches.line.getLength(points[i], points[i + 1],
78329d8997bd43b7c4ad37fc3d6f91eaafa74913c88Romain Guy                    points[i + 2], points[i + 3]);
784c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy            mModelView.scale(length, strokeWidth, 1.0f);
785c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy        }
786759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy        mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
787759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy
788759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy        if (mShader) {
789759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy            mShader->updateTransforms(mCaches.currentProgram, mModelView, *mSnapshot);
790759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy        }
791759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy
792c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy        glDrawArrays(drawMode, 0, elementsCount);
793759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy    }
794759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy
79529d8997bd43b7c4ad37fc3d6f91eaafa74913c88Romain Guy    if (isAA) {
79629d8997bd43b7c4ad37fc3d6f91eaafa74913c88Romain Guy        glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords"));
79729d8997bd43b7c4ad37fc3d6f91eaafa74913c88Romain Guy    }
798759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy}
799759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy
80085bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guyvoid OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
8018aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    const Rect& clip = *mSnapshot->clipRect;
8023d58c03de0d8877b36cdb78b0ca8b5cac7f600e2Romain Guy    drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true);
803c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy}
8049d5316e3f56d138504565ff311145ac01621dff4Romain Guy
805bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guyvoid OpenGLRenderer::drawRect(float left, float top, float right, float bottom, const SkPaint* p) {
8066926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    if (quickReject(left, top, right, bottom)) {
8076926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        return;
8086926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    }
8096926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy
810026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy    SkXfermode::Mode mode;
811a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy    if (!mExtensions.hasFramebufferFetch()) {
812a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy        const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode);
813a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy        if (!isMode) {
814a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            // Assume SRC_OVER
815a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            mode = SkXfermode::kSrcOver_Mode;
816a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy        }
817a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy    } else {
818a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy        mode = getXfermode(p->getXfermode());
819026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy    }
820026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy
821026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy    // Skia draws using the color's alpha channel if < 255
822026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy    // Otherwise, it uses the paint's alpha
823026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy    int color = p->getColor();
824d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy    if (((color >> 24) & 0xff) == 255) {
825026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy        color |= p->getAlpha() << 24;
826026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy    }
827026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy
828026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy    drawColorRect(left, top, right, bottom, color, mode);
829c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy}
8309d5316e3f56d138504565ff311145ac01621dff4Romain Guy
831e8e62a4a032a80409114a37908b5f18ab0080848Romain Guyvoid OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
832e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy        float x, float y, SkPaint* paint) {
833f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy    if (text == NULL || count == 0 || (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) {
834e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy        return;
835e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy    }
836dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy    if (mSnapshot->invisible) return;
837e2d345ea67e2960b37bfdc0fc8626d1bfa747404Romain Guy
838f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy    paint->setAntiAlias(true);
839e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy
840a674ab74e359ac73b4c4dd6b1a3a771836ac7e40Romain Guy    float length = -1.0f;
841e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy    switch (paint->getTextAlign()) {
842e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy        case SkPaint::kCenter_Align:
843e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy            length = paint->measureText(text, bytesCount);
844e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy            x -= length / 2.0f;
845e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy            break;
846e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy        case SkPaint::kRight_Align:
847e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy            length = paint->measureText(text, bytesCount);
848e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy            x -= length;
849e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy            break;
850e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy        default:
851e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy            break;
852e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy    }
853e8e62a4a032a80409114a37908b5f18ab0080848Romain Guy
854694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    int alpha;
855694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    SkXfermode::Mode mode;
856694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    getAlphaAndMode(paint, &alpha, &mode);
857694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
8582542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy    uint32_t color = paint->getColor();
8592542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy    const GLfloat a = alpha / 255.0f;
8602542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy    const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f;
8612542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy    const GLfloat g = a * ((color >>  8) & 0xFF) / 255.0f;
8622542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy    const GLfloat b = a * ((color      ) & 0xFF) / 255.0f;
8632542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy
864b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy    FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(paint);
865b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy    fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()),
866fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            paint->getTextSize());
867e2d345ea67e2960b37bfdc0fc8626d1bfa747404Romain Guy
8681e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    if (mHasShadow) {
8691e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        glActiveTexture(gTextureUnits[0]);
870b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy        mCaches.dropShadowCache.setFontRenderer(fontRenderer);
871fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        const ShadowTexture* shadow = mCaches.dropShadowCache.get(paint, text, bytesCount,
8721e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy                count, mShadowRadius);
8731e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        const AutoTexture autoCleanup(shadow);
8740a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
8752542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy        setupShadow(shadow, x, y, mode, a);
8760a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
8770a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy        // Draw the mesh
8780a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy        glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
879fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords"));
8801e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    }
8811e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
88206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    GLuint textureUnit = 0;
883db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    glActiveTexture(gTextureUnits[textureUnit]);
88406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
885e8cb9c14309b0f01c0159efdf9a7198f44a62642Romain Guy    // Assume that the modelView matrix does not force scales, rotates, etc.
886e8cb9c14309b0f01c0159efdf9a7198f44a62642Romain Guy    const bool linearFilter = mSnapshot->transform->changesBounds();
887e8cb9c14309b0f01c0159efdf9a7198f44a62642Romain Guy    setupTextureAlpha8(fontRenderer.getTexture(linearFilter), 0, 0, textureUnit,
888e8cb9c14309b0f01c0159efdf9a7198f44a62642Romain Guy            x, y, r, g, b, a, mode, false, true);
88906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
89009147fbdc8206a0cac78bfe9083e7e15b3c5689cRomain Guy    const Rect& clip = mSnapshot->getLocalClip();
8918694230ff25fa0a60e480d424843e56b718f0516Romain Guy    clearLayerRegions();
892b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy    fontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y);
893694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
894694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
895fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords"));
896a674ab74e359ac73b4c4dd6b1a3a771836ac7e40Romain Guy
8970a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    drawTextDecorations(text, bytesCount, length, x, y, paint);
898694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
899694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
9007fbcc0492fca03857e3c45064f4aa040af817d55Romain Guyvoid OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) {
901dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy    if (mSnapshot->invisible) return;
902dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy
9037fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy    GLuint textureUnit = 0;
9047fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy    glActiveTexture(gTextureUnits[textureUnit]);
9057fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
906fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    const PathTexture* texture = mCaches.pathCache.get(path, paint);
9079cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy    if (!texture) return;
90822158e139a3d6c6a9787ca0de224e9368f643284Romain Guy    const AutoTexture autoCleanup(texture);
9097fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
9108b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy    const float x = texture->left - texture->offset;
9118b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy    const float y = texture->top - texture->offset;
9128b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy
9138b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy    if (quickReject(x, y, x + texture->width, y + texture->height)) {
9148b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy        return;
9158b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy    }
9168b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy
9177fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy    int alpha;
9187fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy    SkXfermode::Mode mode;
9197fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy    getAlphaAndMode(paint, &alpha, &mode);
9207fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
9217fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy    uint32_t color = paint->getColor();
9227fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy    const GLfloat a = alpha / 255.0f;
9237fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy    const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f;
9247fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy    const GLfloat g = a * ((color >>  8) & 0xFF) / 255.0f;
9257fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy    const GLfloat b = a * ((color      ) & 0xFF) / 255.0f;
9267fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
9270a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    setupTextureAlpha8(texture, textureUnit, x, y, r, g, b, a, mode, true, true);
9280a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
9298694230ff25fa0a60e480d424843e56b718f0516Romain Guy    clearLayerRegions();
9308694230ff25fa0a60e480d424843e56b718f0516Romain Guy
9310a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    // Draw the mesh
9320a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
933fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords"));
9347fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy}
9357fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
9366926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy///////////////////////////////////////////////////////////////////////////////
937d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy// Shaders
938d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy///////////////////////////////////////////////////////////////////////////////
939d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy
940d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guyvoid OpenGLRenderer::resetShader() {
94106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    mShader = NULL;
94206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy}
94306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
94406f96e2652e4855b6520ad9dd70583677605b79aRomain Guyvoid OpenGLRenderer::setupShader(SkiaShader* shader) {
94506f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    mShader = shader;
94606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    if (mShader) {
947fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        mShader->set(&mCaches.textureCache, &mCaches.gradientCache);
94806f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    }
9497fac2e18339f765320d759e8d4c090f92431959eRomain Guy}
9507fac2e18339f765320d759e8d4c090f92431959eRomain Guy
951d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy///////////////////////////////////////////////////////////////////////////////
952db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy// Color filters
953db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy///////////////////////////////////////////////////////////////////////////////
954db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy
955db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guyvoid OpenGLRenderer::resetColorFilter() {
956db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    mColorFilter = NULL;
957db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy}
958db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy
959db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guyvoid OpenGLRenderer::setupColorFilter(SkiaColorFilter* filter) {
960db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    mColorFilter = filter;
961db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy}
962db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy
963db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy///////////////////////////////////////////////////////////////////////////////
9641e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy// Drop shadow
9651e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy///////////////////////////////////////////////////////////////////////////////
9661e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
9671e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guyvoid OpenGLRenderer::resetShadow() {
9681e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    mHasShadow = false;
9691e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy}
9701e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
9711e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guyvoid OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) {
9721e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    mHasShadow = true;
9731e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    mShadowRadius = radius;
9741e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    mShadowDx = dx;
9751e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    mShadowDy = dy;
9761e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    mShadowColor = color;
9771e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy}
9781e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
9791e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy///////////////////////////////////////////////////////////////////////////////
9806926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy// Drawing implementation
9816926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy///////////////////////////////////////////////////////////////////////////////
9826926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy
9830a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guyvoid OpenGLRenderer::setupShadow(const ShadowTexture* texture, float x, float y,
9842542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy        SkXfermode::Mode mode, float alpha) {
9850a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    const float sx = x - texture->left + mShadowDx;
9860a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    const float sy = y - texture->top + mShadowDy;
9870a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
9882542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy    const int shadowAlpha = ((mShadowColor >> 24) & 0xFF);
9892542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy    const GLfloat a = shadowAlpha < 255 ? shadowAlpha / 255.0f : alpha;
9900a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    const GLfloat r = a * ((mShadowColor >> 16) & 0xFF) / 255.0f;
9910a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    const GLfloat g = a * ((mShadowColor >>  8) & 0xFF) / 255.0f;
9920a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    const GLfloat b = a * ((mShadowColor      ) & 0xFF) / 255.0f;
9930a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
9940a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    GLuint textureUnit = 0;
9950a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    setupTextureAlpha8(texture, textureUnit, sx, sy, r, g, b, a, mode, true, false);
9960a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy}
9970a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
9980a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guyvoid OpenGLRenderer::setupTextureAlpha8(const Texture* texture, GLuint& textureUnit,
9990a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy        float x, float y, float r, float g, float b, float a, SkXfermode::Mode mode,
10000a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy        bool transforms, bool applyFilters) {
10010a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    setupTextureAlpha8(texture->id, texture->width, texture->height, textureUnit,
1002759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy            x, y, r, g, b, a, mode, transforms, applyFilters,
1003759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy            &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]);
10040a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy}
10050a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
10060a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guyvoid OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t height,
10070a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy        GLuint& textureUnit, float x, float y, float r, float g, float b, float a,
10080a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy        SkXfermode::Mode mode, bool transforms, bool applyFilters) {
1009759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy    setupTextureAlpha8(texture, width, height, textureUnit,
1010759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy            x, y, r, g, b, a, mode, transforms, applyFilters,
1011759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy            &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]);
1012759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy}
1013759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy
1014759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guyvoid OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t height,
1015759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy        GLuint& textureUnit, float x, float y, float r, float g, float b, float a,
1016759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy        SkXfermode::Mode mode, bool transforms, bool applyFilters,
1017759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy        GLvoid* vertices, GLvoid* texCoords) {
10180a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy     // Describe the required shaders
10190a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy     ProgramDescription description;
10200a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy     description.hasTexture = true;
10210a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy     description.hasAlpha8Texture = true;
1022707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy     const bool setColor = description.setAlpha8Color(r, g, b, a);
10230a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
10240a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy     if (applyFilters) {
10250a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy         if (mShader) {
10260a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy             mShader->describe(description, mExtensions);
10270a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy         }
10280a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy         if (mColorFilter) {
10290a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy             mColorFilter->describe(description, mExtensions);
10300a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy         }
10310a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy     }
10320a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
1033a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy     // Setup the blending mode
1034a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy     chooseBlending(true, mode, description);
1035a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy
10360a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy     // Build and use the appropriate shader
1037fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy     useProgram(mCaches.programCache.get(description));
10380a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
10390a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy     bindTexture(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, textureUnit);
1040fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy     glUniform1i(mCaches.currentProgram->getUniform("sampler"), textureUnit);
10410a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
1042fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy     int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords");
10430a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy     glEnableVertexAttribArray(texCoordsSlot);
10440a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
10450a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy     // Setup attributes
1046fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy     glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
1047759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy             gMeshStride, vertices);
10480a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy     glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE,
1049759ea80dca64ad652110a129e0d8bf93fea79f61Romain Guy             gMeshStride, texCoords);
10500a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
10510a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy     // Setup uniforms
10520a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy     if (transforms) {
10530a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy         mModelView.loadTranslate(x, y, 0.0f);
10540a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy         mModelView.scale(width, height, 1.0f);
10550a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy     } else {
10560a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy         mModelView.loadIdentity();
10570a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy     }
10588aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy     mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
1059707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy     if (setColor) {
1060707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy         mCaches.currentProgram->setColor(r, g, b, a);
1061707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy     }
10620a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
10630a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy     textureUnit++;
10640a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy     if (applyFilters) {
10650a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy         // Setup attributes and uniforms required by the shaders
10660a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy         if (mShader) {
1067fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy             mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit);
10680a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy         }
10690a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy         if (mColorFilter) {
1070fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy             mColorFilter->setupProgram(mCaches.currentProgram);
10710a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy         }
10720a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy     }
10730a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy}
10740a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
1075f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy// Same values used by Skia
10760a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy#define kStdStrikeThru_Offset   (-6.0f / 21.0f)
10770a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy#define kStdUnderline_Offset    (1.0f / 9.0f)
10780a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy#define kStdUnderline_Thickness (1.0f / 18.0f)
10790a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
10800a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guyvoid OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float length,
10810a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy        float x, float y, SkPaint* paint) {
10820a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    // Handle underline and strike-through
10830a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    uint32_t flags = paint->getFlags();
10840a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
10850a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy        float underlineWidth = length;
10860a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy        // If length is > 0.0f, we already measured the text for the text alignment
10870a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy        if (length <= 0.0f) {
10880a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy            underlineWidth = paint->measureText(text, bytesCount);
10890a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy        }
10900a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
10910a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy        float offsetX = 0;
10920a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy        switch (paint->getTextAlign()) {
10930a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy            case SkPaint::kCenter_Align:
10940a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy                offsetX = underlineWidth * 0.5f;
10950a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy                break;
10960a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy            case SkPaint::kRight_Align:
10970a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy                offsetX = underlineWidth;
10980a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy                break;
10990a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy            default:
11000a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy                break;
11010a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy        }
11020a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
11030a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy        if (underlineWidth > 0.0f) {
1104e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy            const float textSize = paint->getTextSize();
1105e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy            const float strokeWidth = textSize * kStdUnderline_Thickness;
11060a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
1107e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy            const float left = x - offsetX;
11080a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy            float top = 0.0f;
1109e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy
1110e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy            const int pointsCount = 4 * (flags & SkPaint::kStrikeThruText_Flag ? 2 : 1);
1111e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy            float points[pointsCount];
1112e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy            int currentPoint = 0;
11130a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
11140a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy            if (flags & SkPaint::kUnderlineText_Flag) {
11150a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy                top = y + textSize * kStdUnderline_Offset;
1116e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = left;
1117e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = top;
1118e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = left + underlineWidth;
1119e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = top;
11200a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy            }
11210a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
11220a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy            if (flags & SkPaint::kStrikeThruText_Flag) {
11230a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy                top = y + textSize * kStdStrikeThru_Offset;
1124e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = left;
1125e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = top;
1126e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = left + underlineWidth;
1127e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = top;
11280a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy            }
1129e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy
1130e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy            SkPaint linesPaint(*paint);
1131e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy            linesPaint.setStrokeWidth(strokeWidth);
1132e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy
1133e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy            drawLines(&points[0], pointsCount, &linesPaint);
11340a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy        }
11350a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    }
11360a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy}
11370a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
1138026c5e16704e817cac7d9c382914c947e34f87e0Romain Guyvoid OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
11391c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy        int color, SkXfermode::Mode mode, bool ignoreTransform) {
11408694230ff25fa0a60e480d424843e56b718f0516Romain Guy    clearLayerRegions();
11418694230ff25fa0a60e480d424843e56b718f0516Romain Guy
1142d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy    // If a shader is set, preserve only the alpha
114306f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    if (mShader) {
1144d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        color |= 0x00ffffff;
1145d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy    }
1146d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy
1147d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy    // Render using pre-multiplied alpha
1148026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy    const int alpha = (color >> 24) & 0xFF;
1149d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy    const GLfloat a = alpha / 255.0f;
1150c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f;
1151c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    const GLfloat g = a * ((color >>  8) & 0xFF) / 255.0f;
1152c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    const GLfloat b = a * ((color      ) & 0xFF) / 255.0f;
1153c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
1154c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy    setupColorRect(left, top, right, bottom, r, g, b, a, mode, ignoreTransform);
1155c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy
1156c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy    // Draw the mesh
1157c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
1158c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy}
1159c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy
1160c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guyvoid OpenGLRenderer::setupColorRect(float left, float top, float right, float bottom,
1161c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy        float r, float g, float b, float a, SkXfermode::Mode mode, bool ignoreTransform) {
116206f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    GLuint textureUnit = 0;
11639d5316e3f56d138504565ff311145ac01621dff4Romain Guy
116406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    // Describe the required shaders
1165889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy    ProgramDescription description;
1166707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy    const bool setColor = description.setColor(r, g, b, a);
1167707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy
116806f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    if (mShader) {
116906f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        mShader->describe(description, mExtensions);
1170c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy    }
1171db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    if (mColorFilter) {
1172db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        mColorFilter->describe(description, mExtensions);
1173db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    }
1174c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
11751c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy    // Setup the blending mode
1176c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy    chooseBlending(a < 1.0f || (mShader && mShader->blend()), mode, description);
1177a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy
117806f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    // Build and use the appropriate shader
1179fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    useProgram(mCaches.programCache.get(description));
1180c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
118106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    // Setup attributes
1182fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
1183ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy            gMeshStride, &mMeshVertices[0].position[0]);
1184c0ac193b9415680f0a69e20a3f5f22d16f8053beRomain Guy
118506f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    // Setup uniforms
1186889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy    mModelView.loadTranslate(left, top, 0.0f);
1187889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy    mModelView.scale(right - left, bottom - top, 1.0f);
118806f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    if (!ignoreTransform) {
11898aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy        mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
1190889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy    } else {
119106f96e2652e4855b6520ad9dd70583677605b79aRomain Guy        mat4 identity;
1192fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        mCaches.currentProgram->set(mOrthoMatrix, mModelView, identity);
1193889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy    }
1194707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy    mCaches.currentProgram->setColor(r, g, b, a);
1195d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy
119606f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    // Setup attributes and uniforms required by the shaders
119706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    if (mShader) {
1198fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit);
1199d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy    }
1200db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    if (mColorFilter) {
1201fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        mColorFilter->setupProgram(mCaches.currentProgram);
1202db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    }
1203d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy}
1204d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy
120582ba814ca0dea659be2cc6523bc0137679d961ceRomain Guyvoid OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
1206a979474f15b454c8e2963f239a3770e200bb227cRomain Guy        const Texture* texture, const SkPaint* paint) {
120782ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    int alpha;
120882ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    SkXfermode::Mode mode;
120982ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    getAlphaAndMode(paint, &alpha, &mode);
121082ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy
12116820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy    drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode,
12126820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy            texture->blend, &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
12136820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy            GL_TRIANGLE_STRIP, gMeshCount);
121485bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy}
121585bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy
1216bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guyvoid OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
1217a979474f15b454c8e2963f239a3770e200bb227cRomain Guy        GLuint texture, float alpha, SkXfermode::Mode mode, bool blend) {
1218a979474f15b454c8e2963f239a3770e200bb227cRomain Guy    drawTextureMesh(left, top, right, bottom, texture, alpha, mode, blend,
12196820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy            &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
12206820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy            GL_TRIANGLE_STRIP, gMeshCount);
1221f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy}
1222f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
1223f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guyvoid OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
1224a979474f15b454c8e2963f239a3770e200bb227cRomain Guy        GLuint texture, float alpha, SkXfermode::Mode mode, bool blend,
12256820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy        GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
1226f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy        bool swapSrcDst, bool ignoreTransform) {
12278694230ff25fa0a60e480d424843e56b718f0516Romain Guy    clearLayerRegions();
12288694230ff25fa0a60e480d424843e56b718f0516Romain Guy
1229889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy    ProgramDescription description;
1230889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy    description.hasTexture = true;
1231707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy    const bool setColor = description.setColor(alpha, alpha, alpha, alpha);
1232db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    if (mColorFilter) {
1233db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        mColorFilter->describe(description, mExtensions);
1234db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    }
1235889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy
1236bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy    mModelView.loadTranslate(left, top, 0.0f);
1237bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy    mModelView.scale(right - left, bottom - top, 1.0f);
1238bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
1239f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy    chooseBlending(blend || alpha < 1.0f, mode, description, swapSrcDst);
1240a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy
1241fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    useProgram(mCaches.programCache.get(description));
1242f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy    if (!ignoreTransform) {
1243f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy        mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
1244f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy    } else {
1245f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy        mat4 m;
1246f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy        mCaches.currentProgram->set(mOrthoMatrix, mModelView, m);
1247f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy    }
1248bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
1249889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy    // Texture
125006f96e2652e4855b6520ad9dd70583677605b79aRomain Guy    bindTexture(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 0);
1251fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    glUniform1i(mCaches.currentProgram->getUniform("sampler"), 0);
1252c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy
1253a979474f15b454c8e2963f239a3770e200bb227cRomain Guy    // Always premultiplied
1254707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy    if (setColor) {
1255707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy        mCaches.currentProgram->setColor(alpha, alpha, alpha, alpha);
1256707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy    }
1257bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
1258889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy    // Mesh
1259fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords");
1260889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy    glEnableVertexAttribArray(texCoordsSlot);
1261fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
1262ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy            gMeshStride, vertices);
1263889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy    glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords);
1264bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
1265db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    // Color filter
1266db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    if (mColorFilter) {
1267fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        mColorFilter->setupProgram(mCaches.currentProgram);
1268db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy    }
1269db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy
12706820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy    glDrawArrays(drawMode, 0, elementsCount);
1271889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy    glDisableVertexAttribArray(texCoordsSlot);
127282ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy}
127382ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy
1274a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guyvoid OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
1275f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy        ProgramDescription& description, bool swapSrcDst) {
127682ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    blend = blend || mode != SkXfermode::kSrcOver_Mode;
127782ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    if (blend) {
1278a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy        if (mode < SkXfermode::kPlus_Mode) {
1279a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            if (!mCaches.blend) {
1280a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy                glEnable(GL_BLEND);
1281a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            }
128282ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy
1283f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy            GLenum sourceMode = swapSrcDst ? gBlendsSwap[mode].src : gBlends[mode].src;
1284f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy            GLenum destMode = swapSrcDst ? gBlendsSwap[mode].dst : gBlends[mode].dst;
128582ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy
1286a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) {
1287a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy                glBlendFunc(sourceMode, destMode);
1288a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy                mCaches.lastSrcMode = sourceMode;
1289a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy                mCaches.lastDstMode = destMode;
1290a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            }
1291a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy        } else {
1292a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            // These blend modes are not supported by OpenGL directly and have
1293a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            // to be implemented using shaders. Since the shader will perform
1294a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            // the blending, turn blending off here
1295a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            if (mExtensions.hasFramebufferFetch()) {
1296a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy                description.framebufferMode = mode;
1297f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy                description.swapSrcDst = swapSrcDst;
1298a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            }
1299a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy
1300a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            if (mCaches.blend) {
1301a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy                glDisable(GL_BLEND);
1302a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            }
1303a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            blend = false;
130482ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy        }
1305fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    } else if (mCaches.blend) {
130682ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy        glDisable(GL_BLEND);
130782ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    }
1308fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    mCaches.blend = blend;
1309bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy}
1310bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
1311889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guybool OpenGLRenderer::useProgram(Program* program) {
1312d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy    if (!program->isInUse()) {
1313fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        if (mCaches.currentProgram != NULL) mCaches.currentProgram->remove();
1314d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        program->use();
1315fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy        mCaches.currentProgram = program;
13166926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy        return false;
1317260e102162322958cf17dbd895cd6bd30dc87e32Romain Guy    }
13186926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    return true;
1319260e102162322958cf17dbd895cd6bd30dc87e32Romain Guy}
1320260e102162322958cf17dbd895cd6bd30dc87e32Romain Guy
1321026c5e16704e817cac7d9c382914c947e34f87e0Romain Guyvoid OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
1322ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy    TextureVertex* v = &mMeshVertices[0];
132382ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    TextureVertex::setUV(v++, u1, v1);
132482ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    TextureVertex::setUV(v++, u2, v1);
132582ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    TextureVertex::setUV(v++, u1, v2);
132682ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    TextureVertex::setUV(v++, u2, v2);
13278ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy}
13288ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy
13298ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guyvoid OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) {
13308ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy    if (paint) {
1331a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy        if (!mExtensions.hasFramebufferFetch()) {
1332a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            const bool isMode = SkXfermode::IsMode(paint->getXfermode(), mode);
1333a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            if (!isMode) {
1334a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy                // Assume SRC_OVER
1335a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy                *mode = SkXfermode::kSrcOver_Mode;
1336a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            }
1337a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy        } else {
1338a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            *mode = getXfermode(paint->getXfermode());
13398ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy        }
13408ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy
13418ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy        // Skia draws using the color's alpha channel if < 255
13428ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy        // Otherwise, it uses the paint's alpha
13438ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy        int color = paint->getColor();
13448ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy        *alpha = (color >> 24) & 0xFF;
13458ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy        if (*alpha == 255) {
13468ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy            *alpha = paint->getAlpha();
13478ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy        }
13488ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy    } else {
13498ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy        *mode = SkXfermode::kSrcOver_Mode;
13508ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy        *alpha = 255;
13518ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy    }
1352026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy}
1353026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy
1354a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain GuySkXfermode::Mode OpenGLRenderer::getXfermode(SkXfermode* mode) {
1355a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy    if (mode == NULL) {
1356a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy        return SkXfermode::kSrcOver_Mode;
1357a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy    }
1358a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy    return mode->fMode;
1359a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy}
1360a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy
1361889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guyvoid OpenGLRenderer::bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit) {
1362889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy    glActiveTexture(gTextureUnits[textureUnit]);
1363ae5575b3421c8fbe590ab046d7d5f2b36ecfd821Romain Guy    glBindTexture(GL_TEXTURE_2D, texture);
1364a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
1365a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
1366a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy}
1367a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy
13689d5316e3f56d138504565ff311145ac01621dff4Romain Guy}; // namespace uirenderer
1369e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy}; // namespace android
1370