OpenGLRenderer.cpp revision 6b109c74982033d4a220cd10a0eab8b024b351c9
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()) {
1796b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik        const bool isFbo = getTargetFbo() == 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
2436b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik    if (getTargetFbo() == 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() {
3506b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik    if (mCaches.debugOverdraw && getTargetFbo() == 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();
4326b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik            mRenderState.bindFramebuffer(getTargetFbo());
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();
4496b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik        mRenderState.bindFramebuffer(getTargetFbo());
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;
8546b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik        GlopBuilder(mRenderState, mCaches, &glop)
8556b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik                .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 */
9546b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik#define DRAW_DOUBLE_STENCIL_IF(COND, DRAW_COMMAND) {                             \
9556b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik        DRAW_COMMAND;                                                            \
9566b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik        if (CC_UNLIKELY(mCaches.debugOverdraw && getTargetFbo() == 0 && COND)) { \
9576b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik            glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);                 \
9586b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik            DRAW_COMMAND;                                                        \
9596b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik            glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);                     \
9606b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik        }                                                                        \
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;
12466b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik            GlopBuilder(mRenderState, mCaches, &glop)
12476b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik                    .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();
12536b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik            renderGlop(glop, false);
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;
14506b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik        GlopBuilder(mRenderState, mCaches, &glop)
14516b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik                .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
15946b109c74982033d4a220cd10a0eab8b024b351c9Chris Craikvoid OpenGLRenderer::renderGlop(const Glop& glop, bool clearLayer) {
15956b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik    // TODO: It would be best if we could do this before quickRejectSetupScissor()
15966b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik    //       changes the scissor test state
15976b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik    if (clearLayer) clearLayerRegions();
15986b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik
1599117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    if (mState.getDirtyClip()) {
1600117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        if (mRenderState.scissor().isEnabled()) {
1601117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik            setScissorFromClip();
1602117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        }
1603117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik
1604117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        setStencilFromClip();
1605117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    }
1606117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    mRenderState.render(glop);
16072ab95d780b023152556d9f8659de734ec7b55047Chris Craik    if (!mRenderState.stencil().isWriteEnabled()) {
16082ab95d780b023152556d9f8659de734ec7b55047Chris Craik        // TODO: specify more clearly when a draw should dirty the layer.
16092ab95d780b023152556d9f8659de734ec7b55047Chris Craik        // is writing to the stencil the only time we should ignore this?
16102ab95d780b023152556d9f8659de734ec7b55047Chris Craik        dirtyLayer(glop.bounds.left, glop.bounds.top, glop.bounds.right, glop.bounds.bottom);
16110519c810a56bded1284fcb2ae40f438878c6585fChris Craik        mDirty = true;
16122ab95d780b023152556d9f8659de734ec7b55047Chris Craik    }
1613117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik}
1614117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik
1615f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy///////////////////////////////////////////////////////////////////////////////
161670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy// Drawing commands
161770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy///////////////////////////////////////////////////////////////////////////////
161870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
161962d307c2402777d5e53b4590af5f32f8c55afd81Chris Craikvoid OpenGLRenderer::setupDraw(bool clearLayer) {
1620f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik    // TODO: It would be best if we could do this before quickRejectSetupScissor()
16218a4ac610e1aaf04931ac1af54b146a7fc8e66114Romain Guy    //       changes the scissor test state
162262d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik    if (clearLayer) clearLayerRegions();
16238ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy    // Make sure setScissor & setStencil happen at the beginning of
16248ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy    // this method
1625984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.getDirtyClip()) {
162665fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik        if (mRenderState.scissor().isEnabled()) {
1627b98a016c6769b9e80d392df22fe77a2fca048d9fChris Craik            setScissorFromClip();
1628b98a016c6769b9e80d392df22fe77a2fca048d9fChris Craik        }
162962d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik
1630adc0d9da8648abfea1035fb1108eceea9fd9b5b1Dohyun Lee        setStencilFromClip();
163170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    }
16323ff0bfdd144bba3b023eda8c49b25fb0d0de8653Romain Guy
163370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    mDescription.reset();
16343ff0bfdd144bba3b023eda8c49b25fb0d0de8653Romain Guy
163570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    mSetShaderColor = false;
163670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    mColorSet = false;
16370519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.a = mColor.r = mColor.g = mColor.b = 0.0f;
163870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    mTextureUnit = 0;
163970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    mTrackDirtyRegions = true;
16403ff0bfdd144bba3b023eda8c49b25fb0d0de8653Romain Guy
16413ff0bfdd144bba3b023eda8c49b25fb0d0de8653Romain Guy    // Enable debug highlight when what we're about to draw is tested against
16423ff0bfdd144bba3b023eda8c49b25fb0d0de8653Romain Guy    // the stencil buffer and if stencil highlight debugging is on
1643117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    mDescription.hasDebugHighlight = !mCaches.debugOverdraw
1644117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik            && mCaches.debugStencilClip == Caches::kStencilShowHighlight
1645117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik            && mRenderState.stencil().isTestEnabled();
164670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
164770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
164870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guyvoid OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
164970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    mDescription.hasTexture = true;
165070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    mDescription.hasAlpha8Texture = isAlpha8;
165170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
165270ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
1653ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guyvoid OpenGLRenderer::setupDrawWithTextureAndColor(bool isAlpha8) {
1654ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    mDescription.hasTexture = true;
1655ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    mDescription.hasColors = true;
1656ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    mDescription.hasAlpha8Texture = isAlpha8;
1657ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy}
1658ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy
1659aa6c24c21c727a196451332448d4e3b11a80be69Romain Guyvoid OpenGLRenderer::setupDrawWithExternalTexture() {
1660aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy    mDescription.hasExternalTexture = true;
1661aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy}
1662aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
166315bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guyvoid OpenGLRenderer::setupDrawNoTexture() {
166496a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().disableTexCoordsVertexArray();
166515bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy}
166615bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy
166791a8c7c62913c2597e3bf5a6d59d2ed5fc7ba4e0Chris Craikvoid OpenGLRenderer::setupDrawVertexAlpha(bool useShadowAlphaInterp) {
166891a8c7c62913c2597e3bf5a6d59d2ed5fc7ba4e0Chris Craik    mDescription.hasVertexAlpha = true;
166991a8c7c62913c2597e3bf5a6d59d2ed5fc7ba4e0Chris Craik    mDescription.useShadowAlphaInterp = useShadowAlphaInterp;
16705b0200bd47e8a9a4dc8d2e6c3a110d522b30bf82Chet Haase}
16715b0200bd47e8a9a4dc8d2e6c3a110d522b30bf82Chet Haase
16728d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guyvoid OpenGLRenderer::setupDrawColor(int color, int alpha) {
16730519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.a = alpha / 255.0f;
16740519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.r = mColor.a * ((color >> 16) & 0xFF) / 255.0f;
16750519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.g = mColor.a * ((color >>  8) & 0xFF) / 255.0f;
16760519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.b = mColor.a * ((color      ) & 0xFF) / 255.0f;
167770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    mColorSet = true;
16780519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mSetShaderColor = mDescription.setColorModulate(mColor.a);
167970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
168070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
168186568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guyvoid OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) {
16820519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.a = alpha / 255.0f;
16830519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.r = mColor.a * ((color >> 16) & 0xFF) / 255.0f;
16840519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.g = mColor.a * ((color >>  8) & 0xFF) / 255.0f;
16850519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.b = mColor.a * ((color      ) & 0xFF) / 255.0f;
168686568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy    mColorSet = true;
16870519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mSetShaderColor = mDescription.setAlpha8ColorModulate(mColor.r, mColor.g, mColor.b, mColor.a);
168886568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy}
168986568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy
16904121063313ac0d6f69f6253cac821d0c1c122086Romain Guyvoid OpenGLRenderer::setupDrawTextGamma(const SkPaint* paint) {
16914121063313ac0d6f69f6253cac821d0c1c122086Romain Guy    mCaches.fontRenderer->describe(mDescription, paint);
16924121063313ac0d6f69f6253cac821d0c1c122086Romain Guy}
16934121063313ac0d6f69f6253cac821d0c1c122086Romain Guy
169470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guyvoid OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) {
16950519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.a = a;
16960519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.r = r;
16970519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.g = g;
16980519c810a56bded1284fcb2ae40f438878c6585fChris Craik    mColor.b = b;
169970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    mColorSet = true;
1700e63f7c622a2086aefa80983c6f41b74fb166bb42Chris Craik    mSetShaderColor = mDescription.setColorModulate(a);
170170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
170270ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
1703d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins IIIvoid OpenGLRenderer::setupDrawShader(const SkShader* shader) {
1704e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (shader != nullptr) {
1705117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        SkiaShader::describe(&mCaches, mDescription, mCaches.extensions(), *shader);
170670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    }
170770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
170870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
170976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenbergervoid OpenGLRenderer::setupDrawColorFilter(const SkColorFilter* filter) {
1710e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (filter == nullptr) {
171176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        return;
171276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    }
171376d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
171476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    SkXfermode::Mode mode;
1715e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (filter->asColorMode(nullptr, &mode)) {
171676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        mDescription.colorOp = ProgramDescription::kColorBlend;
171776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        mDescription.colorMode = mode;
1718e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    } else if (filter->asColorMatrix(nullptr)) {
171976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        mDescription.colorOp = ProgramDescription::kColorMatrix;
172070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    }
172170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
172270ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
1723f09ef51889f75289b041f9e9f949b7b82ed5b686Romain Guyvoid OpenGLRenderer::accountForClear(SkXfermode::Mode mode) {
1724f09ef51889f75289b041f9e9f949b7b82ed5b686Romain Guy    if (mColorSet && mode == SkXfermode::kClear_Mode) {
17250519c810a56bded1284fcb2ae40f438878c6585fChris Craik        mColor.a = 1.0f;
17260519c810a56bded1284fcb2ae40f438878c6585fChris Craik        mColor.r = mColor.g = mColor.b = 0.0f;
172754be1cdf3d63095512120fa7ced5c16e462abffaRomain Guy        mSetShaderColor = mDescription.modulate = true;
1728f09ef51889f75289b041f9e9f949b7b82ed5b686Romain Guy    }
1729f09ef51889f75289b041f9e9f949b7b82ed5b686Romain Guy}
1730f09ef51889f75289b041f9e9f949b7b82ed5b686Romain Guy
173176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenbergervoid OpenGLRenderer::setupDrawBlending(const Layer* layer, bool swapSrcDst) {
173276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    SkXfermode::Mode mode = layer->getMode();
1733f09ef51889f75289b041f9e9f949b7b82ed5b686Romain Guy    // When the blending mode is kClear_Mode, we need to use a modulate color
1734f09ef51889f75289b041f9e9f949b7b82ed5b686Romain Guy    // argb=1,0,0,0
1735f09ef51889f75289b041f9e9f949b7b82ed5b686Romain Guy    accountForClear(mode);
1736d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    // TODO: check shader blending, once we have shader drawing support for layers.
17378dfaa4904205772cdceee63ef3989bcdedf1a914Tom Hudson    bool blend = layer->isBlend()
17388dfaa4904205772cdceee63ef3989bcdedf1a914Tom Hudson            || getLayerAlpha(layer) < 1.0f
17390519c810a56bded1284fcb2ae40f438878c6585fChris Craik            || (mColorSet && mColor.a < 1.0f)
17408dfaa4904205772cdceee63ef3989bcdedf1a914Tom Hudson            || PaintUtils::isBlendedColorFilter(layer->getColorFilter());
1741c3566d06421c8acc0aafb18f7e307e5725ce87e1Chris Craik    chooseBlending(blend, mode, mDescription, swapSrcDst);
174270ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
174370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
174476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenbergervoid OpenGLRenderer::setupDrawBlending(const SkPaint* paint, bool blend, bool swapSrcDst) {
174576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    SkXfermode::Mode mode = getXfermodeDirect(paint);
1746f09ef51889f75289b041f9e9f949b7b82ed5b686Romain Guy    // When the blending mode is kClear_Mode, we need to use a modulate color
1747f09ef51889f75289b041f9e9f949b7b82ed5b686Romain Guy    // argb=1,0,0,0
1748f09ef51889f75289b041f9e9f949b7b82ed5b686Romain Guy    accountForClear(mode);
17490519c810a56bded1284fcb2ae40f438878c6585fChris Craik    blend |= (mColorSet && mColor.a < 1.0f)
1750031888744e24b5c7243ac99ec98b78aff5db1c78Chris Craik            || (getShader(paint) && !getShader(paint)->isOpaque())
1751031888744e24b5c7243ac99ec98b78aff5db1c78Chris Craik            || PaintUtils::isBlendedColorFilter(getColorFilter(paint));
1752c3566d06421c8acc0aafb18f7e307e5725ce87e1Chris Craik    chooseBlending(blend, mode, mDescription, swapSrcDst);
175370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
175470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
175570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guyvoid OpenGLRenderer::setupDrawProgram() {
17566c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    mCaches.setProgram(mDescription);
1757deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    if (mDescription.hasRoundRectClip) {
1758deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik        // TODO: avoid doing this repeatedly, stashing state pointer in program
1759984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson        const RoundRectClipState* state = writableSnapshot()->roundRectClipState;
1760af4d04cab6d48ae0d6a5e79bd30f679af87abaadChris Craik        const Rect& innerRect = state->innerRect;
17616c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik        glUniform4f(mCaches.program().getUniform("roundRectInnerRectLTRB"),
1762af4d04cab6d48ae0d6a5e79bd30f679af87abaadChris Craik                innerRect.left, innerRect.top,
1763af4d04cab6d48ae0d6a5e79bd30f679af87abaadChris Craik                innerRect.right, innerRect.bottom);
17646c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik        glUniformMatrix4fv(mCaches.program().getUniform("roundRectInvTransform"),
1765deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik                1, GL_FALSE, &state->matrix.data[0]);
17664340c260c002f0cf7bc41571673e57913b5df19fChris Craik
17674340c260c002f0cf7bc41571673e57913b5df19fChris Craik        // add half pixel to round out integer rect space to cover pixel centers
17684340c260c002f0cf7bc41571673e57913b5df19fChris Craik        float roundedOutRadius = state->radius + 0.5f;
17696c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik        glUniform1f(mCaches.program().getUniform("roundRectRadius"),
17704340c260c002f0cf7bc41571673e57913b5df19fChris Craik                roundedOutRadius);
1771deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    }
177270ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
177370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
177470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guyvoid OpenGLRenderer::setupDrawDirtyRegionsDisabled() {
177570ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    mTrackDirtyRegions = false;
177670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
177770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
17784063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craikvoid OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset,
17794063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik        float left, float top, float right, float bottom, bool ignoreTransform) {
1780e10e827ed68b0a9487cf8dd1fc545f9a09517ae9Chris Craik    mModelViewMatrix.loadTranslate(left, top, 0.0f);
17814063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik    if (mode == kModelViewMode_TranslateAndScale) {
1782e10e827ed68b0a9487cf8dd1fc545f9a09517ae9Chris Craik        mModelViewMatrix.scale(right - left, bottom - top, 1.0f);
178370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    }
17844063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik
178586568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy    bool dirty = right - left > 0.0f && bottom - top > 0.0f;
1786a64a2bef1048db5a742843f1e3bea9e80d0defc5Chris Craik    const Matrix4& transformMatrix = ignoreTransform ? Matrix4::identity() : *currentTransform();
17876c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik
17886c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    mCaches.program().set(currentSnapshot()->getOrthoMatrix(),
1789e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik            mModelViewMatrix, transformMatrix, offset);
1790a64a2bef1048db5a742843f1e3bea9e80d0defc5Chris Craik    if (dirty && mTrackDirtyRegions) {
1791a64a2bef1048db5a742843f1e3bea9e80d0defc5Chris Craik        if (!ignoreTransform) {
1792a64a2bef1048db5a742843f1e3bea9e80d0defc5Chris Craik            dirtyLayer(left, top, right, bottom, *currentTransform());
1793a64a2bef1048db5a742843f1e3bea9e80d0defc5Chris Craik        } else {
1794a64a2bef1048db5a742843f1e3bea9e80d0defc5Chris Craik            dirtyLayer(left, top, right, bottom);
1795a64a2bef1048db5a742843f1e3bea9e80d0defc5Chris Craik        }
179686568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy    }
179770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
179870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
1799d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins IIIvoid OpenGLRenderer::setupDrawColorUniforms(bool hasShader) {
1800d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    if ((mColorSet && !hasShader) || (hasShader && mSetShaderColor)) {
18010519c810a56bded1284fcb2ae40f438878c6585fChris Craik        mCaches.program().setColor(mColor);
180270ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    }
180370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
180470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
180586568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guyvoid OpenGLRenderer::setupDrawPureColorUniforms() {
18065536841e5452172e7772d84ad5f4a2fc7059c9ddRomain Guy    if (mSetShaderColor) {
18070519c810a56bded1284fcb2ae40f438878c6585fChris Craik        mCaches.program().setColor(mColor);
18085536841e5452172e7772d84ad5f4a2fc7059c9ddRomain Guy    }
18095536841e5452172e7772d84ad5f4a2fc7059c9ddRomain Guy}
18105536841e5452172e7772d84ad5f4a2fc7059c9ddRomain Guy
1811d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins IIIvoid OpenGLRenderer::setupDrawShaderUniforms(const SkShader* shader, bool ignoreTransform) {
1812e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (shader == nullptr) {
1813d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        return;
1814d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    }
1815d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III
1816d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    if (ignoreTransform) {
1817d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        // if ignoreTransform=true was passed to setupDrawModelView, undo currentTransform()
1818d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        // because it was built into modelView / the geometry, and the description needs to
1819d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        // compensate.
1820d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        mat4 modelViewWithoutTransform;
1821d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        modelViewWithoutTransform.loadInverse(*currentTransform());
1822d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        modelViewWithoutTransform.multiply(mModelViewMatrix);
1823d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III        mModelViewMatrix.load(modelViewWithoutTransform);
182470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    }
1825d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III
1826117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    SkiaShader::setupProgram(&mCaches, mModelViewMatrix, &mTextureUnit,
1827117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik            mCaches.extensions(), *shader);
182870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
182970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
183076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenbergervoid OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) {
1831e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (nullptr == filter) {
183276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        return;
183376d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    }
183476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
183576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    SkColor color;
183676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    SkXfermode::Mode mode;
183776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    if (filter->asColorMode(&color, &mode)) {
183876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        const int alpha = SkColorGetA(color);
183976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        const GLfloat a = alpha / 255.0f;
184076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        const GLfloat r = a * SkColorGetR(color) / 255.0f;
184176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        const GLfloat g = a * SkColorGetG(color) / 255.0f;
184276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        const GLfloat b = a * SkColorGetB(color) / 255.0f;
18436c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik        glUniform4f(mCaches.program().getUniform("colorBlend"), r, g, b, a);
184476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        return;
184576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    }
184676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
184776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    SkScalar srcColorMatrix[20];
184876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    if (filter->asColorMatrix(srcColorMatrix)) {
184976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
185076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        float colorMatrix[16];
185176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float));
185276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        memcpy(&colorMatrix[4], &srcColorMatrix[5], 4 * sizeof(float));
185376d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        memcpy(&colorMatrix[8], &srcColorMatrix[10], 4 * sizeof(float));
185476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        memcpy(&colorMatrix[12], &srcColorMatrix[15], 4 * sizeof(float));
185576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
185676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        // Skia uses the range [0..255] for the addition vector, but we need
185776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        // the [0..1] range to apply the vector in GLSL
185876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        float colorVector[4];
185976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        colorVector[0] = srcColorMatrix[4] / 255.0f;
186076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        colorVector[1] = srcColorMatrix[9] / 255.0f;
186176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        colorVector[2] = srcColorMatrix[14] / 255.0f;
186276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        colorVector[3] = srcColorMatrix[19] / 255.0f;
186376d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
18646c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik        glUniformMatrix4fv(mCaches.program().getUniform("colorMatrix"), 1,
186576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger                GL_FALSE, colorMatrix);
18666c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik        glUniform4fv(mCaches.program().getUniform("colorMatrixVector"), 1, colorVector);
186776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        return;
186870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    }
186976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
187076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    // it is an error if we ever get here
187170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
187270ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
18734121063313ac0d6f69f6253cac821d0c1c122086Romain Guyvoid OpenGLRenderer::setupDrawTextGammaUniforms() {
18746c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    mCaches.fontRenderer->setupProgram(mDescription, mCaches.program());
18754121063313ac0d6f69f6253cac821d0c1c122086Romain Guy}
18764121063313ac0d6f69f6253cac821d0c1c122086Romain Guy
187770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guyvoid OpenGLRenderer::setupDrawSimpleMesh() {
187896a5c4c7bab6718524de7253da8309143ab48befChris Craik    bool force = mRenderState.meshState().bindMeshBuffer();
18796c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    mRenderState.meshState().bindPositionVertexPointer(force, nullptr);
188096a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().unbindIndicesBuffer();
188170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
188270ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
188370ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guyvoid OpenGLRenderer::setupDrawTexture(GLuint texture) {
188444eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik    if (texture) mCaches.textureState().bindTexture(texture);
18852d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy    mTextureUnit++;
188696a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().enableTexCoordsVertexArray();
188770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
188870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
1889aa6c24c21c727a196451332448d4e3b11a80be69Romain Guyvoid OpenGLRenderer::setupDrawExternalTexture(GLuint texture) {
189044eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik    mCaches.textureState().bindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
18912d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy    mTextureUnit++;
189296a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().enableTexCoordsVertexArray();
1893aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy}
1894aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
18958f0095cd33558e9cc8a440047908e53b68906f5fRomain Guyvoid OpenGLRenderer::setupDrawTextureTransform() {
18968f0095cd33558e9cc8a440047908e53b68906f5fRomain Guy    mDescription.hasTextureTransform = true;
18978f0095cd33558e9cc8a440047908e53b68906f5fRomain Guy}
18988f0095cd33558e9cc8a440047908e53b68906f5fRomain Guy
18998f0095cd33558e9cc8a440047908e53b68906f5fRomain Guyvoid OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) {
19006c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    glUniformMatrix4fv(mCaches.program().getUniform("mainTextureTransform"), 1,
1901aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy            GL_FALSE, &transform.data[0]);
1902aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy}
1903aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy
1904564acf7c9bff822f608cda0d5df0a64a9f9aaefdChris Craikvoid OpenGLRenderer::setupDrawMesh(const GLvoid* vertices,
1905564acf7c9bff822f608cda0d5df0a64a9f9aaefdChris Craik        const GLvoid* texCoords, GLuint vbo) {
1906f3a910b423db7ad79cf61518bdd9278c048ad0d8Romain Guy    bool force = false;
19073b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    if (!vertices || vbo) {
190896a5c4c7bab6718524de7253da8309143ab48befChris Craik        force = mRenderState.meshState().bindMeshBuffer(vbo);
190970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    } else {
191096a5c4c7bab6718524de7253da8309143ab48befChris Craik        force = mRenderState.meshState().unbindMeshBuffer();
191170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    }
1912d71dd367af604571c7d00ca473184a1b9240eca2Romain Guy
19136c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    mRenderState.meshState().bindPositionVertexPointer(force, vertices);
19146c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    if (mCaches.program().texCoords >= 0) {
19156c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik        mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords);
191615bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy    }
191715bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy
191896a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().unbindIndicesBuffer();
191915bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy}
192015bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy
1921564acf7c9bff822f608cda0d5df0a64a9f9aaefdChris Craikvoid OpenGLRenderer::setupDrawMesh(const GLvoid* vertices,
1922564acf7c9bff822f608cda0d5df0a64a9f9aaefdChris Craik        const GLvoid* texCoords, const GLvoid* colors) {
192396a5c4c7bab6718524de7253da8309143ab48befChris Craik    bool force = mRenderState.meshState().unbindMeshBuffer();
1924ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    GLsizei stride = sizeof(ColorTextureVertex);
1925ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy
19266c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    mRenderState.meshState().bindPositionVertexPointer(force, vertices, stride);
19276c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    if (mCaches.program().texCoords >= 0) {
19286c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik        mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords, stride);
1929ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    }
19306c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    int slot = mCaches.program().getAttrib("colors");
1931ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    if (slot >= 0) {
1932ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy        glEnableVertexAttribArray(slot);
1933ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy        glVertexAttribPointer(slot, 4, GL_FLOAT, GL_FALSE, stride, colors);
1934ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    }
1935ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy
193696a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().unbindIndicesBuffer();
1937ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy}
1938ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy
1939564acf7c9bff822f608cda0d5df0a64a9f9aaefdChris Craikvoid OpenGLRenderer::setupDrawMeshIndices(const GLvoid* vertices,
1940564acf7c9bff822f608cda0d5df0a64a9f9aaefdChris Craik        const GLvoid* texCoords, GLuint vbo) {
19413b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    bool force = false;
19423b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    // If vbo is != 0 we want to treat the vertices parameter as an offset inside
19433b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    // a VBO. However, if vertices is set to NULL and vbo == 0 then we want to
194496a5c4c7bab6718524de7253da8309143ab48befChris Craik    // use the default VBO found in RenderState
19453b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    if (!vertices || vbo) {
194696a5c4c7bab6718524de7253da8309143ab48befChris Craik        force = mRenderState.meshState().bindMeshBuffer(vbo);
19473b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    } else {
194896a5c4c7bab6718524de7253da8309143ab48befChris Craik        force = mRenderState.meshState().unbindMeshBuffer();
19493b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    }
195096a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().bindQuadIndicesBuffer();
19513b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
19526c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    mRenderState.meshState().bindPositionVertexPointer(force, vertices);
19536c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    if (mCaches.program().texCoords >= 0) {
19546c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik        mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords);
19558d0d4783a0206c5884bf0b958d181f450ba5207dRomain Guy    }
195670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy}
195770ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
1958448455fe783b0a711340322dca272b8cc0ebe473Romain Guyvoid OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) {
195996a5c4c7bab6718524de7253da8309143ab48befChris Craik    bool force = mRenderState.meshState().unbindMeshBuffer();
196096a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().bindQuadIndicesBuffer();
19616c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    mRenderState.meshState().bindPositionVertexPointer(force, vertices, kVertexStride);
19625b0200bd47e8a9a4dc8d2e6c3a110d522b30bf82Chet Haase}
19635b0200bd47e8a9a4dc8d2e6c3a110d522b30bf82Chet Haase
196470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy///////////////////////////////////////////////////////////////////////////////
1965f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy// Drawing
1966f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy///////////////////////////////////////////////////////////////////////////////
1967f6a11b8a9e25ff9861bbba19251bea84d8a5daf2Romain Guy
1968107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags) {
19690fe478ea04720a57ef3919dbc23711bc7eba517fRomain Guy    // All the usual checks and setup operations (quickReject, setupDraw, etc.)
19700fe478ea04720a57ef3919dbc23711bc7eba517fRomain Guy    // will be performed by the display list itself
1971a7090e0cfd7c719a6d4c03aae34f5db98754cbddChris Craik    if (renderNode && renderNode->isRenderable()) {
1972f57776b2d195f0937906eb88b777bb55ccc36967Chris Craik        // compute 3d ordering
1973a7090e0cfd7c719a6d4c03aae34f5db98754cbddChris Craik        renderNode->computeOrdering();
1974d90144db52c7297879b950cbbc85137ed123ab5bChris Craik        if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
1975107843de4507b3511006cb9c77b8d0364374385aTom Hudson            startFrame();
1976ff78583d8a73ca35ce65b5d2592570ff6fb9901bChris Craik            ReplayStateStruct replayStruct(*this, dirty, replayFlags);
1977a7090e0cfd7c719a6d4c03aae34f5db98754cbddChris Craik            renderNode->replay(replayStruct, 0);
1978107843de4507b3511006cb9c77b8d0364374385aTom Hudson            return;
1979c3566d06421c8acc0aafb18f7e307e5725ce87e1Chris Craik        }
1980c3566d06421c8acc0aafb18f7e307e5725ce87e1Chris Craik
1981ef8d6f272ae451aaedb0f02249c0f9f0576efdf3Chris Craik        // Don't avoid overdraw when visualizing, since that makes it harder to
1982ef8d6f272ae451aaedb0f02249c0f9f0576efdf3Chris Craik        // debug where it's coming from, and when the problem occurs.
1983ef8d6f272ae451aaedb0f02249c0f9f0576efdf3Chris Craik        bool avoidOverdraw = !mCaches.debugOverdraw;
1984487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk        DeferredDisplayList deferredList(mState.currentClipRect(), avoidOverdraw);
1985ff78583d8a73ca35ce65b5d2592570ff6fb9901bChris Craik        DeferStateStruct deferStruct(deferredList, *this, replayFlags);
1986a7090e0cfd7c719a6d4c03aae34f5db98754cbddChris Craik        renderNode->defer(deferStruct, 0);
198796885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy
198896885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy        flushLayers();
1989107843de4507b3511006cb9c77b8d0364374385aTom Hudson        startFrame();
199096885eb480c5e0526fe2f77d30f6e551f3f3ceabRomain Guy
1991107843de4507b3511006cb9c77b8d0364374385aTom Hudson        deferredList.flush(*this, dirty);
1992107843de4507b3511006cb9c77b8d0364374385aTom Hudson    } else {
1993107843de4507b3511006cb9c77b8d0364374385aTom Hudson        // Even if there is no drawing command(Ex: invisible),
1994107843de4507b3511006cb9c77b8d0364374385aTom Hudson        // it still needs startFrame to clear buffer and start tiling.
1995107843de4507b3511006cb9c77b8d0364374385aTom Hudson        startFrame();
19960fe478ea04720a57ef3919dbc23711bc7eba517fRomain Guy    }
19970fe478ea04720a57ef3919dbc23711bc7eba517fRomain Guy}
19980fe478ea04720a57ef3919dbc23711bc7eba517fRomain Guy
19990519c810a56bded1284fcb2ae40f438878c6585fChris Craikvoid OpenGLRenderer::drawAlphaBitmap(Texture* texture, const SkPaint* paint) {
20000519c810a56bded1284fcb2ae40f438878c6585fChris Craik    float x = 0;
20010519c810a56bded1284fcb2ae40f438878c6585fChris Craik    float y = 0;
2002a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy
2003886b275e529e44a59c54b933453d9bc902973178Romain Guy    texture->setWrap(GL_CLAMP_TO_EDGE, true);
2004886b275e529e44a59c54b933453d9bc902973178Romain Guy
2005a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy    bool ignoreTransform = false;
2006d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    if (currentTransform()->isPureTranslate()) {
20070519c810a56bded1284fcb2ae40f438878c6585fChris Craik        x = (int) floorf(currentTransform()->getTranslateX() + 0.5f);
20080519c810a56bded1284fcb2ae40f438878c6585fChris Craik        y = (int) floorf(currentTransform()->getTranslateY() + 0.5f);
2009a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy        ignoreTransform = true;
2010a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy
2011886b275e529e44a59c54b933453d9bc902973178Romain Guy        texture->setFilter(GL_NEAREST, true);
2012886b275e529e44a59c54b933453d9bc902973178Romain Guy    } else {
20130519c810a56bded1284fcb2ae40f438878c6585fChris Craik        texture->setFilter(PaintUtils::getFilter(paint), true);
20145b7a3150a6dbf193b371854b66fa654937633d3aRomain Guy    }
2015e3c26851dc315b730ea0fe5ef35bb1db81f6d675Romain Guy
20163b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    // No need to check for a UV mapper on the texture object, only ARGB_8888
20173b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    // bitmaps get packed in the atlas
2018886b275e529e44a59c54b933453d9bc902973178Romain Guy    drawAlpha8TextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
201996a5c4c7bab6718524de7253da8309143ab48befChris Craik            paint, (GLvoid*) nullptr, (GLvoid*) kMeshTextureOffset,
2020117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik            GL_TRIANGLE_STRIP, kUnitQuadCount, ignoreTransform);
2021a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy}
2022a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy
202303c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy/**
202403c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy * Important note: this method is intended to draw batches of bitmaps and
202503c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy * will not set the scissor enable or dirty the current layer, if any.
202603c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy * The caller is responsible for properly dirtying the current layer.
202703c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy */
2028107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
2029d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        int bitmapCount, TextureVertex* vertices, bool pureTranslate,
2030d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        const Rect& bounds, const SkPaint* paint) {
203144eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik    mCaches.textureState().activateTexture(0);
203255b6f95ee4ace96c97508bcd14483fb4e9dbeaa0Romain Guy    Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
2033107843de4507b3511006cb9c77b8d0364374385aTom Hudson    if (!texture) return;
20343b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
2035527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik    const AutoTexture autoCleanup(texture);
2036527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik
2037527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik    texture->setWrap(GL_CLAMP_TO_EDGE, true);
20380519c810a56bded1284fcb2ae40f438878c6585fChris Craik    texture->setFilter(pureTranslate ? GL_NEAREST : PaintUtils::getFilter(paint), true);
2039527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik
2040527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik    const float x = (int) floorf(bounds.left + 0.5f);
2041527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik    const float y = (int) floorf(bounds.top + 0.5f);
20421103b3255945d2eb2fa9c191e84e2270b343cca9Mike Reed    if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
2043527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik        drawAlpha8TextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
204476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger                texture->id, paint, &vertices[0].x, &vertices[0].u,
20454063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik                GL_TRIANGLES, bitmapCount * 6, true,
20464063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik                kModelViewMode_Translate, false);
2047527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik    } else {
2048527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik        drawTextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
204976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger                texture->id, paint, texture->blend, &vertices[0].x, &vertices[0].u,
20504063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik                GL_TRIANGLES, bitmapCount * 6, false, true, 0,
20514063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik                kModelViewMode_Translate, false);
2052527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik    }
2053527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik
2054107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
2055527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik}
2056527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik
2057107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
2058796475006f5d670e8383a2050f11719522437a43Chris Craik    if (quickRejectSetupScissor(0, 0, bitmap->width(), bitmap->height())) {
2059107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
20606926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    }
20616926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy
206244eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik    mCaches.textureState().activateTexture(0);
20633b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    Texture* texture = getTexture(bitmap);
2064107843de4507b3511006cb9c77b8d0364374385aTom Hudson    if (!texture) return;
206522158e139a3d6c6a9787ca0de224e9368f643284Romain Guy    const AutoTexture autoCleanup(texture);
206622158e139a3d6c6a9787ca0de224e9368f643284Romain Guy
2067f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik    if (USE_GLOPS) {
2068f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik        bool isAlpha8Texture = bitmap->colorType() == kAlpha_8_SkColorType;
2069f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik        Glop glop;
20706b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik        GlopBuilder(mRenderState, mCaches, &glop)
20716b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik                .setMeshTexturedUnitQuad(texture->uvMapper)
2072f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                .setFillTexturePaint(*texture, isAlpha8Texture, paint, currentSnapshot()->alpha)
2073f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
2074f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
2075f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
2076f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                .build();
2077f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik        renderGlop(glop);
2078f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik        return;
2079f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik    }
2080f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik
20811103b3255945d2eb2fa9c191e84e2270b343cca9Mike Reed    if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
20820519c810a56bded1284fcb2ae40f438878c6585fChris Craik        drawAlphaBitmap(texture, paint);
2083a168d7372132d6c87835878794b6ed43d0d282fdRomain Guy    } else {
20840519c810a56bded1284fcb2ae40f438878c6585fChris Craik        drawTextureRect(texture, paint);
2085886b275e529e44a59c54b933453d9bc902973178Romain Guy    }
2086486590963e2207d68eebd6944fec70d50d41116aChet Haase
2087107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
2088e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy}
2089e651cc6239616a202f6e96ebc2ed93b4b8b3627cRomain Guy
2090107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
2091d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        const float* vertices, const int* colors, const SkPaint* paint) {
2092984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (!vertices || mState.currentlyIgnored()) {
2093107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
20945a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy    }
20955a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
2096b18d2d0079b4dbf5675ab79b7111b3dfb3cc1ad0Romain Guy    float left = FLT_MAX;
2097b18d2d0079b4dbf5675ab79b7111b3dfb3cc1ad0Romain Guy    float top = FLT_MAX;
2098b18d2d0079b4dbf5675ab79b7111b3dfb3cc1ad0Romain Guy    float right = FLT_MIN;
2099b18d2d0079b4dbf5675ab79b7111b3dfb3cc1ad0Romain Guy    float bottom = FLT_MIN;
2100b18d2d0079b4dbf5675ab79b7111b3dfb3cc1ad0Romain Guy
2101ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik    const uint32_t elementCount = meshWidth * meshHeight * 6;
2102b18d2d0079b4dbf5675ab79b7111b3dfb3cc1ad0Romain Guy
2103ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik    std::unique_ptr<ColorTextureVertex[]> mesh(new ColorTextureVertex[elementCount]);
210451d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik    ColorTextureVertex* vertex = &mesh[0];
2105ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy
210651d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik    std::unique_ptr<int[]> tempColors;
2107ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    if (!colors) {
2108ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy        uint32_t colorsCount = (meshWidth + 1) * (meshHeight + 1);
210951d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik        tempColors.reset(new int[colorsCount]);
211051d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik        memset(tempColors.get(), 0xff, colorsCount * sizeof(int));
211151d6a3db97bdd5315f1a17a4b447d10a92217b98Chris Craik        colors = tempColors.get();
2112ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    }
2113a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy
2114ebd52610cfeff6e557fde284a7e1efc5e6438285John Reck    Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap);
21153b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    const UvMapper& mapper(getMapper(texture));
21163b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
21175a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy    for (int32_t y = 0; y < meshHeight; y++) {
21185a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy        for (int32_t x = 0; x < meshWidth; x++) {
21195a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            uint32_t i = (y * (meshWidth + 1) + x) * 2;
21205a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
21215a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            float u1 = float(x) / meshWidth;
21225a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            float u2 = float(x + 1) / meshWidth;
21235a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            float v1 = float(y) / meshHeight;
21245a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            float v2 = float(y + 1) / meshHeight;
21255a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
21263b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            mapper.map(u1, v1, u2, v2);
21273b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
21285a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            int ax = i + (meshWidth + 1) * 2;
21295a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            int ay = ax + 1;
21305a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            int bx = i;
21315a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            int by = bx + 1;
21325a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            int cx = i + 2;
21335a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            int cy = cx + 1;
21345a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            int dx = i + (meshWidth + 1) * 2 + 2;
21355a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy            int dy = dx + 1;
21365a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
2137ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy            ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
2138ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy            ColorTextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2, colors[ax / 2]);
2139ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy            ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
21405a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
2141ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy            ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
2142ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy            ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
2143ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy            ColorTextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1, colors[cx / 2]);
2144b18d2d0079b4dbf5675ab79b7111b3dfb3cc1ad0Romain Guy
2145a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy            left = fminf(left, fminf(vertices[ax], fminf(vertices[bx], vertices[cx])));
2146a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy            top = fminf(top, fminf(vertices[ay], fminf(vertices[by], vertices[cy])));
2147a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy            right = fmaxf(right, fmaxf(vertices[ax], fmaxf(vertices[bx], vertices[cx])));
2148a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy            bottom = fmaxf(bottom, fmaxf(vertices[ay], fmaxf(vertices[by], vertices[cy])));
21495a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy        }
21505a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy    }
21515a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
2152f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik    if (quickRejectSetupScissor(left, top, right, bottom)) {
2153107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
2154a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy    }
2155a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy
2156ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    if (!texture) {
21573b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        texture = mCaches.textureCache.get(bitmap);
21583b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        if (!texture) {
2159107843de4507b3511006cb9c77b8d0364374385aTom Hudson            return;
21603b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        }
2161ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    }
2162a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy    const AutoTexture autoCleanup(texture);
2163a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy
2164ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik    if (USE_GLOPS) {
2165ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik        /*
2166ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik         * TODO: handle alpha_8 textures correctly by applying paint color, but *not*
2167ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik         * shader in that case to mimic the behavior in SkiaCanvas::drawBitmapMesh.
2168ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik         */
2169ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik        bool isAlpha8Texture = false;
2170ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik        Glop glop;
21716b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik        GlopBuilder(mRenderState, mCaches, &glop)
21726b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik                .setMeshColoredTexturedMesh(mesh.get(), elementCount)
2173ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik                .setFillTexturePaint(*texture, isAlpha8Texture, paint, currentSnapshot()->alpha)
2174ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
2175ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik                .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
2176ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
2177ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik                .build();
2178ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik        renderGlop(glop);
2179ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik        return;
2180ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik    }
2181ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik
2182ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik    mCaches.textureState().activateTexture(0);
2183a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy    texture->setWrap(GL_CLAMP_TO_EDGE, true);
21840519c810a56bded1284fcb2ae40f438878c6585fChris Craik    texture->setFilter(PaintUtils::getFilter(paint), true);
2185a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy
2186a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy    int alpha;
2187a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy    SkXfermode::Mode mode;
2188a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy    getAlphaAndMode(paint, &alpha, &mode);
2189a92bb4dc9605c86b8773c929412af2dc242b1fa8Romain Guy
2190ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy
2191ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik    dirtyLayer(left, top, right, bottom, *currentTransform());
2192b18d2d0079b4dbf5675ab79b7111b3dfb3cc1ad0Romain Guy
2193ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik    float a = alpha / 255.0f;
2194ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    setupDraw();
2195ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    setupDrawWithTextureAndColor();
2196ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    setupDrawColor(a, a, a, a);
219776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilter(getColorFilter(paint));
219876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawBlending(paint, true);
2199ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    setupDrawProgram();
2200ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    setupDrawDirtyRegionsDisabled();
2201117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    setupDrawModelView(kModelViewMode_Translate, false, 0, 0, 0, 0);
2202ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    setupDrawTexture(texture->id);
2203ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    setupDrawPureColorUniforms();
220476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilterUniforms(getColorFilter(paint));
22053380cfdc77100e87aa8390386ccf390834dea171Romain Guy    setupDrawMesh(&mesh[0].x, &mesh[0].u, &mesh[0].r);
2206ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy
2207ef2507439c08f4e9c4c9bba1c6243ca9df2ee827Chris Craik    glDrawArrays(GL_TRIANGLES, 0, elementCount);
2208ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy
22096c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    int slot = mCaches.program().getAttrib("colors");
2210ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    if (slot >= 0) {
2211ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy        glDisableVertexAttribArray(slot);
2212ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy    }
2213ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy
2214107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
22155a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy}
22165a7b466a2b4b7ced739bd5c31e022de61650545aRomain Guy
221714100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craikvoid OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, Rect src, Rect dst, const SkPaint* paint) {
221814100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik    if (quickRejectSetupScissor(dst)) {
2219107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
22206926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    }
22216926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy
22223b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    Texture* texture = getTexture(bitmap);
2223107843de4507b3511006cb9c77b8d0364374385aTom Hudson    if (!texture) return;
222422158e139a3d6c6a9787ca0de224e9368f643284Romain Guy    const AutoTexture autoCleanup(texture);
22258ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy
222614100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik    if (USE_GLOPS) {
222714100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        Rect uv(fmax(0.0f, src.left / texture->width),
222814100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik                fmax(0.0f, src.top / texture->height),
222914100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik                fmin(1.0f, src.right / texture->width),
223014100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik                fmin(1.0f, src.bottom / texture->height));
223114100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik
223214100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        bool isAlpha8Texture = bitmap->colorType() == kAlpha_8_SkColorType;
223314100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        Glop glop;
22346b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik        GlopBuilder(mRenderState, mCaches, &glop)
22356b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik                .setMeshTexturedUvQuad(texture->uvMapper, uv)
223614100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik                .setFillTexturePaint(*texture, isAlpha8Texture, paint, currentSnapshot()->alpha)
223714100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
223814100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik                .setModelViewMapUnitToRectSnap(dst)
223914100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
224014100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik                .build();
224114100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        renderGlop(glop);
224214100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        return;
224314100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik    }
224414100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik
224514100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik    mCaches.textureState().activateTexture(0);
224614100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik
22478ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy    const float width = texture->width;
22488ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy    const float height = texture->height;
2249c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy
225014100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik    float u1 = fmax(0.0f, src.left / width);
225114100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik    float v1 = fmax(0.0f, src.top / height);
225214100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik    float u2 = fmin(1.0f, src.right / width);
225314100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik    float v2 = fmin(1.0f, src.bottom / height);
22543b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
22553b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    getMapper(texture).map(u1, v1, u2, v2);
2256c1396e93b6a5286a5183c00c781b62e940a12c1fRomain Guy
225796a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().unbindMeshBuffer();
22588ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy    resetDrawTextureTexCoords(u1, v1, u2, v2);
22598ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy
2260d21b6e1fe337b35f62cf2028e9bd0637fd009a75Romain Guy    texture->setWrap(GL_CLAMP_TO_EDGE, true);
2261d21b6e1fe337b35f62cf2028e9bd0637fd009a75Romain Guy
226214100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik    float scaleX = (dst.right - dst.left) / (src.right - src.left);
226314100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik    float scaleY = (dst.bottom - dst.top) / (src.bottom - src.top);
22646620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy
2265886b275e529e44a59c54b933453d9bc902973178Romain Guy    bool scaled = scaleX != 1.0f || scaleY != 1.0f;
2266886b275e529e44a59c54b933453d9bc902973178Romain Guy    bool ignoreTransform = false;
2267b50149825fae95b2918bcf67b2ddb773b9797068Romain Guy
226814100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik    if (CC_LIKELY(currentTransform()->isPureTranslate())) {
226914100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        float x = (int) floorf(dst.left + currentTransform()->getTranslateX() + 0.5f);
227014100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        float y = (int) floorf(dst.top + currentTransform()->getTranslateY() + 0.5f);
2271886b275e529e44a59c54b933453d9bc902973178Romain Guy
227214100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        dst.right = x + (dst.right - dst.left);
227314100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        dst.bottom = y + (dst.bottom - dst.top);
2274886b275e529e44a59c54b933453d9bc902973178Romain Guy
227514100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        dst.left = x;
227614100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        dst.top = y;
2277886b275e529e44a59c54b933453d9bc902973178Romain Guy
22780519c810a56bded1284fcb2ae40f438878c6585fChris Craik        texture->setFilter(scaled ? PaintUtils::getFilter(paint) : GL_NEAREST, true);
2279886b275e529e44a59c54b933453d9bc902973178Romain Guy        ignoreTransform = true;
22806620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy    } else {
22810519c810a56bded1284fcb2ae40f438878c6585fChris Craik        texture->setFilter(PaintUtils::getFilter(paint), true);
2282886b275e529e44a59c54b933453d9bc902973178Romain Guy    }
2283886b275e529e44a59c54b933453d9bc902973178Romain Guy
22841103b3255945d2eb2fa9c191e84e2270b343cca9Mike Reed    if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
228514100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        drawAlpha8TextureMesh(dst.left, dst.top, dst.right, dst.bottom,
228676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger                texture->id, paint,
22873380cfdc77100e87aa8390386ccf390834dea171Romain Guy                &mMeshVertices[0].x, &mMeshVertices[0].u,
2288117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik                GL_TRIANGLE_STRIP, kUnitQuadCount, ignoreTransform);
2289886b275e529e44a59c54b933453d9bc902973178Romain Guy    } else {
229014100ac9f8efc1a2407e3f5a5c8b2532a49585dbChris Craik        drawTextureMesh(dst.left, dst.top, dst.right, dst.bottom,
229176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger                texture->id, paint, texture->blend,
22923380cfdc77100e87aa8390386ccf390834dea171Romain Guy                &mMeshVertices[0].x, &mMeshVertices[0].u,
2293117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik                GL_TRIANGLE_STRIP, kUnitQuadCount, false, ignoreTransform);
2294886b275e529e44a59c54b933453d9bc902973178Romain Guy    }
2295886b275e529e44a59c54b933453d9bc902973178Romain Guy
22968ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy    resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
2297486590963e2207d68eebd6944fec70d50d41116aChet Haase
2298107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
2299ce0537b80087a6225273040a987414b1dd081aa0Romain Guy}
2300ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
2301107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
2302d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        float left, float top, float right, float bottom, const SkPaint* paint) {
2303f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik    if (quickRejectSetupScissor(left, top, right, bottom)) {
2304107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
23054c2547fa9244e78115cde0a259291053108c3dc7Romain Guy    }
23064c2547fa9244e78115cde0a259291053108c3dc7Romain Guy
2307ebd52610cfeff6e557fde284a7e1efc5e6438285John Reck    AssetAtlas::Entry* entry = mRenderState.assetAtlas().getEntry(bitmap);
23084c2547fa9244e78115cde0a259291053108c3dc7Romain Guy    const Patch* mesh = mCaches.patchCache.get(entry, bitmap->width(), bitmap->height(),
23094c2547fa9244e78115cde0a259291053108c3dc7Romain Guy            right - left, bottom - top, patch);
23104c2547fa9244e78115cde0a259291053108c3dc7Romain Guy
2311107843de4507b3511006cb9c77b8d0364374385aTom Hudson    drawPatch(bitmap, mesh, entry, left, top, right, bottom, paint);
2312be6f9dc1e71b425b7ac1c40c0a2c72d03eb9fbeeRomain Guy}
2313be6f9dc1e71b425b7ac1c40c0a2c72d03eb9fbeeRomain Guy
2314107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh,
2315d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        AssetAtlas::Entry* entry, float left, float top, float right, float bottom,
2316d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        const SkPaint* paint) {
2317f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik    if (quickRejectSetupScissor(left, top, right, bottom)) {
2318107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
23196926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    }
23206926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy
2321211370fd943cf26905001b38b8b1791851b26adcRomain Guy    if (CC_LIKELY(mesh && mesh->verticesCount > 0)) {
232244eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik        mCaches.textureState().activateTexture(0);
2323a404e16e4933857464046d763ed7629cd0c86cbfRomain Guy        Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
2324107843de4507b3511006cb9c77b8d0364374385aTom Hudson        if (!texture) return;
2325a4adcf0239039eb8f005be252409901c41b28839Romain Guy        const AutoTexture autoCleanup(texture);
23263b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
2327a4adcf0239039eb8f005be252409901c41b28839Romain Guy        texture->setWrap(GL_CLAMP_TO_EDGE, true);
2328a4adcf0239039eb8f005be252409901c41b28839Romain Guy        texture->setFilter(GL_LINEAR, true);
2329a4adcf0239039eb8f005be252409901c41b28839Romain Guy
2330d6b65f67717025b1162f86f04e2caa5723566cacChris Craik        const bool pureTranslate = currentTransform()->isPureTranslate();
23315b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        // Mark the current layer dirty where we are going to draw the patch
23328168396d1acbcb5fdd29eeda4c30b2803d5283aeRomain Guy        if (hasLayer() && mesh->hasEmptyQuads) {
2333d6b65f67717025b1162f86f04e2caa5723566cacChris Craik            const float offsetX = left + currentTransform()->getTranslateX();
2334d6b65f67717025b1162f86f04e2caa5723566cacChris Craik            const float offsetY = top + currentTransform()->getTranslateY();
23355b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            const size_t count = mesh->quads.size();
23365b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            for (size_t i = 0; i < count; i++) {
23378ab4079ca27e36e5c584495bcd71b573598ac021Romain Guy                const Rect& bounds = mesh->quads.itemAt(i);
2338211370fd943cf26905001b38b8b1791851b26adcRomain Guy                if (CC_LIKELY(pureTranslate)) {
2339c78b5d50f961ac8f696f8282979ae283cacd3574Romain Guy                    const float x = (int) floorf(bounds.left + offsetX + 0.5f);
2340c78b5d50f961ac8f696f8282979ae283cacd3574Romain Guy                    const float y = (int) floorf(bounds.top + offsetY + 0.5f);
2341c78b5d50f961ac8f696f8282979ae283cacd3574Romain Guy                    dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight());
23426620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy                } else {
2343c78b5d50f961ac8f696f8282979ae283cacd3574Romain Guy                    dirtyLayer(left + bounds.left, top + bounds.top,
2344d6b65f67717025b1162f86f04e2caa5723566cacChris Craik                            left + bounds.right, top + bounds.bottom, *currentTransform());
23456620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy                }
23465b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy            }
23475b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy        }
23485b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
23494063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik        bool ignoreTransform = false;
2350211370fd943cf26905001b38b8b1791851b26adcRomain Guy        if (CC_LIKELY(pureTranslate)) {
2351d6b65f67717025b1162f86f04e2caa5723566cacChris Craik            const float x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f);
2352d6b65f67717025b1162f86f04e2caa5723566cacChris Craik            const float y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f);
23536620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy
23543b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            right = x + right - left;
23553b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy            bottom = y + bottom - top;
23564063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik            left = x;
23574063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik            top = y;
23584063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik            ignoreTransform = true;
23596620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        }
236076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        drawIndexedTextureMesh(left, top, right, bottom, texture->id, paint,
236176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger                texture->blend, (GLvoid*) mesh->offset, (GLvoid*) mesh->textureOffset,
23624063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik                GL_TRIANGLES, mesh->indexCount, false, ignoreTransform,
23634063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik                mCaches.patchCache.getMeshBuffer(), kModelViewMode_Translate, !mesh->hasEmptyQuads);
2364054dc1840941665e32036f9523df51720ad069c8Romain Guy    }
2365486590963e2207d68eebd6944fec70d50d41116aChet Haase
2366107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
2367f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy}
2368f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guy
236903c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy/**
237003c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy * Important note: this method is intended to draw batches of 9-patch objects and
237103c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy * will not set the scissor enable or dirty the current layer, if any.
237203c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy * The caller is responsible for properly dirtying the current layer.
237303c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy */
2374107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
2375d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        TextureVertex* vertices, uint32_t indexCount, const SkPaint* paint) {
237644eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik    mCaches.textureState().activateTexture(0);
237703c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy    Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
2378107843de4507b3511006cb9c77b8d0364374385aTom Hudson    if (!texture) return;
237903c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy    const AutoTexture autoCleanup(texture);
238003c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy
238103c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy    texture->setWrap(GL_CLAMP_TO_EDGE, true);
238203c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy    texture->setFilter(GL_LINEAR, true);
238303c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy
238476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    drawIndexedTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, paint,
238576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger            texture->blend, &vertices[0].x, &vertices[0].u,
23864063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik            GL_TRIANGLES, indexCount, false, true, 0, kModelViewMode_Translate, false);
238703c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy
2388107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
238903c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy}
239003c00b5a135e68d22ca5bb829b899ebda6ed7e9dRomain Guy
2391107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
2392bf75945e7a1ae7c1000682716643c942c1e19ba6Chris Craik        const VertexBuffer& vertexBuffer, const SkPaint* paint, int displayFlags) {
23934063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik    // not missing call to quickReject/dirtyLayer, always done at a higher level
23946d29c8d5218cac0fb35f3b7c253f2bdebd44f15aChris Craik    if (!vertexBuffer.getVertexCount()) {
2395bf09ffb4e0dc820aeae56a3e576aed33cab218daChris Craik        // no vertices to draw
2396107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
2397bf09ffb4e0dc820aeae56a3e576aed33cab218daChris Craik    }
2398bf09ffb4e0dc820aeae56a3e576aed33cab218daChris Craik
2399922d3a7f6f8c1c05a996ee3e91e8cbadfff560c9Chris Craik    if (USE_GLOPS) {
2400117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        bool fudgeOffset = displayFlags & kVertexBuffer_Offset;
2401117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        bool shadowInterp = displayFlags & kVertexBuffer_ShadowInterp;
24026b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik        Glop glop;
24036b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik        GlopBuilder(mRenderState, mCaches, &glop)
24046b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik                .setMeshVertexBuffer(vertexBuffer, shadowInterp)
24050519c810a56bded1284fcb2ae40f438878c6585fChris Craik                .setFillPaint(*paint, currentSnapshot()->alpha)
2406f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), fudgeOffset)
2407117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik                .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds())
24080519c810a56bded1284fcb2ae40f438878c6585fChris Craik                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
2409117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik                .build();
2410117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        renderGlop(glop);
2411117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        return;
2412117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    }
2413117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik
2414117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    const VertexBuffer::MeshFeatureFlags meshFeatureFlags = vertexBuffer.getMeshFeatureFlags();
24150d5ac954a111d19270d6e618ee051a8d6419e1a5Chris Craik    Rect bounds(vertexBuffer.getBounds());
24160d5ac954a111d19270d6e618ee051a8d6419e1a5Chris Craik    bounds.translate(translateX, translateY);
241705f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik    dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform());
241805f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik
241965cd612face362d054a85d0f7e5881c59cd523beChris Craik    int color = paint->getColor();
2420117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    bool isAA = meshFeatureFlags & VertexBuffer::kAlpha;
242165cd612face362d054a85d0f7e5881c59cd523beChris Craik
2422710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    setupDraw();
2423710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    setupDrawNoTexture();
242491a8c7c62913c2597e3bf5a6d59d2ed5fc7ba4e0Chris Craik    if (isAA) setupDrawVertexAlpha((displayFlags & kVertexBuffer_ShadowInterp));
2425117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
242676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilter(getColorFilter(paint));
2427d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShader(getShader(paint));
242876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawBlending(paint, isAA);
2429710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    setupDrawProgram();
2430bf75945e7a1ae7c1000682716643c942c1e19ba6Chris Craik    setupDrawModelView(kModelViewMode_Translate, (displayFlags & kVertexBuffer_Offset),
2431bf75945e7a1ae7c1000682716643c942c1e19ba6Chris Craik            translateX, translateY, 0, 0);
2432d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawColorUniforms(getShader(paint));
243376d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilterUniforms(getColorFilter(paint));
2434d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShaderUniforms(getShader(paint));
2435858aa93ddb6e69e0503382af63bb681b6728aef1Chet Haase
243655bfb4e728fe1db619af5d2c287f4abe711b3343ztenghui    const void* vertices = vertexBuffer.getBuffer();
243796a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().unbindMeshBuffer();
24386c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik    mRenderState.meshState().bindPositionVertexPointer(true, vertices,
24396c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik            isAA ? kAlphaVertexStride : kVertexStride);
244096a5c4c7bab6718524de7253da8309143ab48befChris Craik    mRenderState.meshState().resetTexCoordsVertexPointer();
244163d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui
2442710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    int alphaSlot = -1;
2443710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    if (isAA) {
244496a5c4c7bab6718524de7253da8309143ab48befChris Craik        void* alphaCoords = ((GLbyte*) vertices) + kVertexAlphaOffset;
24456c15ffa196fc9b7724c189d833c3435d8db12266Chris Craik        alphaSlot = mCaches.program().getAttrib("vtxAlpha");
2446710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik        // TODO: avoid enable/disable in back to back uses of the alpha attribute
24476ebdc114e0d72137394f02bc8ffe9d7a782a65c4Chris Craik        glEnableVertexAttribArray(alphaSlot);
244896a5c4c7bab6718524de7253da8309143ab48befChris Craik        glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, kAlphaVertexStride, alphaCoords);
2449710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    }
24506ebdc114e0d72137394f02bc8ffe9d7a782a65c4Chris Craik
2451117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    if (meshFeatureFlags & VertexBuffer::kIndices) {
245296a5c4c7bab6718524de7253da8309143ab48befChris Craik        mRenderState.meshState().unbindIndicesBuffer();
2453e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik        glDrawElements(GL_TRIANGLE_STRIP, vertexBuffer.getIndexCount(),
2454e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik                GL_UNSIGNED_SHORT, vertexBuffer.getIndices());
2455117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    } else {
2456117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        mRenderState.meshState().unbindIndicesBuffer();
2457117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
245863d41abb40b3ce40d8b9bccb1cf186e8158a3687ztenghui    }
24597b63142d2f4bc32beacedcc761453b8aea1f3a86Romain Guy
2460710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    if (isAA) {
24616ebdc114e0d72137394f02bc8ffe9d7a782a65c4Chris Craik        glDisableVertexAttribArray(alphaSlot);
246204299385c681140239b0dc31d9780d087d2b4d7cRomain Guy    }
246365cd612face362d054a85d0f7e5881c59cd523beChris Craik
2464107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
2465858aa93ddb6e69e0503382af63bb681b6728aef1Chet Haase}
2466858aa93ddb6e69e0503382af63bb681b6728aef1Chet Haase
2467858aa93ddb6e69e0503382af63bb681b6728aef1Chet Haase/**
246865cd612face362d054a85d0f7e5881c59cd523beChris Craik * Renders a convex path via tessellation. For AA paths, this function uses a similar approach to
246965cd612face362d054a85d0f7e5881c59cd523beChris Craik * that of AA lines in the drawLines() function.  We expand the convex path by a half pixel in
247065cd612face362d054a85d0f7e5881c59cd523beChris Craik * screen space in all directions. However, instead of using a fragment shader to compute the
247165cd612face362d054a85d0f7e5881c59cd523beChris Craik * translucency of the color from its position, we simply use a varying parameter to define how far
247265cd612face362d054a85d0f7e5881c59cd523beChris Craik * a given pixel is from the edge. For non-AA paths, the expansion and alpha varying are not used.
247365cd612face362d054a85d0f7e5881c59cd523beChris Craik *
247465cd612face362d054a85d0f7e5881c59cd523beChris Craik * Doesn't yet support joins, caps, or path effects.
247599ecdc480dd4f9b550b2a62ea39f77845a4fec49Chet Haase */
2476107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint) {
247765cd612face362d054a85d0f7e5881c59cd523beChris Craik    VertexBuffer vertexBuffer;
247865cd612face362d054a85d0f7e5881c59cd523beChris Craik    // TODO: try clipping large paths to viewport
2479d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    PathTessellator::tessellatePath(path, paint, *currentTransform(), vertexBuffer);
2480107843de4507b3511006cb9c77b8d0364374385aTom Hudson    drawVertexBuffer(vertexBuffer, paint);
248165cd612face362d054a85d0f7e5881c59cd523beChris Craik}
24827b63142d2f4bc32beacedcc761453b8aea1f3a86Romain Guy
248365cd612face362d054a85d0f7e5881c59cd523beChris Craik/**
248465cd612face362d054a85d0f7e5881c59cd523beChris Craik * We create tristrips for the lines much like shape stroke tessellation, using a per-vertex alpha
248565cd612face362d054a85d0f7e5881c59cd523beChris Craik * and additional geometry for defining an alpha slope perimeter.
248665cd612face362d054a85d0f7e5881c59cd523beChris Craik *
248765cd612face362d054a85d0f7e5881c59cd523beChris Craik * Using GL_LINES can be difficult because the rasterization rules for those lines produces some
248865cd612face362d054a85d0f7e5881c59cd523beChris Craik * unexpected results, and may vary between hardware devices. Previously we used a varying-base
248965cd612face362d054a85d0f7e5881c59cd523beChris Craik * in-shader alpha region, but found it to be taxing on some GPUs.
249065cd612face362d054a85d0f7e5881c59cd523beChris Craik *
249165cd612face362d054a85d0f7e5881c59cd523beChris Craik * TODO: try using a fixed input buffer for non-capped lines as in text rendering. this may reduce
249265cd612face362d054a85d0f7e5881c59cd523beChris Craik * memory transfer by removing need for degenerate vertices.
249365cd612face362d054a85d0f7e5881c59cd523beChris Craik */
2494107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawLines(const float* points, int count, const SkPaint* paint) {
2495984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored() || count < 4) return;
24967b63142d2f4bc32beacedcc761453b8aea1f3a86Romain Guy
249765cd612face362d054a85d0f7e5881c59cd523beChris Craik    count &= ~0x3; // round down to nearest four
24987b63142d2f4bc32beacedcc761453b8aea1f3a86Romain Guy
249965cd612face362d054a85d0f7e5881c59cd523beChris Craik    VertexBuffer buffer;
250005f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik    PathTessellator::tessellateLines(points, count, paint, *currentTransform(), buffer);
250105f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik    const Rect& bounds = buffer.getBounds();
2502d71ff91dcd79f6beea4bbe768ab3bcbb1a6d7c39Romain Guy
250305f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik    if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
2504107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
2505d71ff91dcd79f6beea4bbe768ab3bcbb1a6d7c39Romain Guy    }
2506d71ff91dcd79f6beea4bbe768ab3bcbb1a6d7c39Romain Guy
2507bf75945e7a1ae7c1000682716643c942c1e19ba6Chris Craik    int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset;
2508107843de4507b3511006cb9c77b8d0364374385aTom Hudson    drawVertexBuffer(buffer, paint, displayFlags);
25095b0200bd47e8a9a4dc8d2e6c3a110d522b30bf82Chet Haase}
25105b0200bd47e8a9a4dc8d2e6c3a110d522b30bf82Chet Haase
2511107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) {
2512984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored() || count < 2) return;
2513ed6fcb034b44d9a6ac2fc72fee6030417811f234Romain Guy
25146d29c8d5218cac0fb35f3b7c253f2bdebd44f15aChris Craik    count &= ~0x1; // round down to nearest two
25157b63142d2f4bc32beacedcc761453b8aea1f3a86Romain Guy
25166d29c8d5218cac0fb35f3b7c253f2bdebd44f15aChris Craik    VertexBuffer buffer;
251705f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik    PathTessellator::tessellatePoints(points, count, paint, *currentTransform(), buffer);
25187b63142d2f4bc32beacedcc761453b8aea1f3a86Romain Guy
251905f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik    const Rect& bounds = buffer.getBounds();
252005f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik    if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
2521107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
2522ed6fcb034b44d9a6ac2fc72fee6030417811f234Romain Guy    }
2523ed6fcb034b44d9a6ac2fc72fee6030417811f234Romain Guy
2524bf75945e7a1ae7c1000682716643c942c1e19ba6Chris Craik    int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset;
2525107843de4507b3511006cb9c77b8d0364374385aTom Hudson    drawVertexBuffer(buffer, paint, displayFlags);
2526107843de4507b3511006cb9c77b8d0364374385aTom Hudson
2527107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
2528ed6fcb034b44d9a6ac2fc72fee6030417811f234Romain Guy}
2529ed6fcb034b44d9a6ac2fc72fee6030417811f234Romain Guy
2530107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
2531e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy    // No need to check against the clip, we fill the clip region
2532984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored()) return;
2533e45362cad94c014d8b3765cb102db0f8c0d92500Romain Guy
2534487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    Rect clip(mState.currentClipRect());
2535ae88e5e8e9cb6c9539314c4360c5b20f8ec1fefcRomain Guy    clip.snapToPixelBoundaries();
253670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy
253776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    SkPaint paint;
253876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    paint.setColor(color);
253976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    paint.setXfermodeMode(mode);
254076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
254176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    drawColorRect(clip.left, clip.top, clip.right, clip.bottom, &paint, true);
2542486590963e2207d68eebd6944fec70d50d41116aChet Haase
2543107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
2544c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy}
25459d5316e3f56d138504565ff311145ac01621dff4Romain Guy
254630036092b40badecbe64d9c2bff4850132147f78Chris Craikvoid OpenGLRenderer::drawShape(float left, float top, PathTexture* texture,
2547d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        const SkPaint* paint) {
2548107843de4507b3511006cb9c77b8d0364374385aTom Hudson    if (!texture) return;
254901d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    const AutoTexture autoCleanup(texture);
255001d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
255101d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    const float x = left + texture->left - texture->offset;
255201d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    const float y = top + texture->top - texture->offset;
255301d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
255401d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    drawPathTexture(texture, x, y, paint);
2555486590963e2207d68eebd6944fec70d50d41116aChet Haase
2556107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
255701d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy}
255801d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
2559107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
2560d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        float rx, float ry, const SkPaint* p) {
2561984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored()
2562947eabf42d835d0dfb0daa2fe6d869139c7000d6Chris Craik            || quickRejectSetupScissor(left, top, right, bottom, p)
25638dfaa4904205772cdceee63ef3989bcdedf1a914Tom Hudson            || PaintUtils::paintWillNotDraw(*p)) {
2564107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
2565710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    }
256601d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
2567e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (p->getPathEffect() != nullptr) {
256844eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik        mCaches.textureState().activateTexture(0);
256930036092b40badecbe64d9c2bff4850132147f78Chris Craik        PathTexture* texture = mCaches.pathCache.getRoundRect(
2570710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik                right - left, bottom - top, rx, ry, p);
2571107843de4507b3511006cb9c77b8d0364374385aTom Hudson        drawShape(left, top, texture, p);
2572107843de4507b3511006cb9c77b8d0364374385aTom Hudson    } else {
2573107843de4507b3511006cb9c77b8d0364374385aTom Hudson        const VertexBuffer* vertexBuffer = mCaches.tessellationCache.getRoundRect(
2574107843de4507b3511006cb9c77b8d0364374385aTom Hudson                *currentTransform(), *p, right - left, bottom - top, rx, ry);
2575107843de4507b3511006cb9c77b8d0364374385aTom Hudson        drawVertexBuffer(left, top, *vertexBuffer, p);
2576710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    }
2577c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy}
257801d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
2579107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p) {
2580984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored()
2581947eabf42d835d0dfb0daa2fe6d869139c7000d6Chris Craik            || quickRejectSetupScissor(x - radius, y - radius, x + radius, y + radius, p)
25828dfaa4904205772cdceee63ef3989bcdedf1a914Tom Hudson            || PaintUtils::paintWillNotDraw(*p)) {
2583107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
2584710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    }
2585e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (p->getPathEffect() != nullptr) {
258644eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik        mCaches.textureState().activateTexture(0);
258730036092b40badecbe64d9c2bff4850132147f78Chris Craik        PathTexture* texture = mCaches.pathCache.getCircle(radius, p);
2588107843de4507b3511006cb9c77b8d0364374385aTom Hudson        drawShape(x - radius, y - radius, texture, p);
2589cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik    } else {
2590107843de4507b3511006cb9c77b8d0364374385aTom Hudson        SkPath path;
2591107843de4507b3511006cb9c77b8d0364374385aTom Hudson        if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2592107843de4507b3511006cb9c77b8d0364374385aTom Hudson            path.addCircle(x, y, radius + p->getStrokeWidth() / 2);
2593107843de4507b3511006cb9c77b8d0364374385aTom Hudson        } else {
2594107843de4507b3511006cb9c77b8d0364374385aTom Hudson            path.addCircle(x, y, radius);
2595107843de4507b3511006cb9c77b8d0364374385aTom Hudson        }
2596107843de4507b3511006cb9c77b8d0364374385aTom Hudson        drawConvexPath(path, p);
2597cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik    }
2598c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy}
259901d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
2600107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
2601d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        const SkPaint* p) {
2602984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored()
2603947eabf42d835d0dfb0daa2fe6d869139c7000d6Chris Craik            || quickRejectSetupScissor(left, top, right, bottom, p)
26048dfaa4904205772cdceee63ef3989bcdedf1a914Tom Hudson            || PaintUtils::paintWillNotDraw(*p)) {
2605107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
2606710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    }
260701d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
2608e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (p->getPathEffect() != nullptr) {
260944eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik        mCaches.textureState().activateTexture(0);
261030036092b40badecbe64d9c2bff4850132147f78Chris Craik        PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p);
2611107843de4507b3511006cb9c77b8d0364374385aTom Hudson        drawShape(left, top, texture, p);
2612107843de4507b3511006cb9c77b8d0364374385aTom Hudson    } else {
2613107843de4507b3511006cb9c77b8d0364374385aTom Hudson        SkPath path;
2614107843de4507b3511006cb9c77b8d0364374385aTom Hudson        SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2615107843de4507b3511006cb9c77b8d0364374385aTom Hudson        if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2616107843de4507b3511006cb9c77b8d0364374385aTom Hudson            rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
2617107843de4507b3511006cb9c77b8d0364374385aTom Hudson        }
2618107843de4507b3511006cb9c77b8d0364374385aTom Hudson        path.addOval(rect);
2619107843de4507b3511006cb9c77b8d0364374385aTom Hudson        drawConvexPath(path, p);
2620cb4d6009576cf08195dc23f341a3f4939c0878bbChris Craik    }
2621c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy}
2622c1cd9ba335b293f11e1082447ef08e474710a05fRomain Guy
2623107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
2624d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        float startAngle, float sweepAngle, bool useCenter, const SkPaint* p) {
2625984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored()
2626947eabf42d835d0dfb0daa2fe6d869139c7000d6Chris Craik            || quickRejectSetupScissor(left, top, right, bottom, p)
26278dfaa4904205772cdceee63ef3989bcdedf1a914Tom Hudson            || PaintUtils::paintWillNotDraw(*p)) {
2628107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
2629780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    }
26308b2f5267f16c295f12faab810527cd6311997e34Romain Guy
2631780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
2632e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != nullptr || useCenter) {
263344eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik        mCaches.textureState().activateTexture(0);
263430036092b40badecbe64d9c2bff4850132147f78Chris Craik        PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top,
2635780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik                startAngle, sweepAngle, useCenter, p);
2636107843de4507b3511006cb9c77b8d0364374385aTom Hudson        drawShape(left, top, texture, p);
2637107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
2638780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    }
2639780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2640780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2641780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik        rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
2642780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    }
2643780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik
2644780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    SkPath path;
2645780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    if (useCenter) {
2646780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik        path.moveTo(rect.centerX(), rect.centerY());
2647780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    }
2648780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    path.arcTo(rect, startAngle, sweepAngle, !useCenter);
2649780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    if (useCenter) {
2650780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik        path.close();
2651780c12875ce0c0d3fd072484d4b8b3c327cc4f31Chris Craik    }
2652107843de4507b3511006cb9c77b8d0364374385aTom Hudson    drawConvexPath(path, p);
26538b2f5267f16c295f12faab810527cd6311997e34Romain Guy}
26548b2f5267f16c295f12faab810527cd6311997e34Romain Guy
2655cf8675ee176a375f873792684d38a47f78348dffRomain Guy// See SkPaintDefaults.h
2656cf8675ee176a375f873792684d38a47f78348dffRomain Guy#define SkPaintDefaults_MiterLimit SkIntToScalar(4)
2657cf8675ee176a375f873792684d38a47f78348dffRomain Guy
2658107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
2659d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        const SkPaint* p) {
2660984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored()
2661947eabf42d835d0dfb0daa2fe6d869139c7000d6Chris Craik            || quickRejectSetupScissor(left, top, right, bottom, p)
26628dfaa4904205772cdceee63ef3989bcdedf1a914Tom Hudson            || PaintUtils::paintWillNotDraw(*p)) {
2663107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
26646926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy    }
26656926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy
2666710f46d9d6a5bf9ea1c1833384caf61e1934124fChris Craik    if (p->getStyle() != SkPaint::kFill_Style) {
2667cf8675ee176a375f873792684d38a47f78348dffRomain Guy        // only fill style is supported by drawConvexPath, since others have to handle joins
2668e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik        if (p->getPathEffect() != nullptr || p->getStrokeJoin() != SkPaint::kMiter_Join ||
2669cf8675ee176a375f873792684d38a47f78348dffRomain Guy                p->getStrokeMiter() != SkPaintDefaults_MiterLimit) {
267044eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik            mCaches.textureState().activateTexture(0);
267130036092b40badecbe64d9c2bff4850132147f78Chris Craik            PathTexture* texture =
2672c46d07a29e94807e768f8b162ce9f77a88ba6f46Romain Guy                    mCaches.pathCache.getRect(right - left, bottom - top, p);
2673107843de4507b3511006cb9c77b8d0364374385aTom Hudson            drawShape(left, top, texture, p);
2674107843de4507b3511006cb9c77b8d0364374385aTom Hudson        } else {
2675107843de4507b3511006cb9c77b8d0364374385aTom Hudson            SkPath path;
2676107843de4507b3511006cb9c77b8d0364374385aTom Hudson            SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2677107843de4507b3511006cb9c77b8d0364374385aTom Hudson            if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2678107843de4507b3511006cb9c77b8d0364374385aTom Hudson                rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
2679107843de4507b3511006cb9c77b8d0364374385aTom Hudson            }
2680107843de4507b3511006cb9c77b8d0364374385aTom Hudson            path.addRect(rect);
2681107843de4507b3511006cb9c77b8d0364374385aTom Hudson            drawConvexPath(path, p);
2682cf8675ee176a375f873792684d38a47f78348dffRomain Guy        }
2683107843de4507b3511006cb9c77b8d0364374385aTom Hudson    } else {
2684107843de4507b3511006cb9c77b8d0364374385aTom Hudson        if (p->isAntiAlias() && !currentTransform()->isSimple()) {
2685107843de4507b3511006cb9c77b8d0364374385aTom Hudson            SkPath path;
2686107843de4507b3511006cb9c77b8d0364374385aTom Hudson            path.addRect(left, top, right, bottom);
2687107843de4507b3511006cb9c77b8d0364374385aTom Hudson            drawConvexPath(path, p);
2688107843de4507b3511006cb9c77b8d0364374385aTom Hudson        } else {
2689107843de4507b3511006cb9c77b8d0364374385aTom Hudson            drawColorRect(left, top, right, bottom, p);
2690cf8675ee176a375f873792684d38a47f78348dffRomain Guy
2691107843de4507b3511006cb9c77b8d0364374385aTom Hudson            mDirty = true;
2692cf8675ee176a375f873792684d38a47f78348dffRomain Guy        }
2693858aa93ddb6e69e0503382af63bb681b6728aef1Chet Haase    }
2694c7d53494f1fbd9f9d74af89053ff9fdb1ccbac6cRomain Guy}
26959d5316e3f56d138504565ff311145ac01621dff4Romain Guy
2696d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craikvoid OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text,
2697d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        int bytesCount, int count, const float* positions,
269876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        FontRenderer& fontRenderer, int alpha, float x, float y) {
269944eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik    mCaches.textureState().activateTexture(0);
2700416a847633680d94efb926837efdc18726d54918Raph Levien
2701c29a0a4664a4b9871fadd668b632469a0db240b9Derek Sollenberger    TextShadow textShadow;
2702c29a0a4664a4b9871fadd668b632469a0db240b9Derek Sollenberger    if (!getTextShadow(paint, &textShadow)) {
2703c29a0a4664a4b9871fadd668b632469a0db240b9Derek Sollenberger        LOG_ALWAYS_FATAL("failed to query shadow attributes");
2704c29a0a4664a4b9871fadd668b632469a0db240b9Derek Sollenberger    }
2705c29a0a4664a4b9871fadd668b632469a0db240b9Derek Sollenberger
2706416a847633680d94efb926837efdc18726d54918Raph Levien    // NOTE: The drop shadow will not perform gamma correction
2707416a847633680d94efb926837efdc18726d54918Raph Levien    //       if shader-based correction is enabled
2708416a847633680d94efb926837efdc18726d54918Raph Levien    mCaches.dropShadowCache.setFontRenderer(fontRenderer);
27092bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    ShadowTexture* texture = mCaches.dropShadowCache.get(
2710c29a0a4664a4b9871fadd668b632469a0db240b9Derek Sollenberger            paint, text, bytesCount, count, textShadow.radius, positions);
2711cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    // If the drop shadow exceeds the max texture size or couldn't be
2712cf51a4199835e9604aa4c8b3854306f8fbabbf33Romain Guy    // allocated, skip drawing
27132bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    if (!texture) return;
27142bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    const AutoTexture autoCleanup(texture);
2715416a847633680d94efb926837efdc18726d54918Raph Levien
27162bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    const float sx = x - texture->left + textShadow.dx;
27172bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    const float sy = y - texture->top + textShadow.dy;
2718416a847633680d94efb926837efdc18726d54918Raph Levien
27192bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    if (USE_GLOPS) {
27202bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik        Glop glop;
27216b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik        GlopBuilder(mRenderState, mCaches, &glop)
27226b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik                .setMeshTexturedUnitQuad(nullptr)
27232bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik                .setFillShadowTexturePaint(*texture, textShadow.color, *paint, currentSnapshot()->alpha)
2724f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
27252bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik                .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width, sy + texture->height))
27262bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
27272bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik                .build();
27282bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik        renderGlop(glop);
27292bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik        return;
27302bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    }
27312bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik
27322bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * currentSnapshot()->alpha;
2733d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    if (getShader(paint)) {
2734c29a0a4664a4b9871fadd668b632469a0db240b9Derek Sollenberger        textShadow.color = SK_ColorWHITE;
2735416a847633680d94efb926837efdc18726d54918Raph Levien    }
2736416a847633680d94efb926837efdc18726d54918Raph Levien
2737416a847633680d94efb926837efdc18726d54918Raph Levien    setupDraw();
2738416a847633680d94efb926837efdc18726d54918Raph Levien    setupDrawWithTexture(true);
2739c29a0a4664a4b9871fadd668b632469a0db240b9Derek Sollenberger    setupDrawAlpha8Color(textShadow.color, shadowAlpha < 255 ? shadowAlpha : alpha);
274076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilter(getColorFilter(paint));
2741d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShader(getShader(paint));
274276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawBlending(paint, true);
2743416a847633680d94efb926837efdc18726d54918Raph Levien    setupDrawProgram();
27444063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik    setupDrawModelView(kModelViewMode_TranslateAndScale, false,
27452bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik            sx, sy, sx + texture->width, sy + texture->height);
27462bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik    setupDrawTexture(texture->id);
2747416a847633680d94efb926837efdc18726d54918Raph Levien    setupDrawPureColorUniforms();
274876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilterUniforms(getColorFilter(paint));
2749d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShaderUniforms(getShader(paint));
275096a5c4c7bab6718524de7253da8309143ab48befChris Craik    setupDrawMesh(nullptr, (GLvoid*) kMeshTextureOffset);
2751416a847633680d94efb926837efdc18726d54918Raph Levien
2752117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
2753416a847633680d94efb926837efdc18726d54918Raph Levien}
2754416a847633680d94efb926837efdc18726d54918Raph Levien
2755768bffc9b814f6a1f7d9ff59d91285895c23bbe9Romain Guybool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
2756984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * currentSnapshot()->alpha;
27578dfaa4904205772cdceee63ef3989bcdedf1a914Tom Hudson    return MathUtils::isZero(alpha)
27588dfaa4904205772cdceee63ef3989bcdedf1a914Tom Hudson            && PaintUtils::getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
2759768bffc9b814f6a1f7d9ff59d91285895c23bbe9Romain Guy}
2760768bffc9b814f6a1f7d9ff59d91285895c23bbe9Romain Guy
2761107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
2762d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        const float* positions, const SkPaint* paint) {
2763e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) {
2764107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
2765eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy    }
2766eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy
2767671d6cf460531825a321edb200523d0faa7792c9Romain Guy    // NOTE: Skia does not support perspective transform on drawPosText yet
2768d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    if (!currentTransform()->isSimple()) {
2769107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
2770671d6cf460531825a321edb200523d0faa7792c9Romain Guy    }
2771671d6cf460531825a321edb200523d0faa7792c9Romain Guy
277265fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik    mRenderState.scissor().setEnabled(true);
277339a908c1df89e1073627b0dcbce922d826b67055Chris Craik
2774671d6cf460531825a321edb200523d0faa7792c9Romain Guy    float x = 0.0f;
2775671d6cf460531825a321edb200523d0faa7792c9Romain Guy    float y = 0.0f;
2776d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    const bool pureTranslate = currentTransform()->isPureTranslate();
2777671d6cf460531825a321edb200523d0faa7792c9Romain Guy    if (pureTranslate) {
2778d6b65f67717025b1162f86f04e2caa5723566cacChris Craik        x = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f);
2779d6b65f67717025b1162f86f04e2caa5723566cacChris Craik        y = (int) floorf(y + currentTransform()->getTranslateY() + 0.5f);
2780671d6cf460531825a321edb200523d0faa7792c9Romain Guy    }
2781671d6cf460531825a321edb200523d0faa7792c9Romain Guy
2782b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
278359744b79ec302000802cd56d30a1bf70f0183c80Chris Craik    fontRenderer.setFont(paint, SkMatrix::I());
2784671d6cf460531825a321edb200523d0faa7792c9Romain Guy
2785671d6cf460531825a321edb200523d0faa7792c9Romain Guy    int alpha;
2786671d6cf460531825a321edb200523d0faa7792c9Romain Guy    SkXfermode::Mode mode;
2787671d6cf460531825a321edb200523d0faa7792c9Romain Guy    getAlphaAndMode(paint, &alpha, &mode);
2788671d6cf460531825a321edb200523d0faa7792c9Romain Guy
2789c29a0a4664a4b9871fadd668b632469a0db240b9Derek Sollenberger    if (CC_UNLIKELY(hasTextShadow(paint))) {
2790e3a9b24b5e3f9b2058486814a6d27729e51ad466Romain Guy        drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
279176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger                alpha, 0.0f, 0.0f);
2792416a847633680d94efb926837efdc18726d54918Raph Levien    }
2793416a847633680d94efb926837efdc18726d54918Raph Levien
2794671d6cf460531825a321edb200523d0faa7792c9Romain Guy    // Pick the appropriate texture filtering
2795d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    bool linearFilter = currentTransform()->changesBounds();
2796671d6cf460531825a321edb200523d0faa7792c9Romain Guy    if (pureTranslate && !linearFilter) {
2797671d6cf460531825a321edb200523d0faa7792c9Romain Guy        linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f;
2798671d6cf460531825a321edb200523d0faa7792c9Romain Guy    }
2799257ae3502cfad43df681b1783528d645bdabc63fRomain Guy    fontRenderer.setTextureFiltering(linearFilter);
2800671d6cf460531825a321edb200523d0faa7792c9Romain Guy
2801487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    const Rect& clip(pureTranslate ? writableSnapshot()->getClipRect() : writableSnapshot()->getLocalClip());
2802671d6cf460531825a321edb200523d0faa7792c9Romain Guy    Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2803671d6cf460531825a321edb200523d0faa7792c9Romain Guy
2804211370fd943cf26905001b38b8b1791851b26adcRomain Guy    const bool hasActiveLayer = hasLayer();
2805671d6cf460531825a321edb200523d0faa7792c9Romain Guy
28061e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
2807487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    if (fontRenderer.renderPosText(paint, &clip, text, 0, bytesCount, count, x, y,
2808e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik            positions, hasActiveLayer ? &bounds : nullptr, &functor)) {
2809671d6cf460531825a321edb200523d0faa7792c9Romain Guy        if (hasActiveLayer) {
2810671d6cf460531825a321edb200523d0faa7792c9Romain Guy            if (!pureTranslate) {
2811d6b65f67717025b1162f86f04e2caa5723566cacChris Craik                currentTransform()->mapRect(bounds);
2812671d6cf460531825a321edb200523d0faa7792c9Romain Guy            }
2813671d6cf460531825a321edb200523d0faa7792c9Romain Guy            dirtyLayerUnchecked(bounds, getRegion());
2814671d6cf460531825a321edb200523d0faa7792c9Romain Guy        }
2815671d6cf460531825a321edb200523d0faa7792c9Romain Guy    }
2816486590963e2207d68eebd6944fec70d50d41116aChet Haase
2817107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
2818eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy}
2819eb9a5367e8f0e970db8509ffb2584f5376bc62edRomain Guy
282059744b79ec302000802cd56d30a1bf70f0183c80Chris Craikbool OpenGLRenderer::findBestFontTransform(const mat4& transform, SkMatrix* outMatrix) const {
2821624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    if (CC_LIKELY(transform.isPureTranslate())) {
282259744b79ec302000802cd56d30a1bf70f0183c80Chris Craik        outMatrix->setIdentity();
282359744b79ec302000802cd56d30a1bf70f0183c80Chris Craik        return false;
282459744b79ec302000802cd56d30a1bf70f0183c80Chris Craik    } else if (CC_UNLIKELY(transform.isPerspective())) {
282559744b79ec302000802cd56d30a1bf70f0183c80Chris Craik        outMatrix->setIdentity();
282659744b79ec302000802cd56d30a1bf70f0183c80Chris Craik        return true;
282759744b79ec302000802cd56d30a1bf70f0183c80Chris Craik    }
282859744b79ec302000802cd56d30a1bf70f0183c80Chris Craik
282959744b79ec302000802cd56d30a1bf70f0183c80Chris Craik    /**
2830a736cd9d3587a120e5233d627cd8bf06353be107Chris Craik     * Input is a non-perspective, scaling transform. Generate a scale-only transform,
2831a736cd9d3587a120e5233d627cd8bf06353be107Chris Craik     * with values rounded to the nearest int.
283259744b79ec302000802cd56d30a1bf70f0183c80Chris Craik     */
283359744b79ec302000802cd56d30a1bf70f0183c80Chris Craik    float sx, sy;
283459744b79ec302000802cd56d30a1bf70f0183c80Chris Craik    transform.decomposeScale(sx, sy);
2835a736cd9d3587a120e5233d627cd8bf06353be107Chris Craik    outMatrix->setScale(
2836a736cd9d3587a120e5233d627cd8bf06353be107Chris Craik            roundf(fmaxf(1.0f, sx)),
2837a736cd9d3587a120e5233d627cd8bf06353be107Chris Craik            roundf(fmaxf(1.0f, sy)));
2838a736cd9d3587a120e5233d627cd8bf06353be107Chris Craik    return true;
2839624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy}
2840624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy
2841984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonint OpenGLRenderer::getSaveCount() const {
2842984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    return mState.getSaveCount();
2843984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2844984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2845984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonint OpenGLRenderer::save(int flags) {
2846984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    return mState.save(flags);
2847984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2848984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2849984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonvoid OpenGLRenderer::restore() {
2850984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    return mState.restore();
2851984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2852984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2853984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonvoid OpenGLRenderer::restoreToCount(int saveCount) {
2854984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    return mState.restoreToCount(saveCount);
2855984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2856984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2857984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonvoid OpenGLRenderer::translate(float dx, float dy, float dz) {
2858984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    return mState.translate(dx, dy, dz);
2859984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2860984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2861984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonvoid OpenGLRenderer::rotate(float degrees) {
2862984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    return mState.rotate(degrees);
2863984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2864984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2865984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonvoid OpenGLRenderer::scale(float sx, float sy) {
2866984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    return mState.scale(sx, sy);
2867984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2868984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2869984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonvoid OpenGLRenderer::skew(float sx, float sy) {
2870984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    return mState.skew(sx, sy);
2871984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2872984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2873984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonvoid OpenGLRenderer::setMatrix(const Matrix4& matrix) {
2874984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    mState.setMatrix(matrix);
2875984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2876984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2877984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonvoid OpenGLRenderer::concatMatrix(const Matrix4& matrix) {
2878984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    mState.concatMatrix(matrix);
2879984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2880984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2881984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonbool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
2882984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    return mState.clipRect(left, top, right, bottom, op);
2883984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2884984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2885984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonbool OpenGLRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
2886984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    return mState.clipPath(path, op);
2887984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2888984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2889984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonbool OpenGLRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
2890984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    return mState.clipRegion(region, op);
2891984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2892984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2893984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonvoid OpenGLRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
2894984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    mState.setClippingOutline(allocator, outline);
2895984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2896984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2897984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudsonvoid OpenGLRenderer::setClippingRoundRect(LinearAllocator& allocator,
2898984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson        const Rect& rect, float radius, bool highPriority) {
2899984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    mState.setClippingRoundRect(allocator, rect, radius, highPriority);
2900984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson}
2901984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson
2902107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float x, float y,
2903d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
2904527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik        DrawOpMode drawOpMode) {
2905527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik
290603ae272459869b854e5db252fc81a64a516e111fChris Craik    if (drawOpMode == DrawOpMode::kImmediate) {
290728ce94a4ffc7576f40776d212f1ada79fafaa061Chris Craik        // The checks for corner-case ignorable text and quick rejection is only done for immediate
290828ce94a4ffc7576f40776d212f1ada79fafaa061Chris Craik        // drawing as ops from DeferredDisplayList are already filtered for these
2909e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik        if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint) ||
2910f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik                quickRejectSetupScissor(bounds)) {
2911107843de4507b3511006cb9c77b8d0364374385aTom Hudson            return;
291228ce94a4ffc7576f40776d212f1ada79fafaa061Chris Craik        }
2913cac5fd3e09e9dc918753d4aff624bf29a367ade3Romain Guy    }
2914cac5fd3e09e9dc918753d4aff624bf29a367ade3Romain Guy
29153a3fa1be9ab8e11edc660ecb35ae21ae0b5c8cc2Romain Guy    const float oldX = x;
29163a3fa1be9ab8e11edc660ecb35ae21ae0b5c8cc2Romain Guy    const float oldY = y;
2917624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy
2918d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    const mat4& transform = *currentTransform();
2919624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    const bool pureTranslate = transform.isPureTranslate();
2920c74f45a334f0e3725c23cdd270cbcb0efac4ea75Romain Guy
2921211370fd943cf26905001b38b8b1791851b26adcRomain Guy    if (CC_LIKELY(pureTranslate)) {
2922624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy        x = (int) floorf(x + transform.getTranslateX() + 0.5f);
2923624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy        y = (int) floorf(y + transform.getTranslateY() + 0.5f);
29246620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy    }
29256620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy
292686568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy    int alpha;
292786568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy    SkXfermode::Mode mode;
292886568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy    getAlphaAndMode(paint, &alpha, &mode);
29299d13fe25f4f10b25776b1dc5c858f9ebb0b28b30Romain Guy
2930c74f45a334f0e3725c23cdd270cbcb0efac4ea75Romain Guy    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
2931c74f45a334f0e3725c23cdd270cbcb0efac4ea75Romain Guy
2932c29a0a4664a4b9871fadd668b632469a0db240b9Derek Sollenberger    if (CC_UNLIKELY(hasTextShadow(paint))) {
293359744b79ec302000802cd56d30a1bf70f0183c80Chris Craik        fontRenderer.setFont(paint, SkMatrix::I());
2934c74f45a334f0e3725c23cdd270cbcb0efac4ea75Romain Guy        drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
293576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger                alpha, oldX, oldY);
29361e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    }
29371e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
293819d4dd8599cb870923ab349d2ab96cacffd9c6f5Romain Guy    const bool hasActiveLayer = hasLayer();
293919d4dd8599cb870923ab349d2ab96cacffd9c6f5Romain Guy
2940624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // We only pass a partial transform to the font renderer. That partial
2941624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // matrix defines how glyphs are rasterized. Typically we want glyphs
2942624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // to be rasterized at their final size on screen, which means the partial
2943624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // matrix needs to take the scale factor into account.
2944624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // When a partial matrix is used to transform glyphs during rasterization,
2945624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // the mesh is generated with the inverse transform (in the case of scale,
2946624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // the mesh is generated at 1.0 / scale for instance.) This allows us to
2947624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // apply the full transform matrix at draw time in the vertex shader.
2948624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // Applying the full matrix in the shader is the easiest way to handle
2949624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // rotation and perspective and allows us to always generated quads in the
2950624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // font renderer which greatly simplifies the code, clipping in particular.
295159744b79ec302000802cd56d30a1bf70f0183c80Chris Craik    SkMatrix fontTransform;
295259744b79ec302000802cd56d30a1bf70f0183c80Chris Craik    bool linearFilter = findBestFontTransform(transform, &fontTransform)
295359744b79ec302000802cd56d30a1bf70f0183c80Chris Craik            || fabs(y - (int) y) > 0.0f
295459744b79ec302000802cd56d30a1bf70f0183c80Chris Craik            || fabs(x - (int) x) > 0.0f;
29553b753829ae858d424fe109f714745379a6daf455Romain Guy    fontRenderer.setFont(paint, fontTransform);
2956257ae3502cfad43df681b1783528d645bdabc63fRomain Guy    fontRenderer.setTextureFiltering(linearFilter);
295706f96e2652e4855b6520ad9dd70583677605b79aRomain Guy
2958624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy    // TODO: Implement better clipping for scaled/rotated text
2959487a92caef2eb90a62e8f8d7a6fe6315f1c1d8d8Rob Tsuk    const Rect* clip = !pureTranslate ? nullptr : &mState.currentClipRect();
296041541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik    Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
29615b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
2962996e57c84368058be793897ebc355b917a59abc2Raph Levien    bool status;
29631e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
2964527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik
2965527a3aace1dd72432c2e0472a570e030ad04bf16Chris Craik    // don't call issuedrawcommand, do it at end of batch
296603ae272459869b854e5db252fc81a64a516e111fChris Craik    bool forceFinish = (drawOpMode != DrawOpMode::kDefer);
2967a3dc55f83ab583e0a66b893c71b849afa046770aRomain Guy    if (CC_UNLIKELY(paint->getTextAlign() != SkPaint::kLeft_Align)) {
29688b4072d3fb9bb49d774d97689a065204beca1752Raph Levien        SkPaint paintCopy(*paint);
29698b4072d3fb9bb49d774d97689a065204beca1752Raph Levien        paintCopy.setTextAlign(SkPaint::kLeft_Align);
29708b4072d3fb9bb49d774d97689a065204beca1752Raph Levien        status = fontRenderer.renderPosText(&paintCopy, clip, text, 0, bytesCount, count, x, y,
2971e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik                positions, hasActiveLayer ? &layerBounds : nullptr, &functor, forceFinish);
2972996e57c84368058be793897ebc355b917a59abc2Raph Levien    } else {
29738b4072d3fb9bb49d774d97689a065204beca1752Raph Levien        status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
2974e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik                positions, hasActiveLayer ? &layerBounds : nullptr, &functor, forceFinish);
2975996e57c84368058be793897ebc355b917a59abc2Raph Levien    }
29764ff0cf4b83605bff630c4e6f1fabe4f72a3f93a1Romain Guy
297703ae272459869b854e5db252fc81a64a516e111fChris Craik    if ((status || drawOpMode != DrawOpMode::kImmediate) && hasActiveLayer) {
2978624234f69b2a4781d24f3e4c6ae6450729e38397Romain Guy        if (!pureTranslate) {
297941541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik            transform.mapRect(layerBounds);
2980a4adcf0239039eb8f005be252409901c41b28839Romain Guy        }
298141541825bc90dac740e424cdd41a8c997e15cdb7Chris Craik        dirtyLayerUnchecked(layerBounds, getRegion());
29825b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    }
2983694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
2984e63f7c622a2086aefa80983c6f41b74fb166bb42Chris Craik    drawTextDecorations(totalAdvance, oldX, oldY, paint);
2985486590963e2207d68eebd6944fec70d50d41116aChet Haase
2986107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
2987694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
2988694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
2989107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
2990d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) {
2991e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) {
2992107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
299303d58520c3eb6bb7efb7235bfd957550533d6725Romain Guy    }
299403d58520c3eb6bb7efb7235bfd957550533d6725Romain Guy
299539a908c1df89e1073627b0dcbce922d826b67055Chris Craik    // TODO: avoid scissor by calculating maximum bounds using path bounds + font metrics
299665fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik    mRenderState.scissor().setEnabled(true);
299739a908c1df89e1073627b0dcbce922d826b67055Chris Craik
2998b1d0a4ed21168fefcb82232c8f22cb95d60acb85Romain Guy    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
299959744b79ec302000802cd56d30a1bf70f0183c80Chris Craik    fontRenderer.setFont(paint, SkMatrix::I());
3000257ae3502cfad43df681b1783528d645bdabc63fRomain Guy    fontRenderer.setTextureFiltering(true);
300103d58520c3eb6bb7efb7235bfd957550533d6725Romain Guy
300203d58520c3eb6bb7efb7235bfd957550533d6725Romain Guy    int alpha;
300303d58520c3eb6bb7efb7235bfd957550533d6725Romain Guy    SkXfermode::Mode mode;
300403d58520c3eb6bb7efb7235bfd957550533d6725Romain Guy    getAlphaAndMode(paint, &alpha, &mode);
30051e546815bbb736c50679a8aefc25f48561026fc5Victoria Lease    TextSetupFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint);
30069777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
3007984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    const Rect* clip = &writableSnapshot()->getLocalClip();
30089777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
300903d58520c3eb6bb7efb7235bfd957550533d6725Romain Guy
30109777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    const bool hasActiveLayer = hasLayer();
30119777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy
30129777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path,
3013e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik            hOffset, vOffset, hasActiveLayer ? &bounds : nullptr, &functor)) {
30149777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        if (hasActiveLayer) {
3015d6b65f67717025b1162f86f04e2caa5723566cacChris Craik            currentTransform()->mapRect(bounds);
30169777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy            dirtyLayerUnchecked(bounds, getRegion());
30179777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy        }
30189777173eb6c9eb97c7921c8288ebc65e3ab3ce6fRomain Guy    }
3019486590963e2207d68eebd6944fec70d50d41116aChet Haase
3020107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
3021325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy}
3022325740fb444af8fc7fb0119b2e30ce322c2ae134Romain Guy
3023107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
3024984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored()) return;
3025dbc26d2ba13f80a7590c57de2d80530d96832969Romain Guy
302644eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik    mCaches.textureState().activateTexture(0);
30277fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
302830036092b40badecbe64d9c2bff4850132147f78Chris Craik    PathTexture* texture = mCaches.pathCache.get(path, paint);
3029107843de4507b3511006cb9c77b8d0364374385aTom Hudson    if (!texture) return;
303022158e139a3d6c6a9787ca0de224e9368f643284Romain Guy    const AutoTexture autoCleanup(texture);
30317fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
30328b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy    const float x = texture->left - texture->offset;
30338b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy    const float y = texture->top - texture->offset;
30348b55f377655d13a445b08a0a8ed09b6e95c752b0Romain Guy
303501d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    drawPathTexture(texture, x, y, paint);
3036107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
30377fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy}
30387fbcc0492fca03857e3c45064f4aa040af817d55Romain Guy
3039107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
304035643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    if (!layer) {
3041107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
30426c319ca1275c8db892c39b48fc54864c949f9171Romain Guy    }
30436c319ca1275c8db892c39b48fc54864c949f9171Romain Guy
3044e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    mat4* transform = nullptr;
3045b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy    if (layer->isTextureLayer()) {
3046b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy        transform = &layer->getTransform();
3047b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy        if (!transform->isIdentity()) {
30483f085429fd47ebd32ac2463b3eae2a5a6c17be25Chris Craik            save(SkCanvas::kMatrix_SaveFlag);
304914e513058ed4168c94e015638d16f5f87fd8063aChris Craik            concatMatrix(*transform);
3050b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy        }
3051b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy    }
3052b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy
305339a908c1df89e1073627b0dcbce922d826b67055Chris Craik    bool clipRequired = false;
3054e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    const bool rejected = mState.calculateQuickRejectForScissor(
3055e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik            x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(),
3056e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik            &clipRequired, nullptr, false);
30574ff0cf4b83605bff630c4e6f1fabe4f72a3f93a1Romain Guy
305835643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    if (rejected) {
3059b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy        if (transform && !transform->isIdentity()) {
3060b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy            restore();
3061b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy        }
3062107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
306335643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy    }
306435643ddc689913f5b5f80ceed864470d987bd6cdRomain Guy
306562d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik    EVENT_LOGD("drawLayer," RECT_STRING ", clipRequired %d", x, y,
306662d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik            x + layer->layer.getWidth(), y + layer->layer.getHeight(), clipRequired);
306762d307c2402777d5e53b4590af5f32f8c55afd81Chris Craik
30685bb3c730f5ebd2a0db1b02a8981c6fdbea6c1a2eRomain Guy    updateLayer(layer, true);
30692bf68f063b0077ddef6ebfe54f2ae5e063c2c229Romain Guy
307065fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik    mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
307144eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik    mCaches.textureState().activateTexture(0);
30726c319ca1275c8db892c39b48fc54864c949f9171Romain Guy
3073211370fd943cf26905001b38b8b1791851b26adcRomain Guy    if (CC_LIKELY(!layer->region.isEmpty())) {
3074c88e357d1ed9dadfc0efb3dfbe92f24460674ef5Romain Guy        if (layer->region.isRect()) {
307534416eaa1c07b3d7a139e780cea8f8d73219650eChris Craik            DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
307634416eaa1c07b3d7a139e780cea8f8d73219650eChris Craik                    composeLayerRect(layer, layer->regionRect));
3077c88e357d1ed9dadfc0efb3dfbe92f24460674ef5Romain Guy        } else if (layer->mesh) {
3078f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik            if (USE_GLOPS) {
3079f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                Glop glop;
30806b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik                GlopBuilder(mRenderState, mCaches, &glop)
30816b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik                        .setMeshTexturedIndexedQuads(layer->mesh, layer->meshElementCount)
3082f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                        .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode())
3083f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                        .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
3084f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                        .setModelViewOffsetRectSnap(x, y, Rect(0, 0, layer->layer.getWidth(), layer->layer.getHeight()))
3085f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                        .setRoundRectClipState(currentSnapshot()->roundRectClipState)
3086f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                        .build();
3087f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
30889ace8f5e79e76893fe4ca9e4d10f6c4056330485Romain Guy            } else {
3089f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                const float a = getLayerAlpha(layer);
3090f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                setupDraw();
3091f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                setupDrawWithTexture();
3092f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                setupDrawColor(a, a, a, a);
3093f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                setupDrawColorFilter(layer->getColorFilter());
3094f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                setupDrawBlending(layer);
3095f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                setupDrawProgram();
3096f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                setupDrawPureColorUniforms();
3097f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                setupDrawColorFilterUniforms(layer->getColorFilter());
3098f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                setupDrawTexture(layer->getTextureId());
3099f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                if (CC_LIKELY(currentTransform()->isPureTranslate())) {
3100f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    int tx = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f);
3101f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    int ty = (int) floorf(y + currentTransform()->getTranslateY() + 0.5f);
3102f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik
3103f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    layer->setFilter(GL_NEAREST);
3104f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    setupDrawModelView(kModelViewMode_Translate, false, tx, ty,
3105f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                            tx + layer->layer.getWidth(), ty + layer->layer.getHeight(), true);
3106f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                } else {
3107f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    layer->setFilter(GL_LINEAR);
3108f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    setupDrawModelView(kModelViewMode_Translate, false, x, y,
3109f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                            x + layer->layer.getWidth(), y + layer->layer.getHeight());
3110f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                }
3111c88e357d1ed9dadfc0efb3dfbe92f24460674ef5Romain Guy
3112448455fe783b0a711340322dca272b8cc0ebe473Romain Guy
3113f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                TextureVertex* mesh = &layer->mesh[0];
3114f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                GLsizei elementsCount = layer->meshElementCount;
3115448455fe783b0a711340322dca272b8cc0ebe473Romain Guy
3116448455fe783b0a711340322dca272b8cc0ebe473Romain Guy
3117f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                while (elementsCount > 0) {
3118f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    GLsizei drawCount = MathUtils::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
3119f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik
3120f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
3121f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
3122f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                            glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, nullptr));
3123c88e357d1ed9dadfc0efb3dfbe92f24460674ef5Romain Guy
3124f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    elementsCount -= drawCount;
3125f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    // Though there are 4 vertices in a quad, we use 6 indices per
3126f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    // quad to draw with GL_TRIANGLES
3127f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                    mesh += (drawCount / 6) * 4;
3128f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                }
3129f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik            }
31303a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy#if DEBUG_LAYERS_AS_REGIONS
3131e63f7c622a2086aefa80983c6f41b74fb166bb42Chris Craik            drawRegionRectsDebug(layer->region);
31323a3133d876caf60ebff2176ad75c3dcf0259148dRomain Guy#endif
3133c88e357d1ed9dadfc0efb3dfbe92f24460674ef5Romain Guy        }
31344ff0cf4b83605bff630c4e6f1fabe4f72a3f93a1Romain Guy
31355bb3c730f5ebd2a0db1b02a8981c6fdbea6c1a2eRomain Guy        if (layer->debugDrawUpdate) {
31365bb3c730f5ebd2a0db1b02a8981c6fdbea6c1a2eRomain Guy            layer->debugDrawUpdate = false;
313776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
313876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger            SkPaint paint;
313976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger            paint.setColor(0x7f00ff00);
314076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger            drawColorRect(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(), &paint);
31414ff0cf4b83605bff630c4e6f1fabe4f72a3f93a1Romain Guy        }
3142f219da5e32e85deb442468ee9a63bb28eb198557Romain Guy    }
314334416eaa1c07b3d7a139e780cea8f8d73219650eChris Craik    layer->hasDrawnSinceUpdate = true;
3144486590963e2207d68eebd6944fec70d50d41116aChet Haase
3145b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy    if (transform && !transform->isIdentity()) {
3146b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy        restore();
3147b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy    }
3148b2e2f2470693e78baed20617f989d9a166864ed4Romain Guy
3149107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
31506c319ca1275c8db892c39b48fc54864c949f9171Romain Guy}
31516c319ca1275c8db892c39b48fc54864c949f9171Romain Guy
31526926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy///////////////////////////////////////////////////////////////////////////////
31535ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy// Draw filters
31545ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy///////////////////////////////////////////////////////////////////////////////
315509c2d4fe15fbac2faf8a97ba2cc59132ee12222aDerek Sollenbergervoid OpenGLRenderer::setDrawFilter(SkDrawFilter* filter) {
315609c2d4fe15fbac2faf8a97ba2cc59132ee12222aDerek Sollenberger    // We should never get here since we apply the draw filter when stashing
315709c2d4fe15fbac2faf8a97ba2cc59132ee12222aDerek Sollenberger    // the paints in the DisplayList.
315809c2d4fe15fbac2faf8a97ba2cc59132ee12222aDerek Sollenberger    LOG_ALWAYS_FATAL("OpenGLRenderer does not directly support DrawFilters");
31595ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy}
31605ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy
31615ff9df658230d49e42c43586997a02d8e4dd417eRomain Guy///////////////////////////////////////////////////////////////////////////////
31626926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy// Drawing implementation
31636926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy///////////////////////////////////////////////////////////////////////////////
31646926c72e25b8dec3dd4b84af0819fa1937ae7296Romain Guy
3165d218a92c0afb8c0d98135b20b52ac87236e1c935Chris CraikTexture* OpenGLRenderer::getTexture(const SkBitmap* bitmap) {
3166ebd52610cfeff6e557fde284a7e1efc5e6438285John Reck    Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap);
31673b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    if (!texture) {
31683b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        return mCaches.textureCache.get(bitmap);
31693b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    }
31703b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    return texture;
31713b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy}
31723b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
31732bb8f5606d4a28549d95005304305b3aff1ce090Chris Craikvoid OpenGLRenderer::drawPathTexture(PathTexture* texture, float x, float y,
31742bb8f5606d4a28549d95005304305b3aff1ce090Chris Craik        const SkPaint* paint) {
3175f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik    if (quickRejectSetupScissor(x, y, x + texture->width, y + texture->height)) {
317601d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy        return;
317701d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    }
317801d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
3179922d3a7f6f8c1c05a996ee3e91e8cbadfff560c9Chris Craik    if (USE_GLOPS) {
318030036092b40badecbe64d9c2bff4850132147f78Chris Craik        Glop glop;
31816b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik        GlopBuilder(mRenderState, mCaches, &glop)
31826b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik                .setMeshTexturedUnitQuad(nullptr)
318330036092b40badecbe64d9c2bff4850132147f78Chris Craik                .setFillPathTexturePaint(*texture, *paint, currentSnapshot()->alpha)
3184f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
318530036092b40badecbe64d9c2bff4850132147f78Chris Craik                .setModelViewMapUnitToRect(Rect(x, y, x + texture->width, y + texture->height))
318630036092b40badecbe64d9c2bff4850132147f78Chris Craik                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
318730036092b40badecbe64d9c2bff4850132147f78Chris Craik                .build();
318830036092b40badecbe64d9c2bff4850132147f78Chris Craik        renderGlop(glop);
318930036092b40badecbe64d9c2bff4850132147f78Chris Craik        return;
319030036092b40badecbe64d9c2bff4850132147f78Chris Craik    }
319130036092b40badecbe64d9c2bff4850132147f78Chris Craik
319230036092b40badecbe64d9c2bff4850132147f78Chris Craik
319301d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    int alpha;
319401d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    SkXfermode::Mode mode;
319501d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    getAlphaAndMode(paint, &alpha, &mode);
319601d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
319701d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    setupDraw();
319801d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    setupDrawWithTexture(true);
319901d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    setupDrawAlpha8Color(paint->getColor(), alpha);
320076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilter(getColorFilter(paint));
3201d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShader(getShader(paint));
320276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawBlending(paint, true);
320301d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    setupDrawProgram();
32044063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik    setupDrawModelView(kModelViewMode_TranslateAndScale, false,
32054063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik            x, y, x + texture->width, y + texture->height);
320601d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    setupDrawTexture(texture->id);
320701d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy    setupDrawPureColorUniforms();
320876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilterUniforms(getColorFilter(paint));
3209d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShaderUniforms(getShader(paint));
321096a5c4c7bab6718524de7253da8309143ab48befChris Craik    setupDrawMesh(nullptr, (GLvoid*) kMeshTextureOffset);
321101d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
3212117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
321301d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy}
321401d58e43ede5ca98cbebdd166f9b0c545032c01bRomain Guy
3215f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy// Same values used by Skia
32160a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy#define kStdStrikeThru_Offset   (-6.0f / 21.0f)
32170a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy#define kStdUnderline_Offset    (1.0f / 9.0f)
32180a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy#define kStdUnderline_Thickness (1.0f / 18.0f)
32190a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
3220d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craikvoid OpenGLRenderer::drawTextDecorations(float underlineWidth, float x, float y,
3221d218a92c0afb8c0d98135b20b52ac87236e1c935Chris Craik        const SkPaint* paint) {
32220a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    // Handle underline and strike-through
32230a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    uint32_t flags = paint->getFlags();
32240a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
3225726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy        SkPaint paintCopy(*paint);
32260a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
3227211370fd943cf26905001b38b8b1791851b26adcRomain Guy        if (CC_LIKELY(underlineWidth > 0.0f)) {
3228726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy            const float textSize = paintCopy.getTextSize();
3229f6834478b379856d3e5de92ddce7de0e6ba9fa4aRomain Guy            const float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
32300a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
32318b4072d3fb9bb49d774d97689a065204beca1752Raph Levien            const float left = x;
32320a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy            float top = 0.0f;
3233e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy
3234f6834478b379856d3e5de92ddce7de0e6ba9fa4aRomain Guy            int linesCount = 0;
3235f6834478b379856d3e5de92ddce7de0e6ba9fa4aRomain Guy            if (flags & SkPaint::kUnderlineText_Flag) linesCount++;
3236f6834478b379856d3e5de92ddce7de0e6ba9fa4aRomain Guy            if (flags & SkPaint::kStrikeThruText_Flag) linesCount++;
3237f6834478b379856d3e5de92ddce7de0e6ba9fa4aRomain Guy
3238f6834478b379856d3e5de92ddce7de0e6ba9fa4aRomain Guy            const int pointsCount = 4 * linesCount;
3239e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy            float points[pointsCount];
3240e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy            int currentPoint = 0;
32410a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
32420a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy            if (flags & SkPaint::kUnderlineText_Flag) {
32430a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy                top = y + textSize * kStdUnderline_Offset;
3244e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = left;
3245e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = top;
3246e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = left + underlineWidth;
3247e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = top;
32480a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy            }
32490a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
32500a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy            if (flags & SkPaint::kStrikeThruText_Flag) {
32510a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy                top = y + textSize * kStdStrikeThru_Offset;
3252e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = left;
3253e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = top;
3254e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = left + underlineWidth;
3255e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy                points[currentPoint++] = top;
32560a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy            }
3257e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy
3258726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy            paintCopy.setStrokeWidth(strokeWidth);
3259e20ecbd12d26467754a7770d44bcce2ea92335efRomain Guy
3260726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy            drawLines(&points[0], pointsCount, &paintCopy);
32610a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy        }
32620a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy    }
32630a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy}
32640a41749953f35d33f61b3119e3161a82bb5fa59eRomain Guy
3265107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
3266984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored()) {
3267107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
3268672433d90fab7383cd28beac9d4485b566a90940Romain Guy    }
3269672433d90fab7383cd28beac9d4485b566a90940Romain Guy
3270107843de4507b3511006cb9c77b8d0364374385aTom Hudson    drawColorRects(rects, count, paint, false, true, true);
3271735738c4ddf3229caa5f6e634bf591953ac29944Romain Guy}
3272735738c4ddf3229caa5f6e634bf591953ac29944Romain Guy
3273107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawShadow(float casterAlpha,
327405f3d6e5111fd08df5cd9aae2c3d28399dc0e7f5Chris Craik        const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) {
3275984162fb7e4010b6e2908352dbff17ed47eecf06Tom Hudson    if (mState.currentlyIgnored()) return;
3276f57776b2d195f0937906eb88b777bb55ccc36967Chris Craik
327715a07a21eb33e8ca1c7444944fe0541a53380c0cChris Craik    // TODO: use quickRejectWithScissor. For now, always force enable scissor.
327865fe5eeb19e2e15c8b1ee91e8a2dcf0c25e48ca6Chris Craik    mRenderState.scissor().setEnabled(true);
3279f57776b2d195f0937906eb88b777bb55ccc36967Chris Craik
3280f57776b2d195f0937906eb88b777bb55ccc36967Chris Craik    SkPaint paint;
3281ba9b613437c34873fa95800a25fc51720638267cChris Craik    paint.setAntiAlias(true); // want to use AlphaVertex
3282f57776b2d195f0937906eb88b777bb55ccc36967Chris Craik
328314a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui    // The caller has made sure casterAlpha > 0.
328414a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui    float ambientShadowAlpha = mAmbientShadowAlpha;
328514a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui    if (CC_UNLIKELY(mCaches.propertyAmbientShadowStrength >= 0)) {
328614a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui        ambientShadowAlpha = mCaches.propertyAmbientShadowStrength;
328714a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui    }
328814a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui    if (ambientShadowVertexBuffer && ambientShadowAlpha > 0) {
328914a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui        paint.setARGB(casterAlpha * ambientShadowAlpha, 0, 0, 0);
329091a8c7c62913c2597e3bf5a6d59d2ed5fc7ba4e0Chris Craik        drawVertexBuffer(*ambientShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp);
3291ef94c6f88fbb1deb095b1494378befcdb9722839ztenghui    }
3292ef94c6f88fbb1deb095b1494378befcdb9722839ztenghui
329314a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui    float spotShadowAlpha = mSpotShadowAlpha;
329414a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui    if (CC_UNLIKELY(mCaches.propertySpotShadowStrength >= 0)) {
329514a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui        spotShadowAlpha = mCaches.propertySpotShadowStrength;
329614a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui    }
329714a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui    if (spotShadowVertexBuffer && spotShadowAlpha > 0) {
329814a4e35208b7e97bbfa38f36130827c86bfafc2bztenghui        paint.setARGB(casterAlpha * spotShadowAlpha, 0, 0, 0);
329991a8c7c62913c2597e3bf5a6d59d2ed5fc7ba4e0Chris Craik        drawVertexBuffer(*spotShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp);
3300ef94c6f88fbb1deb095b1494378befcdb9722839ztenghui    }
33017b4516e7ea552ad08d6e7277d311ef11bd8f12e8ztenghui
3302107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty=true;
3303f57776b2d195f0937906eb88b777bb55ccc36967Chris Craik}
3304f57776b2d195f0937906eb88b777bb55ccc36967Chris Craik
3305107843de4507b3511006cb9c77b8d0364374385aTom Hudsonvoid OpenGLRenderer::drawColorRects(const float* rects, int count, const SkPaint* paint,
330676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        bool ignoreTransform, bool dirty, bool clip) {
33073b753829ae858d424fe109f714745379a6daf455Romain Guy    if (count == 0) {
3308107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
33093b753829ae858d424fe109f714745379a6daf455Romain Guy    }
3310735738c4ddf3229caa5f6e634bf591953ac29944Romain Guy
3311672433d90fab7383cd28beac9d4485b566a90940Romain Guy    float left = FLT_MAX;
3312672433d90fab7383cd28beac9d4485b566a90940Romain Guy    float top = FLT_MAX;
3313672433d90fab7383cd28beac9d4485b566a90940Romain Guy    float right = FLT_MIN;
3314672433d90fab7383cd28beac9d4485b566a90940Romain Guy    float bottom = FLT_MIN;
3315672433d90fab7383cd28beac9d4485b566a90940Romain Guy
3316448455fe783b0a711340322dca272b8cc0ebe473Romain Guy    Vertex mesh[count];
3317672433d90fab7383cd28beac9d4485b566a90940Romain Guy    Vertex* vertex = mesh;
3318672433d90fab7383cd28beac9d4485b566a90940Romain Guy
33192af4635e4a9e448a65ff541252f8f94bc6ac48e0Chris Craik    for (int index = 0; index < count; index += 4) {
3320672433d90fab7383cd28beac9d4485b566a90940Romain Guy        float l = rects[index + 0];
3321672433d90fab7383cd28beac9d4485b566a90940Romain Guy        float t = rects[index + 1];
3322672433d90fab7383cd28beac9d4485b566a90940Romain Guy        float r = rects[index + 2];
3323672433d90fab7383cd28beac9d4485b566a90940Romain Guy        float b = rects[index + 3];
3324672433d90fab7383cd28beac9d4485b566a90940Romain Guy
33253b753829ae858d424fe109f714745379a6daf455Romain Guy        Vertex::set(vertex++, l, t);
33263b753829ae858d424fe109f714745379a6daf455Romain Guy        Vertex::set(vertex++, r, t);
33273b753829ae858d424fe109f714745379a6daf455Romain Guy        Vertex::set(vertex++, l, b);
33283b753829ae858d424fe109f714745379a6daf455Romain Guy        Vertex::set(vertex++, r, b);
3329672433d90fab7383cd28beac9d4485b566a90940Romain Guy
33303b753829ae858d424fe109f714745379a6daf455Romain Guy        left = fminf(left, l);
33313b753829ae858d424fe109f714745379a6daf455Romain Guy        top = fminf(top, t);
33323b753829ae858d424fe109f714745379a6daf455Romain Guy        right = fmaxf(right, r);
33333b753829ae858d424fe109f714745379a6daf455Romain Guy        bottom = fmaxf(bottom, b);
3334672433d90fab7383cd28beac9d4485b566a90940Romain Guy    }
3335672433d90fab7383cd28beac9d4485b566a90940Romain Guy
3336f0a590781b2c3e34132b2011d3956135add73ae0Chris Craik    if (clip && quickRejectSetupScissor(left, top, right, bottom)) {
3337107843de4507b3511006cb9c77b8d0364374385aTom Hudson        return;
3338a362c69d6cdf448107e5a539f77df73937141870Romain Guy    }
3339672433d90fab7383cd28beac9d4485b566a90940Romain Guy
3340922d3a7f6f8c1c05a996ee3e91e8cbadfff560c9Chris Craik    if (USE_GLOPS) {
33412ab95d780b023152556d9f8659de734ec7b55047Chris Craik        const Matrix4& transform = ignoreTransform ? Matrix4::identity() : *currentTransform();
33422ab95d780b023152556d9f8659de734ec7b55047Chris Craik        Glop glop;
33436b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik        GlopBuilder(mRenderState, mCaches, &glop)
33446b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik                .setMeshIndexedQuads(&mesh[0], count / 4)
33450519c810a56bded1284fcb2ae40f438878c6585fChris Craik                .setFillPaint(*paint, currentSnapshot()->alpha)
3346f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
33472ab95d780b023152556d9f8659de734ec7b55047Chris Craik                .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
33480519c810a56bded1284fcb2ae40f438878c6585fChris Craik                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
33492ab95d780b023152556d9f8659de734ec7b55047Chris Craik                .build();
33502ab95d780b023152556d9f8659de734ec7b55047Chris Craik        renderGlop(glop);
33512ab95d780b023152556d9f8659de734ec7b55047Chris Craik        return;
33522ab95d780b023152556d9f8659de734ec7b55047Chris Craik    }
33532ab95d780b023152556d9f8659de734ec7b55047Chris Craik
33542ab95d780b023152556d9f8659de734ec7b55047Chris Craik    int color = paint->getColor();
33552ab95d780b023152556d9f8659de734ec7b55047Chris Craik    // If a shader is set, preserve only the alpha
33562ab95d780b023152556d9f8659de734ec7b55047Chris Craik    if (getShader(paint)) {
33572ab95d780b023152556d9f8659de734ec7b55047Chris Craik        color |= 0x00ffffff;
33582ab95d780b023152556d9f8659de734ec7b55047Chris Craik    }
33592ab95d780b023152556d9f8659de734ec7b55047Chris Craik
3360672433d90fab7383cd28beac9d4485b566a90940Romain Guy    setupDraw();
3361672433d90fab7383cd28beac9d4485b566a90940Romain Guy    setupDrawNoTexture();
3362d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
3363d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShader(getShader(paint));
336476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilter(getColorFilter(paint));
336576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawBlending(paint);
3366672433d90fab7383cd28beac9d4485b566a90940Romain Guy    setupDrawProgram();
3367672433d90fab7383cd28beac9d4485b566a90940Romain Guy    setupDrawDirtyRegionsDisabled();
33684063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik    setupDrawModelView(kModelViewMode_Translate, false,
33694063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik            0.0f, 0.0f, 0.0f, 0.0f, ignoreTransform);
3370d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawColorUniforms(getShader(paint));
3371d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShaderUniforms(getShader(paint));
337276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilterUniforms(getColorFilter(paint));
3373672433d90fab7383cd28beac9d4485b566a90940Romain Guy
33748ce00301a023eecaeb8891ce906f67b513ebb42aRomain Guy    if (dirty && hasLayer()) {
3375d6b65f67717025b1162f86f04e2caa5723566cacChris Craik        dirtyLayer(left, top, right, bottom, *currentTransform());
3376672433d90fab7383cd28beac9d4485b566a90940Romain Guy    }
3377672433d90fab7383cd28beac9d4485b566a90940Romain Guy
33784063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik    issueIndexedQuadDraw(&mesh[0], count / 4);
3379672433d90fab7383cd28beac9d4485b566a90940Romain Guy
3380107843de4507b3511006cb9c77b8d0364374385aTom Hudson    mDirty = true;
3381672433d90fab7383cd28beac9d4485b566a90940Romain Guy}
3382672433d90fab7383cd28beac9d4485b566a90940Romain Guy
3383026c5e16704e817cac7d9c382914c947e34f87e0Romain Guyvoid OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
338476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        const SkPaint* paint, bool ignoreTransform) {
3385117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik
3386922d3a7f6f8c1c05a996ee3e91e8cbadfff560c9Chris Craik    if (USE_GLOPS) {
3387117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        const Matrix4& transform = ignoreTransform ? Matrix4::identity() : *currentTransform();
3388117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        Glop glop;
33896b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik        GlopBuilder(mRenderState, mCaches, &glop)
33906b109c74982033d4a220cd10a0eab8b024b351c9Chris Craik                .setMeshUnitQuad()
33910519c810a56bded1284fcb2ae40f438878c6585fChris Craik                .setFillPaint(*paint, currentSnapshot()->alpha)
3392f27133df2d179c99d6bc1ae644af09e9153a0071Chris Craik                .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
3393117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik                .setModelViewMapUnitToRect(Rect(left, top, right, bottom))
33940519c810a56bded1284fcb2ae40f438878c6585fChris Craik                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
3395117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik                .build();
3396117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        renderGlop(glop);
3397117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik        return;
3398117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    }
3399117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik
340076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    int color = paint->getColor();
3401d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy    // If a shader is set, preserve only the alpha
3402d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    if (getShader(paint)) {
3403d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy        color |= 0x00ffffff;
3404d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy    }
3405d27977d1a91d5a6b3cc9fa7664ac7e835e7bd895Romain Guy
340670ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    setupDraw();
340715bc6437f8b4cf10dba55c7638d349e7b9563f4fRomain Guy    setupDrawNoTexture();
3408d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
3409d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShader(getShader(paint));
341076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilter(getColorFilter(paint));
341176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawBlending(paint);
341270ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    setupDrawProgram();
34134063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik    setupDrawModelView(kModelViewMode_TranslateAndScale, false,
34144063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik            left, top, right, bottom, ignoreTransform);
3415d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawColorUniforms(getShader(paint));
3416d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShaderUniforms(getShader(paint), ignoreTransform);
341776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilterUniforms(getColorFilter(paint));
341870ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    setupDrawSimpleMesh();
3419c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy
3420117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
3421c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy}
3422c95c8d6bf8fda5c4e8ebd0033b789be7868e6e07Romain Guy
34230519c810a56bded1284fcb2ae40f438878c6585fChris Craikvoid OpenGLRenderer::drawTextureRect(Texture* texture, const SkPaint* paint) {
3424d21b6e1fe337b35f62cf2028e9bd0637fd009a75Romain Guy    texture->setWrap(GL_CLAMP_TO_EDGE, true);
34258164c2d338781c3a3c4a443941070dca5d88f2a7Romain Guy
3426e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    GLvoid* vertices = (GLvoid*) nullptr;
342796a5c4c7bab6718524de7253da8309143ab48befChris Craik    GLvoid* texCoords = (GLvoid*) kMeshTextureOffset;
34283b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
34293b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    if (texture->uvMapper) {
34303380cfdc77100e87aa8390386ccf390834dea171Romain Guy        vertices = &mMeshVertices[0].x;
34313380cfdc77100e87aa8390386ccf390834dea171Romain Guy        texCoords = &mMeshVertices[0].u;
34323b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
34333b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        Rect uvs(0.0f, 0.0f, 1.0f, 1.0f);
34343b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        texture->uvMapper->map(uvs);
34353b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
34363b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        resetDrawTextureTexCoords(uvs.left, uvs.top, uvs.right, uvs.bottom);
34373b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    }
34383b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
3439d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    if (CC_LIKELY(currentTransform()->isPureTranslate())) {
34400519c810a56bded1284fcb2ae40f438878c6585fChris Craik        const float x = (int) floorf(currentTransform()->getTranslateX() + 0.5f);
34410519c810a56bded1284fcb2ae40f438878c6585fChris Craik        const float y = (int) floorf(currentTransform()->getTranslateY() + 0.5f);
34426620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy
3443d21b6e1fe337b35f62cf2028e9bd0637fd009a75Romain Guy        texture->setFilter(GL_NEAREST, true);
34446620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy        drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
344576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger                paint, texture->blend, vertices, texCoords,
3446117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik                GL_TRIANGLE_STRIP, kUnitQuadCount, false, true);
34476620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy    } else {
34480519c810a56bded1284fcb2ae40f438878c6585fChris Craik        texture->setFilter(PaintUtils::getFilter(paint), true);
34490519c810a56bded1284fcb2ae40f438878c6585fChris Craik        drawTextureMesh(0, 0, texture->width, texture->height, texture->id, paint,
3450117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik                texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, kUnitQuadCount);
34513b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    }
34523b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
34533b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    if (texture->uvMapper) {
34543b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
34556620c6d413f972819fada92b574f0fa9e96d36c1Romain Guy    }
345685bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy}
345785bf02fc16784d935fb9eebfa9cb20fe46ff7951Romain Guy
3458f7f93556c8fcc640ab5adef79d021a80a72a645aRomain Guyvoid OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
345976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        GLuint texture, const SkPaint* paint, bool blend,
34606820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy        GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
34614063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik        bool swapSrcDst, bool ignoreTransform, GLuint vbo,
34624063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik        ModelViewMode modelViewMode, bool dirty) {
34638694230ff25fa0a60e480d424843e56b718f0516Romain Guy
346476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    int a;
346576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    SkXfermode::Mode mode;
346676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    getAlphaAndMode(paint, &a, &mode);
346776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    const float alpha = a / 255.0f;
346876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
346970ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    setupDraw();
347070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    setupDrawWithTexture();
347170ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    setupDrawColor(alpha, alpha, alpha, alpha);
347276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilter(getColorFilter(paint));
347376d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawBlending(paint, blend, swapSrcDst);
347470ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    setupDrawProgram();
3475886b275e529e44a59c54b933453d9bc902973178Romain Guy    if (!dirty) setupDrawDirtyRegionsDisabled();
34764063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik    setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
3477886b275e529e44a59c54b933453d9bc902973178Romain Guy    setupDrawTexture(texture);
347886568198f2c83d4ce5c4cd692eda074ba9de9ed2Romain Guy    setupDrawPureColorUniforms();
347976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilterUniforms(getColorFilter(paint));
348070ca14e08ae197547ac412e8a1210e1ebdfb2eb1Romain Guy    setupDrawMesh(vertices, texCoords, vbo);
3481db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy
34826820ac8b14b4558f5d8b833dde80895306a3e137Romain Guy    glDrawArrays(drawMode, 0, elementsCount);
348382ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy}
348482ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy
34853b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guyvoid OpenGLRenderer::drawIndexedTextureMesh(float left, float top, float right, float bottom,
348676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        GLuint texture, const SkPaint* paint, bool blend,
34873b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy        GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
34884063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik        bool swapSrcDst, bool ignoreTransform, GLuint vbo,
34894063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik        ModelViewMode modelViewMode, bool dirty) {
34903b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
349176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    int a;
349276d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    SkXfermode::Mode mode;
349376d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    getAlphaAndMode(paint, &a, &mode);
349476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    const float alpha = a / 255.0f;
349576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
34963b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    setupDraw();
34973b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    setupDrawWithTexture();
34983b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    setupDrawColor(alpha, alpha, alpha, alpha);
349976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilter(getColorFilter(paint));
350076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawBlending(paint, blend, swapSrcDst);
35013b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    setupDrawProgram();
35023b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    if (!dirty) setupDrawDirtyRegionsDisabled();
35034063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik    setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
35043b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    setupDrawTexture(texture);
35053b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    setupDrawPureColorUniforms();
350676d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilterUniforms(getColorFilter(paint));
35073b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy    setupDrawMeshIndices(vertices, texCoords, vbo);
35083b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
3509e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    glDrawElements(drawMode, elementsCount, GL_UNSIGNED_SHORT, nullptr);
35103b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy}
35113b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy
3512886b275e529e44a59c54b933453d9bc902973178Romain Guyvoid OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom,
351376d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger        GLuint texture, const SkPaint* paint,
3514886b275e529e44a59c54b933453d9bc902973178Romain Guy        GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
35154063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik        bool ignoreTransform, ModelViewMode modelViewMode, bool dirty) {
3516886b275e529e44a59c54b933453d9bc902973178Romain Guy
3517e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    int color = paint != nullptr ? paint->getColor() : 0;
351876d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    int alpha;
351976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    SkXfermode::Mode mode;
352076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    getAlphaAndMode(paint, &alpha, &mode);
352176d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger
3522886b275e529e44a59c54b933453d9bc902973178Romain Guy    setupDraw();
3523886b275e529e44a59c54b933453d9bc902973178Romain Guy    setupDrawWithTexture(true);
3524e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik    if (paint != nullptr) {
3525886b275e529e44a59c54b933453d9bc902973178Romain Guy        setupDrawAlpha8Color(color, alpha);
3526886b275e529e44a59c54b933453d9bc902973178Romain Guy    }
352776d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilter(getColorFilter(paint));
3528d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShader(getShader(paint));
352976d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawBlending(paint, true);
3530886b275e529e44a59c54b933453d9bc902973178Romain Guy    setupDrawProgram();
3531886b275e529e44a59c54b933453d9bc902973178Romain Guy    if (!dirty) setupDrawDirtyRegionsDisabled();
35324063a0e03ba2e354cc6d19c0ffc073fd5b8aa2caChris Craik    setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
3533886b275e529e44a59c54b933453d9bc902973178Romain Guy    setupDrawTexture(texture);
3534886b275e529e44a59c54b933453d9bc902973178Romain Guy    setupDrawPureColorUniforms();
353576d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenberger    setupDrawColorFilterUniforms(getColorFilter(paint));
3536d1ad5e62fda248c6d185cde3cb6d9f01a223066cLeon Scroggins III    setupDrawShaderUniforms(getShader(paint), ignoreTransform);
3537886b275e529e44a59c54b933453d9bc902973178Romain Guy    setupDrawMesh(vertices, texCoords);
3538886b275e529e44a59c54b933453d9bc902973178Romain Guy
3539886b275e529e44a59c54b933453d9bc902973178Romain Guy    glDrawArrays(drawMode, 0, elementsCount);
3540886b275e529e44a59c54b933453d9bc902973178Romain Guy}
3541886b275e529e44a59c54b933453d9bc902973178Romain Guy
3542a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guyvoid OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
3543f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy        ProgramDescription& description, bool swapSrcDst) {
3544deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik
3545117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik    if (currentSnapshot()->roundRectClipState != nullptr /*&& !mSkipOutlineClip*/) {
3546deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik        blend = true;
3547deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik        mDescription.hasRoundRectClip = true;
3548deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    }
3549deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik    mSkipOutlineClip = true;
3550deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik
355182ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    blend = blend || mode != SkXfermode::kSrcOver_Mode;
3552c189ef53220059acf2adedc92ac4ac7e6a993e6bRomain Guy
355382ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    if (blend) {
355482bc7a772747fcf8a6fe7097f70bf2981429ffe9Romain Guy        // These blend modes are not supported by OpenGL directly and have
355582bc7a772747fcf8a6fe7097f70bf2981429ffe9Romain Guy        // to be implemented using shaders. Since the shader will perform
355682bc7a772747fcf8a6fe7097f70bf2981429ffe9Romain Guy        // the blending, turn blending off here
355782bc7a772747fcf8a6fe7097f70bf2981429ffe9Romain Guy        // If the blend mode cannot be implemented using shaders, fall
355882bc7a772747fcf8a6fe7097f70bf2981429ffe9Romain Guy        // back to the default SrcOver blend mode instead
355933fa1f774c8e7289fd7c39fbc2c65b9361f2c2c4Romain Guy        if (CC_UNLIKELY(mode > SkXfermode::kScreen_Mode)) {
3560117bdbcfa3e8306dad21e7e01fa71b00cdfa7265Chris Craik            if (CC_UNLIKELY(mCaches.extensions().hasFramebufferFetch())) {
3561a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy                description.framebufferMode = mode;
3562f607bdc167f66b3e7003acaa4736ae46d78c1492Romain Guy                description.swapSrcDst = swapSrcDst;
3563a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy
356444eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik                mRenderState.blend().disable();
356582bc7a772747fcf8a6fe7097f70bf2981429ffe9Romain Guy                return;
356682bc7a772747fcf8a6fe7097f70bf2981429ffe9Romain Guy            } else {
356782bc7a772747fcf8a6fe7097f70bf2981429ffe9Romain Guy                mode = SkXfermode::kSrcOver_Mode;
3568a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy            }
356982bc7a772747fcf8a6fe7097f70bf2981429ffe9Romain Guy        }
357044eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik        mRenderState.blend().enable(mode, swapSrcDst);
357144eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik    } else {
357244eb2c00861098dd3e2950d923646814b4cc57c2Chris Craik        mRenderState.blend().disable();
357382ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    }
3574bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy}
3575bd6b79b40247aea7bfe13d0831c6c0472df6c636Romain Guy
3576026c5e16704e817cac7d9c382914c947e34f87e0Romain Guyvoid OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
3577ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy    TextureVertex* v = &mMeshVertices[0];
357882ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    TextureVertex::setUV(v++, u1, v1);
357982ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    TextureVertex::setUV(v++, u2, v1);
358082ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    TextureVertex::setUV(v++, u1, v2);
358182ba814ca0dea659be2cc6523bc0137679d961ceRomain Guy    TextureVertex::setUV(v++, u2, v2);
35828ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy}
35838ba548f81d1ab5f1750cbf86098c4a14e0b8beadRomain Guy
3584e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craikvoid OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha,
3585e84a208317e0ed388fcdad1e6743c7849acb51b0Chris Craik        SkXfermode::Mode* mode) const {
3586be6f9dc1e71b425b7ac1c40c0a2c72d03eb9fbeeRomain Guy    getAlphaAndModeDirect(paint, alpha,  mode);
358716ecda5317c40fc3da284952d9b3add34d6763aeChris Craik    if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
358816ecda5317c40fc3da284952d9b3add34d6763aeChris Craik        // if drawing a layer, ignore the paint's alpha
358987b515cde53f3c8cc3fdf698c100e67508487e59Romain Guy        *alpha = mDrawModifiers.mOverrideLayerAlpha * 255;
359016ecda5317c40fc3da284952d9b3add34d6763aeChris Craik    }
3591d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    *alpha *= currentSnapshot()->alpha;
3592026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy}
3593026c5e16704e817cac7d9c382914c947e34f87e0Romain Guy
359476d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenbergerfloat OpenGLRenderer::getLayerAlpha(const Layer* layer) const {
359516ecda5317c40fc3da284952d9b3add34d6763aeChris Craik    float alpha;
359616ecda5317c40fc3da284952d9b3add34d6763aeChris Craik    if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
359716ecda5317c40fc3da284952d9b3add34d6763aeChris Craik        alpha = mDrawModifiers.mOverrideLayerAlpha;
359816ecda5317c40fc3da284952d9b3add34d6763aeChris Craik    } else {
359916ecda5317c40fc3da284952d9b3add34d6763aeChris Craik        alpha = layer->getAlpha() / 255.0f;
360016ecda5317c40fc3da284952d9b3add34d6763aeChris Craik    }
3601d6b65f67717025b1162f86f04e2caa5723566cacChris Craik    return alpha * currentSnapshot()->alpha;
360216ecda5317c40fc3da284952d9b3add34d6763aeChris Craik}
360316ecda5317c40fc3da284952d9b3add34d6763aeChris Craik
36049d5316e3f56d138504565ff311145ac01621dff4Romain Guy}; // namespace uirenderer
3605e4d011201cea40d46cb2b2eef401db8fddc5c9c6Romain Guy}; // namespace android
3606