OpenGLRenderer.cpp revision ebd52610cfeff6e557fde284a7e1efc5e6438285
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2010 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
4106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich * Licensed under the Apache License, Version 2.0 (the "License");
5106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich * you may not use this file except in compliance with the License.
6106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
8106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
10106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich * Unless required by applicable law or agreed to in writing, software
11106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich * distributed under the License is distributed on an "AS IS" BASIS,
12106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
178451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes#define LOG_TAG "OpenGLRenderer"
188451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes
198451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes#include <stdlib.h>
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <stdint.h>
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/types.h>
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <SkCanvas.h>
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <SkColor.h>
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <SkShader.h>
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <SkTypeface.h>
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich#include <utils/Log.h>
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/StopWatch.h>
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <private/hwui/DrawGlInfo.h>
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <ui/Rect.h>
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "OpenGLRenderer.h"
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "DeferredDisplayList.h"
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "DisplayListRenderer.h"
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "Fence.h"
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "RenderState.h"
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "PathTessellator.h"
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "Properties.h"
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "ShadowTessellator.h"
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkiaShader.h"
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "utils/GLUtils.h"
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "utils/TraceUtils.h"
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "Vector.h"
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "VertexBuffer.h"
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#if DEBUG_DETAILED_EVENTS
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    #define EVENT_LOGD(...) eventMarkDEBUG(__VA_ARGS__)
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#else
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    #define EVENT_LOGD(...)
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectnamespace android {
56106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevichnamespace uirenderer {
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic GLenum getFilter(const SkPaint* paint) {
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!paint || paint->getFilterLevel() != SkPaint::kNone_FilterLevel) {
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return GL_LINEAR;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
62106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich    return GL_NEAREST;
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// Globals
67106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich///////////////////////////////////////////////////////////////////////////////
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Structure mapping Skia xfermodes to OpenGL blending factors.
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstruct Blender {
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    SkXfermode::Mode mode;
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    GLenum src;
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    GLenum dst;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}; // struct Blender
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// In this array, the index of each Blender equals the value of the first
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic const Blender gBlends[] = {
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kClear_Mode,    GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kSrc_Mode,      GL_ONE,                 GL_ZERO },
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kDst_Mode,      GL_ZERO,                GL_ONE },
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kSrcOver_Mode,  GL_ONE,                 GL_ONE_MINUS_SRC_ALPHA },
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kDstOver_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_ONE },
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kSrcIn_Mode,    GL_DST_ALPHA,           GL_ZERO },
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kDstIn_Mode,    GL_ZERO,                GL_SRC_ALPHA },
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kSrcOut_Mode,   GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kDstOut_Mode,   GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kSrcATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
91106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich    { SkXfermode::kDstATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kModulate_Mode, GL_ZERO,                GL_SRC_COLOR },
95106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich    { SkXfermode::kScreen_Mode,   GL_ONE,                 GL_ONE_MINUS_SRC_COLOR }
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// This array contains the swapped version of each SkXfermode. For instance
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// this array's SrcOver blending mode is actually DstOver. You can refer to
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// createLayer() for more information on the purpose of this array.
101106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevichstatic const Blender gBlendsSwap[] = {
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kClear_Mode,    GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kSrc_Mode,      GL_ZERO,                GL_ONE },
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kDst_Mode,      GL_ONE,                 GL_ZERO },
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kSrcOver_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_ONE },
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kDstOver_Mode,  GL_ONE,                 GL_ONE_MINUS_SRC_ALPHA },
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kSrcIn_Mode,    GL_ZERO,                GL_SRC_ALPHA },
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kDstIn_Mode,    GL_DST_ALPHA,           GL_ZERO },
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kSrcOut_Mode,   GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kDstOut_Mode,   GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kSrcATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kDstATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
113106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich    { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kModulate_Mode, GL_DST_COLOR,           GL_ZERO },
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    { SkXfermode::kScreen_Mode,   GL_ONE_MINUS_DST_COLOR, GL_ONE }
117106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich};
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
120106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich// Functions
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projecttemplate<typename T>
124106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevichstatic inline T min(T a, T b) {
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return a < b ? a : b;
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// Constructors/destructor
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectOpenGLRenderer::OpenGLRenderer(RenderState& renderState)
133106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich        : mFrameStarted(false)
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        , mCaches(Caches::getInstance())
135106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich        , mExtensions(Extensions::getInstance())
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        , mRenderState(renderState)
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        , mScissorOptimizationDisabled(false)
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        , mSuppressTiling(false)
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        , mFirstFrameAfterResize(true)
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        , mLightCenter((Vector3){FLT_MIN, FLT_MIN, FLT_MIN})
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        , mLightRadius(FLT_MIN)
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        , mAmbientShadowAlpha(0)
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        , mSpotShadowAlpha(0) {
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // *set* draw modifiers to be 0
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    memset(&mDrawModifiers, 0, sizeof(mDrawModifiers));
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mDrawModifiers.mOverrideLayerAlpha = 1.0f;
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectOpenGLRenderer::~OpenGLRenderer() {
1528451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes    // The context has already been destroyed at this point, do not call
1538451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes    // GL APIs. All GL state should be kept in Caches.h
1548451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes}
1558451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid OpenGLRenderer::initProperties() {
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char property[PROPERTY_VALUE_MAX];
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (property_get(PROPERTY_DISABLE_SCISSOR_OPTIMIZATION, property, "false")) {
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mScissorOptimizationDisabled = !strcasecmp(property, "true");
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        INIT_LOGD("  Scissor optimization %s",
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mScissorOptimizationDisabled ? "disabled" : "enabled");
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        INIT_LOGD("  Scissor optimization enabled");
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid OpenGLRenderer::initLight(const Vector3& lightCenter, float lightRadius,
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mLightCenter = lightCenter;
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mLightRadius = lightRadius;
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mAmbientShadowAlpha = ambientShadowAlpha;
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mSpotShadowAlpha = spotShadowAlpha;
173106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich}
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// Setup
177106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich///////////////////////////////////////////////////////////////////////////////
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid OpenGLRenderer::onViewportInitialized() {
180106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich    glDisable(GL_DITHER);
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1838451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes    glEnableVertexAttribArray(Program::kBindingPosition);
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mFirstFrameAfterResize = true;
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1878451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughesvoid OpenGLRenderer::setupFrameState(float left, float top,
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float right, float bottom, bool opaque) {
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mCaches.clearGarbage();
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    initializeSaveStack(left, top, right, bottom, mLightCenter);
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mOpaque = opaque;
1928451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes    mTilingClip.set(left, top, right, bottom);
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t OpenGLRenderer::startFrame() {
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mFrameStarted) return DrawGlInfo::kStatusDone;
197106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich    mFrameStarted = true;
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich    mDirtyClip = true;
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom);
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mRenderState.setViewport(getWidth(), getHeight());
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Functors break the tiling extension in pretty spectacular ways
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // This ensures we don't use tiling when a functor is going to be
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // invoked during the frame
208106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich    mSuppressTiling = mCaches.hasRegisteredFunctors()
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            || mFirstFrameAfterResize;
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mFirstFrameAfterResize = false;
211106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    startTilingCurrentClip(true);
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    debugOverdraw(true, true);
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return clear(mTilingClip.left, mTilingClip.top,
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mTilingClip.right, mTilingClip.bottom, mOpaque);
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t OpenGLRenderer::prepareDirty(float left, float top,
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float right, float bottom, bool opaque) {
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    setupFrameState(left, top, right, bottom, opaque);
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Layer renderers will start the frame immediately
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // The framebuffer renderer will first defer the display list
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // for each layer and wait until the first drawing command
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // to start the frame
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (currentSnapshot()->fbo == 0) {
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        syncState();
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        updateLayers();
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
233106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich        return startFrame();
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return DrawGlInfo::kStatusDone;
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid OpenGLRenderer::discardFramebuffer(float left, float top, float right, float bottom) {
240106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich    // If we know that we are going to redraw the entire framebuffer,
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // perform a discard to let the driver know we don't need to preserve
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // the back buffer for this frame.
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mExtensions.hasDiscardFramebuffer() &&
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            left <= 0.0f && top <= 0.0f && right >= getWidth() && bottom >= getHeight()) {
245106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich        const bool isFbo = getTargetFbo() == 0;
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const GLenum attachments[] = {
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                isFbo ? (const GLenum) GL_COLOR_EXT : (const GLenum) GL_COLOR_ATTACHMENT0,
248106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich                isFbo ? (const GLenum) GL_STENCIL_EXT : (const GLenum) GL_STENCIL_ATTACHMENT };
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, attachments);
2508451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes    }
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
253106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevichstatus_t OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!opaque) {
255106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich        mCaches.enableScissor();
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCaches.setScissor(left, getViewportHeight() - bottom, right - left, bottom - top);
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        glClear(GL_COLOR_BUFFER_BIT);
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return DrawGlInfo::kStatusDrew;
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mCaches.resetScissor();
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return DrawGlInfo::kStatusDone;
263106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich}
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid OpenGLRenderer::syncState() {
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mCaches.blend) {
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        glEnable(GL_BLEND);
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        glDisable(GL_BLEND);
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid OpenGLRenderer::startTilingCurrentClip(bool opaque, bool expand) {
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!mSuppressTiling) {
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const Snapshot* snapshot = currentSnapshot();
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const Rect* clip = &mTilingClip;
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (snapshot->flags & Snapshot::kFlagFboTarget) {
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            clip = &(snapshot->layer->clipRect);
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        startTiling(*clip, getViewportHeight(), opaque, expand);
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid OpenGLRenderer::startTiling(const Rect& clip, int windowHeight, bool opaque, bool expand) {
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!mSuppressTiling) {
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if(expand) {
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Expand the startTiling region by 1
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int leftNotZero = (clip.left > 0) ? 1 : 0;
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int topNotZero = (windowHeight - clip.bottom > 0) ? 1 : 0;
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
293106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich            mCaches.startTiling(
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                clip.left - leftNotZero,
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                windowHeight - clip.bottom - topNotZero,
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                clip.right - clip.left + leftNotZero + 1,
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                clip.bottom - clip.top + topNotZero + 1,
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                opaque);
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCaches.startTiling(clip.left, windowHeight - clip.bottom,
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                clip.right - clip.left, clip.bottom - clip.top, opaque);
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
304106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich}
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid OpenGLRenderer::endTiling() {
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!mSuppressTiling) mCaches.endTiling();
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid OpenGLRenderer::finish() {
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    renderOverdraw();
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    endTiling();
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // When finish() is invoked on FBO 0 we've reached the end
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // of the current frame
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (getTargetFbo() == 0) {
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCaches.pathCache.trim();
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCaches.tessellationCache.trim();
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!suppressErrorChecks()) {
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#if DEBUG_OPENGL
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        GLUtils::dumpGLErrors();
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#if DEBUG_MEMORY_USAGE
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCaches.dumpMemoryUsage();
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#else
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCaches.getDebugLevel() & kDebugMemory) {
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCaches.dumpMemoryUsage();
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mFrameStarted = false;
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid OpenGLRenderer::resumeAfterLayer() {
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mRenderState.setViewport(getViewportWidth(), getViewportHeight());
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mRenderState.bindFramebuffer(currentSnapshot()->fbo);
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    debugOverdraw(true, false);
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mCaches.resetScissor();
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    dirtyClip();
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatus_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Rect clip(*currentClipRect());
351106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich    clip.snapToPixelBoundaries();
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Since we don't know what the functor will draw, let's dirty
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // the entire clip region
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (hasLayer()) {
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        dirtyLayerUnchecked(clip, getRegion());
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    DrawGlInfo info;
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    info.clipLeft = clip.left;
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    info.clipTop = clip.top;
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    info.clipRight = clip.right;
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    info.clipBottom = clip.bottom;
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    info.isLayer = hasLayer();
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    info.width = getViewportWidth();
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    info.height = getViewportHeight();
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    currentTransform()->copyTo(&info.transform[0]);
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    bool prevDirtyClip = mDirtyClip;
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // setup GL state for functor
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mDirtyClip) {
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setStencilFromClip(); // can issue draws, so must precede enableScissor()/interrupt()
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mCaches.enableScissor() || prevDirtyClip) {
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setScissorFromClip();
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mRenderState.invokeFunctor(functor, DrawGlInfo::kModeDraw, &info);
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Scissor may have been modified, reset dirty clip
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    dirtyClip();
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return DrawGlInfo::kStatusDrew;
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// Debug
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid OpenGLRenderer::eventMarkDEBUG(const char* fmt, ...) const {
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#if DEBUG_DETAILED_EVENTS
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const int BUFFER_SIZE = 256;
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    va_list ap;
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char buf[BUFFER_SIZE];
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    va_start(ap, fmt);
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    vsnprintf(buf, BUFFER_SIZE, fmt, ap);
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    va_end(ap);
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    eventMark(buf);
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
403106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid OpenGLRenderer::eventMark(const char* name) const {
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mCaches.eventMark(0, name);
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
408106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevichvoid OpenGLRenderer::startMark(const char* name) const {
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mCaches.startMark(0, name);
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
412106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevichvoid OpenGLRenderer::endMark() const {
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mCaches.endMark();
414106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich}
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
416106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevichvoid OpenGLRenderer::debugOverdraw(bool enable, bool clear) {
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    mRenderState.debugOverdraw(enable, clear);
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid OpenGLRenderer::renderOverdraw() {
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (mCaches.debugOverdraw && getTargetFbo() == 0) {
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const Rect* clip = &mTilingClip;
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCaches.enableScissor();
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCaches.setScissor(clip->left, firstSnapshot()->getViewportHeight() - clip->bottom,
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                clip->right - clip->left, clip->bottom - clip->top);
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // 1x overdraw
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCaches.stencil.enableDebugTest(2);
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        drawColor(mCaches.getOverdrawColor(1), SkXfermode::kSrcOver_Mode);
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // 2x overdraw
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCaches.stencil.enableDebugTest(3);
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        drawColor(mCaches.getOverdrawColor(2), SkXfermode::kSrcOver_Mode);
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // 3x overdraw
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCaches.stencil.enableDebugTest(4);
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        drawColor(mCaches.getOverdrawColor(3), SkXfermode::kSrcOver_Mode);
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // 4x overdraw and higher
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCaches.stencil.enableDebugTest(4, true);
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        drawColor(mCaches.getOverdrawColor(4), SkXfermode::kSrcOver_Mode);
443106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCaches.stencil.disable();
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
447106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// Layers
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectbool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {
453106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich    if (layer->deferredUpdateScheduled && layer->renderer
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            && layer->renderNode.get() && layer->renderNode->isRenderable()) {
4558451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes        Rect& dirty = layer->dirtyRect;
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (inFrame) {
458106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich            endTiling();
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            debugOverdraw(false, false);
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
462106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich        if (CC_UNLIKELY(inFrame || mCaches.drawDeferDisabled)) {
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            layer->render(*this);
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            layer->defer(*this);
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (inFrame) {
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            resumeAfterLayer();
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            startTilingCurrentClip();
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        layer->debugDrawUpdate = mCaches.debugLayersUpdates;
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        layer->hasDrawnSinceUpdate = false;
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return false;
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid OpenGLRenderer::updateLayers() {
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // If draw deferring is enabled this method will simply defer
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // the display list of each individual layer. The layers remain
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // in the layer updates list which will be cleared by flushLayers().
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int count = mLayerUpdates.size();
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (count > 0) {
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            startMark("Layer Updates");
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            startMark("Defer Layer Updates");
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Note: it is very important to update the layers in order
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Layer* layer = mLayerUpdates.itemAt(i).get();
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            updateLayer(layer, false);
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLayerUpdates.clear();
502106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich            mRenderState.bindFramebuffer(getTargetFbo());
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
504106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich        endMark();
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
508106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevichvoid OpenGLRenderer::flushLayers() {
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int count = mLayerUpdates.size();
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (count > 0) {
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        startMark("Apply Layer Updates");
512106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Note: it is very important to update the layers in order
514106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich        for (int i = 0; i < count; i++) {
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLayerUpdates.itemAt(i)->flush();
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLayerUpdates.clear();
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mRenderState.bindFramebuffer(getTargetFbo());
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        endMark();
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid OpenGLRenderer::pushLayerUpdate(Layer* layer) {
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (layer) {
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Make sure we don't introduce duplicates.
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // SortedVector would do this automatically but we need to respect
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // the insertion order. The linear search is not an issue since
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // this list is usually very short (typically one item, at most a few)
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mLayerUpdates.itemAt(i) == layer) {
533106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich                return;
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
535106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich        }
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLayerUpdates.push_back(layer);
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
539106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid OpenGLRenderer::cancelLayerUpdate(Layer* layer) {
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (layer) {
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
543106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich            if (mLayerUpdates.itemAt(i) == layer) {
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mLayerUpdates.removeAt(i);
545106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich                break;
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid OpenGLRenderer::flushLayerUpdates() {
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ATRACE_NAME("Update HW Layers");
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    syncState();
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    updateLayers();
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    flushLayers();
556106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich    // Wait for all the layer updates to be executed
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    AutoFence fence;
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid OpenGLRenderer::markLayersAsBuildLayers() {
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    for (size_t i = 0; i < mLayerUpdates.size(); i++) {
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLayerUpdates[i]->wasBuildLayered = true;
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// State management
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid OpenGLRenderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    bool restoreViewport = removed.flags & Snapshot::kFlagIsFboLayer;
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    bool restoreClip = removed.flags & Snapshot::kFlagClipSet;
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    bool restoreLayer = removed.flags & Snapshot::kFlagIsLayer;
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (restoreViewport) {
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mRenderState.setViewport(getViewportWidth(), getViewportHeight());
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (restoreClip) {
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        dirtyClip();
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (restoreLayer) {
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        endMark(); // Savelayer
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ATRACE_END(); // SaveLayer
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        startMark("ComposeLayer");
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        composeLayer(removed, restored);
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        endMark();
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// Layers
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const SkPaint* paint, int flags, const SkPath* convexMask) {
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // force matrix/clip isolation for layer
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    flags |= SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag;
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const int count = saveSnapshot(flags);
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!currentSnapshot()->isIgnored()) {
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        createLayer(left, top, right, bottom, paint, flags, convexMask);
605708c17b4168404042852e480f25a91a02cf14247Jack Palevich    }
606708c17b4168404042852e480f25a91a02cf14247Jack Palevich
607708c17b4168404042852e480f25a91a02cf14247Jack Palevich    return count;
608708c17b4168404042852e480f25a91a02cf14247Jack Palevich}
609708c17b4168404042852e480f25a91a02cf14247Jack Palevich
610708c17b4168404042852e480f25a91a02cf14247Jack Palevichvoid OpenGLRenderer::calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool fboLayer) {
611708c17b4168404042852e480f25a91a02cf14247Jack Palevich    const Rect untransformedBounds(bounds);
612708c17b4168404042852e480f25a91a02cf14247Jack Palevich
613708c17b4168404042852e480f25a91a02cf14247Jack Palevich    currentTransform()->mapRect(bounds);
614708c17b4168404042852e480f25a91a02cf14247Jack Palevich
615708c17b4168404042852e480f25a91a02cf14247Jack Palevich    // Layers only make sense if they are in the framebuffer's bounds
616708c17b4168404042852e480f25a91a02cf14247Jack Palevich    if (bounds.intersect(*currentClipRect())) {
617708c17b4168404042852e480f25a91a02cf14247Jack Palevich        // We cannot work with sub-pixels in this case
618708c17b4168404042852e480f25a91a02cf14247Jack Palevich        bounds.snapToPixelBoundaries();
619708c17b4168404042852e480f25a91a02cf14247Jack Palevich
620708c17b4168404042852e480f25a91a02cf14247Jack Palevich        // When the layer is not an FBO, we may use glCopyTexImage so we
621708c17b4168404042852e480f25a91a02cf14247Jack Palevich        // need to make sure the layer does not extend outside the bounds
622708c17b4168404042852e480f25a91a02cf14247Jack Palevich        // of the framebuffer
623708c17b4168404042852e480f25a91a02cf14247Jack Palevich        const Snapshot& previous = *(currentSnapshot()->previous);
624708c17b4168404042852e480f25a91a02cf14247Jack Palevich        Rect previousViewport(0, 0, previous.getViewportWidth(), previous.getViewportHeight());
625708c17b4168404042852e480f25a91a02cf14247Jack Palevich        if (!bounds.intersect(previousViewport)) {
626708c17b4168404042852e480f25a91a02cf14247Jack Palevich            bounds.setEmpty();
627708c17b4168404042852e480f25a91a02cf14247Jack Palevich        } else if (fboLayer) {
628708c17b4168404042852e480f25a91a02cf14247Jack Palevich            clip.set(bounds);
629708c17b4168404042852e480f25a91a02cf14247Jack Palevich            mat4 inverse;
630708c17b4168404042852e480f25a91a02cf14247Jack Palevich            inverse.loadInverse(*currentTransform());
631708c17b4168404042852e480f25a91a02cf14247Jack Palevich            inverse.mapRect(clip);
632708c17b4168404042852e480f25a91a02cf14247Jack Palevich            clip.snapToPixelBoundaries();
633708c17b4168404042852e480f25a91a02cf14247Jack Palevich            if (clip.intersect(untransformedBounds)) {
634708c17b4168404042852e480f25a91a02cf14247Jack Palevich                clip.translate(-untransformedBounds.left, -untransformedBounds.top);
635708c17b4168404042852e480f25a91a02cf14247Jack Palevich                bounds.set(untransformedBounds);
636708c17b4168404042852e480f25a91a02cf14247Jack Palevich            } else {
637708c17b4168404042852e480f25a91a02cf14247Jack Palevich                clip.setEmpty();
638708c17b4168404042852e480f25a91a02cf14247Jack Palevich            }
639708c17b4168404042852e480f25a91a02cf14247Jack Palevich        }
640708c17b4168404042852e480f25a91a02cf14247Jack Palevich    } else {
641708c17b4168404042852e480f25a91a02cf14247Jack Palevich        bounds.setEmpty();
642708c17b4168404042852e480f25a91a02cf14247Jack Palevich    }
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid OpenGLRenderer::updateSnapshotIgnoreForLayer(const Rect& bounds, const Rect& clip,
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        bool fboLayer, int alpha) {
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize ||
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bounds.getHeight() > mCaches.maxTextureSize ||
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            (fboLayer && clip.isEmpty())) {
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSnapshot->empty = fboLayer;
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    } else {
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSnapshot->invisible = mSnapshot->invisible || (alpha <= 0 && fboLayer);
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
654708c17b4168404042852e480f25a91a02cf14247Jack Palevich}
655708c17b4168404042852e480f25a91a02cf14247Jack Palevich
656708c17b4168404042852e480f25a91a02cf14247Jack Palevichint OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float bottom,
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        const SkPaint* paint, int flags) {
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    const int count = saveSnapshot(flags);
659106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!currentSnapshot()->isIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) {
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // initialize the snapshot as though it almost represents an FBO layer so deferred draw
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // operations will be able to store and restore the current clip and transform info, and
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // quick rejection will be correct (for display lists)
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Rect bounds(left, top, right, bottom);
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Rect clip;
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        calculateLayerBoundsAndClip(bounds, clip, true);
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        updateSnapshotIgnoreForLayer(bounds, clip, true, getAlphaDirect(paint));
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!currentSnapshot()->isIgnored()) {
671106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich            mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
672106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich            mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSnapshot->roundRectClipState = NULL;
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return count;
679106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich}
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Layers are viewed by Skia are slightly different than layers in image editing
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * programs (for instance.) When a layer is created, previously created layers
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and the frame buffer still receive every drawing command. For instance, if a
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * layer is created and a shape intersecting the bounds of the layers and the
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * framebuffer is draw, the shape will be drawn on both (unless the layer was
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * created with the SkCanvas::kClipToLayer_SaveFlag flag.)
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A way to implement layers is to create an FBO for each layer, backed by an RGBA
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * texture. Unfortunately, this is inefficient as it requires every primitive to
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * be drawn n + 1 times, where n is the number of active layers. In practice this
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * means, for every primitive:
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *   - Switch active frame buffer
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *   - Change viewport, clip and projection matrix
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *   - Issue the drawing
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Switching rendering target n + 1 times per drawn primitive is extremely costly.
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * To avoid this, layers are implemented in a different way here, at least in the
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * general case. FBOs are used, as an optimization, when the "clip to layer" flag
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is set. When this flag is set we can redirect all drawing operations into a
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * single FBO.
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This implementation relies on the frame buffer being at least RGBA 8888. When
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a layer is created, only a texture is created, not an FBO. The content of the
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * frame buffer contained within the layer's bounds is copied into this texture
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * using glCopyTexImage2D(). The layer's region is then cleared(1) in the frame
707106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich * buffer and drawing continues as normal. This technique therefore treats the
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * frame buffer as a scratch buffer for the layers.
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * To compose the layers back onto the frame buffer, each layer texture
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (containing the original frame buffer data) is drawn as a simple quad over
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the frame buffer. The trick is that the quad is set as the composition
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * destination in the blending equation, and the frame buffer becomes the source
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * of the composition.
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Drawing layers with an alpha value requires an extra step before composition.
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * An empty quad is drawn over the layer's region in the frame buffer. This quad
718a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich * is drawn with the rgba color (0,0,0,alpha). The alpha value offered by the
719a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich * quad is used to multiply the colors in the frame buffer. This is achieved by
720a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich * changing the GL blend functions for the GL_FUNC_ADD blend equation to
721a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich * GL_ZERO, GL_SRC_ALPHA.
722a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich *
723a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich * Because glCopyTexImage2D() can be slow, an alternative implementation might
724a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich * be use to draw a single clipped layer. The implementation described above
725a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich * is correct in every case.
726a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich *
727a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich * (1) The frame buffer is actually not cleared right away. To allow the GPU
728a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich *     to potentially optimize series of calls to glCopyTexImage2D, the frame
729a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich *     buffer is left untouched until the first drawing operation. Only when
730a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich *     something actually gets drawn are the layers regions cleared.
731a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich */
732a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichbool OpenGLRenderer::createLayer(float left, float top, float right, float bottom,
733a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        const SkPaint* paint, int flags, const SkPath* convexMask) {
734a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top);
735a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
736a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
737a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    const bool fboLayer = flags & SkCanvas::kClipToLayer_SaveFlag;
738a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
739a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    // Window coordinates of the layer
740a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    Rect clip;
741a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    Rect bounds(left, top, right, bottom);
742a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    calculateLayerBoundsAndClip(bounds, clip, fboLayer);
743a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, getAlphaDirect(paint));
744a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
745a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    // Bail out if we won't draw in this snapshot
746a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    if (currentSnapshot()->isIgnored()) {
747a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        return false;
748a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    }
749a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
750a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    mCaches.activeTexture(0);
751a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    Layer* layer = mCaches.layerCache.get(mRenderState, bounds.getWidth(), bounds.getHeight());
752a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    if (!layer) {
753a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        return false;
754a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    }
755a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
756a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    layer->setPaint(paint);
757a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    layer->layer.set(bounds);
758a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()),
759a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            bounds.getWidth() / float(layer->getWidth()), 0.0f);
760a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
761a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    layer->setBlend(true);
762a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    layer->setDirty(false);
763a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    layer->setConvexMask(convexMask); // note: the mask must be cleared before returning to the cache
764a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
765a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    // Save the layer in the snapshot
766a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    mSnapshot->flags |= Snapshot::kFlagIsLayer;
767a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    mSnapshot->layer = layer;
768a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
769a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    ATRACE_FORMAT_BEGIN("%ssaveLayer %ux%u",
770a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            fboLayer ? "" : "unclipped ",
771a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            layer->getWidth(), layer->getHeight());
772a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    startMark("SaveLayer");
773a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    if (fboLayer) {
774a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        return createFboLayer(layer, bounds, clip);
775a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    } else {
776a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        // Copy the framebuffer into the layer
777a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        layer->bindTexture();
778a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        if (!bounds.isEmpty()) {
779a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            if (layer->isEmpty()) {
780a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                // Workaround for some GL drivers. When reading pixels lying outside
781a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                // of the window we should get undefined values for those pixels.
782a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                // Unfortunately some drivers will turn the entire target texture black
783a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                // when reading outside of the window.
784a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->getWidth(), layer->getHeight(),
785a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                        0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
786a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                layer->setEmpty(false);
787a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            }
7888451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes
789a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
790a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                    bounds.left, getViewportHeight() - bounds.bottom,
791a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                    bounds.getWidth(), bounds.getHeight());
7928451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes
793a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            // Enqueue the buffer coordinates to clear the corresponding region later
794a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            mLayers.push(new Rect(bounds));
795a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        }
796a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    }
797a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
798a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    return true;
799a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich}
800a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
801a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichbool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {
802a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    layer->clipRect.set(clip);
803a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    layer->setFbo(mCaches.fboCache.get());
804a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
805a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    mSnapshot->region = &mSnapshot->layer->region;
806a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    mSnapshot->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
807a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    mSnapshot->fbo = layer->getFbo();
808a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
809a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
810a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
811a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    mSnapshot->roundRectClipState = NULL;
812a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
813a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    endTiling();
814a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    debugOverdraw(false, false);
815a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    // Bind texture to FBO
816a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    mRenderState.bindFramebuffer(layer->getFbo());
817a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    layer->bindTexture();
818a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
819a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    // Initialize the texture if needed
820a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    if (layer->isEmpty()) {
821a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        layer->allocateTexture();
822a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        layer->setEmpty(false);
823a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    }
824a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
825a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
826a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            layer->getTexture(), 0);
827a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
8288451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes    // Expand the startTiling region by 1
829a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    startTilingCurrentClip(true, true);
830a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
831a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
832a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    mCaches.enableScissor();
833a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    mCaches.setScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
834a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            clip.getWidth() + 2.0f, clip.getHeight() + 2.0f);
8358451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes    glClear(GL_COLOR_BUFFER_BIT);
836a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
8378451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes    dirtyClip();
838a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
839a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    // Change the ortho projection
840a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    mRenderState.setViewport(bounds.getWidth(), bounds.getHeight());
841a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    return true;
842a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich}
843a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
844a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich/**
845a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich * Read the documentation of createLayer() before doing anything in this method.
846a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich */
847a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichvoid OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& restored) {
848a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    if (!removed.layer) {
849a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        ALOGE("Attempting to compose a layer that does not exist");
850a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        return;
851a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    }
852a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
853a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    Layer* layer = removed.layer;
854a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    const Rect& rect = layer->layer;
855a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    const bool fboLayer = removed.flags & Snapshot::kFlagIsFboLayer;
856a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
857a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    bool clipRequired = false;
858a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom,
859a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            &clipRequired, NULL, false); // safely ignore return, should never be rejected
8608451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes    mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
861a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
8628451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes    if (fboLayer) {
863a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        endTiling();
864a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
865a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        // Detach the texture from the FBO
866a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
867a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
868a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        layer->removeFbo(false);
869a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
870a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        // Unbind current FBO and restore previous one
871a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        mRenderState.bindFramebuffer(restored.fbo);
872a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        debugOverdraw(true, false);
873a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
874a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        startTilingCurrentClip();
875a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    }
876a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
877a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    if (!fboLayer && layer->getAlpha() < 255) {
878a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        SkPaint layerPaint;
879a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        layerPaint.setAlpha(layer->getAlpha());
880a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        layerPaint.setXfermodeMode(SkXfermode::kDstIn_Mode);
881a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        layerPaint.setColorFilter(layer->getColorFilter());
882a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
883a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        drawColorRect(rect.left, rect.top, rect.right, rect.bottom, &layerPaint, true);
884a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        // Required below, composeLayerRect() will divide by 255
885a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        layer->setAlpha(255);
886a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    }
887a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
8888451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes    mCaches.unbindMeshBuffer();
889a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
890a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    mCaches.activeTexture(0);
891a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
892a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    // When the layer is stored in an FBO, we can save a bit of fillrate by
893a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    // drawing only the dirty region
894a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    if (fboLayer) {
895a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *restored.transform);
896a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        composeLayerRegion(layer, rect);
8978451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes    } else if (!rect.isEmpty()) {
898a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
8998451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes
900a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        save(0);
901a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        // the layer contains screen buffer content that shouldn't be alpha modulated
902a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        // (and any necessary alpha modulation was handled drawing into the layer)
903a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        mSnapshot->alpha = 1.0f;
904a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        composeLayerRect(layer, rect, true);
905a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        restore();
906a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    }
907a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
908a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    dirtyClip();
909a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
910a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    // Failing to add the layer to the cache should happen only if the layer is too large
911a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    layer->setConvexMask(NULL);
912a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    if (!mCaches.layerCache.put(layer)) {
913a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        LAYER_LOGD("Deleting layer");
914a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        layer->decStrong(0);
915a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    }
916a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich}
917a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
918a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichvoid OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
919a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    float alpha = getLayerAlpha(layer);
920a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
9218451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes    setupDraw();
922a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    if (layer->getRenderTarget() == GL_TEXTURE_2D) {
923a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        setupDrawWithTexture();
924a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    } else {
925a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        setupDrawWithExternalTexture();
926a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    }
927a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    setupDrawTextureTransform();
928a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    setupDrawColor(alpha, alpha, alpha, alpha);
929a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    setupDrawColorFilter(layer->getColorFilter());
9308451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes    setupDrawBlending(layer);
931a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    setupDrawProgram();
9328451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes    setupDrawPureColorUniforms();
933a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    setupDrawColorFilterUniforms(layer->getColorFilter());
934a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    if (layer->getRenderTarget() == GL_TEXTURE_2D) {
935a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        setupDrawTexture(layer->getTexture());
936a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    } else {
937a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        setupDrawExternalTexture(layer->getTexture());
938a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    }
939a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    if (currentTransform()->isPureTranslate() &&
940a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            !layer->getForceFilter() &&
941a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            layer->getWidth() == (uint32_t) rect.getWidth() &&
942a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            layer->getHeight() == (uint32_t) rect.getHeight()) {
943a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
944a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
945a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
946a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        layer->setFilter(GL_NEAREST);
947a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        setupDrawModelView(kModelViewMode_TranslateAndScale, false,
948a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                x, y, x + rect.getWidth(), y + rect.getHeight(), true);
949a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    } else {
9508451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes        layer->setFilter(GL_LINEAR);
951a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        setupDrawModelView(kModelViewMode_TranslateAndScale, false,
952a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                rect.left, rect.top, rect.right, rect.bottom);
953a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    }
954a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    setupDrawTextureTransformUniforms(layer->getTexTransform());
955a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    setupDrawMesh(&mMeshVertices[0].x, &mMeshVertices[0].u);
956a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
957a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
958a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich}
959a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
960a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichvoid OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
961a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    if (layer->isTextureLayer()) {
962a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        EVENT_LOGD("composeTextureLayerRect");
963a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
964a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        drawTextureLayer(layer, rect);
965a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
9668451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes    } else {
967a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        EVENT_LOGD("composeHardwareLayerRect");
968a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        const Rect& texCoords = layer->texCoords;
969a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        resetDrawTextureTexCoords(texCoords.left, texCoords.top,
970a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                texCoords.right, texCoords.bottom);
971a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
972a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        float x = rect.left;
973a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        float y = rect.top;
974a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        bool simpleTransform = currentTransform()->isPureTranslate() &&
975a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                layer->getWidth() == (uint32_t) rect.getWidth() &&
976a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                layer->getHeight() == (uint32_t) rect.getHeight();
977a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
978a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        if (simpleTransform) {
979a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            // When we're swapping, the layer is already in screen coordinates
980a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            if (!swap) {
981a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
982a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
9838451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes            }
984a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
985a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            layer->setFilter(GL_NEAREST, true);
986a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        } else {
987a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            layer->setFilter(GL_LINEAR, true);
988a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        }
989a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
990a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        SkPaint layerPaint;
991a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        layerPaint.setAlpha(getLayerAlpha(layer) * 255);
992a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        layerPaint.setXfermodeMode(layer->getMode());
993a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        layerPaint.setColorFilter(layer->getColorFilter());
994a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
995a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f;
996a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
997a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                layer->getTexture(), &layerPaint, blend,
998a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                &mMeshVertices[0].x, &mMeshVertices[0].u,
999a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich                GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform);
10008451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes
1001a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
1002a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    }
1003a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich}
1004a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
1005a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich/**
1006a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich * Issues the command X, and if we're composing a save layer to the fbo or drawing a newly updated
1007a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich * hardware layer with overdraw debug on, draws again to the stencil only, so that these draw
1008a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich * operations are correctly counted twice for overdraw. NOTE: assumes composeLayerRegion only used
10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * by saveLayer's restore
10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define DRAW_DOUBLE_STENCIL_IF(COND, DRAW_COMMAND) {                             \
10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        DRAW_COMMAND;                                                            \
1013106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich        if (CC_UNLIKELY(mCaches.debugOverdraw && getTargetFbo() == 0 && COND)) { \
1014106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich            glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);                 \
10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            DRAW_COMMAND;                                                        \
10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);                     \
10178451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes        }                                                                        \
1018106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich    }
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1020106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich#define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND)
10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// This class is purely for inspection. It inherits from SkShader, but Skia does not know how to
10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// use it. The OpenGLRenderer will look at it to find its Layer and whether it is opaque.
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectclass LayerShader : public SkShader {
1025106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevichpublic:
1026106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich    LayerShader(Layer* layer, const SkMatrix* localMatrix)
1027106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich    : INHERITED(localMatrix)
1028106006cbdedc79ce8746ca5449610c69a2f69655Jack Palevich    , mLayer(layer) {
10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1031a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    virtual bool asACustomShader(void** data) const {
1032a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        if (data) {
1033a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich            *data = static_cast<void*>(mLayer);
1034a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        }
1035a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        return true;
1036a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    }
1037a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
1038a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    virtual bool isOpaque() const {
1039a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich        return !mLayer->isBlend();
1040a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    }
1041a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich
1042a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevichprotected:
10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    virtual void shadeSpan(int x, int y, SkPMColor[], int count) {
10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOG_ALWAYS_FATAL("LayerShader should never be drawn with raster backend.");
10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    virtual void flatten(SkWriteBuffer&) const {
10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LOG_ALWAYS_FATAL("LayerShader should never be flattened.");
10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10508451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes
10518451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes    virtual Factory getFactory() const {
10528451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes        LOG_ALWAYS_FATAL("LayerShader should never be created from a stream.");
10538451b25a4422656bbd6657a5855e69c0f4d53c74Elliott Hughes        return NULL;
10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectprivate:
10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Unowned.
10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Layer* mLayer;
1058a6276fdd4253c3a7150ab675678c750473ab6c45Jack Palevich    typedef SkShader INHERITED;
10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectvoid OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (CC_UNLIKELY(layer->region.isEmpty())) return; // nothing to draw
10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (layer->getConvexMask()) {
10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // clip to the area of the layer the mask can be larger
10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        clipRect(rect.left, rect.top, rect.right, rect.bottom, SkRegion::kIntersect_Op);
10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SkPaint paint;
10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        paint.setAntiAlias(true);
10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        paint.setColor(SkColorSetARGB(int(getLayerAlpha(layer) * 255), 0, 0, 0));
1073
1074        // create LayerShader to map SaveLayer content into subsequent draw
1075        SkMatrix shaderMatrix;
1076        shaderMatrix.setTranslate(rect.left, rect.bottom);
1077        shaderMatrix.preScale(1, -1);
1078        LayerShader layerShader(layer, &shaderMatrix);
1079        paint.setShader(&layerShader);
1080
1081        // Since the drawing primitive is defined in local drawing space,
1082        // we don't need to modify the draw matrix
1083        const SkPath* maskPath = layer->getConvexMask();
1084        DRAW_DOUBLE_STENCIL(drawConvexPath(*maskPath, &paint));
1085
1086        paint.setShader(NULL);
1087        restore();
1088
1089        return;
1090    }
1091
1092    if (layer->region.isRect()) {
1093        layer->setRegionAsRect();
1094
1095        DRAW_DOUBLE_STENCIL(composeLayerRect(layer, layer->regionRect));
1096
1097        layer->region.clear();
1098        return;
1099    }
1100
1101    EVENT_LOGD("composeLayerRegion");
1102    // standard Region based draw
1103    size_t count;
1104    const android::Rect* rects;
1105    Region safeRegion;
1106    if (CC_LIKELY(hasRectToRectTransform())) {
1107        rects = layer->region.getArray(&count);
1108    } else {
1109        safeRegion = Region::createTJunctionFreeRegion(layer->region);
1110        rects = safeRegion.getArray(&count);
1111    }
1112
1113    const float alpha = getLayerAlpha(layer);
1114    const float texX = 1.0f / float(layer->getWidth());
1115    const float texY = 1.0f / float(layer->getHeight());
1116    const float height = rect.getHeight();
1117
1118    setupDraw();
1119
1120    // We must get (and therefore bind) the region mesh buffer
1121    // after we setup drawing in case we need to mess with the
1122    // stencil buffer in setupDraw()
1123    TextureVertex* mesh = mCaches.getRegionMesh();
1124    uint32_t numQuads = 0;
1125
1126    setupDrawWithTexture();
1127    setupDrawColor(alpha, alpha, alpha, alpha);
1128    setupDrawColorFilter(layer->getColorFilter());
1129    setupDrawBlending(layer);
1130    setupDrawProgram();
1131    setupDrawDirtyRegionsDisabled();
1132    setupDrawPureColorUniforms();
1133    setupDrawColorFilterUniforms(layer->getColorFilter());
1134    setupDrawTexture(layer->getTexture());
1135    if (currentTransform()->isPureTranslate()) {
1136        const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
1137        const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
1138
1139        layer->setFilter(GL_NEAREST);
1140        setupDrawModelView(kModelViewMode_Translate, false,
1141                x, y, x + rect.getWidth(), y + rect.getHeight(), true);
1142    } else {
1143        layer->setFilter(GL_LINEAR);
1144        setupDrawModelView(kModelViewMode_Translate, false,
1145                rect.left, rect.top, rect.right, rect.bottom);
1146    }
1147    setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
1148
1149    for (size_t i = 0; i < count; i++) {
1150        const android::Rect* r = &rects[i];
1151
1152        const float u1 = r->left * texX;
1153        const float v1 = (height - r->top) * texY;
1154        const float u2 = r->right * texX;
1155        const float v2 = (height - r->bottom) * texY;
1156
1157        // TODO: Reject quads outside of the clip
1158        TextureVertex::set(mesh++, r->left, r->top, u1, v1);
1159        TextureVertex::set(mesh++, r->right, r->top, u2, v1);
1160        TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
1161        TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
1162
1163        numQuads++;
1164
1165        if (numQuads >= gMaxNumberOfQuads) {
1166            DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
1167                            GL_UNSIGNED_SHORT, NULL));
1168            numQuads = 0;
1169            mesh = mCaches.getRegionMesh();
1170        }
1171    }
1172
1173    if (numQuads > 0) {
1174        DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
1175                        GL_UNSIGNED_SHORT, NULL));
1176    }
1177
1178#if DEBUG_LAYERS_AS_REGIONS
1179    drawRegionRectsDebug(layer->region);
1180#endif
1181
1182    layer->region.clear();
1183}
1184
1185#if DEBUG_LAYERS_AS_REGIONS
1186void OpenGLRenderer::drawRegionRectsDebug(const Region& region) {
1187    size_t count;
1188    const android::Rect* rects = region.getArray(&count);
1189
1190    uint32_t colors[] = {
1191            0x7fff0000, 0x7f00ff00,
1192            0x7f0000ff, 0x7fff00ff,
1193    };
1194
1195    int offset = 0;
1196    int32_t top = rects[0].top;
1197
1198    for (size_t i = 0; i < count; i++) {
1199        if (top != rects[i].top) {
1200            offset ^= 0x2;
1201            top = rects[i].top;
1202        }
1203
1204        SkPaint paint;
1205        paint.setColor(colors[offset + (i & 0x1)]);
1206        Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom);
1207        drawColorRect(r.left, r.top, r.right, r.bottom, paint);
1208    }
1209}
1210#endif
1211
1212void OpenGLRenderer::drawRegionRects(const SkRegion& region, const SkPaint& paint, bool dirty) {
1213    Vector<float> rects;
1214
1215    SkRegion::Iterator it(region);
1216    while (!it.done()) {
1217        const SkIRect& r = it.rect();
1218        rects.push(r.fLeft);
1219        rects.push(r.fTop);
1220        rects.push(r.fRight);
1221        rects.push(r.fBottom);
1222        it.next();
1223    }
1224
1225    drawColorRects(rects.array(), rects.size(), &paint, true, dirty, false);
1226}
1227
1228void OpenGLRenderer::dirtyLayer(const float left, const float top,
1229        const float right, const float bottom, const mat4 transform) {
1230    if (hasLayer()) {
1231        Rect bounds(left, top, right, bottom);
1232        transform.mapRect(bounds);
1233        dirtyLayerUnchecked(bounds, getRegion());
1234    }
1235}
1236
1237void OpenGLRenderer::dirtyLayer(const float left, const float top,
1238        const float right, const float bottom) {
1239    if (hasLayer()) {
1240        Rect bounds(left, top, right, bottom);
1241        dirtyLayerUnchecked(bounds, getRegion());
1242    }
1243}
1244
1245void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) {
1246    if (bounds.intersect(*currentClipRect())) {
1247        bounds.snapToPixelBoundaries();
1248        android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
1249        if (!dirty.isEmpty()) {
1250            region->orSelf(dirty);
1251        }
1252    }
1253}
1254
1255void OpenGLRenderer::issueIndexedQuadDraw(Vertex* mesh, GLsizei quadsCount) {
1256    GLsizei elementsCount = quadsCount * 6;
1257    while (elementsCount > 0) {
1258        GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6);
1259
1260        setupDrawIndexedVertices(&mesh[0].x);
1261        glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, NULL);
1262
1263        elementsCount -= drawCount;
1264        // Though there are 4 vertices in a quad, we use 6 indices per
1265        // quad to draw with GL_TRIANGLES
1266        mesh += (drawCount / 6) * 4;
1267    }
1268}
1269
1270void OpenGLRenderer::clearLayerRegions() {
1271    const size_t count = mLayers.size();
1272    if (count == 0) return;
1273
1274    if (!currentSnapshot()->isIgnored()) {
1275        EVENT_LOGD("clearLayerRegions");
1276        // Doing several glScissor/glClear here can negatively impact
1277        // GPUs with a tiler architecture, instead we draw quads with
1278        // the Clear blending mode
1279
1280        // The list contains bounds that have already been clipped
1281        // against their initial clip rect, and the current clip
1282        // is likely different so we need to disable clipping here
1283        bool scissorChanged = mCaches.disableScissor();
1284
1285        Vertex mesh[count * 4];
1286        Vertex* vertex = mesh;
1287
1288        for (uint32_t i = 0; i < count; i++) {
1289            Rect* bounds = mLayers.itemAt(i);
1290
1291            Vertex::set(vertex++, bounds->left, bounds->top);
1292            Vertex::set(vertex++, bounds->right, bounds->top);
1293            Vertex::set(vertex++, bounds->left, bounds->bottom);
1294            Vertex::set(vertex++, bounds->right, bounds->bottom);
1295
1296            delete bounds;
1297        }
1298        // We must clear the list of dirty rects before we
1299        // call setupDraw() to prevent stencil setup to do
1300        // the same thing again
1301        mLayers.clear();
1302
1303        SkPaint clearPaint;
1304        clearPaint.setXfermodeMode(SkXfermode::kClear_Mode);
1305
1306        setupDraw(false);
1307        setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f);
1308        setupDrawBlending(&clearPaint, true);
1309        setupDrawProgram();
1310        setupDrawPureColorUniforms();
1311        setupDrawModelView(kModelViewMode_Translate, false,
1312                0.0f, 0.0f, 0.0f, 0.0f, true);
1313
1314        issueIndexedQuadDraw(&mesh[0], count);
1315
1316        if (scissorChanged) mCaches.enableScissor();
1317    } else {
1318        for (uint32_t i = 0; i < count; i++) {
1319            delete mLayers.itemAt(i);
1320        }
1321        mLayers.clear();
1322    }
1323}
1324
1325///////////////////////////////////////////////////////////////////////////////
1326// State Deferral
1327///////////////////////////////////////////////////////////////////////////////
1328
1329bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) {
1330    const Rect* currentClip = currentClipRect();
1331    const mat4* currentMatrix = currentTransform();
1332
1333    if (stateDeferFlags & kStateDeferFlag_Draw) {
1334        // state has bounds initialized in local coordinates
1335        if (!state.mBounds.isEmpty()) {
1336            currentMatrix->mapRect(state.mBounds);
1337            Rect clippedBounds(state.mBounds);
1338            // NOTE: if we ever want to use this clipping info to drive whether the scissor
1339            // is used, it should more closely duplicate the quickReject logic (in how it uses
1340            // snapToPixelBoundaries)
1341
1342            if(!clippedBounds.intersect(*currentClip)) {
1343                // quick rejected
1344                return true;
1345            }
1346
1347            state.mClipSideFlags = kClipSide_None;
1348            if (!currentClip->contains(state.mBounds)) {
1349                int& flags = state.mClipSideFlags;
1350                // op partially clipped, so record which sides are clipped for clip-aware merging
1351                if (currentClip->left > state.mBounds.left) flags |= kClipSide_Left;
1352                if (currentClip->top > state.mBounds.top) flags |= kClipSide_Top;
1353                if (currentClip->right < state.mBounds.right) flags |= kClipSide_Right;
1354                if (currentClip->bottom < state.mBounds.bottom) flags |= kClipSide_Bottom;
1355            }
1356            state.mBounds.set(clippedBounds);
1357        } else {
1358            // Empty bounds implies size unknown. Label op as conservatively clipped to disable
1359            // overdraw avoidance (since we don't know what it overlaps)
1360            state.mClipSideFlags = kClipSide_ConservativeFull;
1361            state.mBounds.set(*currentClip);
1362        }
1363    }
1364
1365    state.mClipValid = (stateDeferFlags & kStateDeferFlag_Clip);
1366    if (state.mClipValid) {
1367        state.mClip.set(*currentClip);
1368    }
1369
1370    // Transform, drawModifiers, and alpha always deferred, since they are used by state operations
1371    // (Note: saveLayer/restore use colorFilter and alpha, so we just save restore everything)
1372    state.mMatrix.load(*currentMatrix);
1373    state.mDrawModifiers = mDrawModifiers;
1374    state.mAlpha = currentSnapshot()->alpha;
1375
1376    // always store/restore, since it's just a pointer
1377    state.mRoundRectClipState = currentSnapshot()->roundRectClipState;
1378    return false;
1379}
1380
1381void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) {
1382    setMatrix(state.mMatrix);
1383    mSnapshot->alpha = state.mAlpha;
1384    mDrawModifiers = state.mDrawModifiers;
1385    mSnapshot->roundRectClipState = state.mRoundRectClipState;
1386
1387    if (state.mClipValid && !skipClipRestore) {
1388        mSnapshot->setClip(state.mClip.left, state.mClip.top,
1389                state.mClip.right, state.mClip.bottom);
1390        dirtyClip();
1391    }
1392}
1393
1394/**
1395 * Merged multidraw (such as in drawText and drawBitmaps rely on the fact that no clipping is done
1396 * in the draw path. Instead, clipping is done ahead of time - either as a single clip rect (when at
1397 * least one op is clipped), or disabled entirely (because no merged op is clipped)
1398 *
1399 * This method should be called when restoreDisplayState() won't be restoring the clip
1400 */
1401void OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) {
1402    if (clipRect != NULL) {
1403        mSnapshot->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
1404    } else {
1405        mSnapshot->setClip(0, 0, getWidth(), getHeight());
1406    }
1407    dirtyClip();
1408    mCaches.setScissorEnabled(clipRect != NULL || mScissorOptimizationDisabled);
1409}
1410
1411///////////////////////////////////////////////////////////////////////////////
1412// Clipping
1413///////////////////////////////////////////////////////////////////////////////
1414
1415void OpenGLRenderer::setScissorFromClip() {
1416    Rect clip(*currentClipRect());
1417    clip.snapToPixelBoundaries();
1418
1419    if (mCaches.setScissor(clip.left, getViewportHeight() - clip.bottom,
1420            clip.getWidth(), clip.getHeight())) {
1421        mDirtyClip = false;
1422    }
1423}
1424
1425void OpenGLRenderer::ensureStencilBuffer() {
1426    // Thanks to the mismatch between EGL and OpenGL ES FBO we
1427    // cannot attach a stencil buffer to fbo0 dynamically. Let's
1428    // just hope we have one when hasLayer() returns false.
1429    if (hasLayer()) {
1430        attachStencilBufferToLayer(currentSnapshot()->layer);
1431    }
1432}
1433
1434void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) {
1435    // The layer's FBO is already bound when we reach this stage
1436    if (!layer->getStencilRenderBuffer()) {
1437        // GL_QCOM_tiled_rendering doesn't like it if a renderbuffer
1438        // is attached after we initiated tiling. We must turn it off,
1439        // attach the new render buffer then turn tiling back on
1440        endTiling();
1441
1442        RenderBuffer* buffer = mCaches.renderBufferCache.get(
1443                Stencil::getSmallestStencilFormat(), layer->getWidth(), layer->getHeight());
1444        layer->setStencilRenderBuffer(buffer);
1445
1446        startTiling(layer->clipRect, layer->layer.getHeight());
1447    }
1448}
1449
1450void OpenGLRenderer::setStencilFromClip() {
1451    if (!mCaches.debugOverdraw) {
1452        if (!currentSnapshot()->clipRegion->isEmpty()) {
1453            EVENT_LOGD("setStencilFromClip - enabling");
1454
1455            // NOTE: The order here is important, we must set dirtyClip to false
1456            //       before any draw call to avoid calling back into this method
1457            mDirtyClip = false;
1458
1459            ensureStencilBuffer();
1460
1461            mCaches.stencil.enableWrite();
1462
1463            // Clear and update the stencil, but first make sure we restrict drawing
1464            // to the region's bounds
1465            bool resetScissor = mCaches.enableScissor();
1466            if (resetScissor) {
1467                // The scissor was not set so we now need to update it
1468                setScissorFromClip();
1469            }
1470            mCaches.stencil.clear();
1471
1472            // stash and disable the outline clip state, since stencil doesn't account for outline
1473            bool storedSkipOutlineClip = mSkipOutlineClip;
1474            mSkipOutlineClip = true;
1475
1476            SkPaint paint;
1477            paint.setColor(SK_ColorBLACK);
1478            paint.setXfermodeMode(SkXfermode::kSrc_Mode);
1479
1480            // NOTE: We could use the region contour path to generate a smaller mesh
1481            //       Since we are using the stencil we could use the red book path
1482            //       drawing technique. It might increase bandwidth usage though.
1483
1484            // The last parameter is important: we are not drawing in the color buffer
1485            // so we don't want to dirty the current layer, if any
1486            drawRegionRects(*(currentSnapshot()->clipRegion), paint, false);
1487            if (resetScissor) mCaches.disableScissor();
1488            mSkipOutlineClip = storedSkipOutlineClip;
1489
1490            mCaches.stencil.enableTest();
1491
1492            // Draw the region used to generate the stencil if the appropriate debug
1493            // mode is enabled
1494            if (mCaches.debugStencilClip == Caches::kStencilShowRegion) {
1495                paint.setColor(0x7f0000ff);
1496                paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
1497                drawRegionRects(*(currentSnapshot()->clipRegion), paint);
1498            }
1499        } else {
1500            EVENT_LOGD("setStencilFromClip - disabling");
1501            mCaches.stencil.disable();
1502        }
1503    }
1504}
1505
1506/**
1507 * Returns false and sets scissor enable based upon bounds if drawing won't be clipped out.
1508 *
1509 * @param paint if not null, the bounds will be expanded to account for stroke depending on paint
1510 *         style, and tessellated AA ramp
1511 */
1512bool OpenGLRenderer::quickRejectSetupScissor(float left, float top, float right, float bottom,
1513        const SkPaint* paint) {
1514    bool snapOut = paint && paint->isAntiAlias();
1515
1516    if (paint && paint->getStyle() != SkPaint::kFill_Style) {
1517        float outset = paint->getStrokeWidth() * 0.5f;
1518        left -= outset;
1519        top -= outset;
1520        right += outset;
1521        bottom += outset;
1522    }
1523
1524    bool clipRequired = false;
1525    bool roundRectClipRequired = false;
1526    if (calculateQuickRejectForScissor(left, top, right, bottom,
1527            &clipRequired, &roundRectClipRequired, snapOut)) {
1528        return true;
1529    }
1530
1531    // not quick rejected, so enable the scissor if clipRequired
1532    mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
1533    mSkipOutlineClip = !roundRectClipRequired;
1534    return false;
1535}
1536
1537void OpenGLRenderer::debugClip() {
1538#if DEBUG_CLIP_REGIONS
1539    if (!currentSnapshot()->clipRegion->isEmpty()) {
1540        SkPaint paint;
1541        paint.setColor(0x7f00ff00);
1542        drawRegionRects(*(currentSnapshot()->clipRegion, paint);
1543
1544    }
1545#endif
1546}
1547
1548///////////////////////////////////////////////////////////////////////////////
1549// Drawing commands
1550///////////////////////////////////////////////////////////////////////////////
1551
1552void OpenGLRenderer::setupDraw(bool clearLayer) {
1553    // TODO: It would be best if we could do this before quickRejectSetupScissor()
1554    //       changes the scissor test state
1555    if (clearLayer) clearLayerRegions();
1556    // Make sure setScissor & setStencil happen at the beginning of
1557    // this method
1558    if (mDirtyClip) {
1559        if (mCaches.scissorEnabled) {
1560            setScissorFromClip();
1561        }
1562
1563        setStencilFromClip();
1564    }
1565
1566    mDescription.reset();
1567
1568    mSetShaderColor = false;
1569    mColorSet = false;
1570    mColorA = mColorR = mColorG = mColorB = 0.0f;
1571    mTextureUnit = 0;
1572    mTrackDirtyRegions = true;
1573
1574    // Enable debug highlight when what we're about to draw is tested against
1575    // the stencil buffer and if stencil highlight debugging is on
1576    mDescription.hasDebugHighlight = !mCaches.debugOverdraw &&
1577            mCaches.debugStencilClip == Caches::kStencilShowHighlight &&
1578            mCaches.stencil.isTestEnabled();
1579}
1580
1581void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
1582    mDescription.hasTexture = true;
1583    mDescription.hasAlpha8Texture = isAlpha8;
1584}
1585
1586void OpenGLRenderer::setupDrawWithTextureAndColor(bool isAlpha8) {
1587    mDescription.hasTexture = true;
1588    mDescription.hasColors = true;
1589    mDescription.hasAlpha8Texture = isAlpha8;
1590}
1591
1592void OpenGLRenderer::setupDrawWithExternalTexture() {
1593    mDescription.hasExternalTexture = true;
1594}
1595
1596void OpenGLRenderer::setupDrawNoTexture() {
1597    mCaches.disableTexCoordsVertexArray();
1598}
1599
1600void OpenGLRenderer::setupDrawVertexAlpha(bool useShadowAlphaInterp) {
1601    mDescription.hasVertexAlpha = true;
1602    mDescription.useShadowAlphaInterp = useShadowAlphaInterp;
1603}
1604
1605void OpenGLRenderer::setupDrawColor(int color, int alpha) {
1606    mColorA = alpha / 255.0f;
1607    mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f;
1608    mColorG = mColorA * ((color >>  8) & 0xFF) / 255.0f;
1609    mColorB = mColorA * ((color      ) & 0xFF) / 255.0f;
1610    mColorSet = true;
1611    mSetShaderColor = mDescription.setColorModulate(mColorA);
1612}
1613
1614void OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) {
1615    mColorA = alpha / 255.0f;
1616    mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f;
1617    mColorG = mColorA * ((color >>  8) & 0xFF) / 255.0f;
1618    mColorB = mColorA * ((color      ) & 0xFF) / 255.0f;
1619    mColorSet = true;
1620    mSetShaderColor = mDescription.setAlpha8ColorModulate(mColorR, mColorG, mColorB, mColorA);
1621}
1622
1623void OpenGLRenderer::setupDrawTextGamma(const SkPaint* paint) {
1624    mCaches.fontRenderer->describe(mDescription, paint);
1625}
1626
1627void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) {
1628    mColorA = a;
1629    mColorR = r;
1630    mColorG = g;
1631    mColorB = b;
1632    mColorSet = true;
1633    mSetShaderColor = mDescription.setColorModulate(a);
1634}
1635
1636void OpenGLRenderer::setupDrawShader(const SkShader* shader) {
1637    if (shader != NULL) {
1638        SkiaShader::describe(&mCaches, mDescription, mExtensions, *shader);
1639    }
1640}
1641
1642void OpenGLRenderer::setupDrawColorFilter(const SkColorFilter* filter) {
1643    if (filter == NULL) {
1644        return;
1645    }
1646
1647    SkXfermode::Mode mode;
1648    if (filter->asColorMode(NULL, &mode)) {
1649        mDescription.colorOp = ProgramDescription::kColorBlend;
1650        mDescription.colorMode = mode;
1651    } else if (filter->asColorMatrix(NULL)) {
1652        mDescription.colorOp = ProgramDescription::kColorMatrix;
1653    }
1654}
1655
1656void OpenGLRenderer::accountForClear(SkXfermode::Mode mode) {
1657    if (mColorSet && mode == SkXfermode::kClear_Mode) {
1658        mColorA = 1.0f;
1659        mColorR = mColorG = mColorB = 0.0f;
1660        mSetShaderColor = mDescription.modulate = true;
1661    }
1662}
1663
1664void OpenGLRenderer::setupDrawBlending(const Layer* layer, bool swapSrcDst) {
1665    SkXfermode::Mode mode = layer->getMode();
1666    // When the blending mode is kClear_Mode, we need to use a modulate color
1667    // argb=1,0,0,0
1668    accountForClear(mode);
1669    // TODO: check shader blending, once we have shader drawing support for layers.
1670    bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f ||
1671            (mColorSet && mColorA < 1.0f) || isBlendedColorFilter(layer->getColorFilter());
1672    chooseBlending(blend, mode, mDescription, swapSrcDst);
1673}
1674
1675void OpenGLRenderer::setupDrawBlending(const SkPaint* paint, bool blend, bool swapSrcDst) {
1676    SkXfermode::Mode mode = getXfermodeDirect(paint);
1677    // When the blending mode is kClear_Mode, we need to use a modulate color
1678    // argb=1,0,0,0
1679    accountForClear(mode);
1680    blend |= (mColorSet && mColorA < 1.0f) ||
1681            (getShader(paint) && !getShader(paint)->isOpaque()) ||
1682            isBlendedColorFilter(getColorFilter(paint));
1683    chooseBlending(blend, mode, mDescription, swapSrcDst);
1684}
1685
1686void OpenGLRenderer::setupDrawProgram() {
1687    useProgram(mCaches.programCache.get(mDescription));
1688    if (mDescription.hasRoundRectClip) {
1689        // TODO: avoid doing this repeatedly, stashing state pointer in program
1690        const RoundRectClipState* state = mSnapshot->roundRectClipState;
1691        const Rect& innerRect = state->innerRect;
1692        glUniform4f(mCaches.currentProgram->getUniform("roundRectInnerRectLTRB"),
1693                innerRect.left, innerRect.top,
1694                innerRect.right, innerRect.bottom);
1695        glUniformMatrix4fv(mCaches.currentProgram->getUniform("roundRectInvTransform"),
1696                1, GL_FALSE, &state->matrix.data[0]);
1697
1698        // add half pixel to round out integer rect space to cover pixel centers
1699        float roundedOutRadius = state->radius + 0.5f;
1700        glUniform1f(mCaches.currentProgram->getUniform("roundRectRadius"),
1701                roundedOutRadius);
1702    }
1703}
1704
1705void OpenGLRenderer::setupDrawDirtyRegionsDisabled() {
1706    mTrackDirtyRegions = false;
1707}
1708
1709void OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset,
1710        float left, float top, float right, float bottom, bool ignoreTransform) {
1711    mModelViewMatrix.loadTranslate(left, top, 0.0f);
1712    if (mode == kModelViewMode_TranslateAndScale) {
1713        mModelViewMatrix.scale(right - left, bottom - top, 1.0f);
1714    }
1715
1716    bool dirty = right - left > 0.0f && bottom - top > 0.0f;
1717    const Matrix4& transformMatrix = ignoreTransform ? Matrix4::identity() : *currentTransform();
1718    mCaches.currentProgram->set(mSnapshot->getOrthoMatrix(), mModelViewMatrix, transformMatrix, offset);
1719    if (dirty && mTrackDirtyRegions) {
1720        if (!ignoreTransform) {
1721            dirtyLayer(left, top, right, bottom, *currentTransform());
1722        } else {
1723            dirtyLayer(left, top, right, bottom);
1724        }
1725    }
1726}
1727
1728void OpenGLRenderer::setupDrawColorUniforms(bool hasShader) {
1729    if ((mColorSet && !hasShader) || (hasShader && mSetShaderColor)) {
1730        mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
1731    }
1732}
1733
1734void OpenGLRenderer::setupDrawPureColorUniforms() {
1735    if (mSetShaderColor) {
1736        mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
1737    }
1738}
1739
1740void OpenGLRenderer::setupDrawShaderUniforms(const SkShader* shader, bool ignoreTransform) {
1741    if (shader == NULL) {
1742        return;
1743    }
1744
1745    if (ignoreTransform) {
1746        // if ignoreTransform=true was passed to setupDrawModelView, undo currentTransform()
1747        // because it was built into modelView / the geometry, and the description needs to
1748        // compensate.
1749        mat4 modelViewWithoutTransform;
1750        modelViewWithoutTransform.loadInverse(*currentTransform());
1751        modelViewWithoutTransform.multiply(mModelViewMatrix);
1752        mModelViewMatrix.load(modelViewWithoutTransform);
1753    }
1754
1755    SkiaShader::setupProgram(&mCaches, mModelViewMatrix, &mTextureUnit, mExtensions, *shader);
1756}
1757
1758void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) {
1759    if (NULL == filter) {
1760        return;
1761    }
1762
1763    SkColor color;
1764    SkXfermode::Mode mode;
1765    if (filter->asColorMode(&color, &mode)) {
1766        const int alpha = SkColorGetA(color);
1767        const GLfloat a = alpha / 255.0f;
1768        const GLfloat r = a * SkColorGetR(color) / 255.0f;
1769        const GLfloat g = a * SkColorGetG(color) / 255.0f;
1770        const GLfloat b = a * SkColorGetB(color) / 255.0f;
1771        glUniform4f(mCaches.currentProgram->getUniform("colorBlend"), r, g, b, a);
1772        return;
1773    }
1774
1775    SkScalar srcColorMatrix[20];
1776    if (filter->asColorMatrix(srcColorMatrix)) {
1777
1778        float colorMatrix[16];
1779        memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float));
1780        memcpy(&colorMatrix[4], &srcColorMatrix[5], 4 * sizeof(float));
1781        memcpy(&colorMatrix[8], &srcColorMatrix[10], 4 * sizeof(float));
1782        memcpy(&colorMatrix[12], &srcColorMatrix[15], 4 * sizeof(float));
1783
1784        // Skia uses the range [0..255] for the addition vector, but we need
1785        // the [0..1] range to apply the vector in GLSL
1786        float colorVector[4];
1787        colorVector[0] = srcColorMatrix[4] / 255.0f;
1788        colorVector[1] = srcColorMatrix[9] / 255.0f;
1789        colorVector[2] = srcColorMatrix[14] / 255.0f;
1790        colorVector[3] = srcColorMatrix[19] / 255.0f;
1791
1792        glUniformMatrix4fv(mCaches.currentProgram->getUniform("colorMatrix"), 1,
1793                GL_FALSE, colorMatrix);
1794        glUniform4fv(mCaches.currentProgram->getUniform("colorMatrixVector"), 1, colorVector);
1795        return;
1796    }
1797
1798    // it is an error if we ever get here
1799}
1800
1801void OpenGLRenderer::setupDrawTextGammaUniforms() {
1802    mCaches.fontRenderer->setupProgram(mDescription, mCaches.currentProgram);
1803}
1804
1805void OpenGLRenderer::setupDrawSimpleMesh() {
1806    bool force = mCaches.bindMeshBuffer();
1807    mCaches.bindPositionVertexPointer(force, 0);
1808    mCaches.unbindIndicesBuffer();
1809}
1810
1811void OpenGLRenderer::setupDrawTexture(GLuint texture) {
1812    if (texture) bindTexture(texture);
1813    mTextureUnit++;
1814    mCaches.enableTexCoordsVertexArray();
1815}
1816
1817void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) {
1818    bindExternalTexture(texture);
1819    mTextureUnit++;
1820    mCaches.enableTexCoordsVertexArray();
1821}
1822
1823void OpenGLRenderer::setupDrawTextureTransform() {
1824    mDescription.hasTextureTransform = true;
1825}
1826
1827void OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) {
1828    glUniformMatrix4fv(mCaches.currentProgram->getUniform("mainTextureTransform"), 1,
1829            GL_FALSE, &transform.data[0]);
1830}
1831
1832void OpenGLRenderer::setupDrawMesh(const GLvoid* vertices,
1833        const GLvoid* texCoords, GLuint vbo) {
1834    bool force = false;
1835    if (!vertices || vbo) {
1836        force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
1837    } else {
1838        force = mCaches.unbindMeshBuffer();
1839    }
1840
1841    mCaches.bindPositionVertexPointer(force, vertices);
1842    if (mCaches.currentProgram->texCoords >= 0) {
1843        mCaches.bindTexCoordsVertexPointer(force, texCoords);
1844    }
1845
1846    mCaches.unbindIndicesBuffer();
1847}
1848
1849void OpenGLRenderer::setupDrawMesh(const GLvoid* vertices,
1850        const GLvoid* texCoords, const GLvoid* colors) {
1851    bool force = mCaches.unbindMeshBuffer();
1852    GLsizei stride = sizeof(ColorTextureVertex);
1853
1854    mCaches.bindPositionVertexPointer(force, vertices, stride);
1855    if (mCaches.currentProgram->texCoords >= 0) {
1856        mCaches.bindTexCoordsVertexPointer(force, texCoords, stride);
1857    }
1858    int slot = mCaches.currentProgram->getAttrib("colors");
1859    if (slot >= 0) {
1860        glEnableVertexAttribArray(slot);
1861        glVertexAttribPointer(slot, 4, GL_FLOAT, GL_FALSE, stride, colors);
1862    }
1863
1864    mCaches.unbindIndicesBuffer();
1865}
1866
1867void OpenGLRenderer::setupDrawMeshIndices(const GLvoid* vertices,
1868        const GLvoid* texCoords, GLuint vbo) {
1869    bool force = false;
1870    // If vbo is != 0 we want to treat the vertices parameter as an offset inside
1871    // a VBO. However, if vertices is set to NULL and vbo == 0 then we want to
1872    // use the default VBO found in Caches
1873    if (!vertices || vbo) {
1874        force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
1875    } else {
1876        force = mCaches.unbindMeshBuffer();
1877    }
1878    mCaches.bindQuadIndicesBuffer();
1879
1880    mCaches.bindPositionVertexPointer(force, vertices);
1881    if (mCaches.currentProgram->texCoords >= 0) {
1882        mCaches.bindTexCoordsVertexPointer(force, texCoords);
1883    }
1884}
1885
1886void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) {
1887    bool force = mCaches.unbindMeshBuffer();
1888    mCaches.bindQuadIndicesBuffer();
1889    mCaches.bindPositionVertexPointer(force, vertices, gVertexStride);
1890}
1891
1892///////////////////////////////////////////////////////////////////////////////
1893// Drawing
1894///////////////////////////////////////////////////////////////////////////////
1895
1896status_t OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags) {
1897    status_t status;
1898    // All the usual checks and setup operations (quickReject, setupDraw, etc.)
1899    // will be performed by the display list itself
1900    if (renderNode && renderNode->isRenderable()) {
1901        // compute 3d ordering
1902        renderNode->computeOrdering();
1903        if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
1904            status = startFrame();
1905            ReplayStateStruct replayStruct(*this, dirty, replayFlags);
1906            renderNode->replay(replayStruct, 0);
1907            return status | replayStruct.mDrawGlStatus;
1908        }
1909
1910        DeferredDisplayList deferredList(*currentClipRect());
1911        DeferStateStruct deferStruct(deferredList, *this, replayFlags);
1912        renderNode->defer(deferStruct, 0);
1913
1914        flushLayers();
1915        status = startFrame();
1916
1917        return deferredList.flush(*this, dirty) | status;
1918    }
1919
1920    // Even if there is no drawing command(Ex: invisible),
1921    // it still needs startFrame to clear buffer and start tiling.
1922    return startFrame();
1923}
1924
1925void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, const SkPaint* paint) {
1926    int color = paint != NULL ? paint->getColor() : 0;
1927
1928    float x = left;
1929    float y = top;
1930
1931    texture->setWrap(GL_CLAMP_TO_EDGE, true);
1932
1933    bool ignoreTransform = false;
1934    if (currentTransform()->isPureTranslate()) {
1935        x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f);
1936        y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f);
1937        ignoreTransform = true;
1938
1939        texture->setFilter(GL_NEAREST, true);
1940    } else {
1941        texture->setFilter(getFilter(paint), true);
1942    }
1943
1944    // No need to check for a UV mapper on the texture object, only ARGB_8888
1945    // bitmaps get packed in the atlas
1946    drawAlpha8TextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
1947            paint, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset,
1948            GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
1949}
1950
1951/**
1952 * Important note: this method is intended to draw batches of bitmaps and
1953 * will not set the scissor enable or dirty the current layer, if any.
1954 * The caller is responsible for properly dirtying the current layer.
1955 */
1956status_t OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
1957        int bitmapCount, TextureVertex* vertices, bool pureTranslate,
1958        const Rect& bounds, const SkPaint* paint) {
1959    mCaches.activeTexture(0);
1960    Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
1961    if (!texture) return DrawGlInfo::kStatusDone;
1962
1963    const AutoTexture autoCleanup(texture);
1964
1965    texture->setWrap(GL_CLAMP_TO_EDGE, true);
1966    texture->setFilter(pureTranslate ? GL_NEAREST : getFilter(paint), true);
1967
1968    const float x = (int) floorf(bounds.left + 0.5f);
1969    const float y = (int) floorf(bounds.top + 0.5f);
1970    if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
1971        drawAlpha8TextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
1972                texture->id, paint, &vertices[0].x, &vertices[0].u,
1973                GL_TRIANGLES, bitmapCount * 6, true,
1974                kModelViewMode_Translate, false);
1975    } else {
1976        drawTextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
1977                texture->id, paint, texture->blend, &vertices[0].x, &vertices[0].u,
1978                GL_TRIANGLES, bitmapCount * 6, false, true, 0,
1979                kModelViewMode_Translate, false);
1980    }
1981
1982    return DrawGlInfo::kStatusDrew;
1983}
1984
1985status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
1986    if (quickRejectSetupScissor(0, 0, bitmap->width(), bitmap->height())) {
1987        return DrawGlInfo::kStatusDone;
1988    }
1989
1990    mCaches.activeTexture(0);
1991    Texture* texture = getTexture(bitmap);
1992    if (!texture) return DrawGlInfo::kStatusDone;
1993    const AutoTexture autoCleanup(texture);
1994
1995    if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
1996        drawAlphaBitmap(texture, 0, 0, paint);
1997    } else {
1998        drawTextureRect(0, 0, bitmap->width(), bitmap->height(), texture, paint);
1999    }
2000
2001    return DrawGlInfo::kStatusDrew;
2002}
2003
2004status_t OpenGLRenderer::drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint) {
2005    if (quickRejectSetupScissor(0, 0, bitmap->width(), bitmap->height())) {
2006        return DrawGlInfo::kStatusDone;
2007    }
2008
2009    mCaches.activeTexture(0);
2010    Texture* texture = mCaches.textureCache.getTransient(bitmap);
2011    const AutoTexture autoCleanup(texture);
2012
2013    if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
2014        drawAlphaBitmap(texture, 0, 0, paint);
2015    } else {
2016        drawTextureRect(0, 0, bitmap->width(), bitmap->height(), texture, paint);
2017    }
2018
2019    return DrawGlInfo::kStatusDrew;
2020}
2021
2022status_t OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
2023        const float* vertices, const int* colors, const SkPaint* paint) {
2024    if (!vertices || currentSnapshot()->isIgnored()) {
2025        return DrawGlInfo::kStatusDone;
2026    }
2027
2028    // TODO: use quickReject on bounds from vertices
2029    mCaches.enableScissor();
2030
2031    float left = FLT_MAX;
2032    float top = FLT_MAX;
2033    float right = FLT_MIN;
2034    float bottom = FLT_MIN;
2035
2036    const uint32_t count = meshWidth * meshHeight * 6;
2037
2038    Vector<ColorTextureVertex> mesh; // TODO: use C++11 unique_ptr
2039    mesh.setCapacity(count);
2040    ColorTextureVertex* vertex = mesh.editArray();
2041
2042    bool cleanupColors = false;
2043    if (!colors) {
2044        uint32_t colorsCount = (meshWidth + 1) * (meshHeight + 1);
2045        int* newColors = new int[colorsCount];
2046        memset(newColors, 0xff, colorsCount * sizeof(int));
2047        colors = newColors;
2048        cleanupColors = true;
2049    }
2050
2051    mCaches.activeTexture(0);
2052    Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap);
2053    const UvMapper& mapper(getMapper(texture));
2054
2055    for (int32_t y = 0; y < meshHeight; y++) {
2056        for (int32_t x = 0; x < meshWidth; x++) {
2057            uint32_t i = (y * (meshWidth + 1) + x) * 2;
2058
2059            float u1 = float(x) / meshWidth;
2060            float u2 = float(x + 1) / meshWidth;
2061            float v1 = float(y) / meshHeight;
2062            float v2 = float(y + 1) / meshHeight;
2063
2064            mapper.map(u1, v1, u2, v2);
2065
2066            int ax = i + (meshWidth + 1) * 2;
2067            int ay = ax + 1;
2068            int bx = i;
2069            int by = bx + 1;
2070            int cx = i + 2;
2071            int cy = cx + 1;
2072            int dx = i + (meshWidth + 1) * 2 + 2;
2073            int dy = dx + 1;
2074
2075            ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
2076            ColorTextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2, colors[ax / 2]);
2077            ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
2078
2079            ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
2080            ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
2081            ColorTextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1, colors[cx / 2]);
2082
2083            left = fminf(left, fminf(vertices[ax], fminf(vertices[bx], vertices[cx])));
2084            top = fminf(top, fminf(vertices[ay], fminf(vertices[by], vertices[cy])));
2085            right = fmaxf(right, fmaxf(vertices[ax], fmaxf(vertices[bx], vertices[cx])));
2086            bottom = fmaxf(bottom, fmaxf(vertices[ay], fmaxf(vertices[by], vertices[cy])));
2087        }
2088    }
2089
2090    if (quickRejectSetupScissor(left, top, right, bottom)) {
2091        if (cleanupColors) delete[] colors;
2092        return DrawGlInfo::kStatusDone;
2093    }
2094
2095    if (!texture) {
2096        texture = mCaches.textureCache.get(bitmap);
2097        if (!texture) {
2098            if (cleanupColors) delete[] colors;
2099            return DrawGlInfo::kStatusDone;
2100        }
2101    }
2102    const AutoTexture autoCleanup(texture);
2103
2104    texture->setWrap(GL_CLAMP_TO_EDGE, true);
2105    texture->setFilter(getFilter(paint), true);
2106
2107    int alpha;
2108    SkXfermode::Mode mode;
2109    getAlphaAndMode(paint, &alpha, &mode);
2110
2111    float a = alpha / 255.0f;
2112
2113    if (hasLayer()) {
2114        dirtyLayer(left, top, right, bottom, *currentTransform());
2115    }
2116
2117    setupDraw();
2118    setupDrawWithTextureAndColor();
2119    setupDrawColor(a, a, a, a);
2120    setupDrawColorFilter(getColorFilter(paint));
2121    setupDrawBlending(paint, true);
2122    setupDrawProgram();
2123    setupDrawDirtyRegionsDisabled();
2124    setupDrawModelView(kModelViewMode_TranslateAndScale, false, 0.0f, 0.0f, 1.0f, 1.0f);
2125    setupDrawTexture(texture->id);
2126    setupDrawPureColorUniforms();
2127    setupDrawColorFilterUniforms(getColorFilter(paint));
2128    setupDrawMesh(&mesh[0].x, &mesh[0].u, &mesh[0].r);
2129
2130    glDrawArrays(GL_TRIANGLES, 0, count);
2131
2132    int slot = mCaches.currentProgram->getAttrib("colors");
2133    if (slot >= 0) {
2134        glDisableVertexAttribArray(slot);
2135    }
2136
2137    if (cleanupColors) delete[] colors;
2138
2139    return DrawGlInfo::kStatusDrew;
2140}
2141
2142status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap,
2143         float srcLeft, float srcTop, float srcRight, float srcBottom,
2144         float dstLeft, float dstTop, float dstRight, float dstBottom,
2145         const SkPaint* paint) {
2146    if (quickRejectSetupScissor(dstLeft, dstTop, dstRight, dstBottom)) {
2147        return DrawGlInfo::kStatusDone;
2148    }
2149
2150    mCaches.activeTexture(0);
2151    Texture* texture = getTexture(bitmap);
2152    if (!texture) return DrawGlInfo::kStatusDone;
2153    const AutoTexture autoCleanup(texture);
2154
2155    const float width = texture->width;
2156    const float height = texture->height;
2157
2158    float u1 = fmax(0.0f, srcLeft / width);
2159    float v1 = fmax(0.0f, srcTop / height);
2160    float u2 = fmin(1.0f, srcRight / width);
2161    float v2 = fmin(1.0f, srcBottom / height);
2162
2163    getMapper(texture).map(u1, v1, u2, v2);
2164
2165    mCaches.unbindMeshBuffer();
2166    resetDrawTextureTexCoords(u1, v1, u2, v2);
2167
2168    texture->setWrap(GL_CLAMP_TO_EDGE, true);
2169
2170    float scaleX = (dstRight - dstLeft) / (srcRight - srcLeft);
2171    float scaleY = (dstBottom - dstTop) / (srcBottom - srcTop);
2172
2173    bool scaled = scaleX != 1.0f || scaleY != 1.0f;
2174    // Apply a scale transform on the canvas only when a shader is in use
2175    // Skia handles the ratio between the dst and src rects as a scale factor
2176    // when a shader is set
2177    bool useScaleTransform = getShader(paint) && scaled;
2178    bool ignoreTransform = false;
2179
2180    if (CC_LIKELY(currentTransform()->isPureTranslate() && !useScaleTransform)) {
2181        float x = (int) floorf(dstLeft + currentTransform()->getTranslateX() + 0.5f);
2182        float y = (int) floorf(dstTop + currentTransform()->getTranslateY() + 0.5f);
2183
2184        dstRight = x + (dstRight - dstLeft);
2185        dstBottom = y + (dstBottom - dstTop);
2186
2187        dstLeft = x;
2188        dstTop = y;
2189
2190        texture->setFilter(scaled ? getFilter(paint) : GL_NEAREST, true);
2191        ignoreTransform = true;
2192    } else {
2193        texture->setFilter(getFilter(paint), true);
2194    }
2195
2196    if (CC_UNLIKELY(useScaleTransform)) {
2197        save(SkCanvas::kMatrix_SaveFlag);
2198        translate(dstLeft, dstTop);
2199        scale(scaleX, scaleY);
2200
2201        dstLeft = 0.0f;
2202        dstTop = 0.0f;
2203
2204        dstRight = srcRight - srcLeft;
2205        dstBottom = srcBottom - srcTop;
2206    }
2207
2208    if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
2209        drawAlpha8TextureMesh(dstLeft, dstTop, dstRight, dstBottom,
2210                texture->id, paint,
2211                &mMeshVertices[0].x, &mMeshVertices[0].u,
2212                GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
2213    } else {
2214        drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom,
2215                texture->id, paint, texture->blend,
2216                &mMeshVertices[0].x, &mMeshVertices[0].u,
2217                GL_TRIANGLE_STRIP, gMeshCount, false, ignoreTransform);
2218    }
2219
2220    if (CC_UNLIKELY(useScaleTransform)) {
2221        restore();
2222    }
2223
2224    resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
2225
2226    return DrawGlInfo::kStatusDrew;
2227}
2228
2229status_t OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
2230        float left, float top, float right, float bottom, const SkPaint* paint) {
2231    if (quickRejectSetupScissor(left, top, right, bottom)) {
2232        return DrawGlInfo::kStatusDone;
2233    }
2234
2235    AssetAtlas::Entry* entry = mRenderState.assetAtlas().getEntry(bitmap);
2236    const Patch* mesh = mCaches.patchCache.get(entry, bitmap->width(), bitmap->height(),
2237            right - left, bottom - top, patch);
2238
2239    return drawPatch(bitmap, mesh, entry, left, top, right, bottom, paint);
2240}
2241
2242status_t OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh,
2243        AssetAtlas::Entry* entry, float left, float top, float right, float bottom,
2244        const SkPaint* paint) {
2245    if (quickRejectSetupScissor(left, top, right, bottom)) {
2246        return DrawGlInfo::kStatusDone;
2247    }
2248
2249    if (CC_LIKELY(mesh && mesh->verticesCount > 0)) {
2250        mCaches.activeTexture(0);
2251        Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
2252        if (!texture) return DrawGlInfo::kStatusDone;
2253        const AutoTexture autoCleanup(texture);
2254
2255        texture->setWrap(GL_CLAMP_TO_EDGE, true);
2256        texture->setFilter(GL_LINEAR, true);
2257
2258        const bool pureTranslate = currentTransform()->isPureTranslate();
2259        // Mark the current layer dirty where we are going to draw the patch
2260        if (hasLayer() && mesh->hasEmptyQuads) {
2261            const float offsetX = left + currentTransform()->getTranslateX();
2262            const float offsetY = top + currentTransform()->getTranslateY();
2263            const size_t count = mesh->quads.size();
2264            for (size_t i = 0; i < count; i++) {
2265                const Rect& bounds = mesh->quads.itemAt(i);
2266                if (CC_LIKELY(pureTranslate)) {
2267                    const float x = (int) floorf(bounds.left + offsetX + 0.5f);
2268                    const float y = (int) floorf(bounds.top + offsetY + 0.5f);
2269                    dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight());
2270                } else {
2271                    dirtyLayer(left + bounds.left, top + bounds.top,
2272                            left + bounds.right, top + bounds.bottom, *currentTransform());
2273                }
2274            }
2275        }
2276
2277        bool ignoreTransform = false;
2278        if (CC_LIKELY(pureTranslate)) {
2279            const float x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f);
2280            const float y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f);
2281
2282            right = x + right - left;
2283            bottom = y + bottom - top;
2284            left = x;
2285            top = y;
2286            ignoreTransform = true;
2287        }
2288        drawIndexedTextureMesh(left, top, right, bottom, texture->id, paint,
2289                texture->blend, (GLvoid*) mesh->offset, (GLvoid*) mesh->textureOffset,
2290                GL_TRIANGLES, mesh->indexCount, false, ignoreTransform,
2291                mCaches.patchCache.getMeshBuffer(), kModelViewMode_Translate, !mesh->hasEmptyQuads);
2292    }
2293
2294    return DrawGlInfo::kStatusDrew;
2295}
2296
2297/**
2298 * Important note: this method is intended to draw batches of 9-patch objects and
2299 * will not set the scissor enable or dirty the current layer, if any.
2300 * The caller is responsible for properly dirtying the current layer.
2301 */
2302status_t OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
2303        TextureVertex* vertices, uint32_t indexCount, const SkPaint* paint) {
2304    mCaches.activeTexture(0);
2305    Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
2306    if (!texture) return DrawGlInfo::kStatusDone;
2307    const AutoTexture autoCleanup(texture);
2308
2309    texture->setWrap(GL_CLAMP_TO_EDGE, true);
2310    texture->setFilter(GL_LINEAR, true);
2311
2312    drawIndexedTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, paint,
2313            texture->blend, &vertices[0].x, &vertices[0].u,
2314            GL_TRIANGLES, indexCount, false, true, 0, kModelViewMode_Translate, false);
2315
2316    return DrawGlInfo::kStatusDrew;
2317}
2318
2319status_t OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
2320        const VertexBuffer& vertexBuffer, const SkPaint* paint, int displayFlags) {
2321    // not missing call to quickReject/dirtyLayer, always done at a higher level
2322    if (!vertexBuffer.getVertexCount()) {
2323        // no vertices to draw
2324        return DrawGlInfo::kStatusDone;
2325    }
2326
2327    Rect bounds(vertexBuffer.getBounds());
2328    bounds.translate(translateX, translateY);
2329    dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform());
2330
2331    int color = paint->getColor();
2332    bool isAA = paint->isAntiAlias();
2333
2334    setupDraw();
2335    setupDrawNoTexture();
2336    if (isAA) setupDrawVertexAlpha((displayFlags & kVertexBuffer_ShadowInterp));
2337    setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
2338    setupDrawColorFilter(getColorFilter(paint));
2339    setupDrawShader(getShader(paint));
2340    setupDrawBlending(paint, isAA);
2341    setupDrawProgram();
2342    setupDrawModelView(kModelViewMode_Translate, (displayFlags & kVertexBuffer_Offset),
2343            translateX, translateY, 0, 0);
2344    setupDrawColorUniforms(getShader(paint));
2345    setupDrawColorFilterUniforms(getColorFilter(paint));
2346    setupDrawShaderUniforms(getShader(paint));
2347
2348    const void* vertices = vertexBuffer.getBuffer();
2349    bool force = mCaches.unbindMeshBuffer();
2350    mCaches.bindPositionVertexPointer(true, vertices, isAA ? gAlphaVertexStride : gVertexStride);
2351    mCaches.resetTexCoordsVertexPointer();
2352
2353    int alphaSlot = -1;
2354    if (isAA) {
2355        void* alphaCoords = ((GLbyte*) vertices) + gVertexAlphaOffset;
2356        alphaSlot = mCaches.currentProgram->getAttrib("vtxAlpha");
2357        // TODO: avoid enable/disable in back to back uses of the alpha attribute
2358        glEnableVertexAttribArray(alphaSlot);
2359        glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords);
2360    }
2361
2362    const VertexBuffer::Mode mode = vertexBuffer.getMode();
2363    if (mode == VertexBuffer::kStandard) {
2364        mCaches.unbindIndicesBuffer();
2365        glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
2366    } else if (mode == VertexBuffer::kOnePolyRingShadow) {
2367        mCaches.bindShadowIndicesBuffer();
2368        glDrawElements(GL_TRIANGLE_STRIP, ONE_POLY_RING_SHADOW_INDEX_COUNT, GL_UNSIGNED_SHORT, 0);
2369    } else if (mode == VertexBuffer::kTwoPolyRingShadow) {
2370        mCaches.bindShadowIndicesBuffer();
2371        glDrawElements(GL_TRIANGLE_STRIP, TWO_POLY_RING_SHADOW_INDEX_COUNT, GL_UNSIGNED_SHORT, 0);
2372    } else if (mode == VertexBuffer::kIndices) {
2373        mCaches.unbindIndicesBuffer();
2374        glDrawElements(GL_TRIANGLE_STRIP, vertexBuffer.getIndexCount(), GL_UNSIGNED_SHORT,
2375                vertexBuffer.getIndices());
2376    }
2377
2378    if (isAA) {
2379        glDisableVertexAttribArray(alphaSlot);
2380    }
2381
2382    return DrawGlInfo::kStatusDrew;
2383}
2384
2385/**
2386 * Renders a convex path via tessellation. For AA paths, this function uses a similar approach to
2387 * that of AA lines in the drawLines() function.  We expand the convex path by a half pixel in
2388 * screen space in all directions. However, instead of using a fragment shader to compute the
2389 * translucency of the color from its position, we simply use a varying parameter to define how far
2390 * a given pixel is from the edge. For non-AA paths, the expansion and alpha varying are not used.
2391 *
2392 * Doesn't yet support joins, caps, or path effects.
2393 */
2394status_t OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint) {
2395    VertexBuffer vertexBuffer;
2396    // TODO: try clipping large paths to viewport
2397    PathTessellator::tessellatePath(path, paint, *currentTransform(), vertexBuffer);
2398    return drawVertexBuffer(vertexBuffer, paint);
2399}
2400
2401/**
2402 * We create tristrips for the lines much like shape stroke tessellation, using a per-vertex alpha
2403 * and additional geometry for defining an alpha slope perimeter.
2404 *
2405 * Using GL_LINES can be difficult because the rasterization rules for those lines produces some
2406 * unexpected results, and may vary between hardware devices. Previously we used a varying-base
2407 * in-shader alpha region, but found it to be taxing on some GPUs.
2408 *
2409 * TODO: try using a fixed input buffer for non-capped lines as in text rendering. this may reduce
2410 * memory transfer by removing need for degenerate vertices.
2411 */
2412status_t OpenGLRenderer::drawLines(const float* points, int count, const SkPaint* paint) {
2413    if (currentSnapshot()->isIgnored() || count < 4) return DrawGlInfo::kStatusDone;
2414
2415    count &= ~0x3; // round down to nearest four
2416
2417    VertexBuffer buffer;
2418    PathTessellator::tessellateLines(points, count, paint, *currentTransform(), buffer);
2419    const Rect& bounds = buffer.getBounds();
2420
2421    if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
2422        return DrawGlInfo::kStatusDone;
2423    }
2424
2425    int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset;
2426    return drawVertexBuffer(buffer, paint, displayFlags);
2427}
2428
2429status_t OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) {
2430    if (currentSnapshot()->isIgnored() || count < 2) return DrawGlInfo::kStatusDone;
2431
2432    count &= ~0x1; // round down to nearest two
2433
2434    VertexBuffer buffer;
2435    PathTessellator::tessellatePoints(points, count, paint, *currentTransform(), buffer);
2436
2437    const Rect& bounds = buffer.getBounds();
2438    if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
2439        return DrawGlInfo::kStatusDone;
2440    }
2441
2442    int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset;
2443    return drawVertexBuffer(buffer, paint, displayFlags);
2444}
2445
2446status_t OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
2447    // No need to check against the clip, we fill the clip region
2448    if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
2449
2450    Rect clip(*currentClipRect());
2451    clip.snapToPixelBoundaries();
2452
2453    SkPaint paint;
2454    paint.setColor(color);
2455    paint.setXfermodeMode(mode);
2456
2457    drawColorRect(clip.left, clip.top, clip.right, clip.bottom, &paint, true);
2458
2459    return DrawGlInfo::kStatusDrew;
2460}
2461
2462status_t OpenGLRenderer::drawShape(float left, float top, const PathTexture* texture,
2463        const SkPaint* paint) {
2464    if (!texture) return DrawGlInfo::kStatusDone;
2465    const AutoTexture autoCleanup(texture);
2466
2467    const float x = left + texture->left - texture->offset;
2468    const float y = top + texture->top - texture->offset;
2469
2470    drawPathTexture(texture, x, y, paint);
2471
2472    return DrawGlInfo::kStatusDrew;
2473}
2474
2475status_t OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
2476        float rx, float ry, const SkPaint* p) {
2477    if (currentSnapshot()->isIgnored()
2478            || quickRejectSetupScissor(left, top, right, bottom, p)
2479            || paintWillNotDraw(*p)) {
2480        return DrawGlInfo::kStatusDone;
2481    }
2482
2483    if (p->getPathEffect() != 0) {
2484        mCaches.activeTexture(0);
2485        const PathTexture* texture = mCaches.pathCache.getRoundRect(
2486                right - left, bottom - top, rx, ry, p);
2487        return drawShape(left, top, texture, p);
2488    }
2489
2490    const VertexBuffer* vertexBuffer = mCaches.tessellationCache.getRoundRect(
2491            *currentTransform(), *p, right - left, bottom - top, rx, ry);
2492    return drawVertexBuffer(left, top, *vertexBuffer, p);
2493}
2494
2495status_t OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p) {
2496    if (currentSnapshot()->isIgnored()
2497            || quickRejectSetupScissor(x - radius, y - radius, x + radius, y + radius, p)
2498            || paintWillNotDraw(*p)) {
2499        return DrawGlInfo::kStatusDone;
2500    }
2501    if (p->getPathEffect() != 0) {
2502        mCaches.activeTexture(0);
2503        const PathTexture* texture = mCaches.pathCache.getCircle(radius, p);
2504        return drawShape(x - radius, y - radius, texture, p);
2505    }
2506
2507    SkPath path;
2508    if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2509        path.addCircle(x, y, radius + p->getStrokeWidth() / 2);
2510    } else {
2511        path.addCircle(x, y, radius);
2512    }
2513    return drawConvexPath(path, p);
2514}
2515
2516status_t OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
2517        const SkPaint* p) {
2518    if (currentSnapshot()->isIgnored()
2519            || quickRejectSetupScissor(left, top, right, bottom, p)
2520            || paintWillNotDraw(*p)) {
2521        return DrawGlInfo::kStatusDone;
2522    }
2523
2524    if (p->getPathEffect() != 0) {
2525        mCaches.activeTexture(0);
2526        const PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p);
2527        return drawShape(left, top, texture, p);
2528    }
2529
2530    SkPath path;
2531    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2532    if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2533        rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
2534    }
2535    path.addOval(rect);
2536    return drawConvexPath(path, p);
2537}
2538
2539status_t OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
2540        float startAngle, float sweepAngle, bool useCenter, const SkPaint* p) {
2541    if (currentSnapshot()->isIgnored()
2542            || quickRejectSetupScissor(left, top, right, bottom, p)
2543            || paintWillNotDraw(*p)) {
2544        return DrawGlInfo::kStatusDone;
2545    }
2546
2547    // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
2548    if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != 0 || useCenter) {
2549        mCaches.activeTexture(0);
2550        const PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top,
2551                startAngle, sweepAngle, useCenter, p);
2552        return drawShape(left, top, texture, p);
2553    }
2554
2555    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2556    if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2557        rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
2558    }
2559
2560    SkPath path;
2561    if (useCenter) {
2562        path.moveTo(rect.centerX(), rect.centerY());
2563    }
2564    path.arcTo(rect, startAngle, sweepAngle, !useCenter);
2565    if (useCenter) {
2566        path.close();
2567    }
2568    return drawConvexPath(path, p);
2569}
2570
2571// See SkPaintDefaults.h
2572#define SkPaintDefaults_MiterLimit SkIntToScalar(4)
2573
2574status_t OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
2575        const SkPaint* p) {
2576    if (currentSnapshot()->isIgnored()
2577            || quickRejectSetupScissor(left, top, right, bottom, p)
2578            || paintWillNotDraw(*p)) {
2579        return DrawGlInfo::kStatusDone;
2580    }
2581
2582    if (p->getStyle() != SkPaint::kFill_Style) {
2583        // only fill style is supported by drawConvexPath, since others have to handle joins
2584        if (p->getPathEffect() != 0 || p->getStrokeJoin() != SkPaint::kMiter_Join ||
2585                p->getStrokeMiter() != SkPaintDefaults_MiterLimit) {
2586            mCaches.activeTexture(0);
2587            const PathTexture* texture =
2588                    mCaches.pathCache.getRect(right - left, bottom - top, p);
2589            return drawShape(left, top, texture, p);
2590        }
2591
2592        SkPath path;
2593        SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2594        if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2595            rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
2596        }
2597        path.addRect(rect);
2598        return drawConvexPath(path, p);
2599    }
2600
2601    if (p->isAntiAlias() && !currentTransform()->isSimple()) {
2602        SkPath path;
2603        path.addRect(left, top, right, bottom);
2604        return drawConvexPath(path, p);
2605    } else {
2606        drawColorRect(left, top, right, bottom, p);
2607        return DrawGlInfo::kStatusDrew;
2608    }
2609}
2610
2611void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text,
2612        int bytesCount, int count, const float* positions,
2613        FontRenderer& fontRenderer, int alpha, float x, float y) {
2614    mCaches.activeTexture(0);
2615
2616    TextShadow textShadow;
2617    if (!getTextShadow(paint, &textShadow)) {
2618        LOG_ALWAYS_FATAL("failed to query shadow attributes");
2619    }
2620
2621    // NOTE: The drop shadow will not perform gamma correction
2622    //       if shader-based correction is enabled
2623    mCaches.dropShadowCache.setFontRenderer(fontRenderer);
2624    const ShadowTexture* shadow = mCaches.dropShadowCache.get(
2625            paint, text, bytesCount, count, textShadow.radius, positions);
2626    // If the drop shadow exceeds the max texture size or couldn't be
2627    // allocated, skip drawing
2628    if (!shadow) return;
2629    const AutoTexture autoCleanup(shadow);
2630
2631    const float sx = x - shadow->left + textShadow.dx;
2632    const float sy = y - shadow->top + textShadow.dy;
2633
2634    const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * mSnapshot->alpha;
2635    if (getShader(paint)) {
2636        textShadow.color = SK_ColorWHITE;
2637    }
2638
2639    setupDraw();
2640    setupDrawWithTexture(true);
2641    setupDrawAlpha8Color(textShadow.color, shadowAlpha < 255 ? shadowAlpha : alpha);
2642    setupDrawColorFilter(getColorFilter(paint));
2643    setupDrawShader(getShader(paint));
2644    setupDrawBlending(paint, true);
2645    setupDrawProgram();
2646    setupDrawModelView(kModelViewMode_TranslateAndScale, false,
2647            sx, sy, sx + shadow->width, sy + shadow->height);
2648    setupDrawTexture(shadow->id);
2649    setupDrawPureColorUniforms();
2650    setupDrawColorFilterUniforms(getColorFilter(paint));
2651    setupDrawShaderUniforms(getShader(paint));
2652    setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
2653
2654    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
2655}
2656
2657bool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
2658    float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * mSnapshot->alpha;
2659    return alpha == 0.0f && getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
2660}
2661
2662status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
2663        const float* positions, const SkPaint* paint) {
2664    if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint)) {
2665        return DrawGlInfo::kStatusDone;
2666    }
2667
2668    // NOTE: Skia does not support perspective transform on drawPosText yet
2669    if (!currentTransform()->isSimple()) {
2670        return DrawGlInfo::kStatusDone;
2671    }
2672
2673    mCaches.enableScissor();
2674
2675    float x = 0.0f;
2676    float y = 0.0f;
2677    const bool pureTranslate = currentTransform()->isPureTranslate();
2678    if (pureTranslate) {
2679        x = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f);
2680        y = (int) floorf(y + currentTransform()->getTranslateY() + 0.5f);
2681    }
2682
2683    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
2684    fontRenderer.setFont(paint, SkMatrix::I());
2685
2686    int alpha;
2687    SkXfermode::Mode mode;
2688    getAlphaAndMode(paint, &alpha, &mode);
2689
2690    if (CC_UNLIKELY(hasTextShadow(paint))) {
2691        drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
2692                alpha, 0.0f, 0.0f);
2693    }
2694
2695    // Pick the appropriate texture filtering
2696    bool linearFilter = currentTransform()->changesBounds();
2697    if (pureTranslate && !linearFilter) {
2698        linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f;
2699    }
2700    fontRenderer.setTextureFiltering(linearFilter);
2701
2702    const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip();
2703    Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2704
2705    const bool hasActiveLayer = hasLayer();
2706
2707    TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
2708    if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
2709            positions, hasActiveLayer ? &bounds : NULL, &functor)) {
2710        if (hasActiveLayer) {
2711            if (!pureTranslate) {
2712                currentTransform()->mapRect(bounds);
2713            }
2714            dirtyLayerUnchecked(bounds, getRegion());
2715        }
2716    }
2717
2718    return DrawGlInfo::kStatusDrew;
2719}
2720
2721bool OpenGLRenderer::findBestFontTransform(const mat4& transform, SkMatrix* outMatrix) const {
2722    if (CC_LIKELY(transform.isPureTranslate())) {
2723        outMatrix->setIdentity();
2724        return false;
2725    } else if (CC_UNLIKELY(transform.isPerspective())) {
2726        outMatrix->setIdentity();
2727        return true;
2728    }
2729
2730    /**
2731     * Input is a non-perspective, scaling transform. Generate a scale-only transform,
2732     * with values rounded to the nearest int.
2733     */
2734    float sx, sy;
2735    transform.decomposeScale(sx, sy);
2736    outMatrix->setScale(
2737            roundf(fmaxf(1.0f, sx)),
2738            roundf(fmaxf(1.0f, sy)));
2739    return true;
2740}
2741
2742status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float x, float y,
2743        const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
2744        DrawOpMode drawOpMode) {
2745
2746    if (drawOpMode == kDrawOpMode_Immediate) {
2747        // The checks for corner-case ignorable text and quick rejection is only done for immediate
2748        // drawing as ops from DeferredDisplayList are already filtered for these
2749        if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint) ||
2750                quickRejectSetupScissor(bounds)) {
2751            return DrawGlInfo::kStatusDone;
2752        }
2753    }
2754
2755    const float oldX = x;
2756    const float oldY = y;
2757
2758    const mat4& transform = *currentTransform();
2759    const bool pureTranslate = transform.isPureTranslate();
2760
2761    if (CC_LIKELY(pureTranslate)) {
2762        x = (int) floorf(x + transform.getTranslateX() + 0.5f);
2763        y = (int) floorf(y + transform.getTranslateY() + 0.5f);
2764    }
2765
2766    int alpha;
2767    SkXfermode::Mode mode;
2768    getAlphaAndMode(paint, &alpha, &mode);
2769
2770    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
2771
2772    if (CC_UNLIKELY(hasTextShadow(paint))) {
2773        fontRenderer.setFont(paint, SkMatrix::I());
2774        drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
2775                alpha, oldX, oldY);
2776    }
2777
2778    const bool hasActiveLayer = hasLayer();
2779
2780    // We only pass a partial transform to the font renderer. That partial
2781    // matrix defines how glyphs are rasterized. Typically we want glyphs
2782    // to be rasterized at their final size on screen, which means the partial
2783    // matrix needs to take the scale factor into account.
2784    // When a partial matrix is used to transform glyphs during rasterization,
2785    // the mesh is generated with the inverse transform (in the case of scale,
2786    // the mesh is generated at 1.0 / scale for instance.) This allows us to
2787    // apply the full transform matrix at draw time in the vertex shader.
2788    // Applying the full matrix in the shader is the easiest way to handle
2789    // rotation and perspective and allows us to always generated quads in the
2790    // font renderer which greatly simplifies the code, clipping in particular.
2791    SkMatrix fontTransform;
2792    bool linearFilter = findBestFontTransform(transform, &fontTransform)
2793            || fabs(y - (int) y) > 0.0f
2794            || fabs(x - (int) x) > 0.0f;
2795    fontRenderer.setFont(paint, fontTransform);
2796    fontRenderer.setTextureFiltering(linearFilter);
2797
2798    // TODO: Implement better clipping for scaled/rotated text
2799    const Rect* clip = !pureTranslate ? NULL : currentClipRect();
2800    Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2801
2802    bool status;
2803    TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
2804
2805    // don't call issuedrawcommand, do it at end of batch
2806    bool forceFinish = (drawOpMode != kDrawOpMode_Defer);
2807    if (CC_UNLIKELY(paint->getTextAlign() != SkPaint::kLeft_Align)) {
2808        SkPaint paintCopy(*paint);
2809        paintCopy.setTextAlign(SkPaint::kLeft_Align);
2810        status = fontRenderer.renderPosText(&paintCopy, clip, text, 0, bytesCount, count, x, y,
2811                positions, hasActiveLayer ? &layerBounds : NULL, &functor, forceFinish);
2812    } else {
2813        status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
2814                positions, hasActiveLayer ? &layerBounds : NULL, &functor, forceFinish);
2815    }
2816
2817    if ((status || drawOpMode != kDrawOpMode_Immediate) && hasActiveLayer) {
2818        if (!pureTranslate) {
2819            transform.mapRect(layerBounds);
2820        }
2821        dirtyLayerUnchecked(layerBounds, getRegion());
2822    }
2823
2824    drawTextDecorations(totalAdvance, oldX, oldY, paint);
2825
2826    return DrawGlInfo::kStatusDrew;
2827}
2828
2829status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
2830        const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) {
2831    if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint)) {
2832        return DrawGlInfo::kStatusDone;
2833    }
2834
2835    // TODO: avoid scissor by calculating maximum bounds using path bounds + font metrics
2836    mCaches.enableScissor();
2837
2838    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
2839    fontRenderer.setFont(paint, SkMatrix::I());
2840    fontRenderer.setTextureFiltering(true);
2841
2842    int alpha;
2843    SkXfermode::Mode mode;
2844    getAlphaAndMode(paint, &alpha, &mode);
2845    TextSetupFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint);
2846
2847    const Rect* clip = &mSnapshot->getLocalClip();
2848    Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2849
2850    const bool hasActiveLayer = hasLayer();
2851
2852    if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path,
2853            hOffset, vOffset, hasActiveLayer ? &bounds : NULL, &functor)) {
2854        if (hasActiveLayer) {
2855            currentTransform()->mapRect(bounds);
2856            dirtyLayerUnchecked(bounds, getRegion());
2857        }
2858    }
2859
2860    return DrawGlInfo::kStatusDrew;
2861}
2862
2863status_t OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
2864    if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
2865
2866    mCaches.activeTexture(0);
2867
2868    const PathTexture* texture = mCaches.pathCache.get(path, paint);
2869    if (!texture) return DrawGlInfo::kStatusDone;
2870    const AutoTexture autoCleanup(texture);
2871
2872    const float x = texture->left - texture->offset;
2873    const float y = texture->top - texture->offset;
2874
2875    drawPathTexture(texture, x, y, paint);
2876
2877    return DrawGlInfo::kStatusDrew;
2878}
2879
2880status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
2881    if (!layer) {
2882        return DrawGlInfo::kStatusDone;
2883    }
2884
2885    mat4* transform = NULL;
2886    if (layer->isTextureLayer()) {
2887        transform = &layer->getTransform();
2888        if (!transform->isIdentity()) {
2889            save(SkCanvas::kMatrix_SaveFlag);
2890            concatMatrix(*transform);
2891        }
2892    }
2893
2894    bool clipRequired = false;
2895    const bool rejected = calculateQuickRejectForScissor(x, y,
2896            x + layer->layer.getWidth(), y + layer->layer.getHeight(), &clipRequired, NULL, false);
2897
2898    if (rejected) {
2899        if (transform && !transform->isIdentity()) {
2900            restore();
2901        }
2902        return DrawGlInfo::kStatusDone;
2903    }
2904
2905    EVENT_LOGD("drawLayer," RECT_STRING ", clipRequired %d", x, y,
2906            x + layer->layer.getWidth(), y + layer->layer.getHeight(), clipRequired);
2907
2908    updateLayer(layer, true);
2909
2910    mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
2911    mCaches.activeTexture(0);
2912
2913    if (CC_LIKELY(!layer->region.isEmpty())) {
2914        if (layer->region.isRect()) {
2915            DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
2916                    composeLayerRect(layer, layer->regionRect));
2917        } else if (layer->mesh) {
2918
2919            const float a = getLayerAlpha(layer);
2920            setupDraw();
2921            setupDrawWithTexture();
2922            setupDrawColor(a, a, a, a);
2923            setupDrawColorFilter(layer->getColorFilter());
2924            setupDrawBlending(layer);
2925            setupDrawProgram();
2926            setupDrawPureColorUniforms();
2927            setupDrawColorFilterUniforms(layer->getColorFilter());
2928            setupDrawTexture(layer->getTexture());
2929            if (CC_LIKELY(currentTransform()->isPureTranslate())) {
2930                int tx = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f);
2931                int ty = (int) floorf(y + currentTransform()->getTranslateY() + 0.5f);
2932
2933                layer->setFilter(GL_NEAREST);
2934                setupDrawModelView(kModelViewMode_Translate, false, tx, ty,
2935                        tx + layer->layer.getWidth(), ty + layer->layer.getHeight(), true);
2936            } else {
2937                layer->setFilter(GL_LINEAR);
2938                setupDrawModelView(kModelViewMode_Translate, false, x, y,
2939                        x + layer->layer.getWidth(), y + layer->layer.getHeight());
2940            }
2941
2942            TextureVertex* mesh = &layer->mesh[0];
2943            GLsizei elementsCount = layer->meshElementCount;
2944
2945            while (elementsCount > 0) {
2946                GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6);
2947
2948                setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
2949                DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
2950                        glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, NULL));
2951
2952                elementsCount -= drawCount;
2953                // Though there are 4 vertices in a quad, we use 6 indices per
2954                // quad to draw with GL_TRIANGLES
2955                mesh += (drawCount / 6) * 4;
2956            }
2957
2958#if DEBUG_LAYERS_AS_REGIONS
2959            drawRegionRectsDebug(layer->region);
2960#endif
2961        }
2962
2963        if (layer->debugDrawUpdate) {
2964            layer->debugDrawUpdate = false;
2965
2966            SkPaint paint;
2967            paint.setColor(0x7f00ff00);
2968            drawColorRect(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(), &paint);
2969        }
2970    }
2971    layer->hasDrawnSinceUpdate = true;
2972
2973    if (transform && !transform->isIdentity()) {
2974        restore();
2975    }
2976
2977    return DrawGlInfo::kStatusDrew;
2978}
2979
2980///////////////////////////////////////////////////////////////////////////////
2981// Draw filters
2982///////////////////////////////////////////////////////////////////////////////
2983
2984void OpenGLRenderer::resetPaintFilter() {
2985    // when clearing the PaintFilter, the masks should also be cleared for simple DrawModifier
2986    // comparison, see MergingDrawBatch::canMergeWith
2987    mDrawModifiers.mHasDrawFilter = false;
2988    mDrawModifiers.mPaintFilterClearBits = 0;
2989    mDrawModifiers.mPaintFilterSetBits = 0;
2990}
2991
2992void OpenGLRenderer::setupPaintFilter(int clearBits, int setBits) {
2993    // TODO: don't bother with boolean, it's redundant with clear/set bits
2994    mDrawModifiers.mHasDrawFilter = true;
2995    mDrawModifiers.mPaintFilterClearBits = clearBits & SkPaint::kAllFlags;
2996    mDrawModifiers.mPaintFilterSetBits = setBits & SkPaint::kAllFlags;
2997}
2998
2999const SkPaint* OpenGLRenderer::filterPaint(const SkPaint* paint) {
3000    // TODO: use CompatFlagsDrawFilter here, and combine logic with android/graphics/DrawFilter.cpp
3001    // to avoid clobbering 0x02 paint flag
3002
3003    // Equivalent to the Java Paint's FILTER_BITMAP_FLAG.
3004    static const uint32_t sFilterBitmapFlag = 0x02;
3005
3006    if (CC_LIKELY(!mDrawModifiers.mHasDrawFilter || !paint)) {
3007        return paint;
3008    }
3009
3010    const uint32_t clearBits = mDrawModifiers.mPaintFilterClearBits;
3011    const uint32_t setBits = mDrawModifiers.mPaintFilterSetBits;
3012
3013    const uint32_t flags = (paint->getFlags() & ~clearBits) | setBits;
3014    mFilteredPaint = *paint;
3015    mFilteredPaint.setFlags(flags);
3016
3017    // check if paint filter trying to override bitmap filter
3018    if ((clearBits | setBits) & sFilterBitmapFlag) {
3019        mFilteredPaint.setFilterLevel(flags & sFilterBitmapFlag
3020                ? SkPaint::kLow_FilterLevel : SkPaint::kNone_FilterLevel);
3021    }
3022
3023    return &mFilteredPaint;
3024}
3025
3026///////////////////////////////////////////////////////////////////////////////
3027// Drawing implementation
3028///////////////////////////////////////////////////////////////////////////////
3029
3030Texture* OpenGLRenderer::getTexture(const SkBitmap* bitmap) {
3031    Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap);
3032    if (!texture) {
3033        return mCaches.textureCache.get(bitmap);
3034    }
3035    return texture;
3036}
3037
3038void OpenGLRenderer::drawPathTexture(const PathTexture* texture,
3039        float x, float y, const SkPaint* paint) {
3040    if (quickRejectSetupScissor(x, y, x + texture->width, y + texture->height)) {
3041        return;
3042    }
3043
3044    int alpha;
3045    SkXfermode::Mode mode;
3046    getAlphaAndMode(paint, &alpha, &mode);
3047
3048    setupDraw();
3049    setupDrawWithTexture(true);
3050    setupDrawAlpha8Color(paint->getColor(), alpha);
3051    setupDrawColorFilter(getColorFilter(paint));
3052    setupDrawShader(getShader(paint));
3053    setupDrawBlending(paint, true);
3054    setupDrawProgram();
3055    setupDrawModelView(kModelViewMode_TranslateAndScale, false,
3056            x, y, x + texture->width, y + texture->height);
3057    setupDrawTexture(texture->id);
3058    setupDrawPureColorUniforms();
3059    setupDrawColorFilterUniforms(getColorFilter(paint));
3060    setupDrawShaderUniforms(getShader(paint));
3061    setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
3062
3063    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
3064}
3065
3066// Same values used by Skia
3067#define kStdStrikeThru_Offset   (-6.0f / 21.0f)
3068#define kStdUnderline_Offset    (1.0f / 9.0f)
3069#define kStdUnderline_Thickness (1.0f / 18.0f)
3070
3071void OpenGLRenderer::drawTextDecorations(float underlineWidth, float x, float y,
3072        const SkPaint* paint) {
3073    // Handle underline and strike-through
3074    uint32_t flags = paint->getFlags();
3075    if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
3076        SkPaint paintCopy(*paint);
3077
3078        if (CC_LIKELY(underlineWidth > 0.0f)) {
3079            const float textSize = paintCopy.getTextSize();
3080            const float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
3081
3082            const float left = x;
3083            float top = 0.0f;
3084
3085            int linesCount = 0;
3086            if (flags & SkPaint::kUnderlineText_Flag) linesCount++;
3087            if (flags & SkPaint::kStrikeThruText_Flag) linesCount++;
3088
3089            const int pointsCount = 4 * linesCount;
3090            float points[pointsCount];
3091            int currentPoint = 0;
3092
3093            if (flags & SkPaint::kUnderlineText_Flag) {
3094                top = y + textSize * kStdUnderline_Offset;
3095                points[currentPoint++] = left;
3096                points[currentPoint++] = top;
3097                points[currentPoint++] = left + underlineWidth;
3098                points[currentPoint++] = top;
3099            }
3100
3101            if (flags & SkPaint::kStrikeThruText_Flag) {
3102                top = y + textSize * kStdStrikeThru_Offset;
3103                points[currentPoint++] = left;
3104                points[currentPoint++] = top;
3105                points[currentPoint++] = left + underlineWidth;
3106                points[currentPoint++] = top;
3107            }
3108
3109            paintCopy.setStrokeWidth(strokeWidth);
3110
3111            drawLines(&points[0], pointsCount, &paintCopy);
3112        }
3113    }
3114}
3115
3116status_t OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
3117    if (currentSnapshot()->isIgnored()) {
3118        return DrawGlInfo::kStatusDone;
3119    }
3120
3121    return drawColorRects(rects, count, paint, false, true, true);
3122}
3123
3124static void mapPointFakeZ(Vector3& point, const mat4& transformXY, const mat4& transformZ) {
3125    // map z coordinate with true 3d matrix
3126    point.z = transformZ.mapZ(point);
3127
3128    // map x,y coordinates with draw/Skia matrix
3129    transformXY.mapPoint(point.x, point.y);
3130}
3131
3132status_t OpenGLRenderer::drawShadow(float casterAlpha,
3133        const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) {
3134    if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
3135
3136    // TODO: use quickRejectWithScissor. For now, always force enable scissor.
3137    mCaches.enableScissor();
3138
3139    SkPaint paint;
3140    paint.setAntiAlias(true); // want to use AlphaVertex
3141
3142    // The caller has made sure casterAlpha > 0.
3143    float ambientShadowAlpha = mAmbientShadowAlpha;
3144    if (CC_UNLIKELY(mCaches.propertyAmbientShadowStrength >= 0)) {
3145        ambientShadowAlpha = mCaches.propertyAmbientShadowStrength;
3146    }
3147    if (ambientShadowVertexBuffer && ambientShadowAlpha > 0) {
3148        paint.setARGB(casterAlpha * ambientShadowAlpha, 0, 0, 0);
3149        drawVertexBuffer(*ambientShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp);
3150    }
3151
3152    float spotShadowAlpha = mSpotShadowAlpha;
3153    if (CC_UNLIKELY(mCaches.propertySpotShadowStrength >= 0)) {
3154        spotShadowAlpha = mCaches.propertySpotShadowStrength;
3155    }
3156    if (spotShadowVertexBuffer && spotShadowAlpha > 0) {
3157        paint.setARGB(casterAlpha * spotShadowAlpha, 0, 0, 0);
3158        drawVertexBuffer(*spotShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp);
3159    }
3160
3161    return DrawGlInfo::kStatusDrew;
3162}
3163
3164status_t OpenGLRenderer::drawColorRects(const float* rects, int count, const SkPaint* paint,
3165        bool ignoreTransform, bool dirty, bool clip) {
3166    if (count == 0) {
3167        return DrawGlInfo::kStatusDone;
3168    }
3169
3170    int color = paint->getColor();
3171    // If a shader is set, preserve only the alpha
3172    if (getShader(paint)) {
3173        color |= 0x00ffffff;
3174    }
3175
3176    float left = FLT_MAX;
3177    float top = FLT_MAX;
3178    float right = FLT_MIN;
3179    float bottom = FLT_MIN;
3180
3181    Vertex mesh[count];
3182    Vertex* vertex = mesh;
3183
3184    for (int index = 0; index < count; index += 4) {
3185        float l = rects[index + 0];
3186        float t = rects[index + 1];
3187        float r = rects[index + 2];
3188        float b = rects[index + 3];
3189
3190        Vertex::set(vertex++, l, t);
3191        Vertex::set(vertex++, r, t);
3192        Vertex::set(vertex++, l, b);
3193        Vertex::set(vertex++, r, b);
3194
3195        left = fminf(left, l);
3196        top = fminf(top, t);
3197        right = fmaxf(right, r);
3198        bottom = fmaxf(bottom, b);
3199    }
3200
3201    if (clip && quickRejectSetupScissor(left, top, right, bottom)) {
3202        return DrawGlInfo::kStatusDone;
3203    }
3204
3205    setupDraw();
3206    setupDrawNoTexture();
3207    setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
3208    setupDrawShader(getShader(paint));
3209    setupDrawColorFilter(getColorFilter(paint));
3210    setupDrawBlending(paint);
3211    setupDrawProgram();
3212    setupDrawDirtyRegionsDisabled();
3213    setupDrawModelView(kModelViewMode_Translate, false,
3214            0.0f, 0.0f, 0.0f, 0.0f, ignoreTransform);
3215    setupDrawColorUniforms(getShader(paint));
3216    setupDrawShaderUniforms(getShader(paint));
3217    setupDrawColorFilterUniforms(getColorFilter(paint));
3218
3219    if (dirty && hasLayer()) {
3220        dirtyLayer(left, top, right, bottom, *currentTransform());
3221    }
3222
3223    issueIndexedQuadDraw(&mesh[0], count / 4);
3224
3225    return DrawGlInfo::kStatusDrew;
3226}
3227
3228void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
3229        const SkPaint* paint, bool ignoreTransform) {
3230    int color = paint->getColor();
3231    // If a shader is set, preserve only the alpha
3232    if (getShader(paint)) {
3233        color |= 0x00ffffff;
3234    }
3235
3236    setupDraw();
3237    setupDrawNoTexture();
3238    setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
3239    setupDrawShader(getShader(paint));
3240    setupDrawColorFilter(getColorFilter(paint));
3241    setupDrawBlending(paint);
3242    setupDrawProgram();
3243    setupDrawModelView(kModelViewMode_TranslateAndScale, false,
3244            left, top, right, bottom, ignoreTransform);
3245    setupDrawColorUniforms(getShader(paint));
3246    setupDrawShaderUniforms(getShader(paint), ignoreTransform);
3247    setupDrawColorFilterUniforms(getColorFilter(paint));
3248    setupDrawSimpleMesh();
3249
3250    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
3251}
3252
3253void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
3254        Texture* texture, const SkPaint* paint) {
3255    texture->setWrap(GL_CLAMP_TO_EDGE, true);
3256
3257    GLvoid* vertices = (GLvoid*) NULL;
3258    GLvoid* texCoords = (GLvoid*) gMeshTextureOffset;
3259
3260    if (texture->uvMapper) {
3261        vertices = &mMeshVertices[0].x;
3262        texCoords = &mMeshVertices[0].u;
3263
3264        Rect uvs(0.0f, 0.0f, 1.0f, 1.0f);
3265        texture->uvMapper->map(uvs);
3266
3267        resetDrawTextureTexCoords(uvs.left, uvs.top, uvs.right, uvs.bottom);
3268    }
3269
3270    if (CC_LIKELY(currentTransform()->isPureTranslate())) {
3271        const float x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f);
3272        const float y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f);
3273
3274        texture->setFilter(GL_NEAREST, true);
3275        drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
3276                paint, texture->blend, vertices, texCoords,
3277                GL_TRIANGLE_STRIP, gMeshCount, false, true);
3278    } else {
3279        texture->setFilter(getFilter(paint), true);
3280        drawTextureMesh(left, top, right, bottom, texture->id, paint,
3281                texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, gMeshCount);
3282    }
3283
3284    if (texture->uvMapper) {
3285        resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
3286    }
3287}
3288
3289void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
3290        GLuint texture, const SkPaint* paint, bool blend,
3291        GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
3292        bool swapSrcDst, bool ignoreTransform, GLuint vbo,
3293        ModelViewMode modelViewMode, bool dirty) {
3294
3295    int a;
3296    SkXfermode::Mode mode;
3297    getAlphaAndMode(paint, &a, &mode);
3298    const float alpha = a / 255.0f;
3299
3300    setupDraw();
3301    setupDrawWithTexture();
3302    setupDrawColor(alpha, alpha, alpha, alpha);
3303    setupDrawColorFilter(getColorFilter(paint));
3304    setupDrawBlending(paint, blend, swapSrcDst);
3305    setupDrawProgram();
3306    if (!dirty) setupDrawDirtyRegionsDisabled();
3307    setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
3308    setupDrawTexture(texture);
3309    setupDrawPureColorUniforms();
3310    setupDrawColorFilterUniforms(getColorFilter(paint));
3311    setupDrawMesh(vertices, texCoords, vbo);
3312
3313    glDrawArrays(drawMode, 0, elementsCount);
3314}
3315
3316void OpenGLRenderer::drawIndexedTextureMesh(float left, float top, float right, float bottom,
3317        GLuint texture, const SkPaint* paint, bool blend,
3318        GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
3319        bool swapSrcDst, bool ignoreTransform, GLuint vbo,
3320        ModelViewMode modelViewMode, bool dirty) {
3321
3322    int a;
3323    SkXfermode::Mode mode;
3324    getAlphaAndMode(paint, &a, &mode);
3325    const float alpha = a / 255.0f;
3326
3327    setupDraw();
3328    setupDrawWithTexture();
3329    setupDrawColor(alpha, alpha, alpha, alpha);
3330    setupDrawColorFilter(getColorFilter(paint));
3331    setupDrawBlending(paint, blend, swapSrcDst);
3332    setupDrawProgram();
3333    if (!dirty) setupDrawDirtyRegionsDisabled();
3334    setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
3335    setupDrawTexture(texture);
3336    setupDrawPureColorUniforms();
3337    setupDrawColorFilterUniforms(getColorFilter(paint));
3338    setupDrawMeshIndices(vertices, texCoords, vbo);
3339
3340    glDrawElements(drawMode, elementsCount, GL_UNSIGNED_SHORT, NULL);
3341}
3342
3343void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom,
3344        GLuint texture, const SkPaint* paint,
3345        GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
3346        bool ignoreTransform, ModelViewMode modelViewMode, bool dirty) {
3347
3348    int color = paint != NULL ? paint->getColor() : 0;
3349    int alpha;
3350    SkXfermode::Mode mode;
3351    getAlphaAndMode(paint, &alpha, &mode);
3352
3353    setupDraw();
3354    setupDrawWithTexture(true);
3355    if (paint != NULL) {
3356        setupDrawAlpha8Color(color, alpha);
3357    }
3358    setupDrawColorFilter(getColorFilter(paint));
3359    setupDrawShader(getShader(paint));
3360    setupDrawBlending(paint, true);
3361    setupDrawProgram();
3362    if (!dirty) setupDrawDirtyRegionsDisabled();
3363    setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
3364    setupDrawTexture(texture);
3365    setupDrawPureColorUniforms();
3366    setupDrawColorFilterUniforms(getColorFilter(paint));
3367    setupDrawShaderUniforms(getShader(paint), ignoreTransform);
3368    setupDrawMesh(vertices, texCoords);
3369
3370    glDrawArrays(drawMode, 0, elementsCount);
3371}
3372
3373void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
3374        ProgramDescription& description, bool swapSrcDst) {
3375
3376    if (mSnapshot->roundRectClipState != NULL /*&& !mSkipOutlineClip*/) {
3377        blend = true;
3378        mDescription.hasRoundRectClip = true;
3379    }
3380    mSkipOutlineClip = true;
3381
3382    blend = blend || mode != SkXfermode::kSrcOver_Mode;
3383
3384    if (blend) {
3385        // These blend modes are not supported by OpenGL directly and have
3386        // to be implemented using shaders. Since the shader will perform
3387        // the blending, turn blending off here
3388        // If the blend mode cannot be implemented using shaders, fall
3389        // back to the default SrcOver blend mode instead
3390        if (CC_UNLIKELY(mode > SkXfermode::kScreen_Mode)) {
3391            if (CC_UNLIKELY(mExtensions.hasFramebufferFetch())) {
3392                description.framebufferMode = mode;
3393                description.swapSrcDst = swapSrcDst;
3394
3395                if (mCaches.blend) {
3396                    glDisable(GL_BLEND);
3397                    mCaches.blend = false;
3398                }
3399
3400                return;
3401            } else {
3402                mode = SkXfermode::kSrcOver_Mode;
3403            }
3404        }
3405
3406        if (!mCaches.blend) {
3407            glEnable(GL_BLEND);
3408        }
3409
3410        GLenum sourceMode = swapSrcDst ? gBlendsSwap[mode].src : gBlends[mode].src;
3411        GLenum destMode = swapSrcDst ? gBlendsSwap[mode].dst : gBlends[mode].dst;
3412
3413        if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) {
3414            glBlendFunc(sourceMode, destMode);
3415            mCaches.lastSrcMode = sourceMode;
3416            mCaches.lastDstMode = destMode;
3417        }
3418    } else if (mCaches.blend) {
3419        glDisable(GL_BLEND);
3420    }
3421    mCaches.blend = blend;
3422}
3423
3424bool OpenGLRenderer::useProgram(Program* program) {
3425    if (!program->isInUse()) {
3426        if (mCaches.currentProgram != NULL) mCaches.currentProgram->remove();
3427        program->use();
3428        mCaches.currentProgram = program;
3429        return false;
3430    }
3431    return true;
3432}
3433
3434void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
3435    TextureVertex* v = &mMeshVertices[0];
3436    TextureVertex::setUV(v++, u1, v1);
3437    TextureVertex::setUV(v++, u2, v1);
3438    TextureVertex::setUV(v++, u1, v2);
3439    TextureVertex::setUV(v++, u2, v2);
3440}
3441
3442void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) const {
3443    getAlphaAndModeDirect(paint, alpha,  mode);
3444    if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
3445        // if drawing a layer, ignore the paint's alpha
3446        *alpha = mDrawModifiers.mOverrideLayerAlpha * 255;
3447    }
3448    *alpha *= currentSnapshot()->alpha;
3449}
3450
3451float OpenGLRenderer::getLayerAlpha(const Layer* layer) const {
3452    float alpha;
3453    if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
3454        alpha = mDrawModifiers.mOverrideLayerAlpha;
3455    } else {
3456        alpha = layer->getAlpha() / 255.0f;
3457    }
3458    return alpha * currentSnapshot()->alpha;
3459}
3460
3461}; // namespace uirenderer
3462}; // namespace android
3463