OpenGLRenderer.cpp revision 26bf34200e40a0fa8c66366559aa016380cd8c6f
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#include "OpenGLRenderer.h"
1865fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik
19c3566d06421c8acc0aafb18f7e307e5725ce87e1Chris Craik#include "DeferredDisplayList.h"
200fe478ea04720a57ef3919dbc23711bc7eba517fRomain Guy#include "DisplayListRenderer.h"
212dc236b2bae13b9a0ed9b3f7320502aecd7983b3Tom Hudson#include "GammaFontRenderer.h"
22031888744e24b5c7243ac99ec98b78aff5db1c78Chris Craik#include "Glop.h"
23031888744e24b5c7243ac99ec98b78aff5db1c78Chris Craik#include "GlopBuilder.h"
242dc236b2bae13b9a0ed9b3f7320502aecd7983b3Tom Hudson#include "Patch.h"
2565cd612face362d054a85d0f7e5881c59cd523beChris Craik#include "PathTessellator.h"
2687e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy#include "Properties.h"
272dc236b2bae13b9a0ed9b3f7320502aecd7983b3Tom Hudson#include "RenderNode.h"
28031888744e24b5c7243ac99ec98b78aff5db1c78Chris Craik#include "renderstate/MeshState.h"
2965fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik#include "renderstate/RenderState.h"
3055bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#include "ShadowTessellator.h"
31d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III#include "SkiaShader.h"
32a957eea78557cb47a91d44d9e6ee641c58cf1c07Romain Guy#include "Vector.h"
3355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui#include "VertexBuffer.h"
342dc236b2bae13b9a0ed9b3f7320502aecd7983b3Tom Hudson#include "utils/GLUtils.h"
358dfaa4904205772cdceee63ef3989bcdedf1a914Tom Hudson#include "utils/PaintUtils.h"
3606e7fe5a70409d2050b2b3e1286500f5223099daChris Craik#include "utils/TraceUtils.h"
37e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
3865fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik#include <stdlib.h>
3965fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik#include <stdint.h>
4065fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik#include <sys/types.h>
4165fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik
4265fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik#include <SkCanvas.h>
4365fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik#include <SkColor.h>
4465fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik#include <SkShader.h>
4565fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik#include <SkTypeface.h>
4665fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik
4765fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik#include <utils/Log.h>
4865fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik#include <utils/StopWatch.h>
4965fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik
5065fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik#include <private/hwui/DrawGlInfo.h>
5165fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik
5265fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik#include <ui/Rect.h>
5365fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik
5462d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik#if DEBUG_DETAILED_EVENTS
5562d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik    #define EVENT_LOGD(...) eventMarkDEBUG(__VA_ARGS__)
5662d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik#else
5762d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik    #define EVENT_LOGD(...)
5862d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik#endif
5962d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik
600519c810a56bded1284fcb2ae40f438878c6585fChris Craik#define USE_GLOPS true
610519c810a56bded1284fcb2ae40f438878c6585fChris Craik
62e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guynamespace android {
639d5316e3f56d138504565ff311145ac01621dff4Romain Guynamespace uirenderer {
649d5316e3f56d138504565ff311145ac01621dff4Romain Guy
659d5316e3f56d138504565ff311145ac01621dff4Romain Guy///////////////////////////////////////////////////////////////////////////////
66f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy// Constructors/destructor
67f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy///////////////////////////////////////////////////////////////////////////////
68f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
693b20251a355c88193c439f928a84ae69483fb488John ReckOpenGLRenderer::OpenGLRenderer(RenderState& renderState)
70984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson        : mState(*this)
71058fc640017c90120c599d378a4cbc55668b05b7Chris Craik        , mCaches(Caches::getInstance())
72058fc640017c90120c599d378a4cbc55668b05b7Chris Craik        , mRenderState(renderState)
7365fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik        , mFrameStarted(false)
74058fc640017c90120c599d378a4cbc55668b05b7Chris Craik        , mScissorOptimizationDisabled(false)
75284b24358410cb0200e525a5ba36994090c83f20Chris Craik        , mSuppressTiling(false)
76284b24358410cb0200e525a5ba36994090c83f20Chris Craik        , mFirstFrameAfterResize(true)
77107843de4507b3511006cb9c77b8d0364374385aTom Hudson        , mDirty(false)
781aa5d2d7068147ff781cfe911a93f01593a68c79John Reck        , mLightCenter((Vector3){FLT_MIN, FLT_MIN, FLT_MIN})
79058fc640017c90120c599d378a4cbc55668b05b7Chris Craik        , mLightRadius(FLT_MIN)
80058fc640017c90120c599d378a4cbc55668b05b7Chris Craik        , mAmbientShadowAlpha(0)
81058fc640017c90120c599d378a4cbc55668b05b7Chris Craik        , mSpotShadowAlpha(0) {
82527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik    // *set* draw modifiers to be 0
83527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik    memset(&mDrawModifiers, 0, sizeof(mDrawModifiers));
8416ecda5317c40fc3da284952d9b3add34d6763aeChris Craik    mDrawModifiers.mOverrideLayerAlpha = 1.0f;
85026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy
86031888744e24b5c7243ac99ec98b78aff5db1c78Chris Craik    memcpy(mMeshVertices, kUnitQuadVertices, sizeof(kUnitQuadVertices));
87e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy}
88e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
8985bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain GuyOpenGLRenderer::~OpenGLRenderer() {
9029d8997bd43b7c4ad37fc3d6f91eaafa74913c88Romain Guy    // The context has already been destroyed at this point, do not call
9129d8997bd43b7c4ad37fc3d6f91eaafa74913c88Romain Guy    // GL APIs. All GL state should be kept in Caches.h
92e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy}
93e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy
9487e2f757be9b24d369bab354e37c276e851b1fc7Romain Guyvoid OpenGLRenderer::initProperties() {
9587e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy    char property[PROPERTY_VALUE_MAX];
9687e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy    if (property_get(PROPERTY_DISABLE_SCISSOR_OPTIMIZATION, property, "false")) {
9787e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy        mScissorOptimizationDisabled = !strcasecmp(property, "true");
9887e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy        INIT_LOGD("  Scissor optimization %s",
9987e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy                mScissorOptimizationDisabled ? "disabled" : "enabled");
10087e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy    } else {
10187e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy        INIT_LOGD("  Scissor optimization enabled");
10287e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy    }
10313631f3da855f200a151e7837ed9f6b079622b58Romain Guy}
10413631f3da855f200a151e7837ed9f6b079622b58Romain Guy
105058fc640017c90120c599d378a4cbc55668b05b7Chris Craikvoid OpenGLRenderer::initLight(const Vector3& lightCenter, float lightRadius,
106058fc640017c90120c599d378a4cbc55668b05b7Chris Craik        uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
107058fc640017c90120c599d378a4cbc55668b05b7Chris Craik    mLightCenter = lightCenter;
108058fc640017c90120c599d378a4cbc55668b05b7Chris Craik    mLightRadius = lightRadius;
109058fc640017c90120c599d378a4cbc55668b05b7Chris Craik    mAmbientShadowAlpha = ambientShadowAlpha;
110058fc640017c90120c599d378a4cbc55668b05b7Chris Craik    mSpotShadowAlpha = spotShadowAlpha;
111058fc640017c90120c599d378a4cbc55668b05b7Chris Craik}
112058fc640017c90120c599d378a4cbc55668b05b7Chris Craik
11313631f3da855f200a151e7837ed9f6b079622b58Romain Guy///////////////////////////////////////////////////////////////////////////////
114f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy// Setup
115f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy///////////////////////////////////////////////////////////////////////////////
116f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
117797b95b26bbb7557678af78b9a2a61830158920fChris Craikvoid OpenGLRenderer::onViewportInitialized() {
11835643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    glDisable(GL_DITHER);
11935643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
120284b24358410cb0200e525a5ba36994090c83f20Chris Craik    mFirstFrameAfterResize = true;
12135643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy}
12235643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy
12396885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guyvoid OpenGLRenderer::setupFrameState(float left, float top,
124c3fedafc5f50100219449125a000e3138f6fb987Romain Guy        float right, float bottom, bool opaque) {
125fe48f65922d4a3cc4aefe058cee5acec51504a20Romain Guy    mCaches.clearGarbage();
126984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    mState.initializeSaveStack(left, top, right, bottom, mLightCenter);
12796885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy    mOpaque = opaque;
1285f803623559aab395a29d575c37c4e39c23a4b4eChris Craik    mTilingClip.set(left, top, right, bottom);
12996885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy}
130ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy
131107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::startFrame() {
132107843de4507b3511006cb9c77b8d0364374385aTom Hudson    if (mFrameStarted) return;
13396885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy    mFrameStarted = true;
13411cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy
135984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    mState.setDirtyClip(true);
13696885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy
13796885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy    discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom);
13845e4c3df6c00ac98ff6144de9af574877d4fff19Romain Guy
139984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    mRenderState.setViewport(mState.getWidth(), mState.getHeight());
1407d7b5490a0b0763e831b31bc11f17d8159b5914aRomain Guy
14154c1a64d5441a964890b44280e4457e11f4f924aRomain Guy    // Functors break the tiling extension in pretty spectacular ways
14254c1a64d5441a964890b44280e4457e11f4f924aRomain Guy    // This ensures we don't use tiling when a functor is going to be
14354c1a64d5441a964890b44280e4457e11f4f924aRomain Guy    // invoked during the frame
144284b24358410cb0200e525a5ba36994090c83f20Chris Craik    mSuppressTiling = mCaches.hasRegisteredFunctors()
145284b24358410cb0200e525a5ba36994090c83f20Chris Craik            || mFirstFrameAfterResize;
146284b24358410cb0200e525a5ba36994090c83f20Chris Craik    mFirstFrameAfterResize = false;
14754c1a64d5441a964890b44280e4457e11f4f924aRomain Guy
148d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    startTilingCurrentClip(true);
1492b7028eabac80cec170572bc0e945a1d4224e595Romain Guy
1507c450aaa3caac2a05fcb20a177483d0e92378426Romain Guy    debugOverdraw(true, true);
1517c450aaa3caac2a05fcb20a177483d0e92378426Romain Guy
152107843de4507b3511006cb9c77b8d0364374385aTom Hudson    clear(mTilingClip.left, mTilingClip.top,
15396885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy            mTilingClip.right, mTilingClip.bottom, mOpaque);
15496885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy}
15596885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy
156107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::prepareDirty(float left, float top,
15796885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy        float right, float bottom, bool opaque) {
15878dd96d5af20f489f0e8b288617d57774ec284f7Romain Guy
15996885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy    setupFrameState(left, top, right, bottom, opaque);
16096885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy
16196885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy    // Layer renderers will start the frame immediately
16296885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy    // The framebuffer renderer will first defer the display list
16396885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy    // for each layer and wait until the first drawing command
16496885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy    // to start the frame
165d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    if (currentSnapshot()->fbo == 0) {
16644eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik        mRenderState.blend().syncEnabled();
16796885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy        updateLayers();
16896885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy    } else {
169107843de4507b3511006cb9c77b8d0364374385aTom Hudson        startFrame();
17096885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy    }
1717c25aab491707f7324f9941b8cfa9bd2b4b97e76Romain Guy}
1727c25aab491707f7324f9941b8cfa9bd2b4b97e76Romain Guy
173dcfc836b457a87881da409e1acf251515f121446Romain Guyvoid OpenGLRenderer::discardFramebuffer(float left, float top, float right, float bottom) {
174dcfc836b457a87881da409e1acf251515f121446Romain Guy    // If we know that we are going to redraw the entire framebuffer,
175dcfc836b457a87881da409e1acf251515f121446Romain Guy    // perform a discard to let the driver know we don't need to preserve
176dcfc836b457a87881da409e1acf251515f121446Romain Guy    // the back buffer for this frame.
177117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    if (mCaches.extensions().hasDiscardFramebuffer() &&
178984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson            left <= 0.0f && top <= 0.0f && right >= mState.getWidth() && bottom >= mState.getHeight()) {
179984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson        const bool isFbo = onGetTargetFbo() == 0;
180f158198ccc3a1f53bfebaa6b8f4426e80e1867eaRomain Guy        const GLenum attachments[] = {
181f158198ccc3a1f53bfebaa6b8f4426e80e1867eaRomain Guy                isFbo ? (const GLenum) GL_COLOR_EXT : (const GLenum) GL_COLOR_ATTACHMENT0,
182f158198ccc3a1f53bfebaa6b8f4426e80e1867eaRomain Guy                isFbo ? (const GLenum) GL_STENCIL_EXT : (const GLenum) GL_STENCIL_ATTACHMENT };
183dcfc836b457a87881da409e1acf251515f121446Romain Guy        glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, attachments);
184dcfc836b457a87881da409e1acf251515f121446Romain Guy    }
185dcfc836b457a87881da409e1acf251515f121446Romain Guy}
186dcfc836b457a87881da409e1acf251515f121446Romain Guy
187107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
18823d307c8d88f4a3849163b9e5b7cd11d0d4f372cJohn Reck    if (!opaque) {
18965fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik        mRenderState.scissor().setEnabled(true);
19065fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik        mRenderState.scissor().set(left, getViewportHeight() - bottom, right - left, bottom - top);
1916b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy        glClear(GL_COLOR_BUFFER_BIT);
192107843de4507b3511006cb9c77b8d0364374385aTom Hudson        mDirty = true;
193107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
194ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy    }
19544b2fe3fc114ee5f7273c6b0fee2cc999bf244a2Chet Haase
19665fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik    mRenderState.scissor().reset();
197ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy}
198ddf74373616c89e0880a28a2185fd7ce3db91de6Romain Guy
19933f5a59ac3e304970920dda824958870f85f76efhenry.uh_chenvoid OpenGLRenderer::startTilingCurrentClip(bool opaque, bool expand) {
20054c1a64d5441a964890b44280e4457e11f4f924aRomain Guy    if (!mSuppressTiling) {
201d6b65f67717025b1162f86f04e2caa5723566cacChris Craik        const Snapshot* snapshot = currentSnapshot();
202d6b65f67717025b1162f86f04e2caa5723566cacChris Craik
20314e513058ed4168c94e015638d16f5f87fd8063aChris Craik        const Rect* clip = &mTilingClip;
204d6b65f67717025b1162f86f04e2caa5723566cacChris Craik        if (snapshot->flags & Snapshot::kFlagFboTarget) {
205d6b65f67717025b1162f86f04e2caa5723566cacChris Craik            clip = &(snapshot->layer->clipRect);
20654c1a64d5441a964890b44280e4457e11f4f924aRomain Guy        }
20754c1a64d5441a964890b44280e4457e11f4f924aRomain Guy
20833f5a59ac3e304970920dda824958870f85f76efhenry.uh_chen        startTiling(*clip, getViewportHeight(), opaque, expand);
209c3fedafc5f50100219449125a000e3138f6fb987Romain Guy    }
210c3fedafc5f50100219449125a000e3138f6fb987Romain Guy}
211c3fedafc5f50100219449125a000e3138f6fb987Romain Guy
21233f5a59ac3e304970920dda824958870f85f76efhenry.uh_chenvoid OpenGLRenderer::startTiling(const Rect& clip, int windowHeight, bool opaque, bool expand) {
213c3fedafc5f50100219449125a000e3138f6fb987Romain Guy    if (!mSuppressTiling) {
21433f5a59ac3e304970920dda824958870f85f76efhenry.uh_chen        if(expand) {
21533f5a59ac3e304970920dda824958870f85f76efhenry.uh_chen            // Expand the startTiling region by 1
21633f5a59ac3e304970920dda824958870f85f76efhenry.uh_chen            int leftNotZero = (clip.left > 0) ? 1 : 0;
21733f5a59ac3e304970920dda824958870f85f76efhenry.uh_chen            int topNotZero = (windowHeight - clip.bottom > 0) ? 1 : 0;
21833f5a59ac3e304970920dda824958870f85f76efhenry.uh_chen
21933f5a59ac3e304970920dda824958870f85f76efhenry.uh_chen            mCaches.startTiling(
22033f5a59ac3e304970920dda824958870f85f76efhenry.uh_chen                clip.left - leftNotZero,
22133f5a59ac3e304970920dda824958870f85f76efhenry.uh_chen                windowHeight - clip.bottom - topNotZero,
22233f5a59ac3e304970920dda824958870f85f76efhenry.uh_chen                clip.right - clip.left + leftNotZero + 1,
22333f5a59ac3e304970920dda824958870f85f76efhenry.uh_chen                clip.bottom - clip.top + topNotZero + 1,
22433f5a59ac3e304970920dda824958870f85f76efhenry.uh_chen                opaque);
22533f5a59ac3e304970920dda824958870f85f76efhenry.uh_chen        } else {
22633f5a59ac3e304970920dda824958870f85f76efhenry.uh_chen            mCaches.startTiling(clip.left, windowHeight - clip.bottom,
22752036b19a5f82bc4d75cfcbff99c65df8d25a99bRomain Guy                clip.right - clip.left, clip.bottom - clip.top, opaque);
22833f5a59ac3e304970920dda824958870f85f76efhenry.uh_chen        }
2292b7028eabac80cec170572bc0e945a1d4224e595Romain Guy    }
2302b7028eabac80cec170572bc0e945a1d4224e595Romain Guy}
2312b7028eabac80cec170572bc0e945a1d4224e595Romain Guy
2322b7028eabac80cec170572bc0e945a1d4224e595Romain Guyvoid OpenGLRenderer::endTiling() {
23354c1a64d5441a964890b44280e4457e11f4f924aRomain Guy    if (!mSuppressTiling) mCaches.endTiling();
2342b7028eabac80cec170572bc0e945a1d4224e595Romain Guy}
2352b7028eabac80cec170572bc0e945a1d4224e595Romain Guy
236107843de4507b3511006cb9c77b8d0364374385aTom Hudsonbool OpenGLRenderer::finish() {
2377c450aaa3caac2a05fcb20a177483d0e92378426Romain Guy    renderOverdraw();
2382b7028eabac80cec170572bc0e945a1d4224e595Romain Guy    endTiling();
2394ac36f80beb958c77a92a3e1a235f6ed9daaa510Chris Craik    mTempPaths.clear();
2404ac36f80beb958c77a92a3e1a235f6ed9daaa510Chris Craik
241ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    // When finish() is invoked on FBO 0 we've reached the end
242ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    // of the current frame
243984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (onGetTargetFbo() == 0) {
244ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy        mCaches.pathCache.trim();
24505f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik        mCaches.tessellationCache.trim();
246ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy    }
247ca89e2a68703bd428e8b66547d033a6ed35b3595Romain Guy
24811cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy    if (!suppressErrorChecks()) {
249b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy#if DEBUG_OPENGL
250e4aa95e3627226bcb0d8cc3e42dca6e4df8f421cChris Craik        GLUtils::dumpGLErrors();
251b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy#endif
25211cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy
253c15008e72ec00ca20a271c3006dac649fd07533bRomain Guy#if DEBUG_MEMORY_USAGE
254e190aa69756aecfaffabdd4c6d32cb6b3220d842Romain Guy        mCaches.dumpMemoryUsage();
25511cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy#else
25611cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy        if (mCaches.getDebugLevel() & kDebugMemory) {
25711cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy            mCaches.dumpMemoryUsage();
25811cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy        }
259c15008e72ec00ca20a271c3006dac649fd07533bRomain Guy#endif
26011cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy    }
26196885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy
26296885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy    mFrameStarted = false;
263107843de4507b3511006cb9c77b8d0364374385aTom Hudson
264107843de4507b3511006cb9c77b8d0364374385aTom Hudson    return reportAndClearDirty();
265b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy}
266b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy
26735643ddc689913f5b5f80ceed864470d987bd6cdRomain Guyvoid OpenGLRenderer::resumeAfterLayer() {
2683b20251a355c88193c439f928a84ae69483fb488John Reck    mRenderState.setViewport(getViewportWidth(), getViewportHeight());
2693b20251a355c88193c439f928a84ae69483fb488John Reck    mRenderState.bindFramebuffer(currentSnapshot()->fbo);
2707c450aaa3caac2a05fcb20a177483d0e92378426Romain Guy    debugOverdraw(true, false);
27135643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy
27265fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik    mRenderState.scissor().reset();
27335643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    dirtyClip();
27435643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy}
27535643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy
27664bb413a664001c95c8439cf097dc3033f4ed733Andreas Gampevoid OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
277984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored()) return;
278408eb12631376cbdc96803e918decf6ea804d346Chris Craik
279487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    Rect clip(mState.currentClipRect());
28080911b851764b073310fd0bffdf4a7db0d8fdd0bRomain Guy    clip.snapToPixelBoundaries();
28180911b851764b073310fd0bffdf4a7db0d8fdd0bRomain Guy
282d643bb56fdf21973ea75984f0816b7dc024698dfRomain Guy    // Since we don't know what the functor will draw, let's dirty
283d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    // the entire clip region
284d643bb56fdf21973ea75984f0816b7dc024698dfRomain Guy    if (hasLayer()) {
285d643bb56fdf21973ea75984f0816b7dc024698dfRomain Guy        dirtyLayerUnchecked(clip, getRegion());
286d643bb56fdf21973ea75984f0816b7dc024698dfRomain Guy    }
287d643bb56fdf21973ea75984f0816b7dc024698dfRomain Guy
28808aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy    DrawGlInfo info;
28908aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy    info.clipLeft = clip.left;
29008aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy    info.clipTop = clip.top;
29108aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy    info.clipRight = clip.right;
29208aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy    info.clipBottom = clip.bottom;
29308aa2cbd5e62e7ca140f78f8bea0477a19880fd9Romain Guy    info.isLayer = hasLayer();
294a64a2bef1048db5a742843f1e3bea9e80d0defc5Chris Craik    info.width = getViewportWidth();
295a64a2bef1048db5a742843f1e3bea9e80d0defc5Chris Craik    info.height = getViewportHeight();
296d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    currentTransform()->copyTo(&info.transform[0]);
29780911b851764b073310fd0bffdf4a7db0d8fdd0bRomain Guy
298984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    bool prevDirtyClip = mState.getDirtyClip();
29954f574acf4dd5483170b8f79e2f7c70b58763ce7Chris Craik    // setup GL state for functor
300984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.getDirtyClip()) {
30154f574acf4dd5483170b8f79e2f7c70b58763ce7Chris Craik        setStencilFromClip(); // can issue draws, so must precede enableScissor()/interrupt()
30254f574acf4dd5483170b8f79e2f7c70b58763ce7Chris Craik    }
30365fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik    if (mRenderState.scissor().setEnabled(true) || prevDirtyClip) {
30425d2f7bc1ff9b475eff75bfff647466e91dbacb2John Reck        setScissorFromClip();
30525d2f7bc1ff9b475eff75bfff647466e91dbacb2John Reck    }
30654f574acf4dd5483170b8f79e2f7c70b58763ce7Chris Craik
3073b20251a355c88193c439f928a84ae69483fb488John Reck    mRenderState.invokeFunctor(functor, DrawGlInfo::kModeDraw, &info);
3083b20251a355c88193c439f928a84ae69483fb488John Reck    // Scissor may have been modified, reset dirty clip
3093b20251a355c88193c439f928a84ae69483fb488John Reck    dirtyClip();
310cabfcc1364eb7e4de0b15b3574fba45027b45cfcRomain Guy
311107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
312daf98e941e140e8739458126640183b9f296a2abChet Haase}
313daf98e941e140e8739458126640183b9f296a2abChet Haase
314f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy///////////////////////////////////////////////////////////////////////////////
31587e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy// Debug
31687e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy///////////////////////////////////////////////////////////////////////////////
31787e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy
31862d307c2402777d5e53b4590af5f32f8c55afd81Chris Craikvoid OpenGLRenderer::eventMarkDEBUG(const char* fmt, ...) const {
31962d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik#if DEBUG_DETAILED_EVENTS
32062d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik    const int BUFFER_SIZE = 256;
32162d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik    va_list ap;
32262d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik    char buf[BUFFER_SIZE];
32362d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik
32462d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik    va_start(ap, fmt);
32562d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik    vsnprintf(buf, BUFFER_SIZE, fmt, ap);
32662d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik    va_end(ap);
32762d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik
32862d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik    eventMark(buf);
32962d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik#endif
33062d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik}
33162d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik
33262d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik
3330f6675332c04c74909425d1d328f02b32c0ff40eRomain Guyvoid OpenGLRenderer::eventMark(const char* name) const {
3340f6675332c04c74909425d1d328f02b32c0ff40eRomain Guy    mCaches.eventMark(0, name);
3350f6675332c04c74909425d1d328f02b32c0ff40eRomain Guy}
3360f6675332c04c74909425d1d328f02b32c0ff40eRomain Guy
33787e2f757be9b24d369bab354e37c276e851b1fc7Romain Guyvoid OpenGLRenderer::startMark(const char* name) const {
33887e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy    mCaches.startMark(0, name);
33987e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy}
34087e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy
34187e2f757be9b24d369bab354e37c276e851b1fc7Romain Guyvoid OpenGLRenderer::endMark() const {
34287e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy    mCaches.endMark();
34387e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy}
34487e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy
34587e2f757be9b24d369bab354e37c276e851b1fc7Romain Guyvoid OpenGLRenderer::debugOverdraw(bool enable, bool clear) {
3463b20251a355c88193c439f928a84ae69483fb488John Reck    mRenderState.debugOverdraw(enable, clear);
34787e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy}
34887e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy
34987e2f757be9b24d369bab354e37c276e851b1fc7Romain Guyvoid OpenGLRenderer::renderOverdraw() {
350984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mCaches.debugOverdraw && onGetTargetFbo() == 0) {
3515f803623559aab395a29d575c37c4e39c23a4b4eChris Craik        const Rect* clip = &mTilingClip;
35287e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy
35365fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik        mRenderState.scissor().setEnabled(true);
35465fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik        mRenderState.scissor().set(clip->left,
35565fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik                mState.firstSnapshot()->getViewportHeight() - clip->bottom,
35665fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik                clip->right - clip->left,
35765fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik                clip->bottom - clip->top);
35887e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy
359627c6fd91377ead85f74a365438e25610ef1e2eeRomain Guy        // 1x overdraw
36096a5c4c7bab6718524de7253da8309143ab48befChris Craik        mRenderState.stencil().enableDebugTest(2);
361627c6fd91377ead85f74a365438e25610ef1e2eeRomain Guy        drawColor(mCaches.getOverdrawColor(1), SkXfermode::kSrcOver_Mode);
362627c6fd91377ead85f74a365438e25610ef1e2eeRomain Guy
363627c6fd91377ead85f74a365438e25610ef1e2eeRomain Guy        // 2x overdraw
36496a5c4c7bab6718524de7253da8309143ab48befChris Craik        mRenderState.stencil().enableDebugTest(3);
365627c6fd91377ead85f74a365438e25610ef1e2eeRomain Guy        drawColor(mCaches.getOverdrawColor(2), SkXfermode::kSrcOver_Mode);
366627c6fd91377ead85f74a365438e25610ef1e2eeRomain Guy
367627c6fd91377ead85f74a365438e25610ef1e2eeRomain Guy        // 3x overdraw
36896a5c4c7bab6718524de7253da8309143ab48befChris Craik        mRenderState.stencil().enableDebugTest(4);
369627c6fd91377ead85f74a365438e25610ef1e2eeRomain Guy        drawColor(mCaches.getOverdrawColor(3), SkXfermode::kSrcOver_Mode);
370627c6fd91377ead85f74a365438e25610ef1e2eeRomain Guy
371627c6fd91377ead85f74a365438e25610ef1e2eeRomain Guy        // 4x overdraw and higher
37296a5c4c7bab6718524de7253da8309143ab48befChris Craik        mRenderState.stencil().enableDebugTest(4, true);
373627c6fd91377ead85f74a365438e25610ef1e2eeRomain Guy        drawColor(mCaches.getOverdrawColor(4), SkXfermode::kSrcOver_Mode);
374627c6fd91377ead85f74a365438e25610ef1e2eeRomain Guy
37596a5c4c7bab6718524de7253da8309143ab48befChris Craik        mRenderState.stencil().disable();
37687e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy    }
37787e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy}
37887e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy
37987e2f757be9b24d369bab354e37c276e851b1fc7Romain Guy///////////////////////////////////////////////////////////////////////////////
38011cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy// Layers
38111cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy///////////////////////////////////////////////////////////////////////////////
38211cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy
38311cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guybool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {
384a7090e0cfd7c719a6d4c03aae34f5db98754cbddChris Craik    if (layer->deferredUpdateScheduled && layer->renderer
385a7090e0cfd7c719a6d4c03aae34f5db98754cbddChris Craik            && layer->renderNode.get() && layer->renderNode->isRenderable()) {
386405436021da156fbe3c5d4de48bdefa564cf7fc0Romain Guy
3877c450aaa3caac2a05fcb20a177483d0e92378426Romain Guy        if (inFrame) {
3887c450aaa3caac2a05fcb20a177483d0e92378426Romain Guy            endTiling();
3897c450aaa3caac2a05fcb20a177483d0e92378426Romain Guy            debugOverdraw(false, false);
3907c450aaa3caac2a05fcb20a177483d0e92378426Romain Guy        }
39111cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy
39296885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy        if (CC_UNLIKELY(inFrame || mCaches.drawDeferDisabled)) {
39369e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik            layer->render(*this);
39496885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy        } else {
39569e5adffb19135d51bde8e458f4907d7265f3e23Chris Craik            layer->defer(*this);
39696885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy        }
39711cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy
39811cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy        if (inFrame) {
39911cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy            resumeAfterLayer();
400d6b65f67717025b1162f86f04e2caa5723566cacChris Craik            startTilingCurrentClip();
40111cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy        }
40211cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy
4035bb3c730f5ebd2a0db1b02a8981c6fdbea6c1a2eRomain Guy        layer->debugDrawUpdate = mCaches.debugLayersUpdates;
40434416eaa1c07b3d7a139e780cea8f8d73219650eChris Craik        layer->hasDrawnSinceUpdate = false;
40511cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy
40611cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy        return true;
40711cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy    }
40811cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy
40911cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy    return false;
41011cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy}
41111cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy
41211cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guyvoid OpenGLRenderer::updateLayers() {
41396885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy    // If draw deferring is enabled this method will simply defer
41496885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy    // the display list of each individual layer. The layers remain
41596885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy    // in the layer updates list which will be cleared by flushLayers().
41611cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy    int count = mLayerUpdates.size();
41711cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy    if (count > 0) {
41896885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy        if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
41996885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy            startMark("Layer Updates");
42096885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy        } else {
42196885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy            startMark("Defer Layer Updates");
42296885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy        }
42311cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy
4241206b9bba91f7ed899c5c87427cce725fe5aadfcChris Craik        // Note: it is very important to update the layers in order
4251206b9bba91f7ed899c5c87427cce725fe5aadfcChris Craik        for (int i = 0; i < count; i++) {
4260e89e2b7bcb2c035e8cee77f93120e7c5617f8d2John Reck            Layer* layer = mLayerUpdates.itemAt(i).get();
42711cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy            updateLayer(layer, false);
42811cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy        }
42911cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy
43096885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy        if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
43196885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy            mLayerUpdates.clear();
432984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson            mRenderState.bindFramebuffer(onGetTargetFbo());
43396885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy        }
43496885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy        endMark();
43596885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy    }
43696885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy}
43796885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy
43896885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guyvoid OpenGLRenderer::flushLayers() {
43996885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy    int count = mLayerUpdates.size();
44096885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy    if (count > 0) {
44196885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy        startMark("Apply Layer Updates");
44296885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy
4431206b9bba91f7ed899c5c87427cce725fe5aadfcChris Craik        // Note: it is very important to update the layers in order
4441206b9bba91f7ed899c5c87427cce725fe5aadfcChris Craik        for (int i = 0; i < count; i++) {
44570850ea258cbf91477efa57a1f1a23cc0044cc93Chris Craik            mLayerUpdates.itemAt(i)->flush();
44696885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy        }
44796885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy
44896885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy        mLayerUpdates.clear();
449984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson        mRenderState.bindFramebuffer(onGetTargetFbo());
45096885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy
45111cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy        endMark();
45211cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy    }
45311cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy}
45411cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy
45511cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guyvoid OpenGLRenderer::pushLayerUpdate(Layer* layer) {
45611cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy    if (layer) {
45702b49b70ede0b9eb760ff334823aee1d9520ed85Romain Guy        // Make sure we don't introduce duplicates.
45802b49b70ede0b9eb760ff334823aee1d9520ed85Romain Guy        // SortedVector would do this automatically but we need to respect
45902b49b70ede0b9eb760ff334823aee1d9520ed85Romain Guy        // the insertion order. The linear search is not an issue since
46002b49b70ede0b9eb760ff334823aee1d9520ed85Romain Guy        // this list is usually very short (typically one item, at most a few)
46102b49b70ede0b9eb760ff334823aee1d9520ed85Romain Guy        for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
46202b49b70ede0b9eb760ff334823aee1d9520ed85Romain Guy            if (mLayerUpdates.itemAt(i) == layer) {
46302b49b70ede0b9eb760ff334823aee1d9520ed85Romain Guy                return;
46402b49b70ede0b9eb760ff334823aee1d9520ed85Romain Guy            }
46502b49b70ede0b9eb760ff334823aee1d9520ed85Romain Guy        }
46611cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy        mLayerUpdates.push_back(layer);
46711cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy    }
46811cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy}
46911cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy
470e93482f5eac3df581d57e64c2a771a96aa868585Romain Guyvoid OpenGLRenderer::cancelLayerUpdate(Layer* layer) {
471e93482f5eac3df581d57e64c2a771a96aa868585Romain Guy    if (layer) {
472e93482f5eac3df581d57e64c2a771a96aa868585Romain Guy        for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
473e93482f5eac3df581d57e64c2a771a96aa868585Romain Guy            if (mLayerUpdates.itemAt(i) == layer) {
474e93482f5eac3df581d57e64c2a771a96aa868585Romain Guy                mLayerUpdates.removeAt(i);
475e93482f5eac3df581d57e64c2a771a96aa868585Romain Guy                break;
476e93482f5eac3df581d57e64c2a771a96aa868585Romain Guy            }
477e93482f5eac3df581d57e64c2a771a96aa868585Romain Guy        }
478e93482f5eac3df581d57e64c2a771a96aa868585Romain Guy    }
479e93482f5eac3df581d57e64c2a771a96aa868585Romain Guy}
480e93482f5eac3df581d57e64c2a771a96aa868585Romain Guy
481405436021da156fbe3c5d4de48bdefa564cf7fc0Romain Guyvoid OpenGLRenderer::flushLayerUpdates() {
48270850ea258cbf91477efa57a1f1a23cc0044cc93Chris Craik    ATRACE_NAME("Update HW Layers");
48344eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik    mRenderState.blend().syncEnabled();
484405436021da156fbe3c5d4de48bdefa564cf7fc0Romain Guy    updateLayers();
485405436021da156fbe3c5d4de48bdefa564cf7fc0Romain Guy    flushLayers();
486405436021da156fbe3c5d4de48bdefa564cf7fc0Romain Guy    // Wait for all the layer updates to be executed
4875515637540bedd8fc9a1a6e46a4b512dd45520a5John Reck    glFinish();
488405436021da156fbe3c5d4de48bdefa564cf7fc0Romain Guy}
489405436021da156fbe3c5d4de48bdefa564cf7fc0Romain Guy
490443a714fa7c0dd07fee3527cc5bc3d3ca1fb7d44John Reckvoid OpenGLRenderer::markLayersAsBuildLayers() {
491443a714fa7c0dd07fee3527cc5bc3d3ca1fb7d44John Reck    for (size_t i = 0; i < mLayerUpdates.size(); i++) {
492443a714fa7c0dd07fee3527cc5bc3d3ca1fb7d44John Reck        mLayerUpdates[i]->wasBuildLayered = true;
493443a714fa7c0dd07fee3527cc5bc3d3ca1fb7d44John Reck    }
494443a714fa7c0dd07fee3527cc5bc3d3ca1fb7d44John Reck}
495443a714fa7c0dd07fee3527cc5bc3d3ca1fb7d44John Reck
49611cb642756093a4af901b1525375b1eb2b5c3e2bRomain Guy///////////////////////////////////////////////////////////////////////////////
497f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy// State management
498f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy///////////////////////////////////////////////////////////////////////////////
499f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
50014e513058ed4168c94e015638d16f5f87fd8063aChris Craikvoid OpenGLRenderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
501a64a2bef1048db5a742843f1e3bea9e80d0defc5Chris Craik    bool restoreViewport = removed.flags & Snapshot::kFlagIsFboLayer;
50214e513058ed4168c94e015638d16f5f87fd8063aChris Craik    bool restoreClip = removed.flags & Snapshot::kFlagClipSet;
50314e513058ed4168c94e015638d16f5f87fd8063aChris Craik    bool restoreLayer = removed.flags & Snapshot::kFlagIsLayer;
504bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
505a64a2bef1048db5a742843f1e3bea9e80d0defc5Chris Craik    if (restoreViewport) {
5063b20251a355c88193c439f928a84ae69483fb488John Reck        mRenderState.setViewport(getViewportWidth(), getViewportHeight());
507eb99356a0548684a501766e6a524529ab93304c8Romain Guy    }
508eb99356a0548684a501766e6a524529ab93304c8Romain Guy
5092542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy    if (restoreClip) {
510746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy        dirtyClip();
5118fb954263dd2f918ad339045cc6d82e346515599Romain Guy    }
5122542d199745cdf3ec910b8e3e4cff5851ed24e9bRomain Guy
5135ec9924d24495822b589f1a17996655d66273b30Romain Guy    if (restoreLayer) {
5147273daace9303f4662444111c40bb83d3ead4a92Chris Craik        endMark(); // Savelayer
515a8bea8edde2f20cae48e5cc8de782679306b3cc3Chris Craik        ATRACE_END(); // SaveLayer
5167273daace9303f4662444111c40bb83d3ead4a92Chris Craik        startMark("ComposeLayer");
51714e513058ed4168c94e015638d16f5f87fd8063aChris Craik        composeLayer(removed, restored);
5187273daace9303f4662444111c40bb83d3ead4a92Chris Craik        endMark();
5195ec9924d24495822b589f1a17996655d66273b30Romain Guy    }
520d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy}
5215cbbce535744b89df5ecea95de21ee3733298260Romain Guy
522f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy///////////////////////////////////////////////////////////////////////////////
523bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy// Layers
524bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy///////////////////////////////////////////////////////////////////////////////
525bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
526bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guyint OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
5273f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        const SkPaint* paint, int flags, const SkPath* convexMask) {
5284ace7305608442ab35ea9aa65a4220df152c187fChris Craik    // force matrix/clip isolation for layer
5294ace7305608442ab35ea9aa65a4220df152c187fChris Craik    flags |= SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag;
5304ace7305608442ab35ea9aa65a4220df152c187fChris Craik
531984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    const int count = mState.saveSnapshot(flags);
532d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy
533984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (!mState.currentlyIgnored()) {
5343f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        createLayer(left, top, right, bottom, paint, flags, convexMask);
535dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy    }
536d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy
537d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy    return count;
538bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy}
539bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
540d90144db52c7297879b950cbbc85137ed123ab5bChris Craikvoid OpenGLRenderer::calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool fboLayer) {
541d90144db52c7297879b950cbbc85137ed123ab5bChris Craik    const Rect untransformedBounds(bounds);
542d90144db52c7297879b950cbbc85137ed123ab5bChris Craik
543d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    currentTransform()->mapRect(bounds);
544d90144db52c7297879b950cbbc85137ed123ab5bChris Craik
545d90144db52c7297879b950cbbc85137ed123ab5bChris Craik    // Layers only make sense if they are in the framebuffer's bounds
546487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    if (bounds.intersect(mState.currentClipRect())) {
547d90144db52c7297879b950cbbc85137ed123ab5bChris Craik        // We cannot work with sub-pixels in this case
548d90144db52c7297879b950cbbc85137ed123ab5bChris Craik        bounds.snapToPixelBoundaries();
549d90144db52c7297879b950cbbc85137ed123ab5bChris Craik
550d90144db52c7297879b950cbbc85137ed123ab5bChris Craik        // When the layer is not an FBO, we may use glCopyTexImage so we
551d90144db52c7297879b950cbbc85137ed123ab5bChris Craik        // need to make sure the layer does not extend outside the bounds
552d90144db52c7297879b950cbbc85137ed123ab5bChris Craik        // of the framebuffer
553924197513aa2df4c1fb2977c1727f5d2c21f2689Chris Craik        const Snapshot& previous = *(currentSnapshot()->previous);
554924197513aa2df4c1fb2977c1727f5d2c21f2689Chris Craik        Rect previousViewport(0, 0, previous.getViewportWidth(), previous.getViewportHeight());
555924197513aa2df4c1fb2977c1727f5d2c21f2689Chris Craik        if (!bounds.intersect(previousViewport)) {
556d90144db52c7297879b950cbbc85137ed123ab5bChris Craik            bounds.setEmpty();
557d90144db52c7297879b950cbbc85137ed123ab5bChris Craik        } else if (fboLayer) {
558d90144db52c7297879b950cbbc85137ed123ab5bChris Craik            clip.set(bounds);
559d90144db52c7297879b950cbbc85137ed123ab5bChris Craik            mat4 inverse;
560d6b65f67717025b1162f86f04e2caa5723566cacChris Craik            inverse.loadInverse(*currentTransform());
561d90144db52c7297879b950cbbc85137ed123ab5bChris Craik            inverse.mapRect(clip);
562d90144db52c7297879b950cbbc85137ed123ab5bChris Craik            clip.snapToPixelBoundaries();
563d90144db52c7297879b950cbbc85137ed123ab5bChris Craik            if (clip.intersect(untransformedBounds)) {
564d90144db52c7297879b950cbbc85137ed123ab5bChris Craik                clip.translate(-untransformedBounds.left, -untransformedBounds.top);
565d90144db52c7297879b950cbbc85137ed123ab5bChris Craik                bounds.set(untransformedBounds);
566d90144db52c7297879b950cbbc85137ed123ab5bChris Craik            } else {
567d90144db52c7297879b950cbbc85137ed123ab5bChris Craik                clip.setEmpty();
568d90144db52c7297879b950cbbc85137ed123ab5bChris Craik            }
569d90144db52c7297879b950cbbc85137ed123ab5bChris Craik        }
570d90144db52c7297879b950cbbc85137ed123ab5bChris Craik    } else {
571d90144db52c7297879b950cbbc85137ed123ab5bChris Craik        bounds.setEmpty();
572d90144db52c7297879b950cbbc85137ed123ab5bChris Craik    }
573d90144db52c7297879b950cbbc85137ed123ab5bChris Craik}
574d90144db52c7297879b950cbbc85137ed123ab5bChris Craik
575408eb12631376cbdc96803e918decf6ea804d346Chris Craikvoid OpenGLRenderer::updateSnapshotIgnoreForLayer(const Rect& bounds, const Rect& clip,
576408eb12631376cbdc96803e918decf6ea804d346Chris Craik        bool fboLayer, int alpha) {
577408eb12631376cbdc96803e918decf6ea804d346Chris Craik    if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize ||
578408eb12631376cbdc96803e918decf6ea804d346Chris Craik            bounds.getHeight() > mCaches.maxTextureSize ||
579408eb12631376cbdc96803e918decf6ea804d346Chris Craik            (fboLayer && clip.isEmpty())) {
580984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson        writableSnapshot()->empty = fboLayer;
581408eb12631376cbdc96803e918decf6ea804d346Chris Craik    } else {
582984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson        writableSnapshot()->invisible = writableSnapshot()->invisible || (alpha <= 0 && fboLayer);
583408eb12631376cbdc96803e918decf6ea804d346Chris Craik    }
584408eb12631376cbdc96803e918decf6ea804d346Chris Craik}
585408eb12631376cbdc96803e918decf6ea804d346Chris Craik
586d90144db52c7297879b950cbbc85137ed123ab5bChris Craikint OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float bottom,
587d44fbe55a9f434cb5bb0e34c143ba1445141990dDerek Sollenberger        const SkPaint* paint, int flags) {
588984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    const int count = mState.saveSnapshot(flags);
589d90144db52c7297879b950cbbc85137ed123ab5bChris Craik
590984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (!mState.currentlyIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) {
591d90144db52c7297879b950cbbc85137ed123ab5bChris Craik        // initialize the snapshot as though it almost represents an FBO layer so deferred draw
592d90144db52c7297879b950cbbc85137ed123ab5bChris Craik        // operations will be able to store and restore the current clip and transform info, and
593d90144db52c7297879b950cbbc85137ed123ab5bChris Craik        // quick rejection will be correct (for display lists)
594d90144db52c7297879b950cbbc85137ed123ab5bChris Craik
595d90144db52c7297879b950cbbc85137ed123ab5bChris Craik        Rect bounds(left, top, right, bottom);
596d90144db52c7297879b950cbbc85137ed123ab5bChris Craik        Rect clip;
597d90144db52c7297879b950cbbc85137ed123ab5bChris Craik        calculateLayerBoundsAndClip(bounds, clip, true);
598d44fbe55a9f434cb5bb0e34c143ba1445141990dDerek Sollenberger        updateSnapshotIgnoreForLayer(bounds, clip, true, getAlphaDirect(paint));
599d90144db52c7297879b950cbbc85137ed123ab5bChris Craik
600984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson        if (!mState.currentlyIgnored()) {
601984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson            writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f);
602984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson            writableSnapshot()->resetClip(clip.left, clip.top, clip.right, clip.bottom);
603984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson            writableSnapshot()->initializeViewport(bounds.getWidth(), bounds.getHeight());
604e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik            writableSnapshot()->roundRectClipState = nullptr;
605d90144db52c7297879b950cbbc85137ed123ab5bChris Craik        }
606d90144db52c7297879b950cbbc85137ed123ab5bChris Craik    }
607d90144db52c7297879b950cbbc85137ed123ab5bChris Craik
608d90144db52c7297879b950cbbc85137ed123ab5bChris Craik    return count;
609d90144db52c7297879b950cbbc85137ed123ab5bChris Craik}
610d90144db52c7297879b950cbbc85137ed123ab5bChris Craik
6111c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy/**
6121c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * Layers are viewed by Skia are slightly different than layers in image editing
6131c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * programs (for instance.) When a layer is created, previously created layers
6141c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * and the frame buffer still receive every drawing command. For instance, if a
6151c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * layer is created and a shape intersecting the bounds of the layers and the
6161c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * framebuffer is draw, the shape will be drawn on both (unless the layer was
6171c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * created with the SkCanvas::kClipToLayer_SaveFlag flag.)
6181c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy *
6191c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * A way to implement layers is to create an FBO for each layer, backed by an RGBA
6201c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * texture. Unfortunately, this is inefficient as it requires every primitive to
6211c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * be drawn n + 1 times, where n is the number of active layers. In practice this
6221c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * means, for every primitive:
6231c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy *   - Switch active frame buffer
6241c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy *   - Change viewport, clip and projection matrix
6251c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy *   - Issue the drawing
6261c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy *
6271c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * Switching rendering target n + 1 times per drawn primitive is extremely costly.
6286b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy * To avoid this, layers are implemented in a different way here, at least in the
6296b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy * general case. FBOs are used, as an optimization, when the "clip to layer" flag
6306b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy * is set. When this flag is set we can redirect all drawing operations into a
6316b7bd24659fb175fe1f0e97c86c18969918b496aRomain Guy * single FBO.
6321c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy *
6331c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * This implementation relies on the frame buffer being at least RGBA 8888. When
6341c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * a layer is created, only a texture is created, not an FBO. The content of the
6351c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * frame buffer contained within the layer's bounds is copied into this texture
63687a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy * using glCopyTexImage2D(). The layer's region is then cleared(1) in the frame
6371c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * buffer and drawing continues as normal. This technique therefore treats the
6381c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * frame buffer as a scratch buffer for the layers.
6391c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy *
6401c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * To compose the layers back onto the frame buffer, each layer texture
6411c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * (containing the original frame buffer data) is drawn as a simple quad over
6421c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * the frame buffer. The trick is that the quad is set as the composition
6431c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * destination in the blending equation, and the frame buffer becomes the source
6441c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * of the composition.
6451c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy *
6461c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * Drawing layers with an alpha value requires an extra step before composition.
6471c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * An empty quad is drawn over the layer's region in the frame buffer. This quad
6481c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * is drawn with the rgba color (0,0,0,alpha). The alpha value offered by the
6491c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * quad is used to multiply the colors in the frame buffer. This is achieved by
6501c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * changing the GL blend functions for the GL_FUNC_ADD blend equation to
6511c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * GL_ZERO, GL_SRC_ALPHA.
6521c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy *
6531c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * Because glCopyTexImage2D() can be slow, an alternative implementation might
6541c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * be use to draw a single clipped layer. The implementation described above
6551c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * is correct in every case.
65687a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy *
65787a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy * (1) The frame buffer is actually not cleared right away. To allow the GPU
65887a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy *     to potentially optimize series of calls to glCopyTexImage2D, the frame
65987a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy *     buffer is left untouched until the first drawing operation. Only when
66087a76578f76f4a6bceb187da6b7a01899ca0d85aRomain Guy *     something actually gets drawn are the layers regions cleared.
6611c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy */
662d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haasebool OpenGLRenderer::createLayer(float left, float top, float right, float bottom,
6633f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        const SkPaint* paint, int flags, const SkPath* convexMask) {
66407adacf4996c8ca494332ec938786fa15832c722Chris Craik    LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top);
66507adacf4996c8ca494332ec938786fa15832c722Chris Craik    LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
666dda570201ac851dd85af3861f7e575721d3345daRomain Guy
667eb99356a0548684a501766e6a524529ab93304c8Romain Guy    const bool fboLayer = flags & SkCanvas::kClipToLayer_SaveFlag;
668eb99356a0548684a501766e6a524529ab93304c8Romain Guy
669f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy    // Window coordinates of the layer
670d48885a6c8cd27a8a62552c33b5282e9882e19f6Chet Haase    Rect clip;
6718aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    Rect bounds(left, top, right, bottom);
672d90144db52c7297879b950cbbc85137ed123ab5bChris Craik    calculateLayerBoundsAndClip(bounds, clip, fboLayer);
673674554fc36932ca50b15bba41ac6f650254d4e72Derek Sollenberger    updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, getAlphaDirect(paint));
674dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy
675dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy    // Bail out if we won't draw in this snapshot
676984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored()) {
677b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy        return false;
678b025b9c8b4efefadb01937db61a1f8ee7d2452bfRomain Guy    }
679dda570201ac851dd85af3861f7e575721d3345daRomain Guy
68044eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik    mCaches.textureState().activateTexture(0);
6813b20251a355c88193c439f928a84ae69483fb488John Reck    Layer* layer = mCaches.layerCache.get(mRenderState, bounds.getWidth(), bounds.getHeight());
682f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy    if (!layer) {
683f18fd99b5c182329cd8936a9611f0103d8ece44aRomain Guy        return false;
684bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy    }
685bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
686674554fc36932ca50b15bba41ac6f650254d4e72Derek Sollenberger    layer->setPaint(paint);
6878aef54fa17f2a3753d9a8f2027629bc480088f69Romain Guy    layer->layer.set(bounds);
6889ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy    layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()),
6899ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy            bounds.getWidth() / float(layer->getWidth()), 0.0f);
690d44fbe55a9f434cb5bb0e34c143ba1445141990dDerek Sollenberger
691a23eed808a1ae4ec0d818c0a9238385e797fd056Chet Haase    layer->setBlend(true);
6927c25aab491707f7324f9941b8cfa9bd2b4b97e76Romain Guy    layer->setDirty(false);
6933f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    layer->setConvexMask(convexMask); // note: the mask must be cleared before returning to the cache
694dda570201ac851dd85af3861f7e575721d3345daRomain Guy
6958fb954263dd2f918ad339045cc6d82e346515599Romain Guy    // Save the layer in the snapshot
696984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    writableSnapshot()->flags |= Snapshot::kFlagIsLayer;
697984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    writableSnapshot()->layer = layer;
6981d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy
699a8bea8edde2f20cae48e5cc8de782679306b3cc3Chris Craik    ATRACE_FORMAT_BEGIN("%ssaveLayer %ux%u",
700a8bea8edde2f20cae48e5cc8de782679306b3cc3Chris Craik            fboLayer ? "" : "unclipped ",
701a8bea8edde2f20cae48e5cc8de782679306b3cc3Chris Craik            layer->getWidth(), layer->getHeight());
7027273daace9303f4662444111c40bb83d3ead4a92Chris Craik    startMark("SaveLayer");
703eb99356a0548684a501766e6a524529ab93304c8Romain Guy    if (fboLayer) {
704e63f7c622a2086aefa80983c6f41b74fb166bb42Chris Craik        return createFboLayer(layer, bounds, clip);
705eb99356a0548684a501766e6a524529ab93304c8Romain Guy    } else {
706eb99356a0548684a501766e6a524529ab93304c8Romain Guy        // Copy the framebuffer into the layer
7079ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        layer->bindTexture();
708514fb18827186591d66973c2362c859b64b63556Romain Guy        if (!bounds.isEmpty()) {
7099ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy            if (layer->isEmpty()) {
710b254c242d98f4a9d98055726446351e52bece2c6Romain Guy                // Workaround for some GL drivers. When reading pixels lying outside
711b254c242d98f4a9d98055726446351e52bece2c6Romain Guy                // of the window we should get undefined values for those pixels.
712b254c242d98f4a9d98055726446351e52bece2c6Romain Guy                // Unfortunately some drivers will turn the entire target texture black
713b254c242d98f4a9d98055726446351e52bece2c6Romain Guy                // when reading outside of the window.
714b254c242d98f4a9d98055726446351e52bece2c6Romain Guy                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->getWidth(), layer->getHeight(),
715e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik                        0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
7169ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy                layer->setEmpty(false);
717514fb18827186591d66973c2362c859b64b63556Romain Guy            }
7187b5b6abf852c039983eded25ebe43a70fef5a4abRomain Guy
719a64a2bef1048db5a742843f1e3bea9e80d0defc5Chris Craik            glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
720a64a2bef1048db5a742843f1e3bea9e80d0defc5Chris Craik                    bounds.left, getViewportHeight() - bounds.bottom,
721a64a2bef1048db5a742843f1e3bea9e80d0defc5Chris Craik                    bounds.getWidth(), bounds.getHeight());
722b254c242d98f4a9d98055726446351e52bece2c6Romain Guy
72354be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy            // Enqueue the buffer coordinates to clear the corresponding region later
72451d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik            mLayers.push_back(Rect(bounds));
725ae88e5e8e9cb6c9539314c4360c5b20f8ec1fefcRomain Guy        }
726eb99356a0548684a501766e6a524529ab93304c8Romain Guy    }
727f86ef57f8bcd8ba43ce222ec6a8b4f67d3600640Romain Guy
728d55a86120dd1e8ebcc6906c9ffd463f7460348daRomain Guy    return true;
729bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy}
730bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
731e63f7c622a2086aefa80983c6f41b74fb166bb42Chris Craikbool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {
732c3fedafc5f50100219449125a000e3138f6fb987Romain Guy    layer->clipRect.set(clip);
7339ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy    layer->setFbo(mCaches.fboCache.get());
7345b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
735984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    writableSnapshot()->region = &writableSnapshot()->layer->region;
736984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    writableSnapshot()->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
737984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    writableSnapshot()->fbo = layer->getFbo();
738984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f);
739984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    writableSnapshot()->resetClip(clip.left, clip.top, clip.right, clip.bottom);
740984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    writableSnapshot()->initializeViewport(bounds.getWidth(), bounds.getHeight());
741e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    writableSnapshot()->roundRectClipState = nullptr;
7425b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
7432b7028eabac80cec170572bc0e945a1d4224e595Romain Guy    endTiling();
7447c450aaa3caac2a05fcb20a177483d0e92378426Romain Guy    debugOverdraw(false, false);
7455b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    // Bind texture to FBO
7463b20251a355c88193c439f928a84ae69483fb488John Reck    mRenderState.bindFramebuffer(layer->getFbo());
7479ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy    layer->bindTexture();
7485b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
7495b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    // Initialize the texture if needed
7509ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy    if (layer->isEmpty()) {
7510908764b2b3cf5075df4178a5f0a8547dcb7b317Romain Guy        layer->allocateTexture();
7529ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        layer->setEmpty(false);
7535b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    }
7545b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
7555b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
756f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik            layer->getTextureId(), 0);
7575b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
75833f5a59ac3e304970920dda824958870f85f76efhenry.uh_chen    // Expand the startTiling region by 1
75933f5a59ac3e304970920dda824958870f85f76efhenry.uh_chen    startTilingCurrentClip(true, true);
7605b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
7615b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
76265fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik    mRenderState.scissor().setEnabled(true);
76365fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik    mRenderState.scissor().set(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
7645b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            clip.getWidth() + 2.0f, clip.getHeight() + 2.0f);
7655b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    glClear(GL_COLOR_BUFFER_BIT);
7665b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
7675b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    dirtyClip();
7685b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
7695b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    // Change the ortho projection
7703b20251a355c88193c439f928a84ae69483fb488John Reck    mRenderState.setViewport(bounds.getWidth(), bounds.getHeight());
7715b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    return true;
7725b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy}
7735b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
7741c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy/**
7751c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy * Read the documentation of createLayer() before doing anything in this method.
7761c740bce8a762f02b5283045a0e2de7c8fb41277Romain Guy */
77714e513058ed4168c94e015638d16f5f87fd8063aChris Craikvoid OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& restored) {
77814e513058ed4168c94e015638d16f5f87fd8063aChris Craik    if (!removed.layer) {
7793762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        ALOGE("Attempting to compose a layer that does not exist");
7801d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy        return;
7811d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy    }
7821d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy
78314e513058ed4168c94e015638d16f5f87fd8063aChris Craik    Layer* layer = removed.layer;
7848ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy    const Rect& rect = layer->layer;
78514e513058ed4168c94e015638d16f5f87fd8063aChris Craik    const bool fboLayer = removed.flags & Snapshot::kFlagIsFboLayer;
786eb99356a0548684a501766e6a524529ab93304c8Romain Guy
78739a908c1df89e1073627b0dcbce922d826b67055Chris Craik    bool clipRequired = false;
788984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    mState.calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom,
789e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik            &clipRequired, nullptr, false); // safely ignore return, should never be rejected
79065fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik    mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
79139a908c1df89e1073627b0dcbce922d826b67055Chris Craik
792eb99356a0548684a501766e6a524529ab93304c8Romain Guy    if (fboLayer) {
7932b7028eabac80cec170572bc0e945a1d4224e595Romain Guy        endTiling();
7942b7028eabac80cec170572bc0e945a1d4224e595Romain Guy
795e0aa84b7dc087e999e20055dcc04cb6a48d5bd62Romain Guy        // Detach the texture from the FBO
796e0aa84b7dc087e999e20055dcc04cb6a48d5bd62Romain Guy        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
7978ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy
7988ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy        layer->removeFbo(false);
7998ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy
800eb99356a0548684a501766e6a524529ab93304c8Romain Guy        // Unbind current FBO and restore previous one
8013b20251a355c88193c439f928a84ae69483fb488John Reck        mRenderState.bindFramebuffer(restored.fbo);
8027c450aaa3caac2a05fcb20a177483d0e92378426Romain Guy        debugOverdraw(true, false);
8032b7028eabac80cec170572bc0e945a1d4224e595Romain Guy
804d6b65f67717025b1162f86f04e2caa5723566cacChris Craik        startTilingCurrentClip();
805eb99356a0548684a501766e6a524529ab93304c8Romain Guy    }
806eb99356a0548684a501766e6a524529ab93304c8Romain Guy
8079ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy    if (!fboLayer && layer->getAlpha() < 255) {
80876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        SkPaint layerPaint;
80976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        layerPaint.setAlpha(layer->getAlpha());
81076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        layerPaint.setXfermodeMode(SkXfermode::kDstIn_Mode);
81176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        layerPaint.setColorFilter(layer->getColorFilter());
81276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
81376d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        drawColorRect(rect.left, rect.top, rect.right, rect.bottom, &layerPaint, true);
8145b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        // Required below, composeLayerRect() will divide by 255
8159ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        layer->setAlpha(255);
816f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy    }
817f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy
81896a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().unbindMeshBuffer();
8198b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy
82044eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik    mCaches.textureState().activateTexture(0);
8215b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
8225b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    // When the layer is stored in an FBO, we can save a bit of fillrate by
8235b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    // drawing only the dirty region
824eb99356a0548684a501766e6a524529ab93304c8Romain Guy    if (fboLayer) {
82514e513058ed4168c94e015638d16f5f87fd8063aChris Craik        dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *restored.transform);
8265b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        composeLayerRegion(layer, rect);
8279ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy    } else if (!rect.isEmpty()) {
8289ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
829a5ff739d3c9e15d07f1d5c644b4f11205cdac0e8Digish Pandya
830a5ff739d3c9e15d07f1d5c644b4f11205cdac0e8Digish Pandya        save(0);
831a5ff739d3c9e15d07f1d5c644b4f11205cdac0e8Digish Pandya        // the layer contains screen buffer content that shouldn't be alpha modulated
832a5ff739d3c9e15d07f1d5c644b4f11205cdac0e8Digish Pandya        // (and any necessary alpha modulation was handled drawing into the layer)
833984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson        writableSnapshot()->alpha = 1.0f;
8349ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        composeLayerRect(layer, rect, true);
835a5ff739d3c9e15d07f1d5c644b4f11205cdac0e8Digish Pandya        restore();
836eb99356a0548684a501766e6a524529ab93304c8Romain Guy    }
8371d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy
838746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy    dirtyClip();
839746b7401ceb86b5f2805f8c0d3b39ac739152015Romain Guy
840eb99356a0548684a501766e6a524529ab93304c8Romain Guy    // Failing to add the layer to the cache should happen only if the layer is too large
841e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    layer->setConvexMask(nullptr);
8428550c4c7b5952b7a4e1e0ede95c9492d03099a13Romain Guy    if (!mCaches.layerCache.put(layer)) {
84307adacf4996c8ca494332ec938786fa15832c722Chris Craik        LAYER_LOGD("Deleting layer");
844e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik        layer->decStrong(nullptr);
8451d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy    }
8461d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy}
8471d83e1981c8b89da93dff37a4f8b2b1ad8480b44Romain Guy
848aa6c24c21c727a196451332448d4e3b11a80be69Romain Guyvoid OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
84926bf34200e40a0fa8c66366559aa016380cd8c6fChris Craik    if (USE_GLOPS) {
85026bf34200e40a0fa8c66366559aa016380cd8c6fChris Craik        bool snap = !layer->getForceFilter()
85126bf34200e40a0fa8c66366559aa016380cd8c6fChris Craik                && layer->getWidth() == (uint32_t) rect.getWidth()
85226bf34200e40a0fa8c66366559aa016380cd8c6fChris Craik                && layer->getHeight() == (uint32_t) rect.getHeight();
85326bf34200e40a0fa8c66366559aa016380cd8c6fChris Craik        Glop glop;
85426bf34200e40a0fa8c66366559aa016380cd8c6fChris Craik        GlopBuilder aBuilder(mRenderState, mCaches, &glop);
85526bf34200e40a0fa8c66366559aa016380cd8c6fChris Craik        aBuilder.setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
85626bf34200e40a0fa8c66366559aa016380cd8c6fChris Craik                .setFillTextureLayer(*layer, getLayerAlpha(layer))
85726bf34200e40a0fa8c66366559aa016380cd8c6fChris Craik                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
85826bf34200e40a0fa8c66366559aa016380cd8c6fChris Craik                .setModelViewMapUnitToRectOptionalSnap(snap, rect)
85926bf34200e40a0fa8c66366559aa016380cd8c6fChris Craik                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
86026bf34200e40a0fa8c66366559aa016380cd8c6fChris Craik                .build();
86126bf34200e40a0fa8c66366559aa016380cd8c6fChris Craik    }
862aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
86326bf34200e40a0fa8c66366559aa016380cd8c6fChris Craik    float alpha = getLayerAlpha(layer);
864aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy    setupDraw();
8659ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy    if (layer->getRenderTarget() == GL_TEXTURE_2D) {
8668f0095cd33558e9cc8a440047908e53b68906f5fRomain Guy        setupDrawWithTexture();
8678f0095cd33558e9cc8a440047908e53b68906f5fRomain Guy    } else {
8688f0095cd33558e9cc8a440047908e53b68906f5fRomain Guy        setupDrawWithExternalTexture();
8698f0095cd33558e9cc8a440047908e53b68906f5fRomain Guy    }
8708f0095cd33558e9cc8a440047908e53b68906f5fRomain Guy    setupDrawTextureTransform();
871aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy    setupDrawColor(alpha, alpha, alpha, alpha);
87276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilter(layer->getColorFilter());
87376d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawBlending(layer);
874aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy    setupDrawProgram();
875aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy    setupDrawPureColorUniforms();
87676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilterUniforms(layer->getColorFilter());
8779ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy    if (layer->getRenderTarget() == GL_TEXTURE_2D) {
878f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik        setupDrawTexture(layer->getTextureId());
8798f0095cd33558e9cc8a440047908e53b68906f5fRomain Guy    } else {
880f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik        setupDrawExternalTexture(layer->getTextureId());
8818f0095cd33558e9cc8a440047908e53b68906f5fRomain Guy    }
88226bf34200e40a0fa8c66366559aa016380cd8c6fChris Craik    if (currentTransform()->isPureTranslate()
88326bf34200e40a0fa8c66366559aa016380cd8c6fChris Craik            && !layer->getForceFilter()
88426bf34200e40a0fa8c66366559aa016380cd8c6fChris Craik            && layer->getWidth() == (uint32_t) rect.getWidth()
88526bf34200e40a0fa8c66366559aa016380cd8c6fChris Craik            && layer->getHeight() == (uint32_t) rect.getHeight()) {
886d6b65f67717025b1162f86f04e2caa5723566cacChris Craik        const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
887d6b65f67717025b1162f86f04e2caa5723566cacChris Craik        const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
8889ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy
889d21b6e1fe337b35f62cf2028e9bd0637fd009a75Romain Guy        layer->setFilter(GL_NEAREST);
8904063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik        setupDrawModelView(kModelViewMode_TranslateAndScale, false,
8914063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik                x, y, x + rect.getWidth(), y + rect.getHeight(), true);
8929ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy    } else {
893d21b6e1fe337b35f62cf2028e9bd0637fd009a75Romain Guy        layer->setFilter(GL_LINEAR);
8944063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik        setupDrawModelView(kModelViewMode_TranslateAndScale, false,
8954063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik                rect.left, rect.top, rect.right, rect.bottom);
8969ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy    }
8979ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy    setupDrawTextureTransformUniforms(layer->getTexTransform());
8983380cfdc77100e87aa8390386ccf390834dea171Romain Guy    setupDrawMesh(&mMeshVertices[0].x, &mMeshVertices[0].u);
899aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
900117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
901aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy}
902aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
9035b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guyvoid OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
90462d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik    if (layer->isTextureLayer()) {
90562d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik        EVENT_LOGD("composeTextureLayerRect");
90662d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik        resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
90762d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik        drawTextureLayer(layer, rect);
90862d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik        resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
90962d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik    } else {
91062d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik        EVENT_LOGD("composeHardwareLayerRect");
911aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy        const Rect& texCoords = layer->texCoords;
912aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy        resetDrawTextureTexCoords(texCoords.left, texCoords.top,
913aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy                texCoords.right, texCoords.bottom);
9145b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
9159ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        float x = rect.left;
9169ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        float y = rect.top;
917d6b65f67717025b1162f86f04e2caa5723566cacChris Craik        bool simpleTransform = currentTransform()->isPureTranslate() &&
918ec19b4a764d512091a780fc93ced567dfbf80914Romain Guy                layer->getWidth() == (uint32_t) rect.getWidth() &&
919b2479153b743df9e54f7e17c7132a5ecd87fa453Romain Guy                layer->getHeight() == (uint32_t) rect.getHeight();
920b2479153b743df9e54f7e17c7132a5ecd87fa453Romain Guy
921b2479153b743df9e54f7e17c7132a5ecd87fa453Romain Guy        if (simpleTransform) {
9229ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy            // When we're swapping, the layer is already in screen coordinates
9239ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy            if (!swap) {
924d6b65f67717025b1162f86f04e2caa5723566cacChris Craik                x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
925d6b65f67717025b1162f86f04e2caa5723566cacChris Craik                y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
9269ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy            }
9279ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy
928d21b6e1fe337b35f62cf2028e9bd0637fd009a75Romain Guy            layer->setFilter(GL_NEAREST, true);
9299ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        } else {
930d21b6e1fe337b35f62cf2028e9bd0637fd009a75Romain Guy            layer->setFilter(GL_LINEAR, true);
9319ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        }
9329ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy
93376d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        SkPaint layerPaint;
93476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        layerPaint.setAlpha(getLayerAlpha(layer) * 255);
93576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        layerPaint.setXfermodeMode(layer->getMode());
93676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        layerPaint.setColorFilter(layer->getColorFilter());
93776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
93876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f;
9399ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy        drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
940f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                layer->getTextureId(), &layerPaint, blend,
9413380cfdc77100e87aa8390386ccf390834dea171Romain Guy                &mMeshVertices[0].x, &mMeshVertices[0].u,
942117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik                GL_TRIANGLE_STRIP, kUnitQuadCount, swap, swap || simpleTransform);
9435b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
944aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy        resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
945aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy    }
9465b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy}
9475b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
94834416eaa1c07b3d7a139e780cea8f8d73219650eChris Craik/**
94934416eaa1c07b3d7a139e780cea8f8d73219650eChris Craik * Issues the command X, and if we're composing a save layer to the fbo or drawing a newly updated
95034416eaa1c07b3d7a139e780cea8f8d73219650eChris Craik * hardware layer with overdraw debug on, draws again to the stencil only, so that these draw
95134416eaa1c07b3d7a139e780cea8f8d73219650eChris Craik * operations are correctly counted twice for overdraw. NOTE: assumes composeLayerRegion only used
95234416eaa1c07b3d7a139e780cea8f8d73219650eChris Craik * by saveLayer's restore
95334416eaa1c07b3d7a139e780cea8f8d73219650eChris Craik */
954984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson#define DRAW_DOUBLE_STENCIL_IF(COND, DRAW_COMMAND) {                               \
955984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson        DRAW_COMMAND;                                                              \
956984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson        if (CC_UNLIKELY(mCaches.debugOverdraw && onGetTargetFbo() == 0 && COND)) { \
957984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson            glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);                   \
958984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson            DRAW_COMMAND;                                                          \
959984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson            glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);                       \
960984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson        }                                                                          \
96134416eaa1c07b3d7a139e780cea8f8d73219650eChris Craik    }
96234416eaa1c07b3d7a139e780cea8f8d73219650eChris Craik
96334416eaa1c07b3d7a139e780cea8f8d73219650eChris Craik#define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND)
96434416eaa1c07b3d7a139e780cea8f8d73219650eChris Craik
965d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III// This class is purely for inspection. It inherits from SkShader, but Skia does not know how to
966d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III// use it. The OpenGLRenderer will look at it to find its Layer and whether it is opaque.
967d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins IIIclass LayerShader : public SkShader {
968d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins IIIpublic:
969d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    LayerShader(Layer* layer, const SkMatrix* localMatrix)
970d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    : INHERITED(localMatrix)
971d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    , mLayer(layer) {
972d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    }
973d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III
974e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    virtual bool asACustomShader(void** data) const override {
975d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        if (data) {
976d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III            *data = static_cast<void*>(mLayer);
977d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        }
978d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        return true;
979d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    }
980d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III
981e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    virtual bool isOpaque() const override {
982d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        return !mLayer->isBlend();
983d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    }
984d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III
985d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins IIIprotected:
98664bb413a664001c95c8439cf097dc3033f4ed733Andreas Gampe    virtual void shadeSpan(int x, int y, SkPMColor[], int count) {
987d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        LOG_ALWAYS_FATAL("LayerShader should never be drawn with raster backend.");
988d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    }
989d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III
990e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    virtual void flatten(SkWriteBuffer&) const override {
991d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        LOG_ALWAYS_FATAL("LayerShader should never be flattened.");
992d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    }
993d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III
994e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    virtual Factory getFactory() const override {
995d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        LOG_ALWAYS_FATAL("LayerShader should never be created from a stream.");
996e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik        return nullptr;
997d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    }
998d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins IIIprivate:
999d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    // Unowned.
1000d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    Layer* mLayer;
1001d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    typedef SkShader INHERITED;
1002d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III};
1003d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III
10045b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guyvoid OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
10053f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    if (CC_UNLIKELY(layer->region.isEmpty())) return; // nothing to draw
10063f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik
10073f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    if (layer->getConvexMask()) {
10083f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
10093f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik
10103f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        // clip to the area of the layer the mask can be larger
10113f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        clipRect(rect.left, rect.top, rect.right, rect.bottom, SkRegion::kIntersect_Op);
10123f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik
10133f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        SkPaint paint;
10143f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        paint.setAntiAlias(true);
10153f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        paint.setColor(SkColorSetARGB(int(getLayerAlpha(layer) * 255), 0, 0, 0));
10163f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik
10173f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        // create LayerShader to map SaveLayer content into subsequent draw
10183f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        SkMatrix shaderMatrix;
10193f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        shaderMatrix.setTranslate(rect.left, rect.bottom);
10203f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        shaderMatrix.preScale(1, -1);
1021d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        LayerShader layerShader(layer, &shaderMatrix);
1022d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        paint.setShader(&layerShader);
10233f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik
10243f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        // Since the drawing primitive is defined in local drawing space,
10253f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        // we don't need to modify the draw matrix
10263f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        const SkPath* maskPath = layer->getConvexMask();
10273f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        DRAW_DOUBLE_STENCIL(drawConvexPath(*maskPath, &paint));
10283f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik
1029e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik        paint.setShader(nullptr);
10303f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        restore();
10313f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik
10323f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        return;
10333f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    }
10343f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik
10355b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    if (layer->region.isRect()) {
10369fc27819d75e24ad63d7b383d80f5cb66a577a0dRomain Guy        layer->setRegionAsRect();
10379fc27819d75e24ad63d7b383d80f5cb66a577a0dRomain Guy
103834416eaa1c07b3d7a139e780cea8f8d73219650eChris Craik        DRAW_DOUBLE_STENCIL(composeLayerRect(layer, layer->regionRect));
10399fc27819d75e24ad63d7b383d80f5cb66a577a0dRomain Guy
10405b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        layer->region.clear();
10415b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        return;
10425b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    }
10435b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
104462d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik    EVENT_LOGD("composeLayerRegion");
10453f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    // standard Region based draw
10463f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    size_t count;
10473f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    const android::Rect* rects;
10483f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    Region safeRegion;
10493f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    if (CC_LIKELY(hasRectToRectTransform())) {
10503f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        rects = layer->region.getArray(&count);
10513f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    } else {
10523f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        safeRegion = Region::createTJunctionFreeRegion(layer->region);
10533f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        rects = safeRegion.getArray(&count);
10543f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    }
10555b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
10563f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    const float alpha = getLayerAlpha(layer);
10573f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    const float texX = 1.0f / float(layer->getWidth());
10583f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    const float texY = 1.0f / float(layer->getHeight());
10593f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    const float height = rect.getHeight();
10605b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
10613f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    setupDraw();
10628ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy
10633f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    // We must get (and therefore bind) the region mesh buffer
10643f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    // after we setup drawing in case we need to mess with the
10653f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    // stencil buffer in setupDraw()
10663f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    TextureVertex* mesh = mCaches.getRegionMesh();
10673f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    uint32_t numQuads = 0;
10685b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
10693f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    setupDrawWithTexture();
10703f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    setupDrawColor(alpha, alpha, alpha, alpha);
10713f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    setupDrawColorFilter(layer->getColorFilter());
10723f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    setupDrawBlending(layer);
10733f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    setupDrawProgram();
10743f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    setupDrawDirtyRegionsDisabled();
10753f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    setupDrawPureColorUniforms();
10763f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    setupDrawColorFilterUniforms(layer->getColorFilter());
1077f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik    setupDrawTexture(layer->getTextureId());
10783f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    if (currentTransform()->isPureTranslate()) {
10793f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
10803f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
10819ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy
10823f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        layer->setFilter(GL_NEAREST);
10833f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        setupDrawModelView(kModelViewMode_Translate, false,
10843f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik                x, y, x + rect.getWidth(), y + rect.getHeight(), true);
10853f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    } else {
10863f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        layer->setFilter(GL_LINEAR);
10873f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        setupDrawModelView(kModelViewMode_Translate, false,
10883f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik                rect.left, rect.top, rect.right, rect.bottom);
10893f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    }
10903f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
10915b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
10923f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    for (size_t i = 0; i < count; i++) {
10933f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        const android::Rect* r = &rects[i];
10943f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik
10953f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        const float u1 = r->left * texX;
10963f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        const float v1 = (height - r->top) * texY;
10973f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        const float u2 = r->right * texX;
10983f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        const float v2 = (height - r->bottom) * texY;
10995b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
11003f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        // TODO: Reject quads outside of the clip
11013f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        TextureVertex::set(mesh++, r->left, r->top, u1, v1);
11023f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        TextureVertex::set(mesh++, r->right, r->top, u2, v1);
11033f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
11043f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
11053f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik
11063f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        numQuads++;
11073f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik
110896a5c4c7bab6718524de7253da8309143ab48befChris Craik        if (numQuads >= kMaxNumberOfQuads) {
110934416eaa1c07b3d7a139e780cea8f8d73219650eChris Craik            DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
1110e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik                    GL_UNSIGNED_SHORT, nullptr));
11113f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik            numQuads = 0;
11123f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik            mesh = mCaches.getRegionMesh();
11135b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        }
11143f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    }
11153f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik
11163f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    if (numQuads > 0) {
11173f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik        DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
1118e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik                GL_UNSIGNED_SHORT, nullptr));
11193f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    }
11205b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
11215b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy#if DEBUG_LAYERS_AS_REGIONS
11223f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    drawRegionRectsDebug(layer->region);
11235b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy#endif
11245b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
11253f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik    layer->region.clear();
11265b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy}
11275b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
11283a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy#if DEBUG_LAYERS_AS_REGIONS
1129e63f7c622a2086aefa80983c6f41b74fb166bb42Chris Craikvoid OpenGLRenderer::drawRegionRectsDebug(const Region& region) {
11303a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy    size_t count;
11313a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy    const android::Rect* rects = region.getArray(&count);
11323a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy
11333a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy    uint32_t colors[] = {
11343a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy            0x7fff0000, 0x7f00ff00,
11353a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy            0x7f0000ff, 0x7fff00ff,
11363a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy    };
11373a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy
11383a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy    int offset = 0;
11393a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy    int32_t top = rects[0].top;
11403a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy
11413a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy    for (size_t i = 0; i < count; i++) {
11423a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy        if (top != rects[i].top) {
11433a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy            offset ^= 0x2;
11443a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy            top = rects[i].top;
11453a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy        }
11463a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy
114776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        SkPaint paint;
114876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        paint.setColor(colors[offset + (i & 0x1)]);
11493a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy        Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom);
115076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        drawColorRect(r.left, r.top, r.right, r.bottom, paint);
11513a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy    }
11523a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy}
1153e63f7c622a2086aefa80983c6f41b74fb166bb42Chris Craik#endif
11543a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy
115576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenbergervoid OpenGLRenderer::drawRegionRects(const SkRegion& region, const SkPaint& paint, bool dirty) {
11568ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy    Vector<float> rects;
11578ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy
11588ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy    SkRegion::Iterator it(region);
11598ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy    while (!it.done()) {
11608ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy        const SkIRect& r = it.rect();
11618ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy        rects.push(r.fLeft);
11628ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy        rects.push(r.fTop);
11638ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy        rects.push(r.fRight);
11648ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy        rects.push(r.fBottom);
11658ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy        it.next();
11668ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy    }
11678ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy
116876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    drawColorRects(rects.array(), rects.size(), &paint, true, dirty, false);
11698ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy}
11708ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy
11715b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guyvoid OpenGLRenderer::dirtyLayer(const float left, const float top,
11725b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        const float right, const float bottom, const mat4 transform) {
1173f219da5e32e85deb442468ee9a63bb28eb198557Romain Guy    if (hasLayer()) {
11745b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        Rect bounds(left, top, right, bottom);
11755b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        transform.mapRect(bounds);
1176f219da5e32e85deb442468ee9a63bb28eb198557Romain Guy        dirtyLayerUnchecked(bounds, getRegion());
11775b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    }
11785b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy}
11795b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
11805b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guyvoid OpenGLRenderer::dirtyLayer(const float left, const float top,
11815b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        const float right, const float bottom) {
1182f219da5e32e85deb442468ee9a63bb28eb198557Romain Guy    if (hasLayer()) {
11835b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        Rect bounds(left, top, right, bottom);
1184f219da5e32e85deb442468ee9a63bb28eb198557Romain Guy        dirtyLayerUnchecked(bounds, getRegion());
11851bd1bad0b4a75e633c5edbe802bf6fb4dd765161Romain Guy    }
11861bd1bad0b4a75e633c5edbe802bf6fb4dd765161Romain Guy}
11871bd1bad0b4a75e633c5edbe802bf6fb4dd765161Romain Guy
11881bd1bad0b4a75e633c5edbe802bf6fb4dd765161Romain Guyvoid OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) {
1189487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    if (bounds.intersect(mState.currentClipRect())) {
11901bd1bad0b4a75e633c5edbe802bf6fb4dd765161Romain Guy        bounds.snapToPixelBoundaries();
11911bd1bad0b4a75e633c5edbe802bf6fb4dd765161Romain Guy        android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
11921bd1bad0b4a75e633c5edbe802bf6fb4dd765161Romain Guy        if (!dirty.isEmpty()) {
11931bd1bad0b4a75e633c5edbe802bf6fb4dd765161Romain Guy            region->orSelf(dirty);
11945b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        }
11955b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    }
11965b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy}
11975b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
11984063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craikvoid OpenGLRenderer::issueIndexedQuadDraw(Vertex* mesh, GLsizei quadsCount) {
1199448455fe783b0a711340322dca272b8cc0ebe473Romain Guy    GLsizei elementsCount = quadsCount * 6;
1200448455fe783b0a711340322dca272b8cc0ebe473Romain Guy    while (elementsCount > 0) {
1201922d3a7f6f8c1c05a996ee3e91e8cbadfff560c9Chris Craik        GLsizei drawCount = MathUtils::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
1202448455fe783b0a711340322dca272b8cc0ebe473Romain Guy
12033380cfdc77100e87aa8390386ccf390834dea171Romain Guy        setupDrawIndexedVertices(&mesh[0].x);
1204e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik        glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, nullptr);
1205448455fe783b0a711340322dca272b8cc0ebe473Romain Guy
1206448455fe783b0a711340322dca272b8cc0ebe473Romain Guy        elementsCount -= drawCount;
1207448455fe783b0a711340322dca272b8cc0ebe473Romain Guy        // Though there are 4 vertices in a quad, we use 6 indices per
1208448455fe783b0a711340322dca272b8cc0ebe473Romain Guy        // quad to draw with GL_TRIANGLES
1209448455fe783b0a711340322dca272b8cc0ebe473Romain Guy        mesh += (drawCount / 6) * 4;
1210448455fe783b0a711340322dca272b8cc0ebe473Romain Guy    }
1211448455fe783b0a711340322dca272b8cc0ebe473Romain Guy}
1212448455fe783b0a711340322dca272b8cc0ebe473Romain Guy
121354be1cdf3d63095512120fa7ced5c16e462abffaRomain Guyvoid OpenGLRenderer::clearLayerRegions() {
12142bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    const size_t quadCount = mLayers.size();
12152bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    if (quadCount == 0) return;
121654be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy
1217984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (!mState.currentlyIgnored()) {
121862d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik        EVENT_LOGD("clearLayerRegions");
121954be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy        // Doing several glScissor/glClear here can negatively impact
122054be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy        // GPUs with a tiler architecture, instead we draw quads with
122154be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy        // the Clear blending mode
122254be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy
122354be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy        // The list contains bounds that have already been clipped
122454be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy        // against their initial clip rect, and the current clip
122554be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy        // is likely different so we need to disable clipping here
122665fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik        bool scissorChanged = mRenderState.scissor().setEnabled(false);
122754be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy
12282bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik        Vertex mesh[quadCount * 4];
122954be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy        Vertex* vertex = mesh;
123054be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy
12312bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik        for (uint32_t i = 0; i < quadCount; i++) {
123251d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik            const Rect& bounds = mLayers[i];
123354be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy
123451d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik            Vertex::set(vertex++, bounds.left, bounds.top);
123551d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik            Vertex::set(vertex++, bounds.right, bounds.top);
123651d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik            Vertex::set(vertex++, bounds.left, bounds.bottom);
123751d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik            Vertex::set(vertex++, bounds.right, bounds.bottom);
123854be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy        }
1239e67307c816f3fdae2bfba8e9a4410dc015645e91Romain Guy        // We must clear the list of dirty rects before we
1240e67307c816f3fdae2bfba8e9a4410dc015645e91Romain Guy        // call setupDraw() to prevent stencil setup to do
1241e67307c816f3fdae2bfba8e9a4410dc015645e91Romain Guy        // the same thing again
1242e67307c816f3fdae2bfba8e9a4410dc015645e91Romain Guy        mLayers.clear();
124354be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy
12442bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik        if (USE_GLOPS) {
12452bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik            Glop glop;
12462bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik            GlopBuilder aBuilder(mRenderState, mCaches, &glop);
12472bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik            aBuilder.setMeshIndexedQuads(&mesh[0], quadCount)
12482bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik                    .setFillClear()
1249f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false)
1250ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik                    .setModelViewOffsetRect(0, 0, Rect(currentSnapshot()->getClipRect()))
12512bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik                    .setRoundRectClipState(currentSnapshot()->roundRectClipState)
12522bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik                    .build();
12532bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik            renderGlop(glop);
12542bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik        } else {
12552bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik            SkPaint clearPaint;
12562bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik            clearPaint.setXfermodeMode(SkXfermode::kClear_Mode);
125776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
12582bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik            setupDraw(false);
12592bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik            setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f);
12602bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik            setupDrawBlending(&clearPaint, true);
12612bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik            setupDrawProgram();
12622bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik            setupDrawPureColorUniforms();
12632bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik            setupDrawModelView(kModelViewMode_Translate, false,
12642bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik                    0.0f, 0.0f, 0.0f, 0.0f, true);
126554be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy
12662bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik            issueIndexedQuadDraw(&mesh[0], quadCount);
12672bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik        }
12688a4ac610e1aaf04931ac1af54b146a7fc8e66114Romain Guy
126965fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik        if (scissorChanged) mRenderState.scissor().setEnabled(true);
127054be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy    } else {
1271e67307c816f3fdae2bfba8e9a4410dc015645e91Romain Guy        mLayers.clear();
127254be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy    }
127354be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy}
127454be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy
1275bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy///////////////////////////////////////////////////////////////////////////////
1276c3566d06421c8acc0aafb18f7e307e5725ce87e1Chris Craik// State Deferral
1277c3566d06421c8acc0aafb18f7e307e5725ce87e1Chris Craik///////////////////////////////////////////////////////////////////////////////
1278c3566d06421c8acc0aafb18f7e307e5725ce87e1Chris Craik
1279ff78583d8a73ca35ce65b5d2592570ff6fb9901bChris Craikbool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) {
1280487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    const Rect& currentClip = mState.currentClipRect();
1281d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    const mat4* currentMatrix = currentTransform();
1282c3566d06421c8acc0aafb18f7e307e5725ce87e1Chris Craik
1283ff78583d8a73ca35ce65b5d2592570ff6fb9901bChris Craik    if (stateDeferFlags & kStateDeferFlag_Draw) {
1284ff78583d8a73ca35ce65b5d2592570ff6fb9901bChris Craik        // state has bounds initialized in local coordinates
1285ff78583d8a73ca35ce65b5d2592570ff6fb9901bChris Craik        if (!state.mBounds.isEmpty()) {
1286d6b65f67717025b1162f86f04e2caa5723566cacChris Craik            currentMatrix->mapRect(state.mBounds);
128728ce94a4ffc7576f40776d212f1ada79fafaa061Chris Craik            Rect clippedBounds(state.mBounds);
12885e49b307eb99269db2db257760508b8efd7bb97dChris Craik            // NOTE: if we ever want to use this clipping info to drive whether the scissor
12895e49b307eb99269db2db257760508b8efd7bb97dChris Craik            // is used, it should more closely duplicate the quickReject logic (in how it uses
12905e49b307eb99269db2db257760508b8efd7bb97dChris Craik            // snapToPixelBoundaries)
12915e49b307eb99269db2db257760508b8efd7bb97dChris Craik
1292487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            if (!clippedBounds.intersect(currentClip)) {
1293ff78583d8a73ca35ce65b5d2592570ff6fb9901bChris Craik                // quick rejected
1294ff78583d8a73ca35ce65b5d2592570ff6fb9901bChris Craik                return true;
1295ff78583d8a73ca35ce65b5d2592570ff6fb9901bChris Craik            }
129628ce94a4ffc7576f40776d212f1ada79fafaa061Chris Craik
1297a02c4ed885d97e516f844ddb0a96083f1b45b4cbChris Craik            state.mClipSideFlags = kClipSide_None;
1298487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            if (!currentClip.contains(state.mBounds)) {
129928ce94a4ffc7576f40776d212f1ada79fafaa061Chris Craik                int& flags = state.mClipSideFlags;
130028ce94a4ffc7576f40776d212f1ada79fafaa061Chris Craik                // op partially clipped, so record which sides are clipped for clip-aware merging
1301487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk                if (currentClip.left > state.mBounds.left) flags |= kClipSide_Left;
1302487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk                if (currentClip.top > state.mBounds.top) flags |= kClipSide_Top;
1303487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk                if (currentClip.right < state.mBounds.right) flags |= kClipSide_Right;
1304487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk                if (currentClip.bottom < state.mBounds.bottom) flags |= kClipSide_Bottom;
130528ce94a4ffc7576f40776d212f1ada79fafaa061Chris Craik            }
130628ce94a4ffc7576f40776d212f1ada79fafaa061Chris Craik            state.mBounds.set(clippedBounds);
1307ff78583d8a73ca35ce65b5d2592570ff6fb9901bChris Craik        } else {
1308d72b73cea49f29c41661e55eb6bfdbc04f09d809Chris Craik            // Empty bounds implies size unknown. Label op as conservatively clipped to disable
1309d72b73cea49f29c41661e55eb6bfdbc04f09d809Chris Craik            // overdraw avoidance (since we don't know what it overlaps)
1310d72b73cea49f29c41661e55eb6bfdbc04f09d809Chris Craik            state.mClipSideFlags = kClipSide_ConservativeFull;
1311487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            state.mBounds.set(currentClip);
1312c3566d06421c8acc0aafb18f7e307e5725ce87e1Chris Craik        }
1313ff78583d8a73ca35ce65b5d2592570ff6fb9901bChris Craik    }
1314ff78583d8a73ca35ce65b5d2592570ff6fb9901bChris Craik
1315527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik    state.mClipValid = (stateDeferFlags & kStateDeferFlag_Clip);
1316527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik    if (state.mClipValid) {
1317487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        state.mClip.set(currentClip);
1318c3566d06421c8acc0aafb18f7e307e5725ce87e1Chris Craik    }
1319c3566d06421c8acc0aafb18f7e307e5725ce87e1Chris Craik
13207273daace9303f4662444111c40bb83d3ead4a92Chris Craik    // Transform, drawModifiers, and alpha always deferred, since they are used by state operations
13217273daace9303f4662444111c40bb83d3ead4a92Chris Craik    // (Note: saveLayer/restore use colorFilter and alpha, so we just save restore everything)
1322d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    state.mMatrix.load(*currentMatrix);
13237273daace9303f4662444111c40bb83d3ead4a92Chris Craik    state.mDrawModifiers = mDrawModifiers;
1324d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    state.mAlpha = currentSnapshot()->alpha;
1325deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik
1326deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    // always store/restore, since it's just a pointer
1327deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    state.mRoundRectClipState = currentSnapshot()->roundRectClipState;
1328c3566d06421c8acc0aafb18f7e307e5725ce87e1Chris Craik    return false;
1329c3566d06421c8acc0aafb18f7e307e5725ce87e1Chris Craik}
1330c3566d06421c8acc0aafb18f7e307e5725ce87e1Chris Craik
1331527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craikvoid OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) {
133214e513058ed4168c94e015638d16f5f87fd8063aChris Craik    setMatrix(state.mMatrix);
1333984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    writableSnapshot()->alpha = state.mAlpha;
133414e513058ed4168c94e015638d16f5f87fd8063aChris Craik    mDrawModifiers = state.mDrawModifiers;
1335984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    writableSnapshot()->roundRectClipState = state.mRoundRectClipState;
1336ff78583d8a73ca35ce65b5d2592570ff6fb9901bChris Craik
1337527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik    if (state.mClipValid && !skipClipRestore) {
1338984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson        writableSnapshot()->setClip(state.mClip.left, state.mClip.top,
133928ce94a4ffc7576f40776d212f1ada79fafaa061Chris Craik                state.mClip.right, state.mClip.bottom);
1340ff78583d8a73ca35ce65b5d2592570ff6fb9901bChris Craik        dirtyClip();
1341ff78583d8a73ca35ce65b5d2592570ff6fb9901bChris Craik    }
1342c3566d06421c8acc0aafb18f7e307e5725ce87e1Chris Craik}
1343c3566d06421c8acc0aafb18f7e307e5725ce87e1Chris Craik
134428ce94a4ffc7576f40776d212f1ada79fafaa061Chris Craik/**
134528ce94a4ffc7576f40776d212f1ada79fafaa061Chris Craik * Merged multidraw (such as in drawText and drawBitmaps rely on the fact that no clipping is done
134628ce94a4ffc7576f40776d212f1ada79fafaa061Chris Craik * in the draw path. Instead, clipping is done ahead of time - either as a single clip rect (when at
134728ce94a4ffc7576f40776d212f1ada79fafaa061Chris Craik * least one op is clipped), or disabled entirely (because no merged op is clipped)
134828ce94a4ffc7576f40776d212f1ada79fafaa061Chris Craik *
134928ce94a4ffc7576f40776d212f1ada79fafaa061Chris Craik * This method should be called when restoreDisplayState() won't be restoring the clip
135028ce94a4ffc7576f40776d212f1ada79fafaa061Chris Craik */
135128ce94a4ffc7576f40776d212f1ada79fafaa061Chris Craikvoid OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) {
1352e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (clipRect != nullptr) {
1353984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson        writableSnapshot()->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
135428ce94a4ffc7576f40776d212f1ada79fafaa061Chris Craik    } else {
1355984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson        writableSnapshot()->setClip(0, 0, mState.getWidth(), mState.getHeight());
135628ce94a4ffc7576f40776d212f1ada79fafaa061Chris Craik    }
1357527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik    dirtyClip();
135865fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik    bool enableScissor = (clipRect != nullptr) || mScissorOptimizationDisabled;
135965fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik    mRenderState.scissor().setEnabled(enableScissor);
1360527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik}
1361527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik
1362c3566d06421c8acc0aafb18f7e307e5725ce87e1Chris Craik///////////////////////////////////////////////////////////////////////////////
1363f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy// Clipping
1364f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy///////////////////////////////////////////////////////////////////////////////
1365f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
1366bb9524b6bdddc7ac77d8628daa8b366b8a7be4a4Romain Guyvoid OpenGLRenderer::setScissorFromClip() {
1367487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    Rect clip(mState.currentClipRect());
1368e5ebcb0107a939395e03592fd44c746cd09e311dRomain Guy    clip.snapToPixelBoundaries();
13698f85e80b64b89fd38cc23b129f61ec36ddde7f15Romain Guy
137065fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik    if (mRenderState.scissor().set(clip.left, getViewportHeight() - clip.bottom,
13718a4ac610e1aaf04931ac1af54b146a7fc8e66114Romain Guy            clip.getWidth(), clip.getHeight())) {
1372984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson        mState.setDirtyClip(false);
13738a4ac610e1aaf04931ac1af54b146a7fc8e66114Romain Guy    }
13749d5316e3f56d138504565ff311145ac01621dff4Romain Guy}
13759d5316e3f56d138504565ff311145ac01621dff4Romain Guy
13768ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guyvoid OpenGLRenderer::ensureStencilBuffer() {
13778ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy    // Thanks to the mismatch between EGL and OpenGL ES FBO we
13788ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy    // cannot attach a stencil buffer to fbo0 dynamically. Let's
13798ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy    // just hope we have one when hasLayer() returns false.
13808ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy    if (hasLayer()) {
1381d6b65f67717025b1162f86f04e2caa5723566cacChris Craik        attachStencilBufferToLayer(currentSnapshot()->layer);
13828ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy    }
13838ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy}
13848ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy
13858ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guyvoid OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) {
13868ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy    // The layer's FBO is already bound when we reach this stage
13878ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy    if (!layer->getStencilRenderBuffer()) {
1388c3fedafc5f50100219449125a000e3138f6fb987Romain Guy        // GL_QCOM_tiled_rendering doesn't like it if a renderbuffer
1389c3fedafc5f50100219449125a000e3138f6fb987Romain Guy        // is attached after we initiated tiling. We must turn it off,
1390c3fedafc5f50100219449125a000e3138f6fb987Romain Guy        // attach the new render buffer then turn tiling back on
1391c3fedafc5f50100219449125a000e3138f6fb987Romain Guy        endTiling();
1392c3fedafc5f50100219449125a000e3138f6fb987Romain Guy
13938d4aeb7111afac0c3c7e56d4ad5d92f9cfce2ffdRomain Guy        RenderBuffer* buffer = mCaches.renderBufferCache.get(
1394117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik                Stencil::getSmallestStencilFormat(),
1395117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik                layer->getWidth(), layer->getHeight());
13968ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy        layer->setStencilRenderBuffer(buffer);
1397c3fedafc5f50100219449125a000e3138f6fb987Romain Guy
1398f735c8e5cb59d6e1d1aa152fed7a6480a08d1c2aRomain Guy        startTiling(layer->clipRect, layer->layer.getHeight());
13998ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy    }
14008ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy}
14018ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy
1402487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukstatic void handlePoint(std::vector<Vertex>& rectangleVertices, const Matrix4& transform,
1403487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        float x, float y) {
1404487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    Vertex v;
1405487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    v.x = x;
1406487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    v.y = y;
1407487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    transform.mapPoint(v.x, v.y);
1408487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    rectangleVertices.push_back(v);
1409487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
1410487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
1411487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukstatic void handlePointNoTransform(std::vector<Vertex>& rectangleVertices, float x, float y) {
1412487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    Vertex v;
1413487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    v.x = x;
1414487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    v.y = y;
1415487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    rectangleVertices.push_back(v);
1416487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
1417487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
1418487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsukvoid OpenGLRenderer::drawRectangleList(const RectangleList& rectangleList) {
14192bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    int quadCount = rectangleList.getTransformedRectanglesCount();
14202bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    std::vector<Vertex> rectangleVertices(quadCount * 4);
1421487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    Rect scissorBox = rectangleList.calculateBounds();
1422487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    scissorBox.snapToPixelBoundaries();
14232bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    for (int i = 0; i < quadCount; ++i) {
1424487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        const TransformedRectangle& tr(rectangleList.getTransformedRectangle(i));
1425487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        const Matrix4& transform = tr.getTransform();
1426487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        Rect bounds = tr.getBounds();
1427487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        if (transform.rectToRect()) {
1428487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            transform.mapRect(bounds);
1429487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            if (!bounds.intersect(scissorBox)) {
1430487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk                bounds.setEmpty();
1431487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            } else {
1432487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk                handlePointNoTransform(rectangleVertices, bounds.left, bounds.top);
1433487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk                handlePointNoTransform(rectangleVertices, bounds.right, bounds.top);
1434487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk                handlePointNoTransform(rectangleVertices, bounds.left, bounds.bottom);
1435487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk                handlePointNoTransform(rectangleVertices, bounds.right, bounds.bottom);
1436487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            }
1437487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        } else {
1438487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            handlePoint(rectangleVertices, transform, bounds.left, bounds.top);
1439487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            handlePoint(rectangleVertices, transform, bounds.right, bounds.top);
1440487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            handlePoint(rectangleVertices, transform, bounds.left, bounds.bottom);
1441487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            handlePoint(rectangleVertices, transform, bounds.right, bounds.bottom);
1442487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        }
1443487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    }
1444487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
144565fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik    mRenderState.scissor().set(scissorBox.left, getViewportHeight() - scissorBox.bottom,
1446487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            scissorBox.getWidth(), scissorBox.getHeight());
1447487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
14482bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    if (USE_GLOPS) {
14492bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik        Glop glop;
14502bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik        GlopBuilder aBuilder(mRenderState, mCaches, &glop);
14512bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik        aBuilder.setMeshIndexedQuads(&rectangleVertices[0], rectangleVertices.size() / 4)
14522bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik                .setFillBlack()
1453f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false)
14542bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik                .setModelViewOffsetRect(0, 0, scissorBox)
14552bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
14562bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik                .build();
14572bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik        renderGlop(glop);
14582bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik        return;
14592bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    }
14602bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik
1461487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    const SkPaint* paint = nullptr;
1462487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    setupDraw();
1463487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    setupDrawNoTexture();
1464487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    setupDrawColor(0, 0xff * currentSnapshot()->alpha);
1465487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    setupDrawShader(getShader(paint));
1466487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    setupDrawColorFilter(getColorFilter(paint));
1467487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    setupDrawBlending(paint);
1468487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    setupDrawProgram();
1469487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    setupDrawDirtyRegionsDisabled();
1470487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    setupDrawModelView(kModelViewMode_Translate, false,
1471487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            0.0f, 0.0f, 0.0f, 0.0f, true);
1472487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    setupDrawColorUniforms(getShader(paint));
1473487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    setupDrawShaderUniforms(getShader(paint));
1474487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    setupDrawColorFilterUniforms(getColorFilter(paint));
1475487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
1476487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    issueIndexedQuadDraw(&rectangleVertices[0], rectangleVertices.size() / 4);
1477487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk}
1478487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
14798ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guyvoid OpenGLRenderer::setStencilFromClip() {
14808ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy    if (!mCaches.debugOverdraw) {
1481487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        if (!currentSnapshot()->clipIsSimple()) {
1482487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            int incrementThreshold;
148362d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik            EVENT_LOGD("setStencilFromClip - enabling");
148462d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik
14858ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy            // NOTE: The order here is important, we must set dirtyClip to false
14868ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy            //       before any draw call to avoid calling back into this method
1487984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson            mState.setDirtyClip(false);
14888ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy
14898ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy            ensureStencilBuffer();
14908ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy
1491487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            const ClipArea& clipArea = currentSnapshot()->getClipArea();
14928ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy
1493487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            bool isRectangleList = clipArea.isRectangleList();
1494487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            if (isRectangleList) {
1495487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk                incrementThreshold = clipArea.getRectangleList().getTransformedRectanglesCount();
1496487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            } else {
1497487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk                incrementThreshold = 0;
1498487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            }
1499487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
150096a5c4c7bab6718524de7253da8309143ab48befChris Craik            mRenderState.stencil().enableWrite(incrementThreshold);
1501487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
1502487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            // Clean and update the stencil, but first make sure we restrict drawing
15038ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy            // to the region's bounds
150465fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik            bool resetScissor = mRenderState.scissor().setEnabled(true);
15058ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy            if (resetScissor) {
15068ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy                // The scissor was not set so we now need to update it
15078ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy                setScissorFromClip();
15088ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy            }
1509487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk
151096a5c4c7bab6718524de7253da8309143ab48befChris Craik            mRenderState.stencil().clear();
1511deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik
1512deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik            // stash and disable the outline clip state, since stencil doesn't account for outline
1513deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik            bool storedSkipOutlineClip = mSkipOutlineClip;
1514deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik            mSkipOutlineClip = true;
15158ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy
151676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger            SkPaint paint;
151798d608dba6a0b3c15fb08f1fa2c8b9d170124c7cChris Craik            paint.setColor(SK_ColorBLACK);
151876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger            paint.setXfermodeMode(SkXfermode::kSrc_Mode);
151976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
1520487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            if (isRectangleList) {
1521487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk                drawRectangleList(clipArea.getRectangleList());
1522487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            } else {
1523487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk                // NOTE: We could use the region contour path to generate a smaller mesh
1524487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk                //       Since we are using the stencil we could use the red book path
1525487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk                //       drawing technique. It might increase bandwidth usage though.
15268ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy
1527487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk                // The last parameter is important: we are not drawing in the color buffer
1528487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk                // so we don't want to dirty the current layer, if any
1529487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk                drawRegionRects(clipArea.getClipRegion(), paint, false);
1530487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            }
153165fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik            if (resetScissor) mRenderState.scissor().setEnabled(false);
1532deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik            mSkipOutlineClip = storedSkipOutlineClip;
15338ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy
153496a5c4c7bab6718524de7253da8309143ab48befChris Craik            mRenderState.stencil().enableTest(incrementThreshold);
15353ff0bfdd144bba3b023eda8c49b25fb0d0de8653Romain Guy
15363ff0bfdd144bba3b023eda8c49b25fb0d0de8653Romain Guy            // Draw the region used to generate the stencil if the appropriate debug
15373ff0bfdd144bba3b023eda8c49b25fb0d0de8653Romain Guy            // mode is enabled
1538487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            // TODO: Implement for rectangle list clip areas
1539487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk            if (mCaches.debugStencilClip == Caches::kStencilShowRegion &&
1540487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk                    !clipArea.isRectangleList()) {
154176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger                paint.setColor(0x7f0000ff);
154276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger                paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
1543487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk                drawRegionRects(currentSnapshot()->getClipRegion(), paint);
15443ff0bfdd144bba3b023eda8c49b25fb0d0de8653Romain Guy            }
15458ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy        } else {
154662d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik            EVENT_LOGD("setStencilFromClip - disabling");
154796a5c4c7bab6718524de7253da8309143ab48befChris Craik            mRenderState.stencil().disable();
15488ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy        }
15498ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy    }
15508ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy}
15518ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy
1552f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik/**
1553f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik * Returns false and sets scissor enable based upon bounds if drawing won't be clipped out.
1554f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik *
1555f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik * @param paint if not null, the bounds will be expanded to account for stroke depending on paint
1556f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik *         style, and tessellated AA ramp
1557f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik */
1558f0a590781b2c3e34132b2011d3956135add73ae0Chris Craikbool OpenGLRenderer::quickRejectSetupScissor(float left, float top, float right, float bottom,
1559d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        const SkPaint* paint) {
1560f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik    bool snapOut = paint && paint->isAntiAlias();
15615e49b307eb99269db2db257760508b8efd7bb97dChris Craik
1562f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik    if (paint && paint->getStyle() != SkPaint::kFill_Style) {
1563cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik        float outset = paint->getStrokeWidth() * 0.5f;
1564f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik        left -= outset;
1565f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik        top -= outset;
1566f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik        right += outset;
1567f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik        bottom += outset;
1568cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik    }
1569cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik
1570deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    bool clipRequired = false;
1571deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    bool roundRectClipRequired = false;
1572984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.calculateQuickRejectForScissor(left, top, right, bottom,
1573deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik            &clipRequired, &roundRectClipRequired, snapOut)) {
1574dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy        return true;
1575dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy    }
1576dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy
1577f23b25abfb76e75f63103abc882bc91b8327a957Chris Craik    // not quick rejected, so enable the scissor if clipRequired
157865fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik    mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
1579f23b25abfb76e75f63103abc882bc91b8327a957Chris Craik    mSkipOutlineClip = !roundRectClipRequired;
158039a908c1df89e1073627b0dcbce922d826b67055Chris Craik    return false;
1581c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy}
1582c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy
15838ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guyvoid OpenGLRenderer::debugClip() {
1584735738c4ddf3229caa5f6e634bf591953ac29944Romain Guy#if DEBUG_CLIP_REGIONS
1585f23b25abfb76e75f63103abc882bc91b8327a957Chris Craik    if (!currentSnapshot()->clipRegion->isEmpty()) {
158676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        SkPaint paint;
158776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        paint.setColor(0x7f00ff00);
158876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        drawRegionRects(*(currentSnapshot()->clipRegion, paint);
158976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
15908ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy    }
15918ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy#endif
15928ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy}
1593735738c4ddf3229caa5f6e634bf591953ac29944Romain Guy
1594117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craikvoid OpenGLRenderer::renderGlop(const Glop& glop) {
1595117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    if (mState.getDirtyClip()) {
1596117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        if (mRenderState.scissor().isEnabled()) {
1597117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik            setScissorFromClip();
1598117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        }
1599117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik
1600117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        setStencilFromClip();
1601117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    }
1602117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    mRenderState.render(glop);
16032ab95d780b023152556d9f8659de734ec7b55047Chris Craik
16042ab95d780b023152556d9f8659de734ec7b55047Chris Craik    if (!mRenderState.stencil().isWriteEnabled()) {
16052ab95d780b023152556d9f8659de734ec7b55047Chris Craik        // TODO: specify more clearly when a draw should dirty the layer.
16062ab95d780b023152556d9f8659de734ec7b55047Chris Craik        // is writing to the stencil the only time we should ignore this?
16072ab95d780b023152556d9f8659de734ec7b55047Chris Craik        dirtyLayer(glop.bounds.left, glop.bounds.top, glop.bounds.right, glop.bounds.bottom);
16080519c810a56bded1284fcb2ae40f438878c6585fChris Craik        mDirty = true;
16092ab95d780b023152556d9f8659de734ec7b55047Chris Craik    }
1610117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik}
1611117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik
1612f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy///////////////////////////////////////////////////////////////////////////////
161370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy// Drawing commands
161470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy///////////////////////////////////////////////////////////////////////////////
161570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
161662d307c2402777d5e53b4590af5f32f8c55afd81Chris Craikvoid OpenGLRenderer::setupDraw(bool clearLayer) {
1617f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik    // TODO: It would be best if we could do this before quickRejectSetupScissor()
16188a4ac610e1aaf04931ac1af54b146a7fc8e66114Romain Guy    //       changes the scissor test state
161962d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik    if (clearLayer) clearLayerRegions();
16208ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy    // Make sure setScissor & setStencil happen at the beginning of
16218ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy    // this method
1622984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.getDirtyClip()) {
162365fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik        if (mRenderState.scissor().isEnabled()) {
1624b98a016c6769b9e80d392df22fe77a2fca048d9fChris Craik            setScissorFromClip();
1625b98a016c6769b9e80d392df22fe77a2fca048d9fChris Craik        }
162662d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik
1627adc0d9da8648abfea1035fb1108eceea9fd9b5b1Dohyun Lee        setStencilFromClip();
162870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    }
16293ff0bfdd144bba3b023eda8c49b25fb0d0de8653Romain Guy
163070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    mDescription.reset();
16313ff0bfdd144bba3b023eda8c49b25fb0d0de8653Romain Guy
163270ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    mSetShaderColor = false;
163370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    mColorSet = false;
16340519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.a = mColor.r = mColor.g = mColor.b = 0.0f;
163570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    mTextureUnit = 0;
163670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    mTrackDirtyRegions = true;
16373ff0bfdd144bba3b023eda8c49b25fb0d0de8653Romain Guy
16383ff0bfdd144bba3b023eda8c49b25fb0d0de8653Romain Guy    // Enable debug highlight when what we're about to draw is tested against
16393ff0bfdd144bba3b023eda8c49b25fb0d0de8653Romain Guy    // the stencil buffer and if stencil highlight debugging is on
1640117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    mDescription.hasDebugHighlight = !mCaches.debugOverdraw
1641117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik            && mCaches.debugStencilClip == Caches::kStencilShowHighlight
1642117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik            && mRenderState.stencil().isTestEnabled();
164370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
164470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
164570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guyvoid OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
164670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    mDescription.hasTexture = true;
164770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    mDescription.hasAlpha8Texture = isAlpha8;
164870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
164970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
1650ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guyvoid OpenGLRenderer::setupDrawWithTextureAndColor(bool isAlpha8) {
1651ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    mDescription.hasTexture = true;
1652ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    mDescription.hasColors = true;
1653ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    mDescription.hasAlpha8Texture = isAlpha8;
1654ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy}
1655ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy
1656aa6c24c21c727a196451332448d4e3b11a80be69Romain Guyvoid OpenGLRenderer::setupDrawWithExternalTexture() {
1657aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy    mDescription.hasExternalTexture = true;
1658aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy}
1659aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
166015bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guyvoid OpenGLRenderer::setupDrawNoTexture() {
166196a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().disableTexCoordsVertexArray();
166215bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy}
166315bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy
166491a8c7c62913c2597e3bf5a6d59d2ed5fc7ba4e0Chris Craikvoid OpenGLRenderer::setupDrawVertexAlpha(bool useShadowAlphaInterp) {
166591a8c7c62913c2597e3bf5a6d59d2ed5fc7ba4e0Chris Craik    mDescription.hasVertexAlpha = true;
166691a8c7c62913c2597e3bf5a6d59d2ed5fc7ba4e0Chris Craik    mDescription.useShadowAlphaInterp = useShadowAlphaInterp;
16675b0200bd47e8a9a4dc8d2e6c3a110d522b30bf82Chet Haase}
16685b0200bd47e8a9a4dc8d2e6c3a110d522b30bf82Chet Haase
16698d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guyvoid OpenGLRenderer::setupDrawColor(int color, int alpha) {
16700519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.a = alpha / 255.0f;
16710519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.r = mColor.a * ((color >> 16) & 0xFF) / 255.0f;
16720519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.g = mColor.a * ((color >>  8) & 0xFF) / 255.0f;
16730519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.b = mColor.a * ((color      ) & 0xFF) / 255.0f;
167470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    mColorSet = true;
16750519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mSetShaderColor = mDescription.setColorModulate(mColor.a);
167670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
167770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
167886568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guyvoid OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) {
16790519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.a = alpha / 255.0f;
16800519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.r = mColor.a * ((color >> 16) & 0xFF) / 255.0f;
16810519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.g = mColor.a * ((color >>  8) & 0xFF) / 255.0f;
16820519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.b = mColor.a * ((color      ) & 0xFF) / 255.0f;
168386568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy    mColorSet = true;
16840519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mSetShaderColor = mDescription.setAlpha8ColorModulate(mColor.r, mColor.g, mColor.b, mColor.a);
168586568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy}
168686568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy
16874121063313ac0d6f69f6253cac821d0c1c122086Romain Guyvoid OpenGLRenderer::setupDrawTextGamma(const SkPaint* paint) {
16884121063313ac0d6f69f6253cac821d0c1c122086Romain Guy    mCaches.fontRenderer->describe(mDescription, paint);
16894121063313ac0d6f69f6253cac821d0c1c122086Romain Guy}
16904121063313ac0d6f69f6253cac821d0c1c122086Romain Guy
169170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guyvoid OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) {
16920519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.a = a;
16930519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.r = r;
16940519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.g = g;
16950519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.b = b;
169670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    mColorSet = true;
1697e63f7c622a2086aefa80983c6f41b74fb166bb42Chris Craik    mSetShaderColor = mDescription.setColorModulate(a);
169870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
169970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
1700d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins IIIvoid OpenGLRenderer::setupDrawShader(const SkShader* shader) {
1701e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (shader != nullptr) {
1702117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        SkiaShader::describe(&mCaches, mDescription, mCaches.extensions(), *shader);
170370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    }
170470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
170570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
170676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenbergervoid OpenGLRenderer::setupDrawColorFilter(const SkColorFilter* filter) {
1707e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (filter == nullptr) {
170876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        return;
170976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    }
171076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
171176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    SkXfermode::Mode mode;
1712e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (filter->asColorMode(nullptr, &mode)) {
171376d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        mDescription.colorOp = ProgramDescription::kColorBlend;
171476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        mDescription.colorMode = mode;
1715e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    } else if (filter->asColorMatrix(nullptr)) {
171676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        mDescription.colorOp = ProgramDescription::kColorMatrix;
171770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    }
171870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
171970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
1720f09ef51889f75289b041f9e9f949b7b82ed5b686Romain Guyvoid OpenGLRenderer::accountForClear(SkXfermode::Mode mode) {
1721f09ef51889f75289b041f9e9f949b7b82ed5b686Romain Guy    if (mColorSet && mode == SkXfermode::kClear_Mode) {
17220519c810a56bded1284fcb2ae40f438878c6585fChris Craik        mColor.a = 1.0f;
17230519c810a56bded1284fcb2ae40f438878c6585fChris Craik        mColor.r = mColor.g = mColor.b = 0.0f;
172454be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy        mSetShaderColor = mDescription.modulate = true;
1725f09ef51889f75289b041f9e9f949b7b82ed5b686Romain Guy    }
1726f09ef51889f75289b041f9e9f949b7b82ed5b686Romain Guy}
1727f09ef51889f75289b041f9e9f949b7b82ed5b686Romain Guy
172876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenbergervoid OpenGLRenderer::setupDrawBlending(const Layer* layer, bool swapSrcDst) {
172976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    SkXfermode::Mode mode = layer->getMode();
1730f09ef51889f75289b041f9e9f949b7b82ed5b686Romain Guy    // When the blending mode is kClear_Mode, we need to use a modulate color
1731f09ef51889f75289b041f9e9f949b7b82ed5b686Romain Guy    // argb=1,0,0,0
1732f09ef51889f75289b041f9e9f949b7b82ed5b686Romain Guy    accountForClear(mode);
1733d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    // TODO: check shader blending, once we have shader drawing support for layers.
17348dfaa4904205772cdceee63ef3989bcdedf1a914Tom Hudson    bool blend = layer->isBlend()
17358dfaa4904205772cdceee63ef3989bcdedf1a914Tom Hudson            || getLayerAlpha(layer) < 1.0f
17360519c810a56bded1284fcb2ae40f438878c6585fChris Craik            || (mColorSet && mColor.a < 1.0f)
17378dfaa4904205772cdceee63ef3989bcdedf1a914Tom Hudson            || PaintUtils::isBlendedColorFilter(layer->getColorFilter());
1738c3566d06421c8acc0aafb18f7e307e5725ce87e1Chris Craik    chooseBlending(blend, mode, mDescription, swapSrcDst);
173970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
174070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
174176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenbergervoid OpenGLRenderer::setupDrawBlending(const SkPaint* paint, bool blend, bool swapSrcDst) {
174276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    SkXfermode::Mode mode = getXfermodeDirect(paint);
1743f09ef51889f75289b041f9e9f949b7b82ed5b686Romain Guy    // When the blending mode is kClear_Mode, we need to use a modulate color
1744f09ef51889f75289b041f9e9f949b7b82ed5b686Romain Guy    // argb=1,0,0,0
1745f09ef51889f75289b041f9e9f949b7b82ed5b686Romain Guy    accountForClear(mode);
17460519c810a56bded1284fcb2ae40f438878c6585fChris Craik    blend |= (mColorSet && mColor.a < 1.0f)
1747031888744e24b5c7243ac99ec98b78aff5db1c78Chris Craik            || (getShader(paint) && !getShader(paint)->isOpaque())
1748031888744e24b5c7243ac99ec98b78aff5db1c78Chris Craik            || PaintUtils::isBlendedColorFilter(getColorFilter(paint));
1749c3566d06421c8acc0aafb18f7e307e5725ce87e1Chris Craik    chooseBlending(blend, mode, mDescription, swapSrcDst);
175070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
175170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
175270ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guyvoid OpenGLRenderer::setupDrawProgram() {
17536c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    mCaches.setProgram(mDescription);
1754deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    if (mDescription.hasRoundRectClip) {
1755deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik        // TODO: avoid doing this repeatedly, stashing state pointer in program
1756984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson        const RoundRectClipState* state = writableSnapshot()->roundRectClipState;
1757af4d04cab6d48ae0d6a5e79bd30f679af87abaadChris Craik        const Rect& innerRect = state->innerRect;
17586c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik        glUniform4f(mCaches.program().getUniform("roundRectInnerRectLTRB"),
1759af4d04cab6d48ae0d6a5e79bd30f679af87abaadChris Craik                innerRect.left, innerRect.top,
1760af4d04cab6d48ae0d6a5e79bd30f679af87abaadChris Craik                innerRect.right, innerRect.bottom);
17616c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik        glUniformMatrix4fv(mCaches.program().getUniform("roundRectInvTransform"),
1762deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik                1, GL_FALSE, &state->matrix.data[0]);
17634340c260c002f0cf7bc41571673e57913b5df19fChris Craik
17644340c260c002f0cf7bc41571673e57913b5df19fChris Craik        // add half pixel to round out integer rect space to cover pixel centers
17654340c260c002f0cf7bc41571673e57913b5df19fChris Craik        float roundedOutRadius = state->radius + 0.5f;
17666c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik        glUniform1f(mCaches.program().getUniform("roundRectRadius"),
17674340c260c002f0cf7bc41571673e57913b5df19fChris Craik                roundedOutRadius);
1768deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    }
176970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
177070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
177170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guyvoid OpenGLRenderer::setupDrawDirtyRegionsDisabled() {
177270ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    mTrackDirtyRegions = false;
177370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
177470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
17754063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craikvoid OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset,
17764063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik        float left, float top, float right, float bottom, bool ignoreTransform) {
1777e10e827ed68b0a9487cf8dd1fc545f9a09517ae9Chris Craik    mModelViewMatrix.loadTranslate(left, top, 0.0f);
17784063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik    if (mode == kModelViewMode_TranslateAndScale) {
1779e10e827ed68b0a9487cf8dd1fc545f9a09517ae9Chris Craik        mModelViewMatrix.scale(right - left, bottom - top, 1.0f);
178070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    }
17814063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik
178286568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy    bool dirty = right - left > 0.0f && bottom - top > 0.0f;
1783a64a2bef1048db5a742843f1e3bea9e80d0defc5Chris Craik    const Matrix4& transformMatrix = ignoreTransform ? Matrix4::identity() : *currentTransform();
17846c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik
17856c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    mCaches.program().set(currentSnapshot()->getOrthoMatrix(),
1786e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik            mModelViewMatrix, transformMatrix, offset);
1787a64a2bef1048db5a742843f1e3bea9e80d0defc5Chris Craik    if (dirty && mTrackDirtyRegions) {
1788a64a2bef1048db5a742843f1e3bea9e80d0defc5Chris Craik        if (!ignoreTransform) {
1789a64a2bef1048db5a742843f1e3bea9e80d0defc5Chris Craik            dirtyLayer(left, top, right, bottom, *currentTransform());
1790a64a2bef1048db5a742843f1e3bea9e80d0defc5Chris Craik        } else {
1791a64a2bef1048db5a742843f1e3bea9e80d0defc5Chris Craik            dirtyLayer(left, top, right, bottom);
1792a64a2bef1048db5a742843f1e3bea9e80d0defc5Chris Craik        }
179386568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy    }
179470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
179570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
1796d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins IIIvoid OpenGLRenderer::setupDrawColorUniforms(bool hasShader) {
1797d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    if ((mColorSet && !hasShader) || (hasShader && mSetShaderColor)) {
17980519c810a56bded1284fcb2ae40f438878c6585fChris Craik        mCaches.program().setColor(mColor);
179970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    }
180070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
180170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
180286568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guyvoid OpenGLRenderer::setupDrawPureColorUniforms() {
18035536841e5452172e7772d84ad5f4a2fc7059c9ddRomain Guy    if (mSetShaderColor) {
18040519c810a56bded1284fcb2ae40f438878c6585fChris Craik        mCaches.program().setColor(mColor);
18055536841e5452172e7772d84ad5f4a2fc7059c9ddRomain Guy    }
18065536841e5452172e7772d84ad5f4a2fc7059c9ddRomain Guy}
18075536841e5452172e7772d84ad5f4a2fc7059c9ddRomain Guy
1808d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins IIIvoid OpenGLRenderer::setupDrawShaderUniforms(const SkShader* shader, bool ignoreTransform) {
1809e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (shader == nullptr) {
1810d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        return;
1811d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    }
1812d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III
1813d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    if (ignoreTransform) {
1814d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        // if ignoreTransform=true was passed to setupDrawModelView, undo currentTransform()
1815d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        // because it was built into modelView / the geometry, and the description needs to
1816d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        // compensate.
1817d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        mat4 modelViewWithoutTransform;
1818d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        modelViewWithoutTransform.loadInverse(*currentTransform());
1819d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        modelViewWithoutTransform.multiply(mModelViewMatrix);
1820d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        mModelViewMatrix.load(modelViewWithoutTransform);
182170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    }
1822d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III
1823117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    SkiaShader::setupProgram(&mCaches, mModelViewMatrix, &mTextureUnit,
1824117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik            mCaches.extensions(), *shader);
182570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
182670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
182776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenbergervoid OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) {
1828e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (nullptr == filter) {
182976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        return;
183076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    }
183176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
183276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    SkColor color;
183376d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    SkXfermode::Mode mode;
183476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    if (filter->asColorMode(&color, &mode)) {
183576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        const int alpha = SkColorGetA(color);
183676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        const GLfloat a = alpha / 255.0f;
183776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        const GLfloat r = a * SkColorGetR(color) / 255.0f;
183876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        const GLfloat g = a * SkColorGetG(color) / 255.0f;
183976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        const GLfloat b = a * SkColorGetB(color) / 255.0f;
18406c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik        glUniform4f(mCaches.program().getUniform("colorBlend"), r, g, b, a);
184176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        return;
184276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    }
184376d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
184476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    SkScalar srcColorMatrix[20];
184576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    if (filter->asColorMatrix(srcColorMatrix)) {
184676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
184776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        float colorMatrix[16];
184876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float));
184976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        memcpy(&colorMatrix[4], &srcColorMatrix[5], 4 * sizeof(float));
185076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        memcpy(&colorMatrix[8], &srcColorMatrix[10], 4 * sizeof(float));
185176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        memcpy(&colorMatrix[12], &srcColorMatrix[15], 4 * sizeof(float));
185276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
185376d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        // Skia uses the range [0..255] for the addition vector, but we need
185476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        // the [0..1] range to apply the vector in GLSL
185576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        float colorVector[4];
185676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        colorVector[0] = srcColorMatrix[4] / 255.0f;
185776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        colorVector[1] = srcColorMatrix[9] / 255.0f;
185876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        colorVector[2] = srcColorMatrix[14] / 255.0f;
185976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        colorVector[3] = srcColorMatrix[19] / 255.0f;
186076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
18616c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik        glUniformMatrix4fv(mCaches.program().getUniform("colorMatrix"), 1,
186276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger                GL_FALSE, colorMatrix);
18636c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik        glUniform4fv(mCaches.program().getUniform("colorMatrixVector"), 1, colorVector);
186476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        return;
186570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    }
186676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
186776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    // it is an error if we ever get here
186870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
186970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
18704121063313ac0d6f69f6253cac821d0c1c122086Romain Guyvoid OpenGLRenderer::setupDrawTextGammaUniforms() {
18716c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    mCaches.fontRenderer->setupProgram(mDescription, mCaches.program());
18724121063313ac0d6f69f6253cac821d0c1c122086Romain Guy}
18734121063313ac0d6f69f6253cac821d0c1c122086Romain Guy
187470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guyvoid OpenGLRenderer::setupDrawSimpleMesh() {
187596a5c4c7bab6718524de7253da8309143ab48befChris Craik    bool force = mRenderState.meshState().bindMeshBuffer();
18766c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    mRenderState.meshState().bindPositionVertexPointer(force, nullptr);
187796a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().unbindIndicesBuffer();
187870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
187970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
188070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guyvoid OpenGLRenderer::setupDrawTexture(GLuint texture) {
188144eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik    if (texture) mCaches.textureState().bindTexture(texture);
18822d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy    mTextureUnit++;
188396a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().enableTexCoordsVertexArray();
188470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
188570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
1886aa6c24c21c727a196451332448d4e3b11a80be69Romain Guyvoid OpenGLRenderer::setupDrawExternalTexture(GLuint texture) {
188744eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik    mCaches.textureState().bindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
18882d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy    mTextureUnit++;
188996a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().enableTexCoordsVertexArray();
1890aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy}
1891aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
18928f0095cd33558e9cc8a440047908e53b68906f5fRomain Guyvoid OpenGLRenderer::setupDrawTextureTransform() {
18938f0095cd33558e9cc8a440047908e53b68906f5fRomain Guy    mDescription.hasTextureTransform = true;
18948f0095cd33558e9cc8a440047908e53b68906f5fRomain Guy}
18958f0095cd33558e9cc8a440047908e53b68906f5fRomain Guy
18968f0095cd33558e9cc8a440047908e53b68906f5fRomain Guyvoid OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) {
18976c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    glUniformMatrix4fv(mCaches.program().getUniform("mainTextureTransform"), 1,
1898aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy            GL_FALSE, &transform.data[0]);
1899aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy}
1900aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
1901564acf7c9bff822f608cda0d5df0a64a9f9aaefdChris Craikvoid OpenGLRenderer::setupDrawMesh(const GLvoid* vertices,
1902564acf7c9bff822f608cda0d5df0a64a9f9aaefdChris Craik        const GLvoid* texCoords, GLuint vbo) {
1903f3a910b423db7ad79cf61518bdd9278c048ad0d8Romain Guy    bool force = false;
19043b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    if (!vertices || vbo) {
190596a5c4c7bab6718524de7253da8309143ab48befChris Craik        force = mRenderState.meshState().bindMeshBuffer(vbo);
190670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    } else {
190796a5c4c7bab6718524de7253da8309143ab48befChris Craik        force = mRenderState.meshState().unbindMeshBuffer();
190870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    }
1909d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy
19106c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    mRenderState.meshState().bindPositionVertexPointer(force, vertices);
19116c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    if (mCaches.program().texCoords >= 0) {
19126c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik        mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords);
191315bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy    }
191415bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy
191596a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().unbindIndicesBuffer();
191615bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy}
191715bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy
1918564acf7c9bff822f608cda0d5df0a64a9f9aaefdChris Craikvoid OpenGLRenderer::setupDrawMesh(const GLvoid* vertices,
1919564acf7c9bff822f608cda0d5df0a64a9f9aaefdChris Craik        const GLvoid* texCoords, const GLvoid* colors) {
192096a5c4c7bab6718524de7253da8309143ab48befChris Craik    bool force = mRenderState.meshState().unbindMeshBuffer();
1921ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    GLsizei stride = sizeof(ColorTextureVertex);
1922ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy
19236c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    mRenderState.meshState().bindPositionVertexPointer(force, vertices, stride);
19246c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    if (mCaches.program().texCoords >= 0) {
19256c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik        mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords, stride);
1926ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    }
19276c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    int slot = mCaches.program().getAttrib("colors");
1928ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    if (slot >= 0) {
1929ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy        glEnableVertexAttribArray(slot);
1930ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy        glVertexAttribPointer(slot, 4, GL_FLOAT, GL_FALSE, stride, colors);
1931ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    }
1932ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy
193396a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().unbindIndicesBuffer();
1934ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy}
1935ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy
1936564acf7c9bff822f608cda0d5df0a64a9f9aaefdChris Craikvoid OpenGLRenderer::setupDrawMeshIndices(const GLvoid* vertices,
1937564acf7c9bff822f608cda0d5df0a64a9f9aaefdChris Craik        const GLvoid* texCoords, GLuint vbo) {
19383b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    bool force = false;
19393b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    // If vbo is != 0 we want to treat the vertices parameter as an offset inside
19403b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    // a VBO. However, if vertices is set to NULL and vbo == 0 then we want to
194196a5c4c7bab6718524de7253da8309143ab48befChris Craik    // use the default VBO found in RenderState
19423b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    if (!vertices || vbo) {
194396a5c4c7bab6718524de7253da8309143ab48befChris Craik        force = mRenderState.meshState().bindMeshBuffer(vbo);
19443b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    } else {
194596a5c4c7bab6718524de7253da8309143ab48befChris Craik        force = mRenderState.meshState().unbindMeshBuffer();
19463b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    }
194796a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().bindQuadIndicesBuffer();
19483b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
19496c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    mRenderState.meshState().bindPositionVertexPointer(force, vertices);
19506c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    if (mCaches.program().texCoords >= 0) {
19516c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik        mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords);
19528d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy    }
195370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
195470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
1955448455fe783b0a711340322dca272b8cc0ebe473Romain Guyvoid OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) {
195696a5c4c7bab6718524de7253da8309143ab48befChris Craik    bool force = mRenderState.meshState().unbindMeshBuffer();
195796a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().bindQuadIndicesBuffer();
19586c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    mRenderState.meshState().bindPositionVertexPointer(force, vertices, kVertexStride);
19595b0200bd47e8a9a4dc8d2e6c3a110d522b30bf82Chet Haase}
19605b0200bd47e8a9a4dc8d2e6c3a110d522b30bf82Chet Haase
196170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy///////////////////////////////////////////////////////////////////////////////
1962f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy// Drawing
1963f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy///////////////////////////////////////////////////////////////////////////////
1964f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
1965107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags) {
19660fe478ea04720a57ef3919dbc23711bc7eba517fRomain Guy    // All the usual checks and setup operations (quickReject, setupDraw, etc.)
19670fe478ea04720a57ef3919dbc23711bc7eba517fRomain Guy    // will be performed by the display list itself
1968a7090e0cfd7c719a6d4c03aae34f5db98754cbddChris Craik    if (renderNode && renderNode->isRenderable()) {
1969f57776b2d195f0937906eb88b777bb55ccc36967Chris Craik        // compute 3d ordering
1970a7090e0cfd7c719a6d4c03aae34f5db98754cbddChris Craik        renderNode->computeOrdering();
1971d90144db52c7297879b950cbbc85137ed123ab5bChris Craik        if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
1972107843de4507b3511006cb9c77b8d0364374385aTom Hudson            startFrame();
1973ff78583d8a73ca35ce65b5d2592570ff6fb9901bChris Craik            ReplayStateStruct replayStruct(*this, dirty, replayFlags);
1974a7090e0cfd7c719a6d4c03aae34f5db98754cbddChris Craik            renderNode->replay(replayStruct, 0);
1975107843de4507b3511006cb9c77b8d0364374385aTom Hudson            return;
1976c3566d06421c8acc0aafb18f7e307e5725ce87e1Chris Craik        }
1977c3566d06421c8acc0aafb18f7e307e5725ce87e1Chris Craik
1978ef8d6f272ae451aaedb0f02249c0f9f0576efdf3Chris Craik        // Don't avoid overdraw when visualizing, since that makes it harder to
1979ef8d6f272ae451aaedb0f02249c0f9f0576efdf3Chris Craik        // debug where it's coming from, and when the problem occurs.
1980ef8d6f272ae451aaedb0f02249c0f9f0576efdf3Chris Craik        bool avoidOverdraw = !mCaches.debugOverdraw;
1981487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        DeferredDisplayList deferredList(mState.currentClipRect(), avoidOverdraw);
1982ff78583d8a73ca35ce65b5d2592570ff6fb9901bChris Craik        DeferStateStruct deferStruct(deferredList, *this, replayFlags);
1983a7090e0cfd7c719a6d4c03aae34f5db98754cbddChris Craik        renderNode->defer(deferStruct, 0);
198496885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy
198596885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy        flushLayers();
1986107843de4507b3511006cb9c77b8d0364374385aTom Hudson        startFrame();
198796885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy
1988107843de4507b3511006cb9c77b8d0364374385aTom Hudson        deferredList.flush(*this, dirty);
1989107843de4507b3511006cb9c77b8d0364374385aTom Hudson    } else {
1990107843de4507b3511006cb9c77b8d0364374385aTom Hudson        // Even if there is no drawing command(Ex: invisible),
1991107843de4507b3511006cb9c77b8d0364374385aTom Hudson        // it still needs startFrame to clear buffer and start tiling.
1992107843de4507b3511006cb9c77b8d0364374385aTom Hudson        startFrame();
19930fe478ea04720a57ef3919dbc23711bc7eba517fRomain Guy    }
19940fe478ea04720a57ef3919dbc23711bc7eba517fRomain Guy}
19950fe478ea04720a57ef3919dbc23711bc7eba517fRomain Guy
19960519c810a56bded1284fcb2ae40f438878c6585fChris Craikvoid OpenGLRenderer::drawAlphaBitmap(Texture* texture, const SkPaint* paint) {
19970519c810a56bded1284fcb2ae40f438878c6585fChris Craik    float x = 0;
19980519c810a56bded1284fcb2ae40f438878c6585fChris Craik    float y = 0;
1999a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy
2000886b275e529e44a59c54b933453d9bc902973178Romain Guy    texture->setWrap(GL_CLAMP_TO_EDGE, true);
2001886b275e529e44a59c54b933453d9bc902973178Romain Guy
2002a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy    bool ignoreTransform = false;
2003d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    if (currentTransform()->isPureTranslate()) {
20040519c810a56bded1284fcb2ae40f438878c6585fChris Craik        x = (int) floorf(currentTransform()->getTranslateX() + 0.5f);
20050519c810a56bded1284fcb2ae40f438878c6585fChris Craik        y = (int) floorf(currentTransform()->getTranslateY() + 0.5f);
2006a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy        ignoreTransform = true;
2007a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy
2008886b275e529e44a59c54b933453d9bc902973178Romain Guy        texture->setFilter(GL_NEAREST, true);
2009886b275e529e44a59c54b933453d9bc902973178Romain Guy    } else {
20100519c810a56bded1284fcb2ae40f438878c6585fChris Craik        texture->setFilter(PaintUtils::getFilter(paint), true);
20115b7a3150a6dbf193b371854b66fa654937633d3aRomain Guy    }
2012e3c26851dc315b730ea0fe5ef35bb1db81f6d675Romain Guy
20133b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    // No need to check for a UV mapper on the texture object, only ARGB_8888
20143b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    // bitmaps get packed in the atlas
2015886b275e529e44a59c54b933453d9bc902973178Romain Guy    drawAlpha8TextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
201696a5c4c7bab6718524de7253da8309143ab48befChris Craik            paint, (GLvoid*) nullptr, (GLvoid*) kMeshTextureOffset,
2017117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik            GL_TRIANGLE_STRIP, kUnitQuadCount, ignoreTransform);
2018a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy}
2019a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy
202003c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy/**
202103c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy * Important note: this method is intended to draw batches of bitmaps and
202203c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy * will not set the scissor enable or dirty the current layer, if any.
202303c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy * The caller is responsible for properly dirtying the current layer.
202403c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy */
2025107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
2026d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        int bitmapCount, TextureVertex* vertices, bool pureTranslate,
2027d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        const Rect& bounds, const SkPaint* paint) {
202844eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik    mCaches.textureState().activateTexture(0);
202955b6f95ee4ace96c97508bcd14483fb4e9dbeaa0Romain Guy    Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
2030107843de4507b3511006cb9c77b8d0364374385aTom Hudson    if (!texture) return;
20313b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
2032527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik    const AutoTexture autoCleanup(texture);
2033527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik
2034527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik    texture->setWrap(GL_CLAMP_TO_EDGE, true);
20350519c810a56bded1284fcb2ae40f438878c6585fChris Craik    texture->setFilter(pureTranslate ? GL_NEAREST : PaintUtils::getFilter(paint), true);
2036527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik
2037527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik    const float x = (int) floorf(bounds.left + 0.5f);
2038527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik    const float y = (int) floorf(bounds.top + 0.5f);
20391103b3255945d2eb2fa9c191e84e2270b343cca9Mike Reed    if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
2040527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik        drawAlpha8TextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
204176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger                texture->id, paint, &vertices[0].x, &vertices[0].u,
20424063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik                GL_TRIANGLES, bitmapCount * 6, true,
20434063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik                kModelViewMode_Translate, false);
2044527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik    } else {
2045527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik        drawTextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
204676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger                texture->id, paint, texture->blend, &vertices[0].x, &vertices[0].u,
20474063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik                GL_TRIANGLES, bitmapCount * 6, false, true, 0,
20484063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik                kModelViewMode_Translate, false);
2049527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik    }
2050527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik
2051107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
2052527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik}
2053527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik
2054107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
2055796475006f5d670e8383a2050f11719522437a43Chris Craik    if (quickRejectSetupScissor(0, 0, bitmap->width(), bitmap->height())) {
2056107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
20576926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    }
20586926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy
205944eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik    mCaches.textureState().activateTexture(0);
20603b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    Texture* texture = getTexture(bitmap);
2061107843de4507b3511006cb9c77b8d0364374385aTom Hudson    if (!texture) return;
206222158e139a3d6c6a9787ca0de224e9368f643284Romain Guy    const AutoTexture autoCleanup(texture);
206322158e139a3d6c6a9787ca0de224e9368f643284Romain Guy
2064f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik    if (USE_GLOPS) {
2065f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik        bool isAlpha8Texture = bitmap->colorType() == kAlpha_8_SkColorType;
2066f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik        Glop glop;
2067f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik        GlopBuilder aBuilder(mRenderState, mCaches, &glop);
2068f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik        aBuilder.setMeshTexturedUnitQuad(texture->uvMapper)
2069f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                .setFillTexturePaint(*texture, isAlpha8Texture, paint, currentSnapshot()->alpha)
2070f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
2071f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
2072f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
2073f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                .build();
2074f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik        renderGlop(glop);
2075f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik        return;
2076f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik    }
2077f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik
20781103b3255945d2eb2fa9c191e84e2270b343cca9Mike Reed    if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
20790519c810a56bded1284fcb2ae40f438878c6585fChris Craik        drawAlphaBitmap(texture, paint);
2080a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy    } else {
20810519c810a56bded1284fcb2ae40f438878c6585fChris Craik        drawTextureRect(texture, paint);
2082886b275e529e44a59c54b933453d9bc902973178Romain Guy    }
2083486590963e2207d68eebd6944fec70d50d41116aChet Haase
2084107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
2085e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy}
2086e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy
2087107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
2088d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        const float* vertices, const int* colors, const SkPaint* paint) {
2089984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (!vertices || mState.currentlyIgnored()) {
2090107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
20915a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy    }
20925a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
2093b18d2d0079b4dbf5675ab79b7111b3dfb3cc1ad0Romain Guy    float left = FLT_MAX;
2094b18d2d0079b4dbf5675ab79b7111b3dfb3cc1ad0Romain Guy    float top = FLT_MAX;
2095b18d2d0079b4dbf5675ab79b7111b3dfb3cc1ad0Romain Guy    float right = FLT_MIN;
2096b18d2d0079b4dbf5675ab79b7111b3dfb3cc1ad0Romain Guy    float bottom = FLT_MIN;
2097b18d2d0079b4dbf5675ab79b7111b3dfb3cc1ad0Romain Guy
2098ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik    const uint32_t elementCount = meshWidth * meshHeight * 6;
2099b18d2d0079b4dbf5675ab79b7111b3dfb3cc1ad0Romain Guy
2100ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik    std::unique_ptr<ColorTextureVertex[]> mesh(new ColorTextureVertex[elementCount]);
210151d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik    ColorTextureVertex* vertex = &mesh[0];
2102ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy
210351d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik    std::unique_ptr<int[]> tempColors;
2104ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    if (!colors) {
2105ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy        uint32_t colorsCount = (meshWidth + 1) * (meshHeight + 1);
210651d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik        tempColors.reset(new int[colorsCount]);
210751d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik        memset(tempColors.get(), 0xff, colorsCount * sizeof(int));
210851d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik        colors = tempColors.get();
2109ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    }
2110a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy
2111ebd52610cfeff6e557fde284a7e1efc5e6438285John Reck    Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap);
21123b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    const UvMapper& mapper(getMapper(texture));
21133b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
21145a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy    for (int32_t y = 0; y < meshHeight; y++) {
21155a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy        for (int32_t x = 0; x < meshWidth; x++) {
21165a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            uint32_t i = (y * (meshWidth + 1) + x) * 2;
21175a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
21185a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            float u1 = float(x) / meshWidth;
21195a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            float u2 = float(x + 1) / meshWidth;
21205a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            float v1 = float(y) / meshHeight;
21215a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            float v2 = float(y + 1) / meshHeight;
21225a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
21233b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            mapper.map(u1, v1, u2, v2);
21243b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
21255a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            int ax = i + (meshWidth + 1) * 2;
21265a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            int ay = ax + 1;
21275a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            int bx = i;
21285a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            int by = bx + 1;
21295a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            int cx = i + 2;
21305a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            int cy = cx + 1;
21315a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            int dx = i + (meshWidth + 1) * 2 + 2;
21325a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            int dy = dx + 1;
21335a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
2134ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy            ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
2135ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy            ColorTextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2, colors[ax / 2]);
2136ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy            ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
21375a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
2138ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy            ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
2139ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy            ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
2140ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy            ColorTextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1, colors[cx / 2]);
2141b18d2d0079b4dbf5675ab79b7111b3dfb3cc1ad0Romain Guy
2142a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy            left = fminf(left, fminf(vertices[ax], fminf(vertices[bx], vertices[cx])));
2143a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy            top = fminf(top, fminf(vertices[ay], fminf(vertices[by], vertices[cy])));
2144a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy            right = fmaxf(right, fmaxf(vertices[ax], fmaxf(vertices[bx], vertices[cx])));
2145a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy            bottom = fmaxf(bottom, fmaxf(vertices[ay], fmaxf(vertices[by], vertices[cy])));
21465a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy        }
21475a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy    }
21485a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
2149f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik    if (quickRejectSetupScissor(left, top, right, bottom)) {
2150107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
2151a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy    }
2152a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy
2153ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    if (!texture) {
21543b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        texture = mCaches.textureCache.get(bitmap);
21553b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        if (!texture) {
2156107843de4507b3511006cb9c77b8d0364374385aTom Hudson            return;
21573b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        }
2158ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    }
2159a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy    const AutoTexture autoCleanup(texture);
2160a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy
2161ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik    if (USE_GLOPS) {
2162ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik        /*
2163ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik         * TODO: handle alpha_8 textures correctly by applying paint color, but *not*
2164ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik         * shader in that case to mimic the behavior in SkiaCanvas::drawBitmapMesh.
2165ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik         */
2166ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik        bool isAlpha8Texture = false;
2167ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik        Glop glop;
2168ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik        GlopBuilder aBuilder(mRenderState, mCaches, &glop);
2169ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik        aBuilder.setMeshColoredTexturedMesh(mesh.get(), elementCount)
2170ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik                .setFillTexturePaint(*texture, isAlpha8Texture, paint, currentSnapshot()->alpha)
2171ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
2172ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik                .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
2173ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
2174ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik                .build();
2175ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik        renderGlop(glop);
2176ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik        return;
2177ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik    }
2178ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik
2179ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik    mCaches.textureState().activateTexture(0);
2180a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy    texture->setWrap(GL_CLAMP_TO_EDGE, true);
21810519c810a56bded1284fcb2ae40f438878c6585fChris Craik    texture->setFilter(PaintUtils::getFilter(paint), true);
2182a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy
2183a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy    int alpha;
2184a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy    SkXfermode::Mode mode;
2185a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy    getAlphaAndMode(paint, &alpha, &mode);
2186a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy
2187ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy
2188ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik    dirtyLayer(left, top, right, bottom, *currentTransform());
2189b18d2d0079b4dbf5675ab79b7111b3dfb3cc1ad0Romain Guy
2190ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik    float a = alpha / 255.0f;
2191ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    setupDraw();
2192ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    setupDrawWithTextureAndColor();
2193ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    setupDrawColor(a, a, a, a);
219476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilter(getColorFilter(paint));
219576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawBlending(paint, true);
2196ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    setupDrawProgram();
2197ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    setupDrawDirtyRegionsDisabled();
2198117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    setupDrawModelView(kModelViewMode_Translate, false, 0, 0, 0, 0);
2199ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    setupDrawTexture(texture->id);
2200ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    setupDrawPureColorUniforms();
220176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilterUniforms(getColorFilter(paint));
22023380cfdc77100e87aa8390386ccf390834dea171Romain Guy    setupDrawMesh(&mesh[0].x, &mesh[0].u, &mesh[0].r);
2203ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy
2204ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik    glDrawArrays(GL_TRIANGLES, 0, elementCount);
2205ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy
22066c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    int slot = mCaches.program().getAttrib("colors");
2207ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    if (slot >= 0) {
2208ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy        glDisableVertexAttribArray(slot);
2209ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    }
2210ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy
2211107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
22125a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy}
22135a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
221414100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craikvoid OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, Rect src, Rect dst, const SkPaint* paint) {
221514100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik    if (quickRejectSetupScissor(dst)) {
2216107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
22176926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    }
22186926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy
22193b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    Texture* texture = getTexture(bitmap);
2220107843de4507b3511006cb9c77b8d0364374385aTom Hudson    if (!texture) return;
222122158e139a3d6c6a9787ca0de224e9368f643284Romain Guy    const AutoTexture autoCleanup(texture);
22228ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy
222314100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik    if (USE_GLOPS) {
222414100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        Rect uv(fmax(0.0f, src.left / texture->width),
222514100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik                fmax(0.0f, src.top / texture->height),
222614100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik                fmin(1.0f, src.right / texture->width),
222714100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik                fmin(1.0f, src.bottom / texture->height));
222814100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik
222914100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        bool isAlpha8Texture = bitmap->colorType() == kAlpha_8_SkColorType;
223014100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        Glop glop;
223114100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        GlopBuilder aBuilder(mRenderState, mCaches, &glop);
223214100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        aBuilder.setMeshTexturedUvQuad(texture->uvMapper, uv)
223314100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik                .setFillTexturePaint(*texture, isAlpha8Texture, paint, currentSnapshot()->alpha)
223414100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
223514100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik                .setModelViewMapUnitToRectSnap(dst)
223614100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
223714100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik                .build();
223814100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        renderGlop(glop);
223914100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        return;
224014100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik    }
224114100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik
224214100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik    mCaches.textureState().activateTexture(0);
224314100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik
22448ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy    const float width = texture->width;
22458ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy    const float height = texture->height;
2246c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy
224714100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik    float u1 = fmax(0.0f, src.left / width);
224814100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik    float v1 = fmax(0.0f, src.top / height);
224914100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik    float u2 = fmin(1.0f, src.right / width);
225014100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik    float v2 = fmin(1.0f, src.bottom / height);
22513b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
22523b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    getMapper(texture).map(u1, v1, u2, v2);
2253c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy
225496a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().unbindMeshBuffer();
22558ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy    resetDrawTextureTexCoords(u1, v1, u2, v2);
22568ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy
2257d21b6e1fe337b35f62cf2028e9bd0637fd009a75Romain Guy    texture->setWrap(GL_CLAMP_TO_EDGE, true);
2258d21b6e1fe337b35f62cf2028e9bd0637fd009a75Romain Guy
225914100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik    float scaleX = (dst.right - dst.left) / (src.right - src.left);
226014100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik    float scaleY = (dst.bottom - dst.top) / (src.bottom - src.top);
22616620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy
2262886b275e529e44a59c54b933453d9bc902973178Romain Guy    bool scaled = scaleX != 1.0f || scaleY != 1.0f;
2263886b275e529e44a59c54b933453d9bc902973178Romain Guy    bool ignoreTransform = false;
2264b50149825fae95b2918bcf67b2ddb773b9797068Romain Guy
226514100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik    if (CC_LIKELY(currentTransform()->isPureTranslate())) {
226614100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        float x = (int) floorf(dst.left + currentTransform()->getTranslateX() + 0.5f);
226714100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        float y = (int) floorf(dst.top + currentTransform()->getTranslateY() + 0.5f);
2268886b275e529e44a59c54b933453d9bc902973178Romain Guy
226914100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        dst.right = x + (dst.right - dst.left);
227014100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        dst.bottom = y + (dst.bottom - dst.top);
2271886b275e529e44a59c54b933453d9bc902973178Romain Guy
227214100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        dst.left = x;
227314100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        dst.top = y;
2274886b275e529e44a59c54b933453d9bc902973178Romain Guy
22750519c810a56bded1284fcb2ae40f438878c6585fChris Craik        texture->setFilter(scaled ? PaintUtils::getFilter(paint) : GL_NEAREST, true);
2276886b275e529e44a59c54b933453d9bc902973178Romain Guy        ignoreTransform = true;
22776620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy    } else {
22780519c810a56bded1284fcb2ae40f438878c6585fChris Craik        texture->setFilter(PaintUtils::getFilter(paint), true);
2279886b275e529e44a59c54b933453d9bc902973178Romain Guy    }
2280886b275e529e44a59c54b933453d9bc902973178Romain Guy
22811103b3255945d2eb2fa9c191e84e2270b343cca9Mike Reed    if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
228214100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        drawAlpha8TextureMesh(dst.left, dst.top, dst.right, dst.bottom,
228376d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger                texture->id, paint,
22843380cfdc77100e87aa8390386ccf390834dea171Romain Guy                &mMeshVertices[0].x, &mMeshVertices[0].u,
2285117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik                GL_TRIANGLE_STRIP, kUnitQuadCount, ignoreTransform);
2286886b275e529e44a59c54b933453d9bc902973178Romain Guy    } else {
228714100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        drawTextureMesh(dst.left, dst.top, dst.right, dst.bottom,
228876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger                texture->id, paint, texture->blend,
22893380cfdc77100e87aa8390386ccf390834dea171Romain Guy                &mMeshVertices[0].x, &mMeshVertices[0].u,
2290117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik                GL_TRIANGLE_STRIP, kUnitQuadCount, false, ignoreTransform);
2291886b275e529e44a59c54b933453d9bc902973178Romain Guy    }
2292886b275e529e44a59c54b933453d9bc902973178Romain Guy
22938ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy    resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
2294486590963e2207d68eebd6944fec70d50d41116aChet Haase
2295107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
2296ce0537b80087a6225273040a987414b1dd081aa0Romain Guy}
2297ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
2298107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
2299d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        float left, float top, float right, float bottom, const SkPaint* paint) {
2300f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik    if (quickRejectSetupScissor(left, top, right, bottom)) {
2301107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
23024c2547fa9244e78115cde0a259291053108c3dc7Romain Guy    }
23034c2547fa9244e78115cde0a259291053108c3dc7Romain Guy
2304ebd52610cfeff6e557fde284a7e1efc5e6438285John Reck    AssetAtlas::Entry* entry = mRenderState.assetAtlas().getEntry(bitmap);
23054c2547fa9244e78115cde0a259291053108c3dc7Romain Guy    const Patch* mesh = mCaches.patchCache.get(entry, bitmap->width(), bitmap->height(),
23064c2547fa9244e78115cde0a259291053108c3dc7Romain Guy            right - left, bottom - top, patch);
23074c2547fa9244e78115cde0a259291053108c3dc7Romain Guy
2308107843de4507b3511006cb9c77b8d0364374385aTom Hudson    drawPatch(bitmap, mesh, entry, left, top, right, bottom, paint);
2309be6f9dc1e71b425b7ac1c40c0a2c72d03eb9fbeeRomain Guy}
2310be6f9dc1e71b425b7ac1c40c0a2c72d03eb9fbeeRomain Guy
2311107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh,
2312d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        AssetAtlas::Entry* entry, float left, float top, float right, float bottom,
2313d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        const SkPaint* paint) {
2314f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik    if (quickRejectSetupScissor(left, top, right, bottom)) {
2315107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
23166926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    }
23176926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy
2318211370fd943cf26905001b38b8b1791851b26adcRomain Guy    if (CC_LIKELY(mesh && mesh->verticesCount > 0)) {
231944eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik        mCaches.textureState().activateTexture(0);
2320a404e16e4933857464046d763ed7629cd0c86cbfRomain Guy        Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
2321107843de4507b3511006cb9c77b8d0364374385aTom Hudson        if (!texture) return;
2322a4adcf0239039eb8f005be252409901c41b28839Romain Guy        const AutoTexture autoCleanup(texture);
23233b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
2324a4adcf0239039eb8f005be252409901c41b28839Romain Guy        texture->setWrap(GL_CLAMP_TO_EDGE, true);
2325a4adcf0239039eb8f005be252409901c41b28839Romain Guy        texture->setFilter(GL_LINEAR, true);
2326a4adcf0239039eb8f005be252409901c41b28839Romain Guy
2327d6b65f67717025b1162f86f04e2caa5723566cacChris Craik        const bool pureTranslate = currentTransform()->isPureTranslate();
23285b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        // Mark the current layer dirty where we are going to draw the patch
23298168396d1acbcb5fdd29eeda4c30b2803d5283aeRomain Guy        if (hasLayer() && mesh->hasEmptyQuads) {
2330d6b65f67717025b1162f86f04e2caa5723566cacChris Craik            const float offsetX = left + currentTransform()->getTranslateX();
2331d6b65f67717025b1162f86f04e2caa5723566cacChris Craik            const float offsetY = top + currentTransform()->getTranslateY();
23325b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            const size_t count = mesh->quads.size();
23335b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            for (size_t i = 0; i < count; i++) {
23348ab4079ca27e36e5c584495bcd71b573598ac021Romain Guy                const Rect& bounds = mesh->quads.itemAt(i);
2335211370fd943cf26905001b38b8b1791851b26adcRomain Guy                if (CC_LIKELY(pureTranslate)) {
2336c78b5d50f961ac8f696f8282979ae283cacd3574Romain Guy                    const float x = (int) floorf(bounds.left + offsetX + 0.5f);
2337c78b5d50f961ac8f696f8282979ae283cacd3574Romain Guy                    const float y = (int) floorf(bounds.top + offsetY + 0.5f);
2338c78b5d50f961ac8f696f8282979ae283cacd3574Romain Guy                    dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight());
23396620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy                } else {
2340c78b5d50f961ac8f696f8282979ae283cacd3574Romain Guy                    dirtyLayer(left + bounds.left, top + bounds.top,
2341d6b65f67717025b1162f86f04e2caa5723566cacChris Craik                            left + bounds.right, top + bounds.bottom, *currentTransform());
23426620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy                }
23435b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            }
23445b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        }
23455b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
23464063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik        bool ignoreTransform = false;
2347211370fd943cf26905001b38b8b1791851b26adcRomain Guy        if (CC_LIKELY(pureTranslate)) {
2348d6b65f67717025b1162f86f04e2caa5723566cacChris Craik            const float x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f);
2349d6b65f67717025b1162f86f04e2caa5723566cacChris Craik            const float y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f);
23506620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy
23513b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            right = x + right - left;
23523b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            bottom = y + bottom - top;
23534063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik            left = x;
23544063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik            top = y;
23554063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik            ignoreTransform = true;
23566620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        }
235776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        drawIndexedTextureMesh(left, top, right, bottom, texture->id, paint,
235876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger                texture->blend, (GLvoid*) mesh->offset, (GLvoid*) mesh->textureOffset,
23594063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik                GL_TRIANGLES, mesh->indexCount, false, ignoreTransform,
23604063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik                mCaches.patchCache.getMeshBuffer(), kModelViewMode_Translate, !mesh->hasEmptyQuads);
2361054dc1840941665e32036f9523df51720ad069c8Romain Guy    }
2362486590963e2207d68eebd6944fec70d50d41116aChet Haase
2363107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
2364f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy}
2365f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
236603c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy/**
236703c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy * Important note: this method is intended to draw batches of 9-patch objects and
236803c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy * will not set the scissor enable or dirty the current layer, if any.
236903c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy * The caller is responsible for properly dirtying the current layer.
237003c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy */
2371107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
2372d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        TextureVertex* vertices, uint32_t indexCount, const SkPaint* paint) {
237344eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik    mCaches.textureState().activateTexture(0);
237403c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy    Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
2375107843de4507b3511006cb9c77b8d0364374385aTom Hudson    if (!texture) return;
237603c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy    const AutoTexture autoCleanup(texture);
237703c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy
237803c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy    texture->setWrap(GL_CLAMP_TO_EDGE, true);
237903c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy    texture->setFilter(GL_LINEAR, true);
238003c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy
238176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    drawIndexedTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, paint,
238276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger            texture->blend, &vertices[0].x, &vertices[0].u,
23834063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik            GL_TRIANGLES, indexCount, false, true, 0, kModelViewMode_Translate, false);
238403c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy
2385107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
238603c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy}
238703c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy
2388107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
2389bf75945e7a1ae7c1000682716643c942c1e19ba6Chris Craik        const VertexBuffer& vertexBuffer, const SkPaint* paint, int displayFlags) {
23904063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik    // not missing call to quickReject/dirtyLayer, always done at a higher level
23916d29c8d5218cac0fb35f3b7c253f2bdebd44f15aChris Craik    if (!vertexBuffer.getVertexCount()) {
2392bf09ffb4e0dc820aeae56a3e576aed33cab218daChris Craik        // no vertices to draw
2393107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
2394bf09ffb4e0dc820aeae56a3e576aed33cab218daChris Craik    }
2395bf09ffb4e0dc820aeae56a3e576aed33cab218daChris Craik
2396922d3a7f6f8c1c05a996ee3e91e8cbadfff560c9Chris Craik    if (USE_GLOPS) {
2397117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        Glop glop;
2398117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        GlopBuilder aBuilder(mRenderState, mCaches, &glop);
2399117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        bool fudgeOffset = displayFlags & kVertexBuffer_Offset;
2400117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        bool shadowInterp = displayFlags & kVertexBuffer_ShadowInterp;
2401117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        aBuilder.setMeshVertexBuffer(vertexBuffer, shadowInterp)
24020519c810a56bded1284fcb2ae40f438878c6585fChris Craik                .setFillPaint(*paint, currentSnapshot()->alpha)
2403f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), fudgeOffset)
2404117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik                .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds())
24050519c810a56bded1284fcb2ae40f438878c6585fChris Craik                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
2406117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik                .build();
2407117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        renderGlop(glop);
2408117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        return;
2409117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    }
2410117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik
2411117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    const VertexBuffer::MeshFeatureFlags meshFeatureFlags = vertexBuffer.getMeshFeatureFlags();
24120d5ac954a111d19270d6e618ee051a8d6419e1a5Chris Craik    Rect bounds(vertexBuffer.getBounds());
24130d5ac954a111d19270d6e618ee051a8d6419e1a5Chris Craik    bounds.translate(translateX, translateY);
241405f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik    dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform());
241505f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik
241665cd612face362d054a85d0f7e5881c59cd523beChris Craik    int color = paint->getColor();
2417117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    bool isAA = meshFeatureFlags & VertexBuffer::kAlpha;
241865cd612face362d054a85d0f7e5881c59cd523beChris Craik
2419710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    setupDraw();
2420710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    setupDrawNoTexture();
242191a8c7c62913c2597e3bf5a6d59d2ed5fc7ba4e0Chris Craik    if (isAA) setupDrawVertexAlpha((displayFlags & kVertexBuffer_ShadowInterp));
2422117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
242376d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilter(getColorFilter(paint));
2424d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShader(getShader(paint));
242576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawBlending(paint, isAA);
2426710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    setupDrawProgram();
2427bf75945e7a1ae7c1000682716643c942c1e19ba6Chris Craik    setupDrawModelView(kModelViewMode_Translate, (displayFlags & kVertexBuffer_Offset),
2428bf75945e7a1ae7c1000682716643c942c1e19ba6Chris Craik            translateX, translateY, 0, 0);
2429d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawColorUniforms(getShader(paint));
243076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilterUniforms(getColorFilter(paint));
2431d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShaderUniforms(getShader(paint));
2432858aa93ddb6e69e0503382af63bb681b6728aef1Chet Haase
243355bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    const void* vertices = vertexBuffer.getBuffer();
243496a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().unbindMeshBuffer();
24356c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    mRenderState.meshState().bindPositionVertexPointer(true, vertices,
24366c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik            isAA ? kAlphaVertexStride : kVertexStride);
243796a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().resetTexCoordsVertexPointer();
243863d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui
2439710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    int alphaSlot = -1;
2440710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    if (isAA) {
244196a5c4c7bab6718524de7253da8309143ab48befChris Craik        void* alphaCoords = ((GLbyte*) vertices) + kVertexAlphaOffset;
24426c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik        alphaSlot = mCaches.program().getAttrib("vtxAlpha");
2443710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik        // TODO: avoid enable/disable in back to back uses of the alpha attribute
24446ebdc114e0d72137394f02bc8ffe9d7a782a65c4Chris Craik        glEnableVertexAttribArray(alphaSlot);
244596a5c4c7bab6718524de7253da8309143ab48befChris Craik        glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, kAlphaVertexStride, alphaCoords);
2446710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    }
24476ebdc114e0d72137394f02bc8ffe9d7a782a65c4Chris Craik
2448117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    if (meshFeatureFlags & VertexBuffer::kIndices) {
244996a5c4c7bab6718524de7253da8309143ab48befChris Craik        mRenderState.meshState().unbindIndicesBuffer();
2450e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik        glDrawElements(GL_TRIANGLE_STRIP, vertexBuffer.getIndexCount(),
2451e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik                GL_UNSIGNED_SHORT, vertexBuffer.getIndices());
2452117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    } else {
2453117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        mRenderState.meshState().unbindIndicesBuffer();
2454117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
245563d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui    }
24567b63142d2f4bc32beacedcc761453b8aea1f3a86Romain Guy
2457710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    if (isAA) {
24586ebdc114e0d72137394f02bc8ffe9d7a782a65c4Chris Craik        glDisableVertexAttribArray(alphaSlot);
245904299385c681140239b0dc31d9780d087d2b4d7cRomain Guy    }
246065cd612face362d054a85d0f7e5881c59cd523beChris Craik
2461107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
2462858aa93ddb6e69e0503382af63bb681b6728aef1Chet Haase}
2463858aa93ddb6e69e0503382af63bb681b6728aef1Chet Haase
2464858aa93ddb6e69e0503382af63bb681b6728aef1Chet Haase/**
246565cd612face362d054a85d0f7e5881c59cd523beChris Craik * Renders a convex path via tessellation. For AA paths, this function uses a similar approach to
246665cd612face362d054a85d0f7e5881c59cd523beChris Craik * that of AA lines in the drawLines() function.  We expand the convex path by a half pixel in
246765cd612face362d054a85d0f7e5881c59cd523beChris Craik * screen space in all directions. However, instead of using a fragment shader to compute the
246865cd612face362d054a85d0f7e5881c59cd523beChris Craik * translucency of the color from its position, we simply use a varying parameter to define how far
246965cd612face362d054a85d0f7e5881c59cd523beChris Craik * a given pixel is from the edge. For non-AA paths, the expansion and alpha varying are not used.
247065cd612face362d054a85d0f7e5881c59cd523beChris Craik *
247165cd612face362d054a85d0f7e5881c59cd523beChris Craik * Doesn't yet support joins, caps, or path effects.
247299ecdc480dd4f9b550b2a62ea39f77845a4fec49Chet Haase */
2473107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint) {
247465cd612face362d054a85d0f7e5881c59cd523beChris Craik    VertexBuffer vertexBuffer;
247565cd612face362d054a85d0f7e5881c59cd523beChris Craik    // TODO: try clipping large paths to viewport
2476d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    PathTessellator::tessellatePath(path, paint, *currentTransform(), vertexBuffer);
2477107843de4507b3511006cb9c77b8d0364374385aTom Hudson    drawVertexBuffer(vertexBuffer, paint);
247865cd612face362d054a85d0f7e5881c59cd523beChris Craik}
24797b63142d2f4bc32beacedcc761453b8aea1f3a86Romain Guy
248065cd612face362d054a85d0f7e5881c59cd523beChris Craik/**
248165cd612face362d054a85d0f7e5881c59cd523beChris Craik * We create tristrips for the lines much like shape stroke tessellation, using a per-vertex alpha
248265cd612face362d054a85d0f7e5881c59cd523beChris Craik * and additional geometry for defining an alpha slope perimeter.
248365cd612face362d054a85d0f7e5881c59cd523beChris Craik *
248465cd612face362d054a85d0f7e5881c59cd523beChris Craik * Using GL_LINES can be difficult because the rasterization rules for those lines produces some
248565cd612face362d054a85d0f7e5881c59cd523beChris Craik * unexpected results, and may vary between hardware devices. Previously we used a varying-base
248665cd612face362d054a85d0f7e5881c59cd523beChris Craik * in-shader alpha region, but found it to be taxing on some GPUs.
248765cd612face362d054a85d0f7e5881c59cd523beChris Craik *
248865cd612face362d054a85d0f7e5881c59cd523beChris Craik * TODO: try using a fixed input buffer for non-capped lines as in text rendering. this may reduce
248965cd612face362d054a85d0f7e5881c59cd523beChris Craik * memory transfer by removing need for degenerate vertices.
249065cd612face362d054a85d0f7e5881c59cd523beChris Craik */
2491107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawLines(const float* points, int count, const SkPaint* paint) {
2492984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored() || count < 4) return;
24937b63142d2f4bc32beacedcc761453b8aea1f3a86Romain Guy
249465cd612face362d054a85d0f7e5881c59cd523beChris Craik    count &= ~0x3; // round down to nearest four
24957b63142d2f4bc32beacedcc761453b8aea1f3a86Romain Guy
249665cd612face362d054a85d0f7e5881c59cd523beChris Craik    VertexBuffer buffer;
249705f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik    PathTessellator::tessellateLines(points, count, paint, *currentTransform(), buffer);
249805f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik    const Rect& bounds = buffer.getBounds();
2499d71ff91dcd79f6beea4bbe768ab3bcbb1a6d7c39Romain Guy
250005f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik    if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
2501107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
2502d71ff91dcd79f6beea4bbe768ab3bcbb1a6d7c39Romain Guy    }
2503d71ff91dcd79f6beea4bbe768ab3bcbb1a6d7c39Romain Guy
2504bf75945e7a1ae7c1000682716643c942c1e19ba6Chris Craik    int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset;
2505107843de4507b3511006cb9c77b8d0364374385aTom Hudson    drawVertexBuffer(buffer, paint, displayFlags);
25065b0200bd47e8a9a4dc8d2e6c3a110d522b30bf82Chet Haase}
25075b0200bd47e8a9a4dc8d2e6c3a110d522b30bf82Chet Haase
2508107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) {
2509984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored() || count < 2) return;
2510ed6fcb034b44d9a6ac2fc72fee6030417811f234Romain Guy
25116d29c8d5218cac0fb35f3b7c253f2bdebd44f15aChris Craik    count &= ~0x1; // round down to nearest two
25127b63142d2f4bc32beacedcc761453b8aea1f3a86Romain Guy
25136d29c8d5218cac0fb35f3b7c253f2bdebd44f15aChris Craik    VertexBuffer buffer;
251405f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik    PathTessellator::tessellatePoints(points, count, paint, *currentTransform(), buffer);
25157b63142d2f4bc32beacedcc761453b8aea1f3a86Romain Guy
251605f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik    const Rect& bounds = buffer.getBounds();
251705f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik    if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
2518107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
2519ed6fcb034b44d9a6ac2fc72fee6030417811f234Romain Guy    }
2520ed6fcb034b44d9a6ac2fc72fee6030417811f234Romain Guy
2521bf75945e7a1ae7c1000682716643c942c1e19ba6Chris Craik    int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset;
2522107843de4507b3511006cb9c77b8d0364374385aTom Hudson    drawVertexBuffer(buffer, paint, displayFlags);
2523107843de4507b3511006cb9c77b8d0364374385aTom Hudson
2524107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
2525ed6fcb034b44d9a6ac2fc72fee6030417811f234Romain Guy}
2526ed6fcb034b44d9a6ac2fc72fee6030417811f234Romain Guy
2527107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
2528e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy    // No need to check against the clip, we fill the clip region
2529984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored()) return;
2530e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy
2531487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    Rect clip(mState.currentClipRect());
2532ae88e5e8e9cb6c9539314c4360c5b20f8ec1fefcRomain Guy    clip.snapToPixelBoundaries();
253370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
253476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    SkPaint paint;
253576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    paint.setColor(color);
253676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    paint.setXfermodeMode(mode);
253776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
253876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    drawColorRect(clip.left, clip.top, clip.right, clip.bottom, &paint, true);
2539486590963e2207d68eebd6944fec70d50d41116aChet Haase
2540107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
2541c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy}
25429d5316e3f56d138504565ff311145ac01621dff4Romain Guy
254330036092b40badecbe64d9c2bff4850132147f78Chris Craikvoid OpenGLRenderer::drawShape(float left, float top, PathTexture* texture,
2544d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        const SkPaint* paint) {
2545107843de4507b3511006cb9c77b8d0364374385aTom Hudson    if (!texture) return;
254601d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    const AutoTexture autoCleanup(texture);
254701d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
254801d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    const float x = left + texture->left - texture->offset;
254901d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    const float y = top + texture->top - texture->offset;
255001d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
255101d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    drawPathTexture(texture, x, y, paint);
2552486590963e2207d68eebd6944fec70d50d41116aChet Haase
2553107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
255401d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy}
255501d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
2556107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
2557d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        float rx, float ry, const SkPaint* p) {
2558984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored()
2559947eabf42d835d0dfb0daa2fe6d869139c7000d6Chris Craik            || quickRejectSetupScissor(left, top, right, bottom, p)
25608dfaa4904205772cdceee63ef3989bcdedf1a914Tom Hudson            || PaintUtils::paintWillNotDraw(*p)) {
2561107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
2562710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    }
256301d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
2564e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (p->getPathEffect() != nullptr) {
256544eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik        mCaches.textureState().activateTexture(0);
256630036092b40badecbe64d9c2bff4850132147f78Chris Craik        PathTexture* texture = mCaches.pathCache.getRoundRect(
2567710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik                right - left, bottom - top, rx, ry, p);
2568107843de4507b3511006cb9c77b8d0364374385aTom Hudson        drawShape(left, top, texture, p);
2569107843de4507b3511006cb9c77b8d0364374385aTom Hudson    } else {
2570107843de4507b3511006cb9c77b8d0364374385aTom Hudson        const VertexBuffer* vertexBuffer = mCaches.tessellationCache.getRoundRect(
2571107843de4507b3511006cb9c77b8d0364374385aTom Hudson                *currentTransform(), *p, right - left, bottom - top, rx, ry);
2572107843de4507b3511006cb9c77b8d0364374385aTom Hudson        drawVertexBuffer(left, top, *vertexBuffer, p);
2573710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    }
2574c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy}
257501d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
2576107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p) {
2577984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored()
2578947eabf42d835d0dfb0daa2fe6d869139c7000d6Chris Craik            || quickRejectSetupScissor(x - radius, y - radius, x + radius, y + radius, p)
25798dfaa4904205772cdceee63ef3989bcdedf1a914Tom Hudson            || PaintUtils::paintWillNotDraw(*p)) {
2580107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
2581710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    }
2582e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (p->getPathEffect() != nullptr) {
258344eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik        mCaches.textureState().activateTexture(0);
258430036092b40badecbe64d9c2bff4850132147f78Chris Craik        PathTexture* texture = mCaches.pathCache.getCircle(radius, p);
2585107843de4507b3511006cb9c77b8d0364374385aTom Hudson        drawShape(x - radius, y - radius, texture, p);
2586cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik    } else {
2587107843de4507b3511006cb9c77b8d0364374385aTom Hudson        SkPath path;
2588107843de4507b3511006cb9c77b8d0364374385aTom Hudson        if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2589107843de4507b3511006cb9c77b8d0364374385aTom Hudson            path.addCircle(x, y, radius + p->getStrokeWidth() / 2);
2590107843de4507b3511006cb9c77b8d0364374385aTom Hudson        } else {
2591107843de4507b3511006cb9c77b8d0364374385aTom Hudson            path.addCircle(x, y, radius);
2592107843de4507b3511006cb9c77b8d0364374385aTom Hudson        }
2593107843de4507b3511006cb9c77b8d0364374385aTom Hudson        drawConvexPath(path, p);
2594cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik    }
2595c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy}
259601d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
2597107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
2598d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        const SkPaint* p) {
2599984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored()
2600947eabf42d835d0dfb0daa2fe6d869139c7000d6Chris Craik            || quickRejectSetupScissor(left, top, right, bottom, p)
26018dfaa4904205772cdceee63ef3989bcdedf1a914Tom Hudson            || PaintUtils::paintWillNotDraw(*p)) {
2602107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
2603710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    }
260401d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
2605e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (p->getPathEffect() != nullptr) {
260644eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik        mCaches.textureState().activateTexture(0);
260730036092b40badecbe64d9c2bff4850132147f78Chris Craik        PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p);
2608107843de4507b3511006cb9c77b8d0364374385aTom Hudson        drawShape(left, top, texture, p);
2609107843de4507b3511006cb9c77b8d0364374385aTom Hudson    } else {
2610107843de4507b3511006cb9c77b8d0364374385aTom Hudson        SkPath path;
2611107843de4507b3511006cb9c77b8d0364374385aTom Hudson        SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2612107843de4507b3511006cb9c77b8d0364374385aTom Hudson        if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2613107843de4507b3511006cb9c77b8d0364374385aTom Hudson            rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
2614107843de4507b3511006cb9c77b8d0364374385aTom Hudson        }
2615107843de4507b3511006cb9c77b8d0364374385aTom Hudson        path.addOval(rect);
2616107843de4507b3511006cb9c77b8d0364374385aTom Hudson        drawConvexPath(path, p);
2617cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik    }
2618c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy}
2619c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy
2620107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
2621d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        float startAngle, float sweepAngle, bool useCenter, const SkPaint* p) {
2622984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored()
2623947eabf42d835d0dfb0daa2fe6d869139c7000d6Chris Craik            || quickRejectSetupScissor(left, top, right, bottom, p)
26248dfaa4904205772cdceee63ef3989bcdedf1a914Tom Hudson            || PaintUtils::paintWillNotDraw(*p)) {
2625107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
2626780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    }
26278b2f5267f16c295f12faab810527cd6311997e34Romain Guy
2628780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
2629e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != nullptr || useCenter) {
263044eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik        mCaches.textureState().activateTexture(0);
263130036092b40badecbe64d9c2bff4850132147f78Chris Craik        PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top,
2632780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik                startAngle, sweepAngle, useCenter, p);
2633107843de4507b3511006cb9c77b8d0364374385aTom Hudson        drawShape(left, top, texture, p);
2634107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
2635780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    }
2636780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2637780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2638780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik        rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
2639780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    }
2640780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik
2641780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    SkPath path;
2642780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    if (useCenter) {
2643780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik        path.moveTo(rect.centerX(), rect.centerY());
2644780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    }
2645780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    path.arcTo(rect, startAngle, sweepAngle, !useCenter);
2646780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    if (useCenter) {
2647780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik        path.close();
2648780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    }
2649107843de4507b3511006cb9c77b8d0364374385aTom Hudson    drawConvexPath(path, p);
26508b2f5267f16c295f12faab810527cd6311997e34Romain Guy}
26518b2f5267f16c295f12faab810527cd6311997e34Romain Guy
2652cf8675ee176a375f873792684d38a47f78348dffRomain Guy// See SkPaintDefaults.h
2653cf8675ee176a375f873792684d38a47f78348dffRomain Guy#define SkPaintDefaults_MiterLimit SkIntToScalar(4)
2654cf8675ee176a375f873792684d38a47f78348dffRomain Guy
2655107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
2656d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        const SkPaint* p) {
2657984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored()
2658947eabf42d835d0dfb0daa2fe6d869139c7000d6Chris Craik            || quickRejectSetupScissor(left, top, right, bottom, p)
26598dfaa4904205772cdceee63ef3989bcdedf1a914Tom Hudson            || PaintUtils::paintWillNotDraw(*p)) {
2660107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
26616926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    }
26626926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy
2663710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    if (p->getStyle() != SkPaint::kFill_Style) {
2664cf8675ee176a375f873792684d38a47f78348dffRomain Guy        // only fill style is supported by drawConvexPath, since others have to handle joins
2665e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik        if (p->getPathEffect() != nullptr || p->getStrokeJoin() != SkPaint::kMiter_Join ||
2666cf8675ee176a375f873792684d38a47f78348dffRomain Guy                p->getStrokeMiter() != SkPaintDefaults_MiterLimit) {
266744eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik            mCaches.textureState().activateTexture(0);
266830036092b40badecbe64d9c2bff4850132147f78Chris Craik            PathTexture* texture =
2669c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy                    mCaches.pathCache.getRect(right - left, bottom - top, p);
2670107843de4507b3511006cb9c77b8d0364374385aTom Hudson            drawShape(left, top, texture, p);
2671107843de4507b3511006cb9c77b8d0364374385aTom Hudson        } else {
2672107843de4507b3511006cb9c77b8d0364374385aTom Hudson            SkPath path;
2673107843de4507b3511006cb9c77b8d0364374385aTom Hudson            SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2674107843de4507b3511006cb9c77b8d0364374385aTom Hudson            if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2675107843de4507b3511006cb9c77b8d0364374385aTom Hudson                rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
2676107843de4507b3511006cb9c77b8d0364374385aTom Hudson            }
2677107843de4507b3511006cb9c77b8d0364374385aTom Hudson            path.addRect(rect);
2678107843de4507b3511006cb9c77b8d0364374385aTom Hudson            drawConvexPath(path, p);
2679cf8675ee176a375f873792684d38a47f78348dffRomain Guy        }
2680107843de4507b3511006cb9c77b8d0364374385aTom Hudson    } else {
2681107843de4507b3511006cb9c77b8d0364374385aTom Hudson        if (p->isAntiAlias() && !currentTransform()->isSimple()) {
2682107843de4507b3511006cb9c77b8d0364374385aTom Hudson            SkPath path;
2683107843de4507b3511006cb9c77b8d0364374385aTom Hudson            path.addRect(left, top, right, bottom);
2684107843de4507b3511006cb9c77b8d0364374385aTom Hudson            drawConvexPath(path, p);
2685107843de4507b3511006cb9c77b8d0364374385aTom Hudson        } else {
2686107843de4507b3511006cb9c77b8d0364374385aTom Hudson            drawColorRect(left, top, right, bottom, p);
2687cf8675ee176a375f873792684d38a47f78348dffRomain Guy
2688107843de4507b3511006cb9c77b8d0364374385aTom Hudson            mDirty = true;
2689cf8675ee176a375f873792684d38a47f78348dffRomain Guy        }
2690858aa93ddb6e69e0503382af63bb681b6728aef1Chet Haase    }
2691c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy}
26929d5316e3f56d138504565ff311145ac01621dff4Romain Guy
2693d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craikvoid OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text,
2694d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        int bytesCount, int count, const float* positions,
269576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        FontRenderer& fontRenderer, int alpha, float x, float y) {
269644eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik    mCaches.textureState().activateTexture(0);
2697416a847633680d94efb926837efdc18726d54918Raph Levien
2698c29a0a4664a4b9871fadd668b632469a0db240b9Derek Sollenberger    TextShadow textShadow;
2699c29a0a4664a4b9871fadd668b632469a0db240b9Derek Sollenberger    if (!getTextShadow(paint, &textShadow)) {
2700c29a0a4664a4b9871fadd668b632469a0db240b9Derek Sollenberger        LOG_ALWAYS_FATAL("failed to query shadow attributes");
2701c29a0a4664a4b9871fadd668b632469a0db240b9Derek Sollenberger    }
2702c29a0a4664a4b9871fadd668b632469a0db240b9Derek Sollenberger
2703416a847633680d94efb926837efdc18726d54918Raph Levien    // NOTE: The drop shadow will not perform gamma correction
2704416a847633680d94efb926837efdc18726d54918Raph Levien    //       if shader-based correction is enabled
2705416a847633680d94efb926837efdc18726d54918Raph Levien    mCaches.dropShadowCache.setFontRenderer(fontRenderer);
27062bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    ShadowTexture* texture = mCaches.dropShadowCache.get(
2707c29a0a4664a4b9871fadd668b632469a0db240b9Derek Sollenberger            paint, text, bytesCount, count, textShadow.radius, positions);
2708cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    // If the drop shadow exceeds the max texture size or couldn't be
2709cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    // allocated, skip drawing
27102bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    if (!texture) return;
27112bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    const AutoTexture autoCleanup(texture);
2712416a847633680d94efb926837efdc18726d54918Raph Levien
27132bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    const float sx = x - texture->left + textShadow.dx;
27142bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    const float sy = y - texture->top + textShadow.dy;
2715416a847633680d94efb926837efdc18726d54918Raph Levien
27162bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    if (USE_GLOPS) {
27172bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik        Glop glop;
27182bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik        GlopBuilder aBuilder(mRenderState, mCaches, &glop);
2719f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik        aBuilder.setMeshTexturedUnitQuad(nullptr)
27202bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik                .setFillShadowTexturePaint(*texture, textShadow.color, *paint, currentSnapshot()->alpha)
2721f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
27222bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik                .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width, sy + texture->height))
27232bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
27242bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik                .build();
27252bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik        renderGlop(glop);
27262bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik        return;
27272bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    }
27282bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik
27292bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * currentSnapshot()->alpha;
2730d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    if (getShader(paint)) {
2731c29a0a4664a4b9871fadd668b632469a0db240b9Derek Sollenberger        textShadow.color = SK_ColorWHITE;
2732416a847633680d94efb926837efdc18726d54918Raph Levien    }
2733416a847633680d94efb926837efdc18726d54918Raph Levien
2734416a847633680d94efb926837efdc18726d54918Raph Levien    setupDraw();
2735416a847633680d94efb926837efdc18726d54918Raph Levien    setupDrawWithTexture(true);
2736c29a0a4664a4b9871fadd668b632469a0db240b9Derek Sollenberger    setupDrawAlpha8Color(textShadow.color, shadowAlpha < 255 ? shadowAlpha : alpha);
273776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilter(getColorFilter(paint));
2738d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShader(getShader(paint));
273976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawBlending(paint, true);
2740416a847633680d94efb926837efdc18726d54918Raph Levien    setupDrawProgram();
27414063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik    setupDrawModelView(kModelViewMode_TranslateAndScale, false,
27422bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik            sx, sy, sx + texture->width, sy + texture->height);
27432bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    setupDrawTexture(texture->id);
2744416a847633680d94efb926837efdc18726d54918Raph Levien    setupDrawPureColorUniforms();
274576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilterUniforms(getColorFilter(paint));
2746d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShaderUniforms(getShader(paint));
274796a5c4c7bab6718524de7253da8309143ab48befChris Craik    setupDrawMesh(nullptr, (GLvoid*) kMeshTextureOffset);
2748416a847633680d94efb926837efdc18726d54918Raph Levien
2749117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
2750416a847633680d94efb926837efdc18726d54918Raph Levien}
2751416a847633680d94efb926837efdc18726d54918Raph Levien
2752768bffc9b814f6a1f7d9ff59d91285895c23bbe9Romain Guybool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
2753984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * currentSnapshot()->alpha;
27548dfaa4904205772cdceee63ef3989bcdedf1a914Tom Hudson    return MathUtils::isZero(alpha)
27558dfaa4904205772cdceee63ef3989bcdedf1a914Tom Hudson            && PaintUtils::getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
2756768bffc9b814f6a1f7d9ff59d91285895c23bbe9Romain Guy}
2757768bffc9b814f6a1f7d9ff59d91285895c23bbe9Romain Guy
2758107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
2759d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        const float* positions, const SkPaint* paint) {
2760e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) {
2761107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
2762eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy    }
2763eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy
2764671d6cf460531825a321edb200523d0faa7792c9Romain Guy    // NOTE: Skia does not support perspective transform on drawPosText yet
2765d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    if (!currentTransform()->isSimple()) {
2766107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
2767671d6cf460531825a321edb200523d0faa7792c9Romain Guy    }
2768671d6cf460531825a321edb200523d0faa7792c9Romain Guy
276965fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik    mRenderState.scissor().setEnabled(true);
277039a908c1df89e1073627b0dcbce922d826b67055Chris Craik
2771671d6cf460531825a321edb200523d0faa7792c9Romain Guy    float x = 0.0f;
2772671d6cf460531825a321edb200523d0faa7792c9Romain Guy    float y = 0.0f;
2773d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    const bool pureTranslate = currentTransform()->isPureTranslate();
2774671d6cf460531825a321edb200523d0faa7792c9Romain Guy    if (pureTranslate) {
2775d6b65f67717025b1162f86f04e2caa5723566cacChris Craik        x = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f);
2776d6b65f67717025b1162f86f04e2caa5723566cacChris Craik        y = (int) floorf(y + currentTransform()->getTranslateY() + 0.5f);
2777671d6cf460531825a321edb200523d0faa7792c9Romain Guy    }
2778671d6cf460531825a321edb200523d0faa7792c9Romain Guy
2779b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
278059744b79ec302000802cd56d30a1bf70f0183c80Chris Craik    fontRenderer.setFont(paint, SkMatrix::I());
2781671d6cf460531825a321edb200523d0faa7792c9Romain Guy
2782671d6cf460531825a321edb200523d0faa7792c9Romain Guy    int alpha;
2783671d6cf460531825a321edb200523d0faa7792c9Romain Guy    SkXfermode::Mode mode;
2784671d6cf460531825a321edb200523d0faa7792c9Romain Guy    getAlphaAndMode(paint, &alpha, &mode);
2785671d6cf460531825a321edb200523d0faa7792c9Romain Guy
2786c29a0a4664a4b9871fadd668b632469a0db240b9Derek Sollenberger    if (CC_UNLIKELY(hasTextShadow(paint))) {
2787e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy        drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
278876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger                alpha, 0.0f, 0.0f);
2789416a847633680d94efb926837efdc18726d54918Raph Levien    }
2790416a847633680d94efb926837efdc18726d54918Raph Levien
2791671d6cf460531825a321edb200523d0faa7792c9Romain Guy    // Pick the appropriate texture filtering
2792d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    bool linearFilter = currentTransform()->changesBounds();
2793671d6cf460531825a321edb200523d0faa7792c9Romain Guy    if (pureTranslate && !linearFilter) {
2794671d6cf460531825a321edb200523d0faa7792c9Romain Guy        linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f;
2795671d6cf460531825a321edb200523d0faa7792c9Romain Guy    }
2796257ae3502cfad43df681b1783528d645bdabc63fRomain Guy    fontRenderer.setTextureFiltering(linearFilter);
2797671d6cf460531825a321edb200523d0faa7792c9Romain Guy
2798487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    const Rect& clip(pureTranslate ? writableSnapshot()->getClipRect() : writableSnapshot()->getLocalClip());
2799671d6cf460531825a321edb200523d0faa7792c9Romain Guy    Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2800671d6cf460531825a321edb200523d0faa7792c9Romain Guy
2801211370fd943cf26905001b38b8b1791851b26adcRomain Guy    const bool hasActiveLayer = hasLayer();
2802671d6cf460531825a321edb200523d0faa7792c9Romain Guy
28031e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
2804487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    if (fontRenderer.renderPosText(paint, &clip, text, 0, bytesCount, count, x, y,
2805e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik            positions, hasActiveLayer ? &bounds : nullptr, &functor)) {
2806671d6cf460531825a321edb200523d0faa7792c9Romain Guy        if (hasActiveLayer) {
2807671d6cf460531825a321edb200523d0faa7792c9Romain Guy            if (!pureTranslate) {
2808d6b65f67717025b1162f86f04e2caa5723566cacChris Craik                currentTransform()->mapRect(bounds);
2809671d6cf460531825a321edb200523d0faa7792c9Romain Guy            }
2810671d6cf460531825a321edb200523d0faa7792c9Romain Guy            dirtyLayerUnchecked(bounds, getRegion());
2811671d6cf460531825a321edb200523d0faa7792c9Romain Guy        }
2812671d6cf460531825a321edb200523d0faa7792c9Romain Guy    }
2813486590963e2207d68eebd6944fec70d50d41116aChet Haase
2814107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
2815eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy}
2816eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy
281759744b79ec302000802cd56d30a1bf70f0183c80Chris Craikbool OpenGLRenderer::findBestFontTransform(const mat4& transform, SkMatrix* outMatrix) const {
2818624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    if (CC_LIKELY(transform.isPureTranslate())) {
281959744b79ec302000802cd56d30a1bf70f0183c80Chris Craik        outMatrix->setIdentity();
282059744b79ec302000802cd56d30a1bf70f0183c80Chris Craik        return false;
282159744b79ec302000802cd56d30a1bf70f0183c80Chris Craik    } else if (CC_UNLIKELY(transform.isPerspective())) {
282259744b79ec302000802cd56d30a1bf70f0183c80Chris Craik        outMatrix->setIdentity();
282359744b79ec302000802cd56d30a1bf70f0183c80Chris Craik        return true;
282459744b79ec302000802cd56d30a1bf70f0183c80Chris Craik    }
282559744b79ec302000802cd56d30a1bf70f0183c80Chris Craik
282659744b79ec302000802cd56d30a1bf70f0183c80Chris Craik    /**
2827a736cd9d3587a120e5233d627cd8bf06353be107Chris Craik     * Input is a non-perspective, scaling transform. Generate a scale-only transform,
2828a736cd9d3587a120e5233d627cd8bf06353be107Chris Craik     * with values rounded to the nearest int.
282959744b79ec302000802cd56d30a1bf70f0183c80Chris Craik     */
283059744b79ec302000802cd56d30a1bf70f0183c80Chris Craik    float sx, sy;
283159744b79ec302000802cd56d30a1bf70f0183c80Chris Craik    transform.decomposeScale(sx, sy);
2832a736cd9d3587a120e5233d627cd8bf06353be107Chris Craik    outMatrix->setScale(
2833a736cd9d3587a120e5233d627cd8bf06353be107Chris Craik            roundf(fmaxf(1.0f, sx)),
2834a736cd9d3587a120e5233d627cd8bf06353be107Chris Craik            roundf(fmaxf(1.0f, sy)));
2835a736cd9d3587a120e5233d627cd8bf06353be107Chris Craik    return true;
2836624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy}
2837624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy
2838984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonint OpenGLRenderer::getSaveCount() const {
2839984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    return mState.getSaveCount();
2840984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2841984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2842984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonint OpenGLRenderer::save(int flags) {
2843984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    return mState.save(flags);
2844984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2845984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2846984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonvoid OpenGLRenderer::restore() {
2847984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    return mState.restore();
2848984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2849984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2850984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonvoid OpenGLRenderer::restoreToCount(int saveCount) {
2851984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    return mState.restoreToCount(saveCount);
2852984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2853984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2854984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonvoid OpenGLRenderer::translate(float dx, float dy, float dz) {
2855984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    return mState.translate(dx, dy, dz);
2856984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2857984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2858984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonvoid OpenGLRenderer::rotate(float degrees) {
2859984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    return mState.rotate(degrees);
2860984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2861984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2862984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonvoid OpenGLRenderer::scale(float sx, float sy) {
2863984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    return mState.scale(sx, sy);
2864984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2865984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2866984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonvoid OpenGLRenderer::skew(float sx, float sy) {
2867984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    return mState.skew(sx, sy);
2868984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2869984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2870984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonvoid OpenGLRenderer::setMatrix(const Matrix4& matrix) {
2871984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    mState.setMatrix(matrix);
2872984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2873984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2874984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonvoid OpenGLRenderer::concatMatrix(const Matrix4& matrix) {
2875984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    mState.concatMatrix(matrix);
2876984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2877984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2878984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonbool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
2879984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    return mState.clipRect(left, top, right, bottom, op);
2880984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2881984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2882984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonbool OpenGLRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
2883984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    return mState.clipPath(path, op);
2884984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2885984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2886984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonbool OpenGLRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
2887984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    return mState.clipRegion(region, op);
2888984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2889984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2890984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonvoid OpenGLRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
2891984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    mState.setClippingOutline(allocator, outline);
2892984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2893984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2894984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonvoid OpenGLRenderer::setClippingRoundRect(LinearAllocator& allocator,
2895984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson        const Rect& rect, float radius, bool highPriority) {
2896984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    mState.setClippingRoundRect(allocator, rect, radius, highPriority);
2897984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2898984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2899107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float x, float y,
2900d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
2901527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik        DrawOpMode drawOpMode) {
2902527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik
290303ae272459869b854e5db252fc81a64a516e111fChris Craik    if (drawOpMode == DrawOpMode::kImmediate) {
290428ce94a4ffc7576f40776d212f1ada79fafaa061Chris Craik        // The checks for corner-case ignorable text and quick rejection is only done for immediate
290528ce94a4ffc7576f40776d212f1ada79fafaa061Chris Craik        // drawing as ops from DeferredDisplayList are already filtered for these
2906e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik        if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint) ||
2907f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik                quickRejectSetupScissor(bounds)) {
2908107843de4507b3511006cb9c77b8d0364374385aTom Hudson            return;
290928ce94a4ffc7576f40776d212f1ada79fafaa061Chris Craik        }
2910cac5fd3e09e9dc918753d4aff624bf29a367ade3Romain Guy    }
2911cac5fd3e09e9dc918753d4aff624bf29a367ade3Romain Guy
29123a3fa1be9ab8e11edc660ecb35ae21ae0b5c8cc2Romain Guy    const float oldX = x;
29133a3fa1be9ab8e11edc660ecb35ae21ae0b5c8cc2Romain Guy    const float oldY = y;
2914624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy
2915d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    const mat4& transform = *currentTransform();
2916624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    const bool pureTranslate = transform.isPureTranslate();
2917c74f45a334f0e3725c23cdd270cbcb0efac4ea75Romain Guy
2918211370fd943cf26905001b38b8b1791851b26adcRomain Guy    if (CC_LIKELY(pureTranslate)) {
2919624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy        x = (int) floorf(x + transform.getTranslateX() + 0.5f);
2920624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy        y = (int) floorf(y + transform.getTranslateY() + 0.5f);
29216620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy    }
29226620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy
292386568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy    int alpha;
292486568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy    SkXfermode::Mode mode;
292586568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy    getAlphaAndMode(paint, &alpha, &mode);
29269d13fe25f4f10b25776b1dc5c858f9ebb0b28b30Romain Guy
2927c74f45a334f0e3725c23cdd270cbcb0efac4ea75Romain Guy    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
2928c74f45a334f0e3725c23cdd270cbcb0efac4ea75Romain Guy
2929c29a0a4664a4b9871fadd668b632469a0db240b9Derek Sollenberger    if (CC_UNLIKELY(hasTextShadow(paint))) {
293059744b79ec302000802cd56d30a1bf70f0183c80Chris Craik        fontRenderer.setFont(paint, SkMatrix::I());
2931c74f45a334f0e3725c23cdd270cbcb0efac4ea75Romain Guy        drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
293276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger                alpha, oldX, oldY);
29331e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    }
29341e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
293519d4dd8599cb870923ab349d2ab96cacffd9c6f5Romain Guy    const bool hasActiveLayer = hasLayer();
293619d4dd8599cb870923ab349d2ab96cacffd9c6f5Romain Guy
2937624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // We only pass a partial transform to the font renderer. That partial
2938624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // matrix defines how glyphs are rasterized. Typically we want glyphs
2939624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // to be rasterized at their final size on screen, which means the partial
2940624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // matrix needs to take the scale factor into account.
2941624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // When a partial matrix is used to transform glyphs during rasterization,
2942624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // the mesh is generated with the inverse transform (in the case of scale,
2943624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // the mesh is generated at 1.0 / scale for instance.) This allows us to
2944624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // apply the full transform matrix at draw time in the vertex shader.
2945624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // Applying the full matrix in the shader is the easiest way to handle
2946624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // rotation and perspective and allows us to always generated quads in the
2947624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // font renderer which greatly simplifies the code, clipping in particular.
294859744b79ec302000802cd56d30a1bf70f0183c80Chris Craik    SkMatrix fontTransform;
294959744b79ec302000802cd56d30a1bf70f0183c80Chris Craik    bool linearFilter = findBestFontTransform(transform, &fontTransform)
295059744b79ec302000802cd56d30a1bf70f0183c80Chris Craik            || fabs(y - (int) y) > 0.0f
295159744b79ec302000802cd56d30a1bf70f0183c80Chris Craik            || fabs(x - (int) x) > 0.0f;
29523b753829ae858d424fe109f714745379a6daf455Romain Guy    fontRenderer.setFont(paint, fontTransform);
2953257ae3502cfad43df681b1783528d645bdabc63fRomain Guy    fontRenderer.setTextureFiltering(linearFilter);
295406f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
2955624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // TODO: Implement better clipping for scaled/rotated text
2956487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    const Rect* clip = !pureTranslate ? nullptr : &mState.currentClipRect();
295741541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik    Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
29585b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
2959996e57c84368058be793897ebc355b917a59abc2Raph Levien    bool status;
29601e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
2961527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik
2962527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik    // don't call issuedrawcommand, do it at end of batch
296303ae272459869b854e5db252fc81a64a516e111fChris Craik    bool forceFinish = (drawOpMode != DrawOpMode::kDefer);
2964a3dc55f83ab583e0a66b893c71b849afa046770aRomain Guy    if (CC_UNLIKELY(paint->getTextAlign() != SkPaint::kLeft_Align)) {
29658b4072d3fb9bb49d774d97689a065204beca1752Raph Levien        SkPaint paintCopy(*paint);
29668b4072d3fb9bb49d774d97689a065204beca1752Raph Levien        paintCopy.setTextAlign(SkPaint::kLeft_Align);
29678b4072d3fb9bb49d774d97689a065204beca1752Raph Levien        status = fontRenderer.renderPosText(&paintCopy, clip, text, 0, bytesCount, count, x, y,
2968e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik                positions, hasActiveLayer ? &layerBounds : nullptr, &functor, forceFinish);
2969996e57c84368058be793897ebc355b917a59abc2Raph Levien    } else {
29708b4072d3fb9bb49d774d97689a065204beca1752Raph Levien        status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
2971e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik                positions, hasActiveLayer ? &layerBounds : nullptr, &functor, forceFinish);
2972996e57c84368058be793897ebc355b917a59abc2Raph Levien    }
29734ff0cf4b83605bff630c4e6f1fabe4f72a3f93a1Romain Guy
297403ae272459869b854e5db252fc81a64a516e111fChris Craik    if ((status || drawOpMode != DrawOpMode::kImmediate) && hasActiveLayer) {
2975624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy        if (!pureTranslate) {
297641541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik            transform.mapRect(layerBounds);
2977a4adcf0239039eb8f005be252409901c41b28839Romain Guy        }
297841541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik        dirtyLayerUnchecked(layerBounds, getRegion());
29795b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    }
2980694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
2981e63f7c622a2086aefa80983c6f41b74fb166bb42Chris Craik    drawTextDecorations(totalAdvance, oldX, oldY, paint);
2982486590963e2207d68eebd6944fec70d50d41116aChet Haase
2983107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
2984694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
2985694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
2986107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
2987d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) {
2988e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) {
2989107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
299003d58520c3eb6bb7efb7235bfd957550533d6725Romain Guy    }
299103d58520c3eb6bb7efb7235bfd957550533d6725Romain Guy
299239a908c1df89e1073627b0dcbce922d826b67055Chris Craik    // TODO: avoid scissor by calculating maximum bounds using path bounds + font metrics
299365fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik    mRenderState.scissor().setEnabled(true);
299439a908c1df89e1073627b0dcbce922d826b67055Chris Craik
2995b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
299659744b79ec302000802cd56d30a1bf70f0183c80Chris Craik    fontRenderer.setFont(paint, SkMatrix::I());
2997257ae3502cfad43df681b1783528d645bdabc63fRomain Guy    fontRenderer.setTextureFiltering(true);
299803d58520c3eb6bb7efb7235bfd957550533d6725Romain Guy
299903d58520c3eb6bb7efb7235bfd957550533d6725Romain Guy    int alpha;
300003d58520c3eb6bb7efb7235bfd957550533d6725Romain Guy    SkXfermode::Mode mode;
300103d58520c3eb6bb7efb7235bfd957550533d6725Romain Guy    getAlphaAndMode(paint, &alpha, &mode);
30021e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    TextSetupFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint);
30039777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
3004984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    const Rect* clip = &writableSnapshot()->getLocalClip();
30059777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
300603d58520c3eb6bb7efb7235bfd957550533d6725Romain Guy
30079777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    const bool hasActiveLayer = hasLayer();
30089777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
30099777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path,
3010e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik            hOffset, vOffset, hasActiveLayer ? &bounds : nullptr, &functor)) {
30119777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        if (hasActiveLayer) {
3012d6b65f67717025b1162f86f04e2caa5723566cacChris Craik            currentTransform()->mapRect(bounds);
30139777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            dirtyLayerUnchecked(bounds, getRegion());
30149777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        }
30159777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
3016486590963e2207d68eebd6944fec70d50d41116aChet Haase
3017107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
3018325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy}
3019325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy
3020107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
3021984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored()) return;
3022dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy
302344eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik    mCaches.textureState().activateTexture(0);
30247fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
302530036092b40badecbe64d9c2bff4850132147f78Chris Craik    PathTexture* texture = mCaches.pathCache.get(path, paint);
3026107843de4507b3511006cb9c77b8d0364374385aTom Hudson    if (!texture) return;
302722158e139a3d6c6a9787ca0de224e9368f643284Romain Guy    const AutoTexture autoCleanup(texture);
30287fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
30298b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy    const float x = texture->left - texture->offset;
30308b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy    const float y = texture->top - texture->offset;
30318b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy
303201d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    drawPathTexture(texture, x, y, paint);
3033107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
30347fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy}
30357fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
3036107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
303735643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    if (!layer) {
3038107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
30396c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    }
30406c319ca1275c8db892c39b48fc54864c949f9171Romain Guy
3041e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    mat4* transform = nullptr;
3042b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy    if (layer->isTextureLayer()) {
3043b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy        transform = &layer->getTransform();
3044b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy        if (!transform->isIdentity()) {
30453f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik            save(SkCanvas::kMatrix_SaveFlag);
304614e513058ed4168c94e015638d16f5f87fd8063aChris Craik            concatMatrix(*transform);
3047b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy        }
3048b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy    }
3049b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy
305039a908c1df89e1073627b0dcbce922d826b67055Chris Craik    bool clipRequired = false;
3051e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    const bool rejected = mState.calculateQuickRejectForScissor(
3052e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik            x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(),
3053e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik            &clipRequired, nullptr, false);
30544ff0cf4b83605bff630c4e6f1fabe4f72a3f93a1Romain Guy
305535643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    if (rejected) {
3056b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy        if (transform && !transform->isIdentity()) {
3057b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy            restore();
3058b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy        }
3059107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
306035643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    }
306135643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy
306262d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik    EVENT_LOGD("drawLayer," RECT_STRING ", clipRequired %d", x, y,
306362d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik            x + layer->layer.getWidth(), y + layer->layer.getHeight(), clipRequired);
306462d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik
30655bb3c730f5ebd2a0db1b02a8981c6fdbea6c1a2eRomain Guy    updateLayer(layer, true);
30662bf68f063b0077ddef6ebfe54f2ae5e063c2c229Romain Guy
306765fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik    mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
306844eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik    mCaches.textureState().activateTexture(0);
30696c319ca1275c8db892c39b48fc54864c949f9171Romain Guy
3070211370fd943cf26905001b38b8b1791851b26adcRomain Guy    if (CC_LIKELY(!layer->region.isEmpty())) {
3071c88e357d1ed9dadfc0efb3dfbe92f24460674ef5Romain Guy        if (layer->region.isRect()) {
307234416eaa1c07b3d7a139e780cea8f8d73219650eChris Craik            DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
307334416eaa1c07b3d7a139e780cea8f8d73219650eChris Craik                    composeLayerRect(layer, layer->regionRect));
3074c88e357d1ed9dadfc0efb3dfbe92f24460674ef5Romain Guy        } else if (layer->mesh) {
3075f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik            if (USE_GLOPS) {
3076f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                Glop glop;
3077f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                GlopBuilder aBuilder(mRenderState, mCaches, &glop);
3078f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                aBuilder.setMeshTexturedIndexedQuads(layer->mesh, layer->meshElementCount)
3079f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                        .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode())
3080f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                        .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
3081f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                        .setModelViewOffsetRectSnap(x, y, Rect(0, 0, layer->layer.getWidth(), layer->layer.getHeight()))
3082f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                        .setRoundRectClipState(currentSnapshot()->roundRectClipState)
3083f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                        .build();
3084f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
30859ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy            } else {
3086f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                const float a = getLayerAlpha(layer);
3087f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                setupDraw();
3088f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                setupDrawWithTexture();
3089f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                setupDrawColor(a, a, a, a);
3090f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                setupDrawColorFilter(layer->getColorFilter());
3091f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                setupDrawBlending(layer);
3092f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                setupDrawProgram();
3093f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                setupDrawPureColorUniforms();
3094f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                setupDrawColorFilterUniforms(layer->getColorFilter());
3095f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                setupDrawTexture(layer->getTextureId());
3096f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                if (CC_LIKELY(currentTransform()->isPureTranslate())) {
3097f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    int tx = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f);
3098f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    int ty = (int) floorf(y + currentTransform()->getTranslateY() + 0.5f);
3099f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik
3100f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    layer->setFilter(GL_NEAREST);
3101f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    setupDrawModelView(kModelViewMode_Translate, false, tx, ty,
3102f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                            tx + layer->layer.getWidth(), ty + layer->layer.getHeight(), true);
3103f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                } else {
3104f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    layer->setFilter(GL_LINEAR);
3105f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    setupDrawModelView(kModelViewMode_Translate, false, x, y,
3106f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                            x + layer->layer.getWidth(), y + layer->layer.getHeight());
3107f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                }
3108c88e357d1ed9dadfc0efb3dfbe92f24460674ef5Romain Guy
3109448455fe783b0a711340322dca272b8cc0ebe473Romain Guy
3110f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                TextureVertex* mesh = &layer->mesh[0];
3111f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                GLsizei elementsCount = layer->meshElementCount;
3112448455fe783b0a711340322dca272b8cc0ebe473Romain Guy
3113448455fe783b0a711340322dca272b8cc0ebe473Romain Guy
3114f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                while (elementsCount > 0) {
3115f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    GLsizei drawCount = MathUtils::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
3116f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik
3117f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
3118f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
3119f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                            glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, nullptr));
3120c88e357d1ed9dadfc0efb3dfbe92f24460674ef5Romain Guy
3121f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    elementsCount -= drawCount;
3122f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    // Though there are 4 vertices in a quad, we use 6 indices per
3123f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    // quad to draw with GL_TRIANGLES
3124f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    mesh += (drawCount / 6) * 4;
3125f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                }
3126f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik            }
31273a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy#if DEBUG_LAYERS_AS_REGIONS
3128e63f7c622a2086aefa80983c6f41b74fb166bb42Chris Craik            drawRegionRectsDebug(layer->region);
31293a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy#endif
3130c88e357d1ed9dadfc0efb3dfbe92f24460674ef5Romain Guy        }
31314ff0cf4b83605bff630c4e6f1fabe4f72a3f93a1Romain Guy
31325bb3c730f5ebd2a0db1b02a8981c6fdbea6c1a2eRomain Guy        if (layer->debugDrawUpdate) {
31335bb3c730f5ebd2a0db1b02a8981c6fdbea6c1a2eRomain Guy            layer->debugDrawUpdate = false;
313476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
313576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger            SkPaint paint;
313676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger            paint.setColor(0x7f00ff00);
313776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger            drawColorRect(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(), &paint);
31384ff0cf4b83605bff630c4e6f1fabe4f72a3f93a1Romain Guy        }
3139f219da5e32e85deb442468ee9a63bb28eb198557Romain Guy    }
314034416eaa1c07b3d7a139e780cea8f8d73219650eChris Craik    layer->hasDrawnSinceUpdate = true;
3141486590963e2207d68eebd6944fec70d50d41116aChet Haase
3142b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy    if (transform && !transform->isIdentity()) {
3143b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy        restore();
3144b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy    }
3145b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy
3146107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
31476c319ca1275c8db892c39b48fc54864c949f9171Romain Guy}
31486c319ca1275c8db892c39b48fc54864c949f9171Romain Guy
31496926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy///////////////////////////////////////////////////////////////////////////////
31505ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy// Draw filters
31515ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy///////////////////////////////////////////////////////////////////////////////
315209c2d4fe15fbac2faf8a97ba2cc59132ee12222aDerek Sollenbergervoid OpenGLRenderer::setDrawFilter(SkDrawFilter* filter) {
315309c2d4fe15fbac2faf8a97ba2cc59132ee12222aDerek Sollenberger    // We should never get here since we apply the draw filter when stashing
315409c2d4fe15fbac2faf8a97ba2cc59132ee12222aDerek Sollenberger    // the paints in the DisplayList.
315509c2d4fe15fbac2faf8a97ba2cc59132ee12222aDerek Sollenberger    LOG_ALWAYS_FATAL("OpenGLRenderer does not directly support DrawFilters");
31565ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy}
31575ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy
31585ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy///////////////////////////////////////////////////////////////////////////////
31596926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy// Drawing implementation
31606926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy///////////////////////////////////////////////////////////////////////////////
31616926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy
3162d218a92c0afb8c0d98135b20b52ac87236e1c935Chris CraikTexture* OpenGLRenderer::getTexture(const SkBitmap* bitmap) {
3163ebd52610cfeff6e557fde284a7e1efc5e6438285John Reck    Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap);
31643b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    if (!texture) {
31653b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        return mCaches.textureCache.get(bitmap);
31663b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    }
31673b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    return texture;
31683b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy}
31693b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
31702bb8f5606d4a28549d95005304305b3aff1ce090Chris Craikvoid OpenGLRenderer::drawPathTexture(PathTexture* texture, float x, float y,
31712bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik        const SkPaint* paint) {
3172f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik    if (quickRejectSetupScissor(x, y, x + texture->width, y + texture->height)) {
317301d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy        return;
317401d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    }
317501d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
3176922d3a7f6f8c1c05a996ee3e91e8cbadfff560c9Chris Craik    if (USE_GLOPS) {
317730036092b40badecbe64d9c2bff4850132147f78Chris Craik        Glop glop;
317830036092b40badecbe64d9c2bff4850132147f78Chris Craik        GlopBuilder aBuilder(mRenderState, mCaches, &glop);
3179f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik        aBuilder.setMeshTexturedUnitQuad(nullptr)
318030036092b40badecbe64d9c2bff4850132147f78Chris Craik                .setFillPathTexturePaint(*texture, *paint, currentSnapshot()->alpha)
3181f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
318230036092b40badecbe64d9c2bff4850132147f78Chris Craik                .setModelViewMapUnitToRect(Rect(x, y, x + texture->width, y + texture->height))
318330036092b40badecbe64d9c2bff4850132147f78Chris Craik                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
318430036092b40badecbe64d9c2bff4850132147f78Chris Craik                .build();
318530036092b40badecbe64d9c2bff4850132147f78Chris Craik        renderGlop(glop);
318630036092b40badecbe64d9c2bff4850132147f78Chris Craik        return;
318730036092b40badecbe64d9c2bff4850132147f78Chris Craik    }
318830036092b40badecbe64d9c2bff4850132147f78Chris Craik
318930036092b40badecbe64d9c2bff4850132147f78Chris Craik
319001d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    int alpha;
319101d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    SkXfermode::Mode mode;
319201d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    getAlphaAndMode(paint, &alpha, &mode);
319301d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
319401d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    setupDraw();
319501d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    setupDrawWithTexture(true);
319601d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    setupDrawAlpha8Color(paint->getColor(), alpha);
319776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilter(getColorFilter(paint));
3198d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShader(getShader(paint));
319976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawBlending(paint, true);
320001d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    setupDrawProgram();
32014063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik    setupDrawModelView(kModelViewMode_TranslateAndScale, false,
32024063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik            x, y, x + texture->width, y + texture->height);
320301d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    setupDrawTexture(texture->id);
320401d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    setupDrawPureColorUniforms();
320576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilterUniforms(getColorFilter(paint));
3206d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShaderUniforms(getShader(paint));
320796a5c4c7bab6718524de7253da8309143ab48befChris Craik    setupDrawMesh(nullptr, (GLvoid*) kMeshTextureOffset);
320801d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
3209117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
321001d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy}
321101d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
3212f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy// Same values used by Skia
32130a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy#define kStdStrikeThru_Offset   (-6.0f / 21.0f)
32140a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy#define kStdUnderline_Offset    (1.0f / 9.0f)
32150a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy#define kStdUnderline_Thickness (1.0f / 18.0f)
32160a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
3217d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craikvoid OpenGLRenderer::drawTextDecorations(float underlineWidth, float x, float y,
3218d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        const SkPaint* paint) {
32190a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    // Handle underline and strike-through
32200a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    uint32_t flags = paint->getFlags();
32210a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
3222726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy        SkPaint paintCopy(*paint);
32230a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
3224211370fd943cf26905001b38b8b1791851b26adcRomain Guy        if (CC_LIKELY(underlineWidth > 0.0f)) {
3225726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy            const float textSize = paintCopy.getTextSize();
3226f6834478b379856d3e5de92ddce7de0e6ba9fa4aRomain Guy            const float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
32270a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
32288b4072d3fb9bb49d774d97689a065204beca1752Raph Levien            const float left = x;
32290a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy            float top = 0.0f;
3230e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy
3231f6834478b379856d3e5de92ddce7de0e6ba9fa4aRomain Guy            int linesCount = 0;
3232f6834478b379856d3e5de92ddce7de0e6ba9fa4aRomain Guy            if (flags & SkPaint::kUnderlineText_Flag) linesCount++;
3233f6834478b379856d3e5de92ddce7de0e6ba9fa4aRomain Guy            if (flags & SkPaint::kStrikeThruText_Flag) linesCount++;
3234f6834478b379856d3e5de92ddce7de0e6ba9fa4aRomain Guy
3235f6834478b379856d3e5de92ddce7de0e6ba9fa4aRomain Guy            const int pointsCount = 4 * linesCount;
3236e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy            float points[pointsCount];
3237e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy            int currentPoint = 0;
32380a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
32390a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy            if (flags & SkPaint::kUnderlineText_Flag) {
32400a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy                top = y + textSize * kStdUnderline_Offset;
3241e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = left;
3242e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = top;
3243e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = left + underlineWidth;
3244e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = top;
32450a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy            }
32460a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
32470a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy            if (flags & SkPaint::kStrikeThruText_Flag) {
32480a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy                top = y + textSize * kStdStrikeThru_Offset;
3249e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = left;
3250e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = top;
3251e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = left + underlineWidth;
3252e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = top;
32530a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy            }
3254e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy
3255726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy            paintCopy.setStrokeWidth(strokeWidth);
3256e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy
3257726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy            drawLines(&points[0], pointsCount, &paintCopy);
32580a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy        }
32590a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    }
32600a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy}
32610a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
3262107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
3263984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored()) {
3264107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
3265672433d90fab7383cd28beac9d4485b566a90940Romain Guy    }
3266672433d90fab7383cd28beac9d4485b566a90940Romain Guy
3267107843de4507b3511006cb9c77b8d0364374385aTom Hudson    drawColorRects(rects, count, paint, false, true, true);
3268735738c4ddf3229caa5f6e634bf591953ac29944Romain Guy}
3269735738c4ddf3229caa5f6e634bf591953ac29944Romain Guy
3270107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawShadow(float casterAlpha,
327105f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik        const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) {
3272984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored()) return;
3273f57776b2d195f0937906eb88b777bb55ccc36967Chris Craik
327415a07a21eb33e8ca1c7444944fe0541a53380c0cChris Craik    // TODO: use quickRejectWithScissor. For now, always force enable scissor.
327565fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik    mRenderState.scissor().setEnabled(true);
3276f57776b2d195f0937906eb88b777bb55ccc36967Chris Craik
3277f57776b2d195f0937906eb88b777bb55ccc36967Chris Craik    SkPaint paint;
3278ba9b613437c34873fa95800a25fc51720638267cChris Craik    paint.setAntiAlias(true); // want to use AlphaVertex
3279f57776b2d195f0937906eb88b777bb55ccc36967Chris Craik
328014a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui    // The caller has made sure casterAlpha > 0.
328114a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui    float ambientShadowAlpha = mAmbientShadowAlpha;
328214a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui    if (CC_UNLIKELY(mCaches.propertyAmbientShadowStrength >= 0)) {
328314a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui        ambientShadowAlpha = mCaches.propertyAmbientShadowStrength;
328414a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui    }
328514a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui    if (ambientShadowVertexBuffer && ambientShadowAlpha > 0) {
328614a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui        paint.setARGB(casterAlpha * ambientShadowAlpha, 0, 0, 0);
328791a8c7c62913c2597e3bf5a6d59d2ed5fc7ba4e0Chris Craik        drawVertexBuffer(*ambientShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp);
3288ef94c6f88fbb1deb095b1494378befcdb9722839ztenghui    }
3289ef94c6f88fbb1deb095b1494378befcdb9722839ztenghui
329014a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui    float spotShadowAlpha = mSpotShadowAlpha;
329114a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui    if (CC_UNLIKELY(mCaches.propertySpotShadowStrength >= 0)) {
329214a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui        spotShadowAlpha = mCaches.propertySpotShadowStrength;
329314a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui    }
329414a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui    if (spotShadowVertexBuffer && spotShadowAlpha > 0) {
329514a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui        paint.setARGB(casterAlpha * spotShadowAlpha, 0, 0, 0);
329691a8c7c62913c2597e3bf5a6d59d2ed5fc7ba4e0Chris Craik        drawVertexBuffer(*spotShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp);
3297ef94c6f88fbb1deb095b1494378befcdb9722839ztenghui    }
32987b4516e7ea552ad08d6e7277d311ef11bd8f12e8ztenghui
3299107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty=true;
3300f57776b2d195f0937906eb88b777bb55ccc36967Chris Craik}
3301f57776b2d195f0937906eb88b777bb55ccc36967Chris Craik
3302107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawColorRects(const float* rects, int count, const SkPaint* paint,
330376d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        bool ignoreTransform, bool dirty, bool clip) {
33043b753829ae858d424fe109f714745379a6daf455Romain Guy    if (count == 0) {
3305107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
33063b753829ae858d424fe109f714745379a6daf455Romain Guy    }
3307735738c4ddf3229caa5f6e634bf591953ac29944Romain Guy
3308672433d90fab7383cd28beac9d4485b566a90940Romain Guy    float left = FLT_MAX;
3309672433d90fab7383cd28beac9d4485b566a90940Romain Guy    float top = FLT_MAX;
3310672433d90fab7383cd28beac9d4485b566a90940Romain Guy    float right = FLT_MIN;
3311672433d90fab7383cd28beac9d4485b566a90940Romain Guy    float bottom = FLT_MIN;
3312672433d90fab7383cd28beac9d4485b566a90940Romain Guy
3313448455fe783b0a711340322dca272b8cc0ebe473Romain Guy    Vertex mesh[count];
3314672433d90fab7383cd28beac9d4485b566a90940Romain Guy    Vertex* vertex = mesh;
3315672433d90fab7383cd28beac9d4485b566a90940Romain Guy
33162af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    for (int index = 0; index < count; index += 4) {
3317672433d90fab7383cd28beac9d4485b566a90940Romain Guy        float l = rects[index + 0];
3318672433d90fab7383cd28beac9d4485b566a90940Romain Guy        float t = rects[index + 1];
3319672433d90fab7383cd28beac9d4485b566a90940Romain Guy        float r = rects[index + 2];
3320672433d90fab7383cd28beac9d4485b566a90940Romain Guy        float b = rects[index + 3];
3321672433d90fab7383cd28beac9d4485b566a90940Romain Guy
33223b753829ae858d424fe109f714745379a6daf455Romain Guy        Vertex::set(vertex++, l, t);
33233b753829ae858d424fe109f714745379a6daf455Romain Guy        Vertex::set(vertex++, r, t);
33243b753829ae858d424fe109f714745379a6daf455Romain Guy        Vertex::set(vertex++, l, b);
33253b753829ae858d424fe109f714745379a6daf455Romain Guy        Vertex::set(vertex++, r, b);
3326672433d90fab7383cd28beac9d4485b566a90940Romain Guy
33273b753829ae858d424fe109f714745379a6daf455Romain Guy        left = fminf(left, l);
33283b753829ae858d424fe109f714745379a6daf455Romain Guy        top = fminf(top, t);
33293b753829ae858d424fe109f714745379a6daf455Romain Guy        right = fmaxf(right, r);
33303b753829ae858d424fe109f714745379a6daf455Romain Guy        bottom = fmaxf(bottom, b);
3331672433d90fab7383cd28beac9d4485b566a90940Romain Guy    }
3332672433d90fab7383cd28beac9d4485b566a90940Romain Guy
3333f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik    if (clip && quickRejectSetupScissor(left, top, right, bottom)) {
3334107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
3335a362c69d6cdf448107e5a539f77df73937141870Romain Guy    }
3336672433d90fab7383cd28beac9d4485b566a90940Romain Guy
3337922d3a7f6f8c1c05a996ee3e91e8cbadfff560c9Chris Craik    if (USE_GLOPS) {
33382ab95d780b023152556d9f8659de734ec7b55047Chris Craik        const Matrix4& transform = ignoreTransform ? Matrix4::identity() : *currentTransform();
33392ab95d780b023152556d9f8659de734ec7b55047Chris Craik        Glop glop;
33402ab95d780b023152556d9f8659de734ec7b55047Chris Craik        GlopBuilder aBuilder(mRenderState, mCaches, &glop);
33412ab95d780b023152556d9f8659de734ec7b55047Chris Craik        aBuilder.setMeshIndexedQuads(&mesh[0], count / 4)
33420519c810a56bded1284fcb2ae40f438878c6585fChris Craik                .setFillPaint(*paint, currentSnapshot()->alpha)
3343f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
33442ab95d780b023152556d9f8659de734ec7b55047Chris Craik                .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
33450519c810a56bded1284fcb2ae40f438878c6585fChris Craik                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
33462ab95d780b023152556d9f8659de734ec7b55047Chris Craik                .build();
33472ab95d780b023152556d9f8659de734ec7b55047Chris Craik        renderGlop(glop);
33482ab95d780b023152556d9f8659de734ec7b55047Chris Craik        return;
33492ab95d780b023152556d9f8659de734ec7b55047Chris Craik    }
33502ab95d780b023152556d9f8659de734ec7b55047Chris Craik
33512ab95d780b023152556d9f8659de734ec7b55047Chris Craik    int color = paint->getColor();
33522ab95d780b023152556d9f8659de734ec7b55047Chris Craik    // If a shader is set, preserve only the alpha
33532ab95d780b023152556d9f8659de734ec7b55047Chris Craik    if (getShader(paint)) {
33542ab95d780b023152556d9f8659de734ec7b55047Chris Craik        color |= 0x00ffffff;
33552ab95d780b023152556d9f8659de734ec7b55047Chris Craik    }
33562ab95d780b023152556d9f8659de734ec7b55047Chris Craik
3357672433d90fab7383cd28beac9d4485b566a90940Romain Guy    setupDraw();
3358672433d90fab7383cd28beac9d4485b566a90940Romain Guy    setupDrawNoTexture();
3359d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
3360d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShader(getShader(paint));
336176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilter(getColorFilter(paint));
336276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawBlending(paint);
3363672433d90fab7383cd28beac9d4485b566a90940Romain Guy    setupDrawProgram();
3364672433d90fab7383cd28beac9d4485b566a90940Romain Guy    setupDrawDirtyRegionsDisabled();
33654063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik    setupDrawModelView(kModelViewMode_Translate, false,
33664063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik            0.0f, 0.0f, 0.0f, 0.0f, ignoreTransform);
3367d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawColorUniforms(getShader(paint));
3368d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShaderUniforms(getShader(paint));
336976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilterUniforms(getColorFilter(paint));
3370672433d90fab7383cd28beac9d4485b566a90940Romain Guy
33718ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy    if (dirty && hasLayer()) {
3372d6b65f67717025b1162f86f04e2caa5723566cacChris Craik        dirtyLayer(left, top, right, bottom, *currentTransform());
3373672433d90fab7383cd28beac9d4485b566a90940Romain Guy    }
3374672433d90fab7383cd28beac9d4485b566a90940Romain Guy
33754063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik    issueIndexedQuadDraw(&mesh[0], count / 4);
3376672433d90fab7383cd28beac9d4485b566a90940Romain Guy
3377107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
3378672433d90fab7383cd28beac9d4485b566a90940Romain Guy}
3379672433d90fab7383cd28beac9d4485b566a90940Romain Guy
3380026c5e16704e817cac7d9c382914c947e34f87e0Romain Guyvoid OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
338176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        const SkPaint* paint, bool ignoreTransform) {
3382117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik
3383922d3a7f6f8c1c05a996ee3e91e8cbadfff560c9Chris Craik    if (USE_GLOPS) {
3384117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        const Matrix4& transform = ignoreTransform ? Matrix4::identity() : *currentTransform();
3385117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        Glop glop;
3386117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        GlopBuilder aBuilder(mRenderState, mCaches, &glop);
3387117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        aBuilder.setMeshUnitQuad()
33880519c810a56bded1284fcb2ae40f438878c6585fChris Craik                .setFillPaint(*paint, currentSnapshot()->alpha)
3389f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
3390117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik                .setModelViewMapUnitToRect(Rect(left, top, right, bottom))
33910519c810a56bded1284fcb2ae40f438878c6585fChris Craik                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
3392117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik                .build();
3393117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        renderGlop(glop);
3394117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        return;
3395117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    }
3396117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik
339776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    int color = paint->getColor();
3398d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy    // If a shader is set, preserve only the alpha
3399d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    if (getShader(paint)) {
3400d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        color |= 0x00ffffff;
3401d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy    }
3402d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy
340370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    setupDraw();
340415bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy    setupDrawNoTexture();
3405d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
3406d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShader(getShader(paint));
340776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilter(getColorFilter(paint));
340876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawBlending(paint);
340970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    setupDrawProgram();
34104063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik    setupDrawModelView(kModelViewMode_TranslateAndScale, false,
34114063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik            left, top, right, bottom, ignoreTransform);
3412d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawColorUniforms(getShader(paint));
3413d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShaderUniforms(getShader(paint), ignoreTransform);
341476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilterUniforms(getColorFilter(paint));
341570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    setupDrawSimpleMesh();
3416c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy
3417117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
3418c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy}
3419c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy
34200519c810a56bded1284fcb2ae40f438878c6585fChris Craikvoid OpenGLRenderer::drawTextureRect(Texture* texture, const SkPaint* paint) {
3421d21b6e1fe337b35f62cf2028e9bd0637fd009a75Romain Guy    texture->setWrap(GL_CLAMP_TO_EDGE, true);
34228164c2d338781c3a3c4a443941070dca5d88f2a7Romain Guy
3423e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    GLvoid* vertices = (GLvoid*) nullptr;
342496a5c4c7bab6718524de7253da8309143ab48befChris Craik    GLvoid* texCoords = (GLvoid*) kMeshTextureOffset;
34253b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
34263b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    if (texture->uvMapper) {
34273380cfdc77100e87aa8390386ccf390834dea171Romain Guy        vertices = &mMeshVertices[0].x;
34283380cfdc77100e87aa8390386ccf390834dea171Romain Guy        texCoords = &mMeshVertices[0].u;
34293b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
34303b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        Rect uvs(0.0f, 0.0f, 1.0f, 1.0f);
34313b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        texture->uvMapper->map(uvs);
34323b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
34333b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        resetDrawTextureTexCoords(uvs.left, uvs.top, uvs.right, uvs.bottom);
34343b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    }
34353b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
3436d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    if (CC_LIKELY(currentTransform()->isPureTranslate())) {
34370519c810a56bded1284fcb2ae40f438878c6585fChris Craik        const float x = (int) floorf(currentTransform()->getTranslateX() + 0.5f);
34380519c810a56bded1284fcb2ae40f438878c6585fChris Craik        const float y = (int) floorf(currentTransform()->getTranslateY() + 0.5f);
34396620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy
3440d21b6e1fe337b35f62cf2028e9bd0637fd009a75Romain Guy        texture->setFilter(GL_NEAREST, true);
34416620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
344276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger                paint, texture->blend, vertices, texCoords,
3443117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik                GL_TRIANGLE_STRIP, kUnitQuadCount, false, true);
34446620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy    } else {
34450519c810a56bded1284fcb2ae40f438878c6585fChris Craik        texture->setFilter(PaintUtils::getFilter(paint), true);
34460519c810a56bded1284fcb2ae40f438878c6585fChris Craik        drawTextureMesh(0, 0, texture->width, texture->height, texture->id, paint,
3447117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik                texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, kUnitQuadCount);
34483b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    }
34493b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
34503b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    if (texture->uvMapper) {
34513b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
34526620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy    }
345385bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy}
345485bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy
3455f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guyvoid OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
345676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        GLuint texture, const SkPaint* paint, bool blend,
34576820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy        GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
34584063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik        bool swapSrcDst, bool ignoreTransform, GLuint vbo,
34594063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik        ModelViewMode modelViewMode, bool dirty) {
34608694230ff25fa0a60e480d424843e56b718f0516Romain Guy
346176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    int a;
346276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    SkXfermode::Mode mode;
346376d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    getAlphaAndMode(paint, &a, &mode);
346476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    const float alpha = a / 255.0f;
346576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
346670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    setupDraw();
346770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    setupDrawWithTexture();
346870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    setupDrawColor(alpha, alpha, alpha, alpha);
346976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilter(getColorFilter(paint));
347076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawBlending(paint, blend, swapSrcDst);
347170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    setupDrawProgram();
3472886b275e529e44a59c54b933453d9bc902973178Romain Guy    if (!dirty) setupDrawDirtyRegionsDisabled();
34734063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik    setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
3474886b275e529e44a59c54b933453d9bc902973178Romain Guy    setupDrawTexture(texture);
347586568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy    setupDrawPureColorUniforms();
347676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilterUniforms(getColorFilter(paint));
347770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    setupDrawMesh(vertices, texCoords, vbo);
3478db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy
34796820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy    glDrawArrays(drawMode, 0, elementsCount);
348082ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy}
348182ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy
34823b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guyvoid OpenGLRenderer::drawIndexedTextureMesh(float left, float top, float right, float bottom,
348376d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        GLuint texture, const SkPaint* paint, bool blend,
34843b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
34854063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik        bool swapSrcDst, bool ignoreTransform, GLuint vbo,
34864063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik        ModelViewMode modelViewMode, bool dirty) {
34873b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
348876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    int a;
348976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    SkXfermode::Mode mode;
349076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    getAlphaAndMode(paint, &a, &mode);
349176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    const float alpha = a / 255.0f;
349276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
34933b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    setupDraw();
34943b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    setupDrawWithTexture();
34953b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    setupDrawColor(alpha, alpha, alpha, alpha);
349676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilter(getColorFilter(paint));
349776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawBlending(paint, blend, swapSrcDst);
34983b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    setupDrawProgram();
34993b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    if (!dirty) setupDrawDirtyRegionsDisabled();
35004063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik    setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
35013b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    setupDrawTexture(texture);
35023b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    setupDrawPureColorUniforms();
350376d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilterUniforms(getColorFilter(paint));
35043b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    setupDrawMeshIndices(vertices, texCoords, vbo);
35053b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
3506e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    glDrawElements(drawMode, elementsCount, GL_UNSIGNED_SHORT, nullptr);
35073b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy}
35083b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
3509886b275e529e44a59c54b933453d9bc902973178Romain Guyvoid OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom,
351076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        GLuint texture, const SkPaint* paint,
3511886b275e529e44a59c54b933453d9bc902973178Romain Guy        GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
35124063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik        bool ignoreTransform, ModelViewMode modelViewMode, bool dirty) {
3513886b275e529e44a59c54b933453d9bc902973178Romain Guy
3514e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    int color = paint != nullptr ? paint->getColor() : 0;
351576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    int alpha;
351676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    SkXfermode::Mode mode;
351776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    getAlphaAndMode(paint, &alpha, &mode);
351876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
3519886b275e529e44a59c54b933453d9bc902973178Romain Guy    setupDraw();
3520886b275e529e44a59c54b933453d9bc902973178Romain Guy    setupDrawWithTexture(true);
3521e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (paint != nullptr) {
3522886b275e529e44a59c54b933453d9bc902973178Romain Guy        setupDrawAlpha8Color(color, alpha);
3523886b275e529e44a59c54b933453d9bc902973178Romain Guy    }
352476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilter(getColorFilter(paint));
3525d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShader(getShader(paint));
352676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawBlending(paint, true);
3527886b275e529e44a59c54b933453d9bc902973178Romain Guy    setupDrawProgram();
3528886b275e529e44a59c54b933453d9bc902973178Romain Guy    if (!dirty) setupDrawDirtyRegionsDisabled();
35294063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik    setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
3530886b275e529e44a59c54b933453d9bc902973178Romain Guy    setupDrawTexture(texture);
3531886b275e529e44a59c54b933453d9bc902973178Romain Guy    setupDrawPureColorUniforms();
353276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilterUniforms(getColorFilter(paint));
3533d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShaderUniforms(getShader(paint), ignoreTransform);
3534886b275e529e44a59c54b933453d9bc902973178Romain Guy    setupDrawMesh(vertices, texCoords);
3535886b275e529e44a59c54b933453d9bc902973178Romain Guy
3536886b275e529e44a59c54b933453d9bc902973178Romain Guy    glDrawArrays(drawMode, 0, elementsCount);
3537886b275e529e44a59c54b933453d9bc902973178Romain Guy}
3538886b275e529e44a59c54b933453d9bc902973178Romain Guy
3539a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guyvoid OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
3540f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy        ProgramDescription& description, bool swapSrcDst) {
3541deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik
3542117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    if (currentSnapshot()->roundRectClipState != nullptr /*&& !mSkipOutlineClip*/) {
3543deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik        blend = true;
3544deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik        mDescription.hasRoundRectClip = true;
3545deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    }
3546deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    mSkipOutlineClip = true;
3547deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik
354882ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    blend = blend || mode != SkXfermode::kSrcOver_Mode;
3549c189ef53220059acf2adedc92ac4ac7e6a993e6bRomain Guy
355082ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    if (blend) {
355182bc7a772747fcf8a6fe7097f70bf2981429ffe9Romain Guy        // These blend modes are not supported by OpenGL directly and have
355282bc7a772747fcf8a6fe7097f70bf2981429ffe9Romain Guy        // to be implemented using shaders. Since the shader will perform
355382bc7a772747fcf8a6fe7097f70bf2981429ffe9Romain Guy        // the blending, turn blending off here
355482bc7a772747fcf8a6fe7097f70bf2981429ffe9Romain Guy        // If the blend mode cannot be implemented using shaders, fall
355582bc7a772747fcf8a6fe7097f70bf2981429ffe9Romain Guy        // back to the default SrcOver blend mode instead
355633fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy        if (CC_UNLIKELY(mode > SkXfermode::kScreen_Mode)) {
3557117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik            if (CC_UNLIKELY(mCaches.extensions().hasFramebufferFetch())) {
3558a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy                description.framebufferMode = mode;
3559f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy                description.swapSrcDst = swapSrcDst;
3560a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy
356144eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik                mRenderState.blend().disable();
356282bc7a772747fcf8a6fe7097f70bf2981429ffe9Romain Guy                return;
356382bc7a772747fcf8a6fe7097f70bf2981429ffe9Romain Guy            } else {
356482bc7a772747fcf8a6fe7097f70bf2981429ffe9Romain Guy                mode = SkXfermode::kSrcOver_Mode;
3565a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            }
356682bc7a772747fcf8a6fe7097f70bf2981429ffe9Romain Guy        }
356744eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik        mRenderState.blend().enable(mode, swapSrcDst);
356844eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik    } else {
356944eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik        mRenderState.blend().disable();
357082ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    }
3571bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy}
3572bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
3573026c5e16704e817cac7d9c382914c947e34f87e0Romain Guyvoid OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
3574ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy    TextureVertex* v = &mMeshVertices[0];
357582ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    TextureVertex::setUV(v++, u1, v1);
357682ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    TextureVertex::setUV(v++, u2, v1);
357782ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    TextureVertex::setUV(v++, u1, v2);
357882ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    TextureVertex::setUV(v++, u2, v2);
35798ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy}
35808ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy
3581e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craikvoid OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha,
3582e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik        SkXfermode::Mode* mode) const {
3583be6f9dc1e71b425b7ac1c40c0a2c72d03eb9fbeeRomain Guy    getAlphaAndModeDirect(paint, alpha,  mode);
358416ecda5317c40fc3da284952d9b3add34d6763aeChris Craik    if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
358516ecda5317c40fc3da284952d9b3add34d6763aeChris Craik        // if drawing a layer, ignore the paint's alpha
358687b515cde53f3c8cc3fdf698c100e67508487e59Romain Guy        *alpha = mDrawModifiers.mOverrideLayerAlpha * 255;
358716ecda5317c40fc3da284952d9b3add34d6763aeChris Craik    }
3588d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    *alpha *= currentSnapshot()->alpha;
3589026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy}
3590026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy
359176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenbergerfloat OpenGLRenderer::getLayerAlpha(const Layer* layer) const {
359216ecda5317c40fc3da284952d9b3add34d6763aeChris Craik    float alpha;
359316ecda5317c40fc3da284952d9b3add34d6763aeChris Craik    if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
359416ecda5317c40fc3da284952d9b3add34d6763aeChris Craik        alpha = mDrawModifiers.mOverrideLayerAlpha;
359516ecda5317c40fc3da284952d9b3add34d6763aeChris Craik    } else {
359616ecda5317c40fc3da284952d9b3add34d6763aeChris Craik        alpha = layer->getAlpha() / 255.0f;
359716ecda5317c40fc3da284952d9b3add34d6763aeChris Craik    }
3598d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    return alpha * currentSnapshot()->alpha;
359916ecda5317c40fc3da284952d9b3add34d6763aeChris Craik}
360016ecda5317c40fc3da284952d9b3add34d6763aeChris Craik
36019d5316e3f56d138504565ff311145ac01621dff4Romain Guy}; // namespace uirenderer
3602e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy}; // namespace android
3603