blob: c40258bd5bddfa6aa4a61524a1177526125bfad3 [file] [log] [blame]
Romain Guye4d01122010-06-16 18:44:05 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Romain Guy85bf02f2010-06-22 13:11:24 -070017#define LOG_TAG "OpenGLRenderer"
Romain Guye4d01122010-06-16 18:44:05 -070018
19#include <stdlib.h>
20#include <stdint.h>
21#include <sys/types.h>
22
Romain Guy5cbbce52010-06-27 22:59:20 -070023#include <SkCanvas.h>
Chris Craik98d608d2014-07-17 12:25:11 -070024#include <SkColor.h>
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -040025#include <SkShader.h>
Romain Guy694b5192010-07-21 21:33:20 -070026#include <SkTypeface.h>
Romain Guy5cbbce52010-06-27 22:59:20 -070027
Romain Guye4d01122010-06-16 18:44:05 -070028#include <utils/Log.h>
Romain Guye2d345e2010-09-24 18:39:22 -070029#include <utils/StopWatch.h>
Romain Guye4d01122010-06-16 18:44:05 -070030
Romain Guy08aa2cb2011-03-17 11:06:57 -070031#include <private/hwui/DrawGlInfo.h>
32
Romain Guy5b3b3522010-10-27 18:57:51 -070033#include <ui/Rect.h>
34
Romain Guy85bf02f2010-06-22 13:11:24 -070035#include "OpenGLRenderer.h"
Chris Craikc3566d02013-02-04 16:16:33 -080036#include "DeferredDisplayList.h"
Romain Guy0fe478e2010-11-08 12:08:41 -080037#include "DisplayListRenderer.h"
Romain Guy40543602013-06-12 15:31:28 -070038#include "Fence.h"
Tom Hudson2dc236b2014-10-15 15:46:42 -040039#include "GammaFontRenderer.h"
40#include "Patch.h"
Chris Craik65cd6122012-12-10 17:56:27 -080041#include "PathTessellator.h"
Romain Guy87e2f7572012-09-24 11:37:12 -070042#include "Properties.h"
Tom Hudson2dc236b2014-10-15 15:46:42 -040043#include "RenderNode.h"
44#include "RenderState.h"
ztenghui55bfb4e2013-12-03 10:38:55 -080045#include "ShadowTessellator.h"
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -040046#include "SkiaShader.h"
Romain Guya957eea2010-12-08 18:34:42 -080047#include "Vector.h"
ztenghui55bfb4e2013-12-03 10:38:55 -080048#include "VertexBuffer.h"
Tom Hudson2dc236b2014-10-15 15:46:42 -040049#include "utils/GLUtils.h"
Romain Guye4d01122010-06-16 18:44:05 -070050
Chris Craik62d307c2014-07-29 10:35:13 -070051#if DEBUG_DETAILED_EVENTS
52 #define EVENT_LOGD(...) eventMarkDEBUG(__VA_ARGS__)
53#else
54 #define EVENT_LOGD(...)
55#endif
56
Chris Craika8bea8e2014-09-24 11:29:43 -070057static void atraceFormatBegin(const char* fmt, ...) {
58 const int BUFFER_SIZE = 256;
59 va_list ap;
60 char buf[BUFFER_SIZE];
61
62 va_start(ap, fmt);
63 vsnprintf(buf, BUFFER_SIZE, fmt, ap);
64 va_end(ap);
65
66 ATRACE_BEGIN(buf);
67}
68
69#define ATRACE_FORMAT_BEGIN(fmt, ...) \
70 if (CC_UNLIKELY(ATRACE_ENABLED())) atraceFormatBegin(fmt, ##__VA_ARGS__)
71
Romain Guye4d01122010-06-16 18:44:05 -070072namespace android {
Romain Guy9d5316e2010-06-24 19:30:36 -070073namespace uirenderer {
74
Chris Craik678625242014-02-28 12:26:34 -080075static GLenum getFilter(const SkPaint* paint) {
76 if (!paint || paint->getFilterLevel() != SkPaint::kNone_FilterLevel) {
77 return GL_LINEAR;
78 }
79 return GL_NEAREST;
80}
Romain Guyd21b6e12011-11-30 20:21:23 -080081
Romain Guy9d5316e2010-06-24 19:30:36 -070082///////////////////////////////////////////////////////////////////////////////
83// Globals
84///////////////////////////////////////////////////////////////////////////////
85
Romain Guy889f8d12010-07-29 14:37:42 -070086/**
87 * Structure mapping Skia xfermodes to OpenGL blending factors.
88 */
89struct Blender {
90 SkXfermode::Mode mode;
91 GLenum src;
92 GLenum dst;
93}; // struct Blender
94
Romain Guy026c5e162010-06-28 17:12:22 -070095// In this array, the index of each Blender equals the value of the first
96// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
97static const Blender gBlends[] = {
Romain Guy2ffefd42011-09-08 15:33:03 -070098 { SkXfermode::kClear_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
99 { SkXfermode::kSrc_Mode, GL_ONE, GL_ZERO },
100 { SkXfermode::kDst_Mode, GL_ZERO, GL_ONE },
101 { SkXfermode::kSrcOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA },
102 { SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE },
103 { SkXfermode::kSrcIn_Mode, GL_DST_ALPHA, GL_ZERO },
104 { SkXfermode::kDstIn_Mode, GL_ZERO, GL_SRC_ALPHA },
105 { SkXfermode::kSrcOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
106 { SkXfermode::kDstOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
107 { SkXfermode::kSrcATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
108 { SkXfermode::kDstATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
109 { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
110 { SkXfermode::kPlus_Mode, GL_ONE, GL_ONE },
Derek Sollenbergerd81ec452013-02-04 15:42:26 -0500111 { SkXfermode::kModulate_Mode, GL_ZERO, GL_SRC_COLOR },
Romain Guy2ffefd42011-09-08 15:33:03 -0700112 { SkXfermode::kScreen_Mode, GL_ONE, GL_ONE_MINUS_SRC_COLOR }
Romain Guy026c5e162010-06-28 17:12:22 -0700113};
Romain Guye4d01122010-06-16 18:44:05 -0700114
Romain Guy87a76572010-09-13 18:11:21 -0700115// This array contains the swapped version of each SkXfermode. For instance
116// this array's SrcOver blending mode is actually DstOver. You can refer to
117// createLayer() for more information on the purpose of this array.
Romain Guyf607bdc2010-09-10 19:20:06 -0700118static const Blender gBlendsSwap[] = {
Romain Guy2ffefd42011-09-08 15:33:03 -0700119 { SkXfermode::kClear_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
120 { SkXfermode::kSrc_Mode, GL_ZERO, GL_ONE },
121 { SkXfermode::kDst_Mode, GL_ONE, GL_ZERO },
122 { SkXfermode::kSrcOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE },
123 { SkXfermode::kDstOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA },
124 { SkXfermode::kSrcIn_Mode, GL_ZERO, GL_SRC_ALPHA },
125 { SkXfermode::kDstIn_Mode, GL_DST_ALPHA, GL_ZERO },
126 { SkXfermode::kSrcOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
127 { SkXfermode::kDstOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
128 { SkXfermode::kSrcATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
129 { SkXfermode::kDstATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
130 { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
131 { SkXfermode::kPlus_Mode, GL_ONE, GL_ONE },
Derek Sollenbergerd81ec452013-02-04 15:42:26 -0500132 { SkXfermode::kModulate_Mode, GL_DST_COLOR, GL_ZERO },
Romain Guy2ffefd42011-09-08 15:33:03 -0700133 { SkXfermode::kScreen_Mode, GL_ONE_MINUS_DST_COLOR, GL_ONE }
Romain Guyf607bdc2010-09-10 19:20:06 -0700134};
135
Romain Guyf6a11b82010-06-23 17:47:49 -0700136///////////////////////////////////////////////////////////////////////////////
Romain Guy448455f2013-07-22 13:57:50 -0700137// Functions
138///////////////////////////////////////////////////////////////////////////////
139
140template<typename T>
141static inline T min(T a, T b) {
142 return a < b ? a : b;
143}
144
145///////////////////////////////////////////////////////////////////////////////
Romain Guyf6a11b82010-06-23 17:47:49 -0700146// Constructors/destructor
147///////////////////////////////////////////////////////////////////////////////
148
John Reck3b202512014-06-23 13:13:08 -0700149OpenGLRenderer::OpenGLRenderer(RenderState& renderState)
Chris Craik058fc642014-07-23 18:19:28 -0700150 : mFrameStarted(false)
151 , mCaches(Caches::getInstance())
John Reck3b202512014-06-23 13:13:08 -0700152 , mExtensions(Extensions::getInstance())
Chris Craik058fc642014-07-23 18:19:28 -0700153 , mRenderState(renderState)
154 , mScissorOptimizationDisabled(false)
Chris Craik284b2432014-09-18 16:05:35 -0700155 , mSuppressTiling(false)
156 , mFirstFrameAfterResize(true)
Chris Craik058fc642014-07-23 18:19:28 -0700157 , mCountOverdraw(false)
John Reck1aa5d2d2014-07-24 13:38:28 -0700158 , mLightCenter((Vector3){FLT_MIN, FLT_MIN, FLT_MIN})
Chris Craik058fc642014-07-23 18:19:28 -0700159 , mLightRadius(FLT_MIN)
160 , mAmbientShadowAlpha(0)
161 , mSpotShadowAlpha(0) {
Chris Craik527a3aa2013-03-04 10:19:31 -0800162 // *set* draw modifiers to be 0
163 memset(&mDrawModifiers, 0, sizeof(mDrawModifiers));
Chris Craik16ecda52013-03-29 10:59:59 -0700164 mDrawModifiers.mOverrideLayerAlpha = 1.0f;
Romain Guy026c5e162010-06-28 17:12:22 -0700165
Romain Guyac670c02010-07-27 17:39:27 -0700166 memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
Romain Guye4d01122010-06-16 18:44:05 -0700167}
168
Romain Guy85bf02f2010-06-22 13:11:24 -0700169OpenGLRenderer::~OpenGLRenderer() {
Romain Guy29d89972010-09-22 16:10:57 -0700170 // The context has already been destroyed at this point, do not call
171 // GL APIs. All GL state should be kept in Caches.h
Romain Guye4d01122010-06-16 18:44:05 -0700172}
173
Romain Guy87e2f7572012-09-24 11:37:12 -0700174void OpenGLRenderer::initProperties() {
175 char property[PROPERTY_VALUE_MAX];
176 if (property_get(PROPERTY_DISABLE_SCISSOR_OPTIMIZATION, property, "false")) {
177 mScissorOptimizationDisabled = !strcasecmp(property, "true");
178 INIT_LOGD(" Scissor optimization %s",
179 mScissorOptimizationDisabled ? "disabled" : "enabled");
180 } else {
181 INIT_LOGD(" Scissor optimization enabled");
182 }
Romain Guy13631f32012-01-30 17:41:55 -0800183}
184
Chris Craik058fc642014-07-23 18:19:28 -0700185void OpenGLRenderer::initLight(const Vector3& lightCenter, float lightRadius,
186 uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
187 mLightCenter = lightCenter;
188 mLightRadius = lightRadius;
189 mAmbientShadowAlpha = ambientShadowAlpha;
190 mSpotShadowAlpha = spotShadowAlpha;
191}
192
Romain Guy13631f32012-01-30 17:41:55 -0800193///////////////////////////////////////////////////////////////////////////////
Romain Guyf6a11b82010-06-23 17:47:49 -0700194// Setup
195///////////////////////////////////////////////////////////////////////////////
196
Chris Craik797b95b2014-05-20 18:10:25 -0700197void OpenGLRenderer::onViewportInitialized() {
Romain Guy35643dd2012-09-18 15:40:58 -0700198 glDisable(GL_DITHER);
199 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
200
201 glEnableVertexAttribArray(Program::kBindingPosition);
Chris Craik284b2432014-09-18 16:05:35 -0700202 mFirstFrameAfterResize = true;
Romain Guy35643dd2012-09-18 15:40:58 -0700203}
204
Romain Guy96885eb2013-03-26 15:05:58 -0700205void OpenGLRenderer::setupFrameState(float left, float top,
Romain Guyc3fedaf2013-01-29 17:26:25 -0800206 float right, float bottom, bool opaque) {
Romain Guyfe48f652010-11-11 15:36:56 -0800207 mCaches.clearGarbage();
Chris Craik69e5adf2014-08-14 13:34:01 -0700208 initializeSaveStack(left, top, right, bottom, mLightCenter);
Romain Guy96885eb2013-03-26 15:05:58 -0700209 mOpaque = opaque;
Chris Craik5f803622013-03-21 14:39:04 -0700210 mTilingClip.set(left, top, right, bottom);
Romain Guy96885eb2013-03-26 15:05:58 -0700211}
212
213status_t OpenGLRenderer::startFrame() {
214 if (mFrameStarted) return DrawGlInfo::kStatusDone;
215 mFrameStarted = true;
216
Romain Guy41308e22012-10-22 20:02:43 -0700217 mDirtyClip = true;
Romain Guyddf74372012-05-22 14:07:07 -0700218
Romain Guy96885eb2013-03-26 15:05:58 -0700219 discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom);
Romain Guy11cb6422012-09-21 00:39:43 -0700220
John Reck3b202512014-06-23 13:13:08 -0700221 mRenderState.setViewport(getWidth(), getHeight());
Romain Guy7d7b5492011-01-24 16:33:45 -0800222
Romain Guy54c1a642012-09-27 17:55:46 -0700223 // Functors break the tiling extension in pretty spectacular ways
224 // This ensures we don't use tiling when a functor is going to be
225 // invoked during the frame
Chris Craik284b2432014-09-18 16:05:35 -0700226 mSuppressTiling = mCaches.hasRegisteredFunctors()
227 || mFirstFrameAfterResize;
228 mFirstFrameAfterResize = false;
Romain Guy54c1a642012-09-27 17:55:46 -0700229
Chris Craikd6b65f62014-01-01 14:45:21 -0800230 startTilingCurrentClip(true);
Romain Guy2b7028e2012-09-19 17:25:38 -0700231
Romain Guy7c450aa2012-09-21 19:15:00 -0700232 debugOverdraw(true, true);
233
Romain Guy96885eb2013-03-26 15:05:58 -0700234 return clear(mTilingClip.left, mTilingClip.top,
235 mTilingClip.right, mTilingClip.bottom, mOpaque);
236}
237
Romain Guy96885eb2013-03-26 15:05:58 -0700238status_t OpenGLRenderer::prepareDirty(float left, float top,
239 float right, float bottom, bool opaque) {
Romain Guy78dd96d2013-05-03 14:24:16 -0700240
Romain Guy96885eb2013-03-26 15:05:58 -0700241 setupFrameState(left, top, right, bottom, opaque);
242
243 // Layer renderers will start the frame immediately
244 // The framebuffer renderer will first defer the display list
245 // for each layer and wait until the first drawing command
246 // to start the frame
Chris Craikd6b65f62014-01-01 14:45:21 -0800247 if (currentSnapshot()->fbo == 0) {
Romain Guy96885eb2013-03-26 15:05:58 -0700248 syncState();
249 updateLayers();
250 } else {
251 return startFrame();
252 }
253
254 return DrawGlInfo::kStatusDone;
Romain Guy7c25aab2012-10-18 15:05:02 -0700255}
256
Romain Guydcfc8362013-01-03 13:08:57 -0800257void OpenGLRenderer::discardFramebuffer(float left, float top, float right, float bottom) {
258 // If we know that we are going to redraw the entire framebuffer,
259 // perform a discard to let the driver know we don't need to preserve
260 // the back buffer for this frame.
Romain Guy3bbacf22013-02-06 16:51:04 -0800261 if (mExtensions.hasDiscardFramebuffer() &&
Chris Craik14e51302013-12-30 15:32:54 -0800262 left <= 0.0f && top <= 0.0f && right >= getWidth() && bottom >= getHeight()) {
Romain Guyf1581982013-01-31 17:20:30 -0800263 const bool isFbo = getTargetFbo() == 0;
264 const GLenum attachments[] = {
265 isFbo ? (const GLenum) GL_COLOR_EXT : (const GLenum) GL_COLOR_ATTACHMENT0,
266 isFbo ? (const GLenum) GL_STENCIL_EXT : (const GLenum) GL_STENCIL_ATTACHMENT };
Romain Guydcfc8362013-01-03 13:08:57 -0800267 glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, attachments);
268 }
269}
270
Romain Guy7c25aab2012-10-18 15:05:02 -0700271status_t OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
Romain Guy78dd96d2013-05-03 14:24:16 -0700272 if (!opaque || mCountOverdraw) {
Romain Guy586cae32012-07-13 15:28:31 -0700273 mCaches.enableScissor();
Chris Craika64a2be2014-05-14 14:17:01 -0700274 mCaches.setScissor(left, getViewportHeight() - bottom, right - left, bottom - top);
Romain Guy6b7bd242010-10-06 19:49:23 -0700275 glClear(GL_COLOR_BUFFER_BIT);
Chet Haase44b2fe32012-06-06 19:03:58 -0700276 return DrawGlInfo::kStatusDrew;
Romain Guyddf74372012-05-22 14:07:07 -0700277 }
Chet Haase44b2fe32012-06-06 19:03:58 -0700278
Romain Guy7c25aab2012-10-18 15:05:02 -0700279 mCaches.resetScissor();
Chet Haase44b2fe32012-06-06 19:03:58 -0700280 return DrawGlInfo::kStatusDone;
Romain Guyddf74372012-05-22 14:07:07 -0700281}
282
283void OpenGLRenderer::syncState() {
Romain Guyddf74372012-05-22 14:07:07 -0700284 if (mCaches.blend) {
285 glEnable(GL_BLEND);
286 } else {
287 glDisable(GL_BLEND);
Romain Guy6b7bd242010-10-06 19:49:23 -0700288 }
Romain Guybb9524b2010-06-22 18:56:38 -0700289}
290
henry.uh_chen33f5a592014-07-02 19:36:56 +0800291void OpenGLRenderer::startTilingCurrentClip(bool opaque, bool expand) {
Romain Guy54c1a642012-09-27 17:55:46 -0700292 if (!mSuppressTiling) {
Chris Craikd6b65f62014-01-01 14:45:21 -0800293 const Snapshot* snapshot = currentSnapshot();
294
Chris Craik14e51302013-12-30 15:32:54 -0800295 const Rect* clip = &mTilingClip;
Chris Craikd6b65f62014-01-01 14:45:21 -0800296 if (snapshot->flags & Snapshot::kFlagFboTarget) {
297 clip = &(snapshot->layer->clipRect);
Romain Guy54c1a642012-09-27 17:55:46 -0700298 }
Romain Guy2b7028e2012-09-19 17:25:38 -0700299
henry.uh_chen33f5a592014-07-02 19:36:56 +0800300 startTiling(*clip, getViewportHeight(), opaque, expand);
Romain Guyc3fedaf2013-01-29 17:26:25 -0800301 }
302}
303
henry.uh_chen33f5a592014-07-02 19:36:56 +0800304void OpenGLRenderer::startTiling(const Rect& clip, int windowHeight, bool opaque, bool expand) {
Romain Guyc3fedaf2013-01-29 17:26:25 -0800305 if (!mSuppressTiling) {
henry.uh_chen33f5a592014-07-02 19:36:56 +0800306 if(expand) {
307 // Expand the startTiling region by 1
308 int leftNotZero = (clip.left > 0) ? 1 : 0;
309 int topNotZero = (windowHeight - clip.bottom > 0) ? 1 : 0;
310
311 mCaches.startTiling(
312 clip.left - leftNotZero,
313 windowHeight - clip.bottom - topNotZero,
314 clip.right - clip.left + leftNotZero + 1,
315 clip.bottom - clip.top + topNotZero + 1,
316 opaque);
317 } else {
318 mCaches.startTiling(clip.left, windowHeight - clip.bottom,
Romain Guy52036b12013-02-14 18:03:37 -0800319 clip.right - clip.left, clip.bottom - clip.top, opaque);
henry.uh_chen33f5a592014-07-02 19:36:56 +0800320 }
Romain Guy54c1a642012-09-27 17:55:46 -0700321 }
Romain Guy2b7028e2012-09-19 17:25:38 -0700322}
323
324void OpenGLRenderer::endTiling() {
Romain Guy54c1a642012-09-27 17:55:46 -0700325 if (!mSuppressTiling) mCaches.endTiling();
Romain Guy2b7028e2012-09-19 17:25:38 -0700326}
327
Romain Guyb025b9c2010-09-16 14:16:48 -0700328void OpenGLRenderer::finish() {
Romain Guy7c450aa2012-09-21 19:15:00 -0700329 renderOverdraw();
Romain Guy2b7028e2012-09-19 17:25:38 -0700330 endTiling();
331
Romain Guyca89e2a2013-03-08 17:44:20 -0800332 // When finish() is invoked on FBO 0 we've reached the end
333 // of the current frame
334 if (getTargetFbo() == 0) {
335 mCaches.pathCache.trim();
Chris Craik05f3d6e2014-06-02 16:27:04 -0700336 mCaches.tessellationCache.trim();
Romain Guyca89e2a2013-03-08 17:44:20 -0800337 }
338
Romain Guy11cb6422012-09-21 00:39:43 -0700339 if (!suppressErrorChecks()) {
Romain Guyb025b9c2010-09-16 14:16:48 -0700340#if DEBUG_OPENGL
Chris Craike4aa95e2014-05-08 13:57:05 -0700341 GLUtils::dumpGLErrors();
Romain Guyb025b9c2010-09-16 14:16:48 -0700342#endif
Romain Guy11cb6422012-09-21 00:39:43 -0700343
Romain Guyc15008e2010-11-10 11:59:15 -0800344#if DEBUG_MEMORY_USAGE
Romain Guye190aa62010-11-10 19:01:29 -0800345 mCaches.dumpMemoryUsage();
Romain Guy11cb6422012-09-21 00:39:43 -0700346#else
347 if (mCaches.getDebugLevel() & kDebugMemory) {
348 mCaches.dumpMemoryUsage();
349 }
Romain Guyc15008e2010-11-10 11:59:15 -0800350#endif
Romain Guy11cb6422012-09-21 00:39:43 -0700351 }
Romain Guy96885eb2013-03-26 15:05:58 -0700352
Romain Guy78dd96d2013-05-03 14:24:16 -0700353 if (mCountOverdraw) {
354 countOverdraw();
355 }
356
Romain Guy96885eb2013-03-26 15:05:58 -0700357 mFrameStarted = false;
Romain Guyb025b9c2010-09-16 14:16:48 -0700358}
359
Romain Guy35643dd2012-09-18 15:40:58 -0700360void OpenGLRenderer::resumeAfterLayer() {
John Reck3b202512014-06-23 13:13:08 -0700361 mRenderState.setViewport(getViewportWidth(), getViewportHeight());
362 mRenderState.bindFramebuffer(currentSnapshot()->fbo);
Romain Guy7c450aa2012-09-21 19:15:00 -0700363 debugOverdraw(true, false);
Romain Guy35643dd2012-09-18 15:40:58 -0700364
365 mCaches.resetScissor();
366 dirtyClip();
367}
368
Romain Guy8f3b8e32012-03-27 16:33:45 -0700369status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
Chris Craikd6b65f62014-01-01 14:45:21 -0800370 if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
Chris Craik408eb122013-03-26 18:55:15 -0700371
Chris Craikd6b65f62014-01-01 14:45:21 -0800372 Rect clip(*currentClipRect());
Romain Guy80911b82011-03-16 15:30:12 -0700373 clip.snapToPixelBoundaries();
374
Romain Guyd643bb52011-03-01 14:55:21 -0800375 // Since we don't know what the functor will draw, let's dirty
Chris Craikd6b65f62014-01-01 14:45:21 -0800376 // the entire clip region
Romain Guyd643bb52011-03-01 14:55:21 -0800377 if (hasLayer()) {
Romain Guyd643bb52011-03-01 14:55:21 -0800378 dirtyLayerUnchecked(clip, getRegion());
379 }
Romain Guyd643bb52011-03-01 14:55:21 -0800380
Romain Guy08aa2cb2011-03-17 11:06:57 -0700381 DrawGlInfo info;
382 info.clipLeft = clip.left;
383 info.clipTop = clip.top;
384 info.clipRight = clip.right;
385 info.clipBottom = clip.bottom;
386 info.isLayer = hasLayer();
Chris Craika64a2be2014-05-14 14:17:01 -0700387 info.width = getViewportWidth();
388 info.height = getViewportHeight();
Chris Craikd6b65f62014-01-01 14:45:21 -0800389 currentTransform()->copyTo(&info.transform[0]);
Romain Guy80911b82011-03-16 15:30:12 -0700390
John Reck3b202512014-06-23 13:13:08 -0700391 bool prevDirtyClip = mDirtyClip;
Chris Craik54f574a2013-08-26 11:23:46 -0700392 // setup GL state for functor
393 if (mDirtyClip) {
Chris Craik54f574a2013-08-26 11:23:46 -0700394 setStencilFromClip(); // can issue draws, so must precede enableScissor()/interrupt()
395 }
John Reck3b202512014-06-23 13:13:08 -0700396 if (mCaches.enableScissor() || prevDirtyClip) {
John Reck25d2f7b2013-09-10 13:12:09 -0700397 setScissorFromClip();
398 }
Chris Craik54f574a2013-08-26 11:23:46 -0700399
John Reck3b202512014-06-23 13:13:08 -0700400 mRenderState.invokeFunctor(functor, DrawGlInfo::kModeDraw, &info);
401 // Scissor may have been modified, reset dirty clip
402 dirtyClip();
Romain Guycabfcc12011-03-07 18:06:46 -0800403
John Reck750ca6d2014-03-28 16:33:18 -0700404 return DrawGlInfo::kStatusDrew;
Chet Haasedaf98e92011-01-10 14:10:36 -0800405}
406
Romain Guyf6a11b82010-06-23 17:47:49 -0700407///////////////////////////////////////////////////////////////////////////////
Romain Guy87e2f7572012-09-24 11:37:12 -0700408// Debug
409///////////////////////////////////////////////////////////////////////////////
410
Chris Craik62d307c2014-07-29 10:35:13 -0700411void OpenGLRenderer::eventMarkDEBUG(const char* fmt, ...) const {
412#if DEBUG_DETAILED_EVENTS
413 const int BUFFER_SIZE = 256;
414 va_list ap;
415 char buf[BUFFER_SIZE];
416
417 va_start(ap, fmt);
418 vsnprintf(buf, BUFFER_SIZE, fmt, ap);
419 va_end(ap);
420
421 eventMark(buf);
422#endif
423}
424
425
Romain Guy0f667532013-03-01 14:31:04 -0800426void OpenGLRenderer::eventMark(const char* name) const {
427 mCaches.eventMark(0, name);
428}
429
Romain Guy87e2f7572012-09-24 11:37:12 -0700430void OpenGLRenderer::startMark(const char* name) const {
431 mCaches.startMark(0, name);
432}
433
434void OpenGLRenderer::endMark() const {
435 mCaches.endMark();
436}
437
438void OpenGLRenderer::debugOverdraw(bool enable, bool clear) {
John Reck3b202512014-06-23 13:13:08 -0700439 mRenderState.debugOverdraw(enable, clear);
Romain Guy87e2f7572012-09-24 11:37:12 -0700440}
441
442void OpenGLRenderer::renderOverdraw() {
443 if (mCaches.debugOverdraw && getTargetFbo() == 0) {
Chris Craik5f803622013-03-21 14:39:04 -0700444 const Rect* clip = &mTilingClip;
Romain Guy87e2f7572012-09-24 11:37:12 -0700445
446 mCaches.enableScissor();
Chris Craika64a2be2014-05-14 14:17:01 -0700447 mCaches.setScissor(clip->left, firstSnapshot()->getViewportHeight() - clip->bottom,
Romain Guy87e2f7572012-09-24 11:37:12 -0700448 clip->right - clip->left, clip->bottom - clip->top);
449
Romain Guy627c6fd2013-08-21 11:53:18 -0700450 // 1x overdraw
Romain Guy87e2f7572012-09-24 11:37:12 -0700451 mCaches.stencil.enableDebugTest(2);
Romain Guy627c6fd2013-08-21 11:53:18 -0700452 drawColor(mCaches.getOverdrawColor(1), SkXfermode::kSrcOver_Mode);
453
454 // 2x overdraw
Romain Guy87e2f7572012-09-24 11:37:12 -0700455 mCaches.stencil.enableDebugTest(3);
Romain Guy627c6fd2013-08-21 11:53:18 -0700456 drawColor(mCaches.getOverdrawColor(2), SkXfermode::kSrcOver_Mode);
457
458 // 3x overdraw
Romain Guy87e2f7572012-09-24 11:37:12 -0700459 mCaches.stencil.enableDebugTest(4);
Romain Guy627c6fd2013-08-21 11:53:18 -0700460 drawColor(mCaches.getOverdrawColor(3), SkXfermode::kSrcOver_Mode);
461
462 // 4x overdraw and higher
Romain Guy87e2f7572012-09-24 11:37:12 -0700463 mCaches.stencil.enableDebugTest(4, true);
Romain Guy627c6fd2013-08-21 11:53:18 -0700464 drawColor(mCaches.getOverdrawColor(4), SkXfermode::kSrcOver_Mode);
465
Romain Guy87e2f7572012-09-24 11:37:12 -0700466 mCaches.stencil.disable();
467 }
468}
469
Romain Guy78dd96d2013-05-03 14:24:16 -0700470void OpenGLRenderer::countOverdraw() {
Chris Craik14e51302013-12-30 15:32:54 -0800471 size_t count = getWidth() * getHeight();
Romain Guy78dd96d2013-05-03 14:24:16 -0700472 uint32_t* buffer = new uint32_t[count];
Chris Craik14e51302013-12-30 15:32:54 -0800473 glReadPixels(0, 0, getWidth(), getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, &buffer[0]);
Romain Guy78dd96d2013-05-03 14:24:16 -0700474
475 size_t total = 0;
476 for (size_t i = 0; i < count; i++) {
477 total += buffer[i] & 0xff;
478 }
479
480 mOverdraw = total / float(count);
481
482 delete[] buffer;
483}
484
Romain Guy87e2f7572012-09-24 11:37:12 -0700485///////////////////////////////////////////////////////////////////////////////
Romain Guy11cb6422012-09-21 00:39:43 -0700486// Layers
487///////////////////////////////////////////////////////////////////////////////
488
489bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {
Chris Craika7090e02014-06-20 16:01:00 -0700490 if (layer->deferredUpdateScheduled && layer->renderer
491 && layer->renderNode.get() && layer->renderNode->isRenderable()) {
Romain Guy40543602013-06-12 15:31:28 -0700492 ATRACE_CALL();
493
Romain Guy11cb6422012-09-21 00:39:43 -0700494 Rect& dirty = layer->dirtyRect;
495
Romain Guy7c450aa2012-09-21 19:15:00 -0700496 if (inFrame) {
497 endTiling();
498 debugOverdraw(false, false);
499 }
Romain Guy11cb6422012-09-21 00:39:43 -0700500
Romain Guy96885eb2013-03-26 15:05:58 -0700501 if (CC_UNLIKELY(inFrame || mCaches.drawDeferDisabled)) {
Chris Craik69e5adf2014-08-14 13:34:01 -0700502 layer->render(*this);
Romain Guy96885eb2013-03-26 15:05:58 -0700503 } else {
Chris Craik69e5adf2014-08-14 13:34:01 -0700504 layer->defer(*this);
Romain Guy96885eb2013-03-26 15:05:58 -0700505 }
Romain Guy11cb6422012-09-21 00:39:43 -0700506
507 if (inFrame) {
508 resumeAfterLayer();
Chris Craikd6b65f62014-01-01 14:45:21 -0800509 startTilingCurrentClip();
Romain Guy11cb6422012-09-21 00:39:43 -0700510 }
511
Romain Guy5bb3c732012-11-29 17:52:58 -0800512 layer->debugDrawUpdate = mCaches.debugLayersUpdates;
Chris Craik34416ea2013-04-15 16:08:28 -0700513 layer->hasDrawnSinceUpdate = false;
Romain Guy11cb6422012-09-21 00:39:43 -0700514
515 return true;
516 }
517
518 return false;
519}
520
521void OpenGLRenderer::updateLayers() {
Romain Guy96885eb2013-03-26 15:05:58 -0700522 // If draw deferring is enabled this method will simply defer
523 // the display list of each individual layer. The layers remain
524 // in the layer updates list which will be cleared by flushLayers().
Romain Guy11cb6422012-09-21 00:39:43 -0700525 int count = mLayerUpdates.size();
526 if (count > 0) {
Romain Guy96885eb2013-03-26 15:05:58 -0700527 if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
528 startMark("Layer Updates");
529 } else {
530 startMark("Defer Layer Updates");
531 }
Romain Guy11cb6422012-09-21 00:39:43 -0700532
Chris Craik1206b9b2013-04-04 14:46:24 -0700533 // Note: it is very important to update the layers in order
534 for (int i = 0; i < count; i++) {
Romain Guy11cb6422012-09-21 00:39:43 -0700535 Layer* layer = mLayerUpdates.itemAt(i);
536 updateLayer(layer, false);
Romain Guy96885eb2013-03-26 15:05:58 -0700537 if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
538 mCaches.resourceCache.decrementRefcount(layer);
539 }
Romain Guy11cb6422012-09-21 00:39:43 -0700540 }
Romain Guy11cb6422012-09-21 00:39:43 -0700541
Romain Guy96885eb2013-03-26 15:05:58 -0700542 if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
543 mLayerUpdates.clear();
John Reck3b202512014-06-23 13:13:08 -0700544 mRenderState.bindFramebuffer(getTargetFbo());
Romain Guy96885eb2013-03-26 15:05:58 -0700545 }
546 endMark();
547 }
548}
549
550void OpenGLRenderer::flushLayers() {
551 int count = mLayerUpdates.size();
552 if (count > 0) {
553 startMark("Apply Layer Updates");
554 char layerName[12];
555
Chris Craik1206b9b2013-04-04 14:46:24 -0700556 // Note: it is very important to update the layers in order
557 for (int i = 0; i < count; i++) {
Chris Craika8bea8e2014-09-24 11:29:43 -0700558 Layer* layer = mLayerUpdates.itemAt(i);
559
Romain Guy96885eb2013-03-26 15:05:58 -0700560 sprintf(layerName, "Layer #%d", i);
Romain Guy02b49b72013-03-29 12:37:16 -0700561 startMark(layerName);
Chris Craika8bea8e2014-09-24 11:29:43 -0700562 ATRACE_FORMAT_BEGIN("flushLayer %ux%u", layer->getWidth(), layer->getHeight());
Romain Guy02b49b72013-03-29 12:37:16 -0700563
Romain Guy02b49b72013-03-29 12:37:16 -0700564 layer->flush();
Chris Craika8bea8e2014-09-24 11:29:43 -0700565
Romain Guy40543602013-06-12 15:31:28 -0700566 ATRACE_END();
Chris Craika8bea8e2014-09-24 11:29:43 -0700567 endMark();
Romain Guy40543602013-06-12 15:31:28 -0700568
Romain Guy02b49b72013-03-29 12:37:16 -0700569 mCaches.resourceCache.decrementRefcount(layer);
Romain Guy96885eb2013-03-26 15:05:58 -0700570 }
571
572 mLayerUpdates.clear();
John Reck3b202512014-06-23 13:13:08 -0700573 mRenderState.bindFramebuffer(getTargetFbo());
Romain Guy96885eb2013-03-26 15:05:58 -0700574
Romain Guy11cb6422012-09-21 00:39:43 -0700575 endMark();
576 }
577}
578
579void OpenGLRenderer::pushLayerUpdate(Layer* layer) {
580 if (layer) {
Romain Guy02b49b72013-03-29 12:37:16 -0700581 // Make sure we don't introduce duplicates.
582 // SortedVector would do this automatically but we need to respect
583 // the insertion order. The linear search is not an issue since
584 // this list is usually very short (typically one item, at most a few)
585 for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
586 if (mLayerUpdates.itemAt(i) == layer) {
587 return;
588 }
589 }
Romain Guy11cb6422012-09-21 00:39:43 -0700590 mLayerUpdates.push_back(layer);
591 mCaches.resourceCache.incrementRefcount(layer);
592 }
593}
594
Romain Guye93482f2013-06-17 13:14:51 -0700595void OpenGLRenderer::cancelLayerUpdate(Layer* layer) {
596 if (layer) {
597 for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
598 if (mLayerUpdates.itemAt(i) == layer) {
599 mLayerUpdates.removeAt(i);
600 mCaches.resourceCache.decrementRefcount(layer);
601 break;
602 }
603 }
604 }
605}
606
Romain Guy11cb6422012-09-21 00:39:43 -0700607void OpenGLRenderer::clearLayerUpdates() {
608 size_t count = mLayerUpdates.size();
609 if (count > 0) {
610 mCaches.resourceCache.lock();
611 for (size_t i = 0; i < count; i++) {
612 mCaches.resourceCache.decrementRefcountLocked(mLayerUpdates.itemAt(i));
613 }
614 mCaches.resourceCache.unlock();
615 mLayerUpdates.clear();
616 }
617}
618
Romain Guy40543602013-06-12 15:31:28 -0700619void OpenGLRenderer::flushLayerUpdates() {
John Recka7c2ea22014-08-08 13:21:00 -0700620 ATRACE_CALL();
Romain Guy40543602013-06-12 15:31:28 -0700621 syncState();
622 updateLayers();
623 flushLayers();
624 // Wait for all the layer updates to be executed
625 AutoFence fence;
626}
627
John Reck443a7142014-09-04 17:40:05 -0700628void OpenGLRenderer::markLayersAsBuildLayers() {
629 for (size_t i = 0; i < mLayerUpdates.size(); i++) {
630 mLayerUpdates[i]->wasBuildLayered = true;
631 }
632}
633
Romain Guy11cb6422012-09-21 00:39:43 -0700634///////////////////////////////////////////////////////////////////////////////
Romain Guyf6a11b82010-06-23 17:47:49 -0700635// State management
636///////////////////////////////////////////////////////////////////////////////
637
Chris Craik14e51302013-12-30 15:32:54 -0800638void OpenGLRenderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
Chris Craika64a2be2014-05-14 14:17:01 -0700639 bool restoreViewport = removed.flags & Snapshot::kFlagIsFboLayer;
Chris Craik14e51302013-12-30 15:32:54 -0800640 bool restoreClip = removed.flags & Snapshot::kFlagClipSet;
641 bool restoreLayer = removed.flags & Snapshot::kFlagIsLayer;
Romain Guybd6b79b2010-06-26 00:13:53 -0700642
Chris Craika64a2be2014-05-14 14:17:01 -0700643 if (restoreViewport) {
John Reck3b202512014-06-23 13:13:08 -0700644 mRenderState.setViewport(getViewportWidth(), getViewportHeight());
Romain Guyeb993562010-10-05 18:14:38 -0700645 }
646
Romain Guy2542d192010-08-18 11:47:12 -0700647 if (restoreClip) {
Romain Guy746b7402010-10-26 16:27:31 -0700648 dirtyClip();
Romain Guy8fb95422010-08-17 18:38:51 -0700649 }
Romain Guy2542d192010-08-18 11:47:12 -0700650
Romain Guy5ec99242010-11-03 16:19:08 -0700651 if (restoreLayer) {
Chris Craik7273daa2013-03-28 11:25:24 -0700652 endMark(); // Savelayer
Chris Craika8bea8e2014-09-24 11:29:43 -0700653 ATRACE_END(); // SaveLayer
Chris Craik7273daa2013-03-28 11:25:24 -0700654 startMark("ComposeLayer");
Chris Craik14e51302013-12-30 15:32:54 -0800655 composeLayer(removed, restored);
Chris Craik7273daa2013-03-28 11:25:24 -0700656 endMark();
Romain Guy5ec99242010-11-03 16:19:08 -0700657 }
Romain Guybb9524b2010-06-22 18:56:38 -0700658}
659
Romain Guyf6a11b82010-06-23 17:47:49 -0700660///////////////////////////////////////////////////////////////////////////////
Romain Guybd6b79b2010-06-26 00:13:53 -0700661// Layers
662///////////////////////////////////////////////////////////////////////////////
663
664int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
Chris Craik3f0854292014-04-15 16:18:08 -0700665 const SkPaint* paint, int flags, const SkPath* convexMask) {
Chris Craik4ace7302014-09-14 15:49:54 -0700666 // force matrix/clip isolation for layer
667 flags |= SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag;
668
Romain Guyeb993562010-10-05 18:14:38 -0700669 const int count = saveSnapshot(flags);
Romain Guyd55a8612010-06-28 17:42:46 -0700670
Chris Craikd6b65f62014-01-01 14:45:21 -0800671 if (!currentSnapshot()->isIgnored()) {
Chris Craik3f0854292014-04-15 16:18:08 -0700672 createLayer(left, top, right, bottom, paint, flags, convexMask);
Romain Guydbc26d22010-10-11 17:58:29 -0700673 }
Romain Guyd55a8612010-06-28 17:42:46 -0700674
675 return count;
Romain Guybd6b79b2010-06-26 00:13:53 -0700676}
677
Chris Craikd90144d2013-03-19 15:03:48 -0700678void OpenGLRenderer::calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool fboLayer) {
679 const Rect untransformedBounds(bounds);
680
Chris Craikd6b65f62014-01-01 14:45:21 -0800681 currentTransform()->mapRect(bounds);
Chris Craikd90144d2013-03-19 15:03:48 -0700682
683 // Layers only make sense if they are in the framebuffer's bounds
Chris Craikd6b65f62014-01-01 14:45:21 -0800684 if (bounds.intersect(*currentClipRect())) {
Chris Craikd90144d2013-03-19 15:03:48 -0700685 // We cannot work with sub-pixels in this case
686 bounds.snapToPixelBoundaries();
687
688 // When the layer is not an FBO, we may use glCopyTexImage so we
689 // need to make sure the layer does not extend outside the bounds
690 // of the framebuffer
Chris Craik92419752014-05-15 13:21:28 -0700691 const Snapshot& previous = *(currentSnapshot()->previous);
692 Rect previousViewport(0, 0, previous.getViewportWidth(), previous.getViewportHeight());
693 if (!bounds.intersect(previousViewport)) {
Chris Craikd90144d2013-03-19 15:03:48 -0700694 bounds.setEmpty();
695 } else if (fboLayer) {
696 clip.set(bounds);
697 mat4 inverse;
Chris Craikd6b65f62014-01-01 14:45:21 -0800698 inverse.loadInverse(*currentTransform());
Chris Craikd90144d2013-03-19 15:03:48 -0700699 inverse.mapRect(clip);
700 clip.snapToPixelBoundaries();
701 if (clip.intersect(untransformedBounds)) {
702 clip.translate(-untransformedBounds.left, -untransformedBounds.top);
703 bounds.set(untransformedBounds);
704 } else {
705 clip.setEmpty();
706 }
707 }
708 } else {
709 bounds.setEmpty();
710 }
711}
712
Chris Craik408eb122013-03-26 18:55:15 -0700713void OpenGLRenderer::updateSnapshotIgnoreForLayer(const Rect& bounds, const Rect& clip,
714 bool fboLayer, int alpha) {
715 if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize ||
716 bounds.getHeight() > mCaches.maxTextureSize ||
717 (fboLayer && clip.isEmpty())) {
718 mSnapshot->empty = fboLayer;
719 } else {
Chris Craik74cf7e62014-08-07 14:34:46 -0700720 mSnapshot->invisible = mSnapshot->invisible || (alpha <= 0 && fboLayer);
Chris Craik408eb122013-03-26 18:55:15 -0700721 }
722}
723
Chris Craikd90144d2013-03-19 15:03:48 -0700724int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float bottom,
Derek Sollenbergerd44fbe52014-02-05 16:47:00 -0500725 const SkPaint* paint, int flags) {
Chris Craikd90144d2013-03-19 15:03:48 -0700726 const int count = saveSnapshot(flags);
727
Chris Craikd6b65f62014-01-01 14:45:21 -0800728 if (!currentSnapshot()->isIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) {
Chris Craikd90144d2013-03-19 15:03:48 -0700729 // initialize the snapshot as though it almost represents an FBO layer so deferred draw
730 // operations will be able to store and restore the current clip and transform info, and
731 // quick rejection will be correct (for display lists)
732
733 Rect bounds(left, top, right, bottom);
734 Rect clip;
735 calculateLayerBoundsAndClip(bounds, clip, true);
Derek Sollenbergerd44fbe52014-02-05 16:47:00 -0500736 updateSnapshotIgnoreForLayer(bounds, clip, true, getAlphaDirect(paint));
Chris Craikd90144d2013-03-19 15:03:48 -0700737
Chris Craikd6b65f62014-01-01 14:45:21 -0800738 if (!currentSnapshot()->isIgnored()) {
Chris Craikd90144d2013-03-19 15:03:48 -0700739 mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
740 mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
Chris Craika64a2be2014-05-14 14:17:01 -0700741 mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
Chris Craikdeeda3d2014-05-05 19:09:33 -0700742 mSnapshot->roundRectClipState = NULL;
Chris Craikd90144d2013-03-19 15:03:48 -0700743 }
744 }
745
746 return count;
747}
748
Romain Guy1c740bc2010-09-13 18:00:09 -0700749/**
750 * Layers are viewed by Skia are slightly different than layers in image editing
751 * programs (for instance.) When a layer is created, previously created layers
752 * and the frame buffer still receive every drawing command. For instance, if a
753 * layer is created and a shape intersecting the bounds of the layers and the
754 * framebuffer is draw, the shape will be drawn on both (unless the layer was
755 * created with the SkCanvas::kClipToLayer_SaveFlag flag.)
756 *
757 * A way to implement layers is to create an FBO for each layer, backed by an RGBA
758 * texture. Unfortunately, this is inefficient as it requires every primitive to
759 * be drawn n + 1 times, where n is the number of active layers. In practice this
760 * means, for every primitive:
761 * - Switch active frame buffer
762 * - Change viewport, clip and projection matrix
763 * - Issue the drawing
764 *
765 * Switching rendering target n + 1 times per drawn primitive is extremely costly.
Romain Guy6b7bd242010-10-06 19:49:23 -0700766 * To avoid this, layers are implemented in a different way here, at least in the
767 * general case. FBOs are used, as an optimization, when the "clip to layer" flag
768 * is set. When this flag is set we can redirect all drawing operations into a
769 * single FBO.
Romain Guy1c740bc2010-09-13 18:00:09 -0700770 *
771 * This implementation relies on the frame buffer being at least RGBA 8888. When
772 * a layer is created, only a texture is created, not an FBO. The content of the
773 * frame buffer contained within the layer's bounds is copied into this texture
Romain Guy87a76572010-09-13 18:11:21 -0700774 * using glCopyTexImage2D(). The layer's region is then cleared(1) in the frame
Romain Guy1c740bc2010-09-13 18:00:09 -0700775 * buffer and drawing continues as normal. This technique therefore treats the
776 * frame buffer as a scratch buffer for the layers.
777 *
778 * To compose the layers back onto the frame buffer, each layer texture
779 * (containing the original frame buffer data) is drawn as a simple quad over
780 * the frame buffer. The trick is that the quad is set as the composition
781 * destination in the blending equation, and the frame buffer becomes the source
782 * of the composition.
783 *
784 * Drawing layers with an alpha value requires an extra step before composition.
785 * An empty quad is drawn over the layer's region in the frame buffer. This quad
786 * is drawn with the rgba color (0,0,0,alpha). The alpha value offered by the
787 * quad is used to multiply the colors in the frame buffer. This is achieved by
788 * changing the GL blend functions for the GL_FUNC_ADD blend equation to
789 * GL_ZERO, GL_SRC_ALPHA.
790 *
791 * Because glCopyTexImage2D() can be slow, an alternative implementation might
792 * be use to draw a single clipped layer. The implementation described above
793 * is correct in every case.
Romain Guy87a76572010-09-13 18:11:21 -0700794 *
795 * (1) The frame buffer is actually not cleared right away. To allow the GPU
796 * to potentially optimize series of calls to glCopyTexImage2D, the frame
797 * buffer is left untouched until the first drawing operation. Only when
798 * something actually gets drawn are the layers regions cleared.
Romain Guy1c740bc2010-09-13 18:00:09 -0700799 */
Chet Haased48885a2012-08-28 17:43:28 -0700800bool OpenGLRenderer::createLayer(float left, float top, float right, float bottom,
Chris Craik3f0854292014-04-15 16:18:08 -0700801 const SkPaint* paint, int flags, const SkPath* convexMask) {
Romain Guyeb993562010-10-05 18:14:38 -0700802 LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top);
Romain Guyfb8b7632010-08-23 21:05:08 -0700803 LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
Romain Guy8ba548f2010-06-30 19:21:21 -0700804
Romain Guyeb993562010-10-05 18:14:38 -0700805 const bool fboLayer = flags & SkCanvas::kClipToLayer_SaveFlag;
806
Romain Guyf607bdc2010-09-10 19:20:06 -0700807 // Window coordinates of the layer
Chet Haased48885a2012-08-28 17:43:28 -0700808 Rect clip;
Romain Guy8aef54f2010-09-01 15:13:49 -0700809 Rect bounds(left, top, right, bottom);
Chris Craikd90144d2013-03-19 15:03:48 -0700810 calculateLayerBoundsAndClip(bounds, clip, fboLayer);
Derek Sollenberger674554f2014-02-19 16:47:32 +0000811 updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, getAlphaDirect(paint));
Romain Guydbc26d22010-10-11 17:58:29 -0700812
813 // Bail out if we won't draw in this snapshot
Chris Craikd6b65f62014-01-01 14:45:21 -0800814 if (currentSnapshot()->isIgnored()) {
Romain Guyb025b9c2010-09-16 14:16:48 -0700815 return false;
816 }
Romain Guyf18fd992010-07-08 11:45:51 -0700817
Romain Guya1d3c912011-12-13 14:55:06 -0800818 mCaches.activeTexture(0);
John Reck3b202512014-06-23 13:13:08 -0700819 Layer* layer = mCaches.layerCache.get(mRenderState, bounds.getWidth(), bounds.getHeight());
Romain Guydda57022010-07-06 11:39:32 -0700820 if (!layer) {
Romain Guyf18fd992010-07-08 11:45:51 -0700821 return false;
Romain Guybd6b79b2010-06-26 00:13:53 -0700822 }
823
Derek Sollenberger674554f2014-02-19 16:47:32 +0000824 layer->setPaint(paint);
Romain Guy8aef54f2010-09-01 15:13:49 -0700825 layer->layer.set(bounds);
Romain Guy9ace8f52011-07-07 20:50:11 -0700826 layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()),
827 bounds.getWidth() / float(layer->getWidth()), 0.0f);
Derek Sollenbergerd44fbe52014-02-05 16:47:00 -0500828
Chet Haasea23eed82012-04-12 15:19:04 -0700829 layer->setBlend(true);
Romain Guy7c25aab2012-10-18 15:05:02 -0700830 layer->setDirty(false);
Chris Craik3f0854292014-04-15 16:18:08 -0700831 layer->setConvexMask(convexMask); // note: the mask must be cleared before returning to the cache
Romain Guydda57022010-07-06 11:39:32 -0700832
Romain Guy8fb95422010-08-17 18:38:51 -0700833 // Save the layer in the snapshot
Chet Haased48885a2012-08-28 17:43:28 -0700834 mSnapshot->flags |= Snapshot::kFlagIsLayer;
835 mSnapshot->layer = layer;
Romain Guy1d83e192010-08-17 11:37:00 -0700836
Chris Craika8bea8e2014-09-24 11:29:43 -0700837 ATRACE_FORMAT_BEGIN("%ssaveLayer %ux%u",
838 fboLayer ? "" : "unclipped ",
839 layer->getWidth(), layer->getHeight());
Chris Craik7273daa2013-03-28 11:25:24 -0700840 startMark("SaveLayer");
Romain Guyeb993562010-10-05 18:14:38 -0700841 if (fboLayer) {
Chris Craike63f7c622013-10-17 10:30:55 -0700842 return createFboLayer(layer, bounds, clip);
Romain Guyeb993562010-10-05 18:14:38 -0700843 } else {
844 // Copy the framebuffer into the layer
Romain Guy9ace8f52011-07-07 20:50:11 -0700845 layer->bindTexture();
Romain Guy514fb182011-01-19 14:38:29 -0800846 if (!bounds.isEmpty()) {
Romain Guy9ace8f52011-07-07 20:50:11 -0700847 if (layer->isEmpty()) {
Romain Guyb254c242013-06-27 17:15:24 -0700848 // Workaround for some GL drivers. When reading pixels lying outside
849 // of the window we should get undefined values for those pixels.
850 // Unfortunately some drivers will turn the entire target texture black
851 // when reading outside of the window.
852 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->getWidth(), layer->getHeight(),
853 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
Romain Guy9ace8f52011-07-07 20:50:11 -0700854 layer->setEmpty(false);
Romain Guy514fb182011-01-19 14:38:29 -0800855 }
Romain Guy7b5b6ab2011-03-14 18:05:08 -0700856
Chris Craika64a2be2014-05-14 14:17:01 -0700857 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
858 bounds.left, getViewportHeight() - bounds.bottom,
859 bounds.getWidth(), bounds.getHeight());
Romain Guyb254c242013-06-27 17:15:24 -0700860
Romain Guy54be1cd2011-06-13 19:04:27 -0700861 // Enqueue the buffer coordinates to clear the corresponding region later
862 mLayers.push(new Rect(bounds));
Romain Guyae88e5e2010-10-22 17:49:18 -0700863 }
Romain Guyeb993562010-10-05 18:14:38 -0700864 }
Romain Guyf86ef572010-07-01 11:05:42 -0700865
Romain Guyd55a8612010-06-28 17:42:46 -0700866 return true;
Romain Guybd6b79b2010-06-26 00:13:53 -0700867}
868
Chris Craike63f7c622013-10-17 10:30:55 -0700869bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {
Romain Guyc3fedaf2013-01-29 17:26:25 -0800870 layer->clipRect.set(clip);
Romain Guy9ace8f52011-07-07 20:50:11 -0700871 layer->setFbo(mCaches.fboCache.get());
Romain Guy5b3b3522010-10-27 18:57:51 -0700872
Chet Haased48885a2012-08-28 17:43:28 -0700873 mSnapshot->region = &mSnapshot->layer->region;
Chris Craika64a2be2014-05-14 14:17:01 -0700874 mSnapshot->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
Chet Haased48885a2012-08-28 17:43:28 -0700875 mSnapshot->fbo = layer->getFbo();
876 mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
877 mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
Chris Craika64a2be2014-05-14 14:17:01 -0700878 mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
Chris Craikdeeda3d2014-05-05 19:09:33 -0700879 mSnapshot->roundRectClipState = NULL;
Romain Guy5b3b3522010-10-27 18:57:51 -0700880
Romain Guy2b7028e2012-09-19 17:25:38 -0700881 endTiling();
Romain Guy7c450aa2012-09-21 19:15:00 -0700882 debugOverdraw(false, false);
Romain Guy5b3b3522010-10-27 18:57:51 -0700883 // Bind texture to FBO
John Reck3b202512014-06-23 13:13:08 -0700884 mRenderState.bindFramebuffer(layer->getFbo());
Romain Guy9ace8f52011-07-07 20:50:11 -0700885 layer->bindTexture();
Romain Guy5b3b3522010-10-27 18:57:51 -0700886
887 // Initialize the texture if needed
Romain Guy9ace8f52011-07-07 20:50:11 -0700888 if (layer->isEmpty()) {
Romain Guy09087642013-04-04 12:27:54 -0700889 layer->allocateTexture();
Romain Guy9ace8f52011-07-07 20:50:11 -0700890 layer->setEmpty(false);
Romain Guy5b3b3522010-10-27 18:57:51 -0700891 }
892
893 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
Romain Guy9ace8f52011-07-07 20:50:11 -0700894 layer->getTexture(), 0);
Romain Guy5b3b3522010-10-27 18:57:51 -0700895
henry.uh_chen33f5a592014-07-02 19:36:56 +0800896 // Expand the startTiling region by 1
897 startTilingCurrentClip(true, true);
Romain Guy5b3b3522010-10-27 18:57:51 -0700898
899 // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
Romain Guy586cae32012-07-13 15:28:31 -0700900 mCaches.enableScissor();
Romain Guy8f85e802011-12-14 19:23:32 -0800901 mCaches.setScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
Romain Guy5b3b3522010-10-27 18:57:51 -0700902 clip.getWidth() + 2.0f, clip.getHeight() + 2.0f);
Romain Guy5b3b3522010-10-27 18:57:51 -0700903 glClear(GL_COLOR_BUFFER_BIT);
904
905 dirtyClip();
906
907 // Change the ortho projection
John Reck3b202512014-06-23 13:13:08 -0700908 mRenderState.setViewport(bounds.getWidth(), bounds.getHeight());
Romain Guy5b3b3522010-10-27 18:57:51 -0700909 return true;
910}
911
Romain Guy1c740bc2010-09-13 18:00:09 -0700912/**
913 * Read the documentation of createLayer() before doing anything in this method.
914 */
Chris Craik14e51302013-12-30 15:32:54 -0800915void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& restored) {
916 if (!removed.layer) {
Steve Block3762c312012-01-06 19:20:56 +0000917 ALOGE("Attempting to compose a layer that does not exist");
Romain Guy1d83e192010-08-17 11:37:00 -0700918 return;
919 }
920
Chris Craik14e51302013-12-30 15:32:54 -0800921 Layer* layer = removed.layer;
Romain Guy8ce00302013-01-15 18:51:42 -0800922 const Rect& rect = layer->layer;
Chris Craik14e51302013-12-30 15:32:54 -0800923 const bool fboLayer = removed.flags & Snapshot::kFlagIsFboLayer;
Romain Guyeb993562010-10-05 18:14:38 -0700924
Chris Craik39a908c2013-06-13 14:39:01 -0700925 bool clipRequired = false;
Chris Craikf0a59072013-11-19 18:00:46 -0800926 calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom,
Chris Craikdeeda3d2014-05-05 19:09:33 -0700927 &clipRequired, NULL, false); // safely ignore return, should never be rejected
Chris Craik39a908c2013-06-13 14:39:01 -0700928 mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
929
Romain Guyeb993562010-10-05 18:14:38 -0700930 if (fboLayer) {
Romain Guy2b7028e2012-09-19 17:25:38 -0700931 endTiling();
932
Romain Guye0aa84b2012-04-03 19:30:26 -0700933 // Detach the texture from the FBO
934 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
Romain Guy8ce00302013-01-15 18:51:42 -0800935
936 layer->removeFbo(false);
937
Romain Guyeb993562010-10-05 18:14:38 -0700938 // Unbind current FBO and restore previous one
John Reck3b202512014-06-23 13:13:08 -0700939 mRenderState.bindFramebuffer(restored.fbo);
Romain Guy7c450aa2012-09-21 19:15:00 -0700940 debugOverdraw(true, false);
Romain Guy2b7028e2012-09-19 17:25:38 -0700941
Chris Craikd6b65f62014-01-01 14:45:21 -0800942 startTilingCurrentClip();
Romain Guyeb993562010-10-05 18:14:38 -0700943 }
944
Romain Guy9ace8f52011-07-07 20:50:11 -0700945 if (!fboLayer && layer->getAlpha() < 255) {
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -0500946 SkPaint layerPaint;
947 layerPaint.setAlpha(layer->getAlpha());
948 layerPaint.setXfermodeMode(SkXfermode::kDstIn_Mode);
949 layerPaint.setColorFilter(layer->getColorFilter());
950
951 drawColorRect(rect.left, rect.top, rect.right, rect.bottom, &layerPaint, true);
Romain Guy5b3b3522010-10-27 18:57:51 -0700952 // Required below, composeLayerRect() will divide by 255
Romain Guy9ace8f52011-07-07 20:50:11 -0700953 layer->setAlpha(255);
Romain Guyf607bdc2010-09-10 19:20:06 -0700954 }
955
Romain Guy03750a02010-10-18 14:06:08 -0700956 mCaches.unbindMeshBuffer();
Romain Guy8b55f372010-08-18 17:10:07 -0700957
Romain Guya1d3c912011-12-13 14:55:06 -0800958 mCaches.activeTexture(0);
Romain Guy1d83e192010-08-17 11:37:00 -0700959
Romain Guy5b3b3522010-10-27 18:57:51 -0700960 // When the layer is stored in an FBO, we can save a bit of fillrate by
961 // drawing only the dirty region
962 if (fboLayer) {
Chris Craik14e51302013-12-30 15:32:54 -0800963 dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *restored.transform);
Romain Guy5b3b3522010-10-27 18:57:51 -0700964 composeLayerRegion(layer, rect);
Romain Guy9ace8f52011-07-07 20:50:11 -0700965 } else if (!rect.isEmpty()) {
966 dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
Digish Pandyaa5ff7392013-11-04 06:30:25 +0530967
968 save(0);
969 // the layer contains screen buffer content that shouldn't be alpha modulated
970 // (and any necessary alpha modulation was handled drawing into the layer)
971 mSnapshot->alpha = 1.0f;
Romain Guy9ace8f52011-07-07 20:50:11 -0700972 composeLayerRect(layer, rect, true);
Digish Pandyaa5ff7392013-11-04 06:30:25 +0530973 restore();
Romain Guy5b3b3522010-10-27 18:57:51 -0700974 }
Romain Guy8b55f372010-08-18 17:10:07 -0700975
Romain Guy746b7402010-10-26 16:27:31 -0700976 dirtyClip();
977
Romain Guyeb993562010-10-05 18:14:38 -0700978 // Failing to add the layer to the cache should happen only if the layer is too large
Chris Craik3f0854292014-04-15 16:18:08 -0700979 layer->setConvexMask(NULL);
Romain Guy8550c4c2010-10-08 15:49:53 -0700980 if (!mCaches.layerCache.put(layer)) {
Romain Guy1d83e192010-08-17 11:37:00 -0700981 LAYER_LOGD("Deleting layer");
Chet Haase603f6de2012-09-14 15:31:25 -0700982 Caches::getInstance().resourceCache.decrementRefcount(layer);
Romain Guy1d83e192010-08-17 11:37:00 -0700983 }
984}
985
Romain Guyaa6c24c2011-04-28 18:40:04 -0700986void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
Romain Guy24589392013-06-19 12:17:01 -0700987 float alpha = getLayerAlpha(layer);
Romain Guyaa6c24c2011-04-28 18:40:04 -0700988
989 setupDraw();
Romain Guy9ace8f52011-07-07 20:50:11 -0700990 if (layer->getRenderTarget() == GL_TEXTURE_2D) {
Romain Guy8f0095c2011-05-02 17:24:22 -0700991 setupDrawWithTexture();
992 } else {
993 setupDrawWithExternalTexture();
994 }
995 setupDrawTextureTransform();
Romain Guyaa6c24c2011-04-28 18:40:04 -0700996 setupDrawColor(alpha, alpha, alpha, alpha);
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -0500997 setupDrawColorFilter(layer->getColorFilter());
998 setupDrawBlending(layer);
Romain Guyaa6c24c2011-04-28 18:40:04 -0700999 setupDrawProgram();
Romain Guyaa6c24c2011-04-28 18:40:04 -07001000 setupDrawPureColorUniforms();
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05001001 setupDrawColorFilterUniforms(layer->getColorFilter());
Romain Guy9ace8f52011-07-07 20:50:11 -07001002 if (layer->getRenderTarget() == GL_TEXTURE_2D) {
1003 setupDrawTexture(layer->getTexture());
Romain Guy8f0095c2011-05-02 17:24:22 -07001004 } else {
Romain Guy9ace8f52011-07-07 20:50:11 -07001005 setupDrawExternalTexture(layer->getTexture());
Romain Guy8f0095c2011-05-02 17:24:22 -07001006 }
Chris Craikd6b65f62014-01-01 14:45:21 -08001007 if (currentTransform()->isPureTranslate() &&
Chris Craik9757ac02014-02-25 18:50:17 -08001008 !layer->getForceFilter() &&
Romain Guyec19b4a2011-07-07 21:05:04 -07001009 layer->getWidth() == (uint32_t) rect.getWidth() &&
1010 layer->getHeight() == (uint32_t) rect.getHeight()) {
Chris Craikd6b65f62014-01-01 14:45:21 -08001011 const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
1012 const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
Romain Guy9ace8f52011-07-07 20:50:11 -07001013
Romain Guyd21b6e12011-11-30 20:21:23 -08001014 layer->setFilter(GL_NEAREST);
Chris Craik4063a0e2013-11-15 16:06:56 -08001015 setupDrawModelView(kModelViewMode_TranslateAndScale, false,
1016 x, y, x + rect.getWidth(), y + rect.getHeight(), true);
Romain Guy9ace8f52011-07-07 20:50:11 -07001017 } else {
Romain Guyd21b6e12011-11-30 20:21:23 -08001018 layer->setFilter(GL_LINEAR);
Chris Craik4063a0e2013-11-15 16:06:56 -08001019 setupDrawModelView(kModelViewMode_TranslateAndScale, false,
1020 rect.left, rect.top, rect.right, rect.bottom);
Romain Guy9ace8f52011-07-07 20:50:11 -07001021 }
1022 setupDrawTextureTransformUniforms(layer->getTexTransform());
Romain Guy3380cfd2013-08-15 16:57:57 -07001023 setupDrawMesh(&mMeshVertices[0].x, &mMeshVertices[0].u);
Romain Guyaa6c24c2011-04-28 18:40:04 -07001024
1025 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
Romain Guyaa6c24c2011-04-28 18:40:04 -07001026}
1027
Romain Guy5b3b3522010-10-27 18:57:51 -07001028void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
Chris Craik62d307c2014-07-29 10:35:13 -07001029 if (layer->isTextureLayer()) {
1030 EVENT_LOGD("composeTextureLayerRect");
1031 resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
1032 drawTextureLayer(layer, rect);
1033 resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
1034 } else {
1035 EVENT_LOGD("composeHardwareLayerRect");
Romain Guyaa6c24c2011-04-28 18:40:04 -07001036 const Rect& texCoords = layer->texCoords;
1037 resetDrawTextureTexCoords(texCoords.left, texCoords.top,
1038 texCoords.right, texCoords.bottom);
Romain Guy5b3b3522010-10-27 18:57:51 -07001039
Romain Guy9ace8f52011-07-07 20:50:11 -07001040 float x = rect.left;
1041 float y = rect.top;
Chris Craikd6b65f62014-01-01 14:45:21 -08001042 bool simpleTransform = currentTransform()->isPureTranslate() &&
Romain Guyec19b4a2011-07-07 21:05:04 -07001043 layer->getWidth() == (uint32_t) rect.getWidth() &&
Romain Guyb2479152011-07-08 11:57:29 -07001044 layer->getHeight() == (uint32_t) rect.getHeight();
1045
1046 if (simpleTransform) {
Romain Guy9ace8f52011-07-07 20:50:11 -07001047 // When we're swapping, the layer is already in screen coordinates
1048 if (!swap) {
Chris Craikd6b65f62014-01-01 14:45:21 -08001049 x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
1050 y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
Romain Guy9ace8f52011-07-07 20:50:11 -07001051 }
1052
Romain Guyd21b6e12011-11-30 20:21:23 -08001053 layer->setFilter(GL_NEAREST, true);
Romain Guy9ace8f52011-07-07 20:50:11 -07001054 } else {
Romain Guyd21b6e12011-11-30 20:21:23 -08001055 layer->setFilter(GL_LINEAR, true);
Romain Guy9ace8f52011-07-07 20:50:11 -07001056 }
1057
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05001058 SkPaint layerPaint;
1059 layerPaint.setAlpha(getLayerAlpha(layer) * 255);
1060 layerPaint.setXfermodeMode(layer->getMode());
1061 layerPaint.setColorFilter(layer->getColorFilter());
1062
1063 bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f;
Romain Guy9ace8f52011-07-07 20:50:11 -07001064 drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05001065 layer->getTexture(), &layerPaint, blend,
Romain Guy3380cfd2013-08-15 16:57:57 -07001066 &mMeshVertices[0].x, &mMeshVertices[0].u,
Romain Guy9ace8f52011-07-07 20:50:11 -07001067 GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform);
Romain Guy5b3b3522010-10-27 18:57:51 -07001068
Romain Guyaa6c24c2011-04-28 18:40:04 -07001069 resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
Romain Guyaa6c24c2011-04-28 18:40:04 -07001070 }
Romain Guy5b3b3522010-10-27 18:57:51 -07001071}
1072
Chris Craik34416ea2013-04-15 16:08:28 -07001073/**
1074 * Issues the command X, and if we're composing a save layer to the fbo or drawing a newly updated
1075 * hardware layer with overdraw debug on, draws again to the stencil only, so that these draw
1076 * operations are correctly counted twice for overdraw. NOTE: assumes composeLayerRegion only used
1077 * by saveLayer's restore
1078 */
1079#define DRAW_DOUBLE_STENCIL_IF(COND, DRAW_COMMAND) { \
1080 DRAW_COMMAND; \
1081 if (CC_UNLIKELY(mCaches.debugOverdraw && getTargetFbo() == 0 && COND)) { \
1082 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); \
1083 DRAW_COMMAND; \
1084 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); \
1085 } \
1086 }
1087
1088#define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND)
1089
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04001090// This class is purely for inspection. It inherits from SkShader, but Skia does not know how to
1091// use it. The OpenGLRenderer will look at it to find its Layer and whether it is opaque.
1092class LayerShader : public SkShader {
1093public:
1094 LayerShader(Layer* layer, const SkMatrix* localMatrix)
1095 : INHERITED(localMatrix)
1096 , mLayer(layer) {
1097 }
1098
1099 virtual bool asACustomShader(void** data) const {
1100 if (data) {
1101 *data = static_cast<void*>(mLayer);
1102 }
1103 return true;
1104 }
1105
1106 virtual bool isOpaque() const {
1107 return !mLayer->isBlend();
1108 }
1109
1110protected:
1111 virtual void shadeSpan(int x, int y, SkPMColor[], int count) {
1112 LOG_ALWAYS_FATAL("LayerShader should never be drawn with raster backend.");
1113 }
1114
1115 virtual void flatten(SkWriteBuffer&) const {
1116 LOG_ALWAYS_FATAL("LayerShader should never be flattened.");
1117 }
1118
1119 virtual Factory getFactory() const {
1120 LOG_ALWAYS_FATAL("LayerShader should never be created from a stream.");
1121 return NULL;
1122 }
1123private:
1124 // Unowned.
1125 Layer* mLayer;
1126 typedef SkShader INHERITED;
1127};
1128
Romain Guy5b3b3522010-10-27 18:57:51 -07001129void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
Chris Craik3f0854292014-04-15 16:18:08 -07001130 if (CC_UNLIKELY(layer->region.isEmpty())) return; // nothing to draw
1131
1132 if (layer->getConvexMask()) {
1133 save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
1134
1135 // clip to the area of the layer the mask can be larger
1136 clipRect(rect.left, rect.top, rect.right, rect.bottom, SkRegion::kIntersect_Op);
1137
1138 SkPaint paint;
1139 paint.setAntiAlias(true);
1140 paint.setColor(SkColorSetARGB(int(getLayerAlpha(layer) * 255), 0, 0, 0));
1141
Chris Craik3f0854292014-04-15 16:18:08 -07001142 // create LayerShader to map SaveLayer content into subsequent draw
1143 SkMatrix shaderMatrix;
1144 shaderMatrix.setTranslate(rect.left, rect.bottom);
1145 shaderMatrix.preScale(1, -1);
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04001146 LayerShader layerShader(layer, &shaderMatrix);
1147 paint.setShader(&layerShader);
Chris Craik3f0854292014-04-15 16:18:08 -07001148
1149 // Since the drawing primitive is defined in local drawing space,
1150 // we don't need to modify the draw matrix
1151 const SkPath* maskPath = layer->getConvexMask();
1152 DRAW_DOUBLE_STENCIL(drawConvexPath(*maskPath, &paint));
1153
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04001154 paint.setShader(NULL);
Chris Craik3f0854292014-04-15 16:18:08 -07001155 restore();
1156
1157 return;
1158 }
1159
Romain Guy5b3b3522010-10-27 18:57:51 -07001160 if (layer->region.isRect()) {
Romain Guy9fc27812011-04-27 14:21:41 -07001161 layer->setRegionAsRect();
1162
Chris Craik34416ea2013-04-15 16:08:28 -07001163 DRAW_DOUBLE_STENCIL(composeLayerRect(layer, layer->regionRect));
Romain Guy9fc27812011-04-27 14:21:41 -07001164
Romain Guy5b3b3522010-10-27 18:57:51 -07001165 layer->region.clear();
1166 return;
1167 }
1168
Chris Craik62d307c2014-07-29 10:35:13 -07001169 EVENT_LOGD("composeLayerRegion");
Chris Craik3f0854292014-04-15 16:18:08 -07001170 // standard Region based draw
1171 size_t count;
1172 const android::Rect* rects;
1173 Region safeRegion;
1174 if (CC_LIKELY(hasRectToRectTransform())) {
1175 rects = layer->region.getArray(&count);
1176 } else {
1177 safeRegion = Region::createTJunctionFreeRegion(layer->region);
1178 rects = safeRegion.getArray(&count);
1179 }
Romain Guy5b3b3522010-10-27 18:57:51 -07001180
Chris Craik3f0854292014-04-15 16:18:08 -07001181 const float alpha = getLayerAlpha(layer);
1182 const float texX = 1.0f / float(layer->getWidth());
1183 const float texY = 1.0f / float(layer->getHeight());
1184 const float height = rect.getHeight();
Romain Guy5b3b3522010-10-27 18:57:51 -07001185
Chris Craik3f0854292014-04-15 16:18:08 -07001186 setupDraw();
Romain Guy8ce00302013-01-15 18:51:42 -08001187
Chris Craik3f0854292014-04-15 16:18:08 -07001188 // We must get (and therefore bind) the region mesh buffer
1189 // after we setup drawing in case we need to mess with the
1190 // stencil buffer in setupDraw()
1191 TextureVertex* mesh = mCaches.getRegionMesh();
1192 uint32_t numQuads = 0;
Romain Guy5b3b3522010-10-27 18:57:51 -07001193
Chris Craik3f0854292014-04-15 16:18:08 -07001194 setupDrawWithTexture();
1195 setupDrawColor(alpha, alpha, alpha, alpha);
1196 setupDrawColorFilter(layer->getColorFilter());
1197 setupDrawBlending(layer);
1198 setupDrawProgram();
1199 setupDrawDirtyRegionsDisabled();
1200 setupDrawPureColorUniforms();
1201 setupDrawColorFilterUniforms(layer->getColorFilter());
1202 setupDrawTexture(layer->getTexture());
1203 if (currentTransform()->isPureTranslate()) {
1204 const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
1205 const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
Romain Guy9ace8f52011-07-07 20:50:11 -07001206
Chris Craik3f0854292014-04-15 16:18:08 -07001207 layer->setFilter(GL_NEAREST);
1208 setupDrawModelView(kModelViewMode_Translate, false,
1209 x, y, x + rect.getWidth(), y + rect.getHeight(), true);
1210 } else {
1211 layer->setFilter(GL_LINEAR);
1212 setupDrawModelView(kModelViewMode_Translate, false,
1213 rect.left, rect.top, rect.right, rect.bottom);
1214 }
1215 setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
Romain Guy5b3b3522010-10-27 18:57:51 -07001216
Chris Craik3f0854292014-04-15 16:18:08 -07001217 for (size_t i = 0; i < count; i++) {
1218 const android::Rect* r = &rects[i];
Romain Guy5b3b3522010-10-27 18:57:51 -07001219
Chris Craik3f0854292014-04-15 16:18:08 -07001220 const float u1 = r->left * texX;
1221 const float v1 = (height - r->top) * texY;
1222 const float u2 = r->right * texX;
1223 const float v2 = (height - r->bottom) * texY;
Romain Guy5b3b3522010-10-27 18:57:51 -07001224
Chris Craik3f0854292014-04-15 16:18:08 -07001225 // TODO: Reject quads outside of the clip
1226 TextureVertex::set(mesh++, r->left, r->top, u1, v1);
1227 TextureVertex::set(mesh++, r->right, r->top, u2, v1);
1228 TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
1229 TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
Romain Guy5b3b3522010-10-27 18:57:51 -07001230
Chris Craik3f0854292014-04-15 16:18:08 -07001231 numQuads++;
Romain Guy5b3b3522010-10-27 18:57:51 -07001232
Chris Craik3f0854292014-04-15 16:18:08 -07001233 if (numQuads >= gMaxNumberOfQuads) {
Chris Craik34416ea2013-04-15 16:08:28 -07001234 DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
1235 GL_UNSIGNED_SHORT, NULL));
Chris Craik3f0854292014-04-15 16:18:08 -07001236 numQuads = 0;
1237 mesh = mCaches.getRegionMesh();
Romain Guy5b3b3522010-10-27 18:57:51 -07001238 }
Chris Craik3f0854292014-04-15 16:18:08 -07001239 }
1240
1241 if (numQuads > 0) {
1242 DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
1243 GL_UNSIGNED_SHORT, NULL));
1244 }
Romain Guy5b3b3522010-10-27 18:57:51 -07001245
Romain Guy5b3b3522010-10-27 18:57:51 -07001246#if DEBUG_LAYERS_AS_REGIONS
Chris Craik3f0854292014-04-15 16:18:08 -07001247 drawRegionRectsDebug(layer->region);
Romain Guy5b3b3522010-10-27 18:57:51 -07001248#endif
1249
Chris Craik3f0854292014-04-15 16:18:08 -07001250 layer->region.clear();
Romain Guy5b3b3522010-10-27 18:57:51 -07001251}
1252
Romain Guy3a3133d2011-02-01 22:59:58 -08001253#if DEBUG_LAYERS_AS_REGIONS
Chris Craike63f7c622013-10-17 10:30:55 -07001254void OpenGLRenderer::drawRegionRectsDebug(const Region& region) {
Romain Guy3a3133d2011-02-01 22:59:58 -08001255 size_t count;
1256 const android::Rect* rects = region.getArray(&count);
1257
1258 uint32_t colors[] = {
1259 0x7fff0000, 0x7f00ff00,
1260 0x7f0000ff, 0x7fff00ff,
1261 };
1262
1263 int offset = 0;
1264 int32_t top = rects[0].top;
1265
1266 for (size_t i = 0; i < count; i++) {
1267 if (top != rects[i].top) {
1268 offset ^= 0x2;
1269 top = rects[i].top;
1270 }
1271
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05001272 SkPaint paint;
1273 paint.setColor(colors[offset + (i & 0x1)]);
Romain Guy3a3133d2011-02-01 22:59:58 -08001274 Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom);
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05001275 drawColorRect(r.left, r.top, r.right, r.bottom, paint);
Romain Guy3a3133d2011-02-01 22:59:58 -08001276 }
Romain Guy3a3133d2011-02-01 22:59:58 -08001277}
Chris Craike63f7c622013-10-17 10:30:55 -07001278#endif
Romain Guy3a3133d2011-02-01 22:59:58 -08001279
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05001280void OpenGLRenderer::drawRegionRects(const SkRegion& region, const SkPaint& paint, bool dirty) {
Romain Guy8ce00302013-01-15 18:51:42 -08001281 Vector<float> rects;
1282
1283 SkRegion::Iterator it(region);
1284 while (!it.done()) {
1285 const SkIRect& r = it.rect();
1286 rects.push(r.fLeft);
1287 rects.push(r.fTop);
1288 rects.push(r.fRight);
1289 rects.push(r.fBottom);
Romain Guy8ce00302013-01-15 18:51:42 -08001290 it.next();
1291 }
1292
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05001293 drawColorRects(rects.array(), rects.size(), &paint, true, dirty, false);
Romain Guy8ce00302013-01-15 18:51:42 -08001294}
1295
Romain Guy5b3b3522010-10-27 18:57:51 -07001296void OpenGLRenderer::dirtyLayer(const float left, const float top,
1297 const float right, const float bottom, const mat4 transform) {
Romain Guyf219da52011-01-16 12:54:25 -08001298 if (hasLayer()) {
Romain Guy5b3b3522010-10-27 18:57:51 -07001299 Rect bounds(left, top, right, bottom);
1300 transform.mapRect(bounds);
Romain Guyf219da52011-01-16 12:54:25 -08001301 dirtyLayerUnchecked(bounds, getRegion());
Romain Guy5b3b3522010-10-27 18:57:51 -07001302 }
Romain Guy5b3b3522010-10-27 18:57:51 -07001303}
1304
1305void OpenGLRenderer::dirtyLayer(const float left, const float top,
1306 const float right, const float bottom) {
Romain Guyf219da52011-01-16 12:54:25 -08001307 if (hasLayer()) {
Romain Guy5b3b3522010-10-27 18:57:51 -07001308 Rect bounds(left, top, right, bottom);
Romain Guyf219da52011-01-16 12:54:25 -08001309 dirtyLayerUnchecked(bounds, getRegion());
Romain Guy1bd1bad2011-01-14 20:07:20 -08001310 }
Romain Guy1bd1bad2011-01-14 20:07:20 -08001311}
1312
1313void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) {
Chris Craikd6b65f62014-01-01 14:45:21 -08001314 if (bounds.intersect(*currentClipRect())) {
Romain Guy1bd1bad2011-01-14 20:07:20 -08001315 bounds.snapToPixelBoundaries();
1316 android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
1317 if (!dirty.isEmpty()) {
1318 region->orSelf(dirty);
Romain Guy5b3b3522010-10-27 18:57:51 -07001319 }
1320 }
Romain Guy5b3b3522010-10-27 18:57:51 -07001321}
1322
Chris Craik4063a0e2013-11-15 16:06:56 -08001323void OpenGLRenderer::issueIndexedQuadDraw(Vertex* mesh, GLsizei quadsCount) {
Romain Guy448455f2013-07-22 13:57:50 -07001324 GLsizei elementsCount = quadsCount * 6;
1325 while (elementsCount > 0) {
1326 GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6);
1327
Romain Guy3380cfd2013-08-15 16:57:57 -07001328 setupDrawIndexedVertices(&mesh[0].x);
Romain Guy448455f2013-07-22 13:57:50 -07001329 glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, NULL);
1330
1331 elementsCount -= drawCount;
1332 // Though there are 4 vertices in a quad, we use 6 indices per
1333 // quad to draw with GL_TRIANGLES
1334 mesh += (drawCount / 6) * 4;
1335 }
1336}
1337
Romain Guy54be1cd2011-06-13 19:04:27 -07001338void OpenGLRenderer::clearLayerRegions() {
1339 const size_t count = mLayers.size();
1340 if (count == 0) return;
1341
Chris Craikd6b65f62014-01-01 14:45:21 -08001342 if (!currentSnapshot()->isIgnored()) {
Chris Craik62d307c2014-07-29 10:35:13 -07001343 EVENT_LOGD("clearLayerRegions");
Romain Guy54be1cd2011-06-13 19:04:27 -07001344 // Doing several glScissor/glClear here can negatively impact
1345 // GPUs with a tiler architecture, instead we draw quads with
1346 // the Clear blending mode
1347
1348 // The list contains bounds that have already been clipped
1349 // against their initial clip rect, and the current clip
1350 // is likely different so we need to disable clipping here
Romain Guy8a4ac612012-07-17 17:32:48 -07001351 bool scissorChanged = mCaches.disableScissor();
Romain Guy54be1cd2011-06-13 19:04:27 -07001352
Romain Guy448455f2013-07-22 13:57:50 -07001353 Vertex mesh[count * 4];
Romain Guy54be1cd2011-06-13 19:04:27 -07001354 Vertex* vertex = mesh;
1355
1356 for (uint32_t i = 0; i < count; i++) {
1357 Rect* bounds = mLayers.itemAt(i);
1358
Romain Guy54be1cd2011-06-13 19:04:27 -07001359 Vertex::set(vertex++, bounds->left, bounds->top);
1360 Vertex::set(vertex++, bounds->right, bounds->top);
1361 Vertex::set(vertex++, bounds->left, bounds->bottom);
Romain Guy54be1cd2011-06-13 19:04:27 -07001362 Vertex::set(vertex++, bounds->right, bounds->bottom);
1363
1364 delete bounds;
1365 }
Romain Guye67307c2013-02-11 18:01:20 -08001366 // We must clear the list of dirty rects before we
1367 // call setupDraw() to prevent stencil setup to do
1368 // the same thing again
1369 mLayers.clear();
Romain Guy54be1cd2011-06-13 19:04:27 -07001370
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05001371 SkPaint clearPaint;
1372 clearPaint.setXfermodeMode(SkXfermode::kClear_Mode);
1373
Romain Guy54be1cd2011-06-13 19:04:27 -07001374 setupDraw(false);
1375 setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f);
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05001376 setupDrawBlending(&clearPaint, true);
Romain Guy54be1cd2011-06-13 19:04:27 -07001377 setupDrawProgram();
1378 setupDrawPureColorUniforms();
Chris Craik4063a0e2013-11-15 16:06:56 -08001379 setupDrawModelView(kModelViewMode_Translate, false,
1380 0.0f, 0.0f, 0.0f, 0.0f, true);
Romain Guy54be1cd2011-06-13 19:04:27 -07001381
Chris Craik4063a0e2013-11-15 16:06:56 -08001382 issueIndexedQuadDraw(&mesh[0], count);
Romain Guy8a4ac612012-07-17 17:32:48 -07001383
1384 if (scissorChanged) mCaches.enableScissor();
Romain Guy54be1cd2011-06-13 19:04:27 -07001385 } else {
1386 for (uint32_t i = 0; i < count; i++) {
1387 delete mLayers.itemAt(i);
1388 }
Romain Guye67307c2013-02-11 18:01:20 -08001389 mLayers.clear();
Romain Guy54be1cd2011-06-13 19:04:27 -07001390 }
Romain Guy54be1cd2011-06-13 19:04:27 -07001391}
1392
Romain Guybd6b79b2010-06-26 00:13:53 -07001393///////////////////////////////////////////////////////////////////////////////
Chris Craikc3566d02013-02-04 16:16:33 -08001394// State Deferral
1395///////////////////////////////////////////////////////////////////////////////
1396
Chris Craikff785832013-03-08 13:12:16 -08001397bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) {
Chris Craikd6b65f62014-01-01 14:45:21 -08001398 const Rect* currentClip = currentClipRect();
1399 const mat4* currentMatrix = currentTransform();
Chris Craikc3566d02013-02-04 16:16:33 -08001400
Chris Craikff785832013-03-08 13:12:16 -08001401 if (stateDeferFlags & kStateDeferFlag_Draw) {
1402 // state has bounds initialized in local coordinates
1403 if (!state.mBounds.isEmpty()) {
Chris Craikd6b65f62014-01-01 14:45:21 -08001404 currentMatrix->mapRect(state.mBounds);
Chris Craik28ce94a2013-05-31 11:38:03 -07001405 Rect clippedBounds(state.mBounds);
Chris Craik5e49b302013-07-30 19:05:20 -07001406 // NOTE: if we ever want to use this clipping info to drive whether the scissor
1407 // is used, it should more closely duplicate the quickReject logic (in how it uses
1408 // snapToPixelBoundaries)
1409
Chris Craikd6b65f62014-01-01 14:45:21 -08001410 if(!clippedBounds.intersect(*currentClip)) {
Chris Craikff785832013-03-08 13:12:16 -08001411 // quick rejected
1412 return true;
1413 }
Chris Craik28ce94a2013-05-31 11:38:03 -07001414
Chris Craika02c4ed2013-06-14 13:43:58 -07001415 state.mClipSideFlags = kClipSide_None;
Chris Craikd6b65f62014-01-01 14:45:21 -08001416 if (!currentClip->contains(state.mBounds)) {
Chris Craik28ce94a2013-05-31 11:38:03 -07001417 int& flags = state.mClipSideFlags;
1418 // op partially clipped, so record which sides are clipped for clip-aware merging
Chris Craikd6b65f62014-01-01 14:45:21 -08001419 if (currentClip->left > state.mBounds.left) flags |= kClipSide_Left;
1420 if (currentClip->top > state.mBounds.top) flags |= kClipSide_Top;
1421 if (currentClip->right < state.mBounds.right) flags |= kClipSide_Right;
1422 if (currentClip->bottom < state.mBounds.bottom) flags |= kClipSide_Bottom;
Chris Craik28ce94a2013-05-31 11:38:03 -07001423 }
1424 state.mBounds.set(clippedBounds);
Chris Craikff785832013-03-08 13:12:16 -08001425 } else {
Chris Craikd72b73c2013-06-17 13:52:06 -07001426 // Empty bounds implies size unknown. Label op as conservatively clipped to disable
1427 // overdraw avoidance (since we don't know what it overlaps)
1428 state.mClipSideFlags = kClipSide_ConservativeFull;
Chris Craikd6b65f62014-01-01 14:45:21 -08001429 state.mBounds.set(*currentClip);
Chris Craikc3566d02013-02-04 16:16:33 -08001430 }
1431 }
1432
Chris Craik527a3aa2013-03-04 10:19:31 -08001433 state.mClipValid = (stateDeferFlags & kStateDeferFlag_Clip);
1434 if (state.mClipValid) {
Chris Craikd6b65f62014-01-01 14:45:21 -08001435 state.mClip.set(*currentClip);
Chris Craikff785832013-03-08 13:12:16 -08001436 }
1437
Chris Craik7273daa2013-03-28 11:25:24 -07001438 // Transform, drawModifiers, and alpha always deferred, since they are used by state operations
1439 // (Note: saveLayer/restore use colorFilter and alpha, so we just save restore everything)
Chris Craikd6b65f62014-01-01 14:45:21 -08001440 state.mMatrix.load(*currentMatrix);
Chris Craik7273daa2013-03-28 11:25:24 -07001441 state.mDrawModifiers = mDrawModifiers;
Chris Craikd6b65f62014-01-01 14:45:21 -08001442 state.mAlpha = currentSnapshot()->alpha;
Chris Craikdeeda3d2014-05-05 19:09:33 -07001443
1444 // always store/restore, since it's just a pointer
1445 state.mRoundRectClipState = currentSnapshot()->roundRectClipState;
Chris Craikc3566d02013-02-04 16:16:33 -08001446 return false;
1447}
1448
Chris Craik527a3aa2013-03-04 10:19:31 -08001449void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) {
Chris Craik14e51302013-12-30 15:32:54 -08001450 setMatrix(state.mMatrix);
Chris Craik7273daa2013-03-28 11:25:24 -07001451 mSnapshot->alpha = state.mAlpha;
Chris Craik14e51302013-12-30 15:32:54 -08001452 mDrawModifiers = state.mDrawModifiers;
Chris Craikdeeda3d2014-05-05 19:09:33 -07001453 mSnapshot->roundRectClipState = state.mRoundRectClipState;
Chris Craikff785832013-03-08 13:12:16 -08001454
Chris Craik527a3aa2013-03-04 10:19:31 -08001455 if (state.mClipValid && !skipClipRestore) {
Chris Craik28ce94a2013-05-31 11:38:03 -07001456 mSnapshot->setClip(state.mClip.left, state.mClip.top,
1457 state.mClip.right, state.mClip.bottom);
Chris Craikff785832013-03-08 13:12:16 -08001458 dirtyClip();
1459 }
Chris Craikc3566d02013-02-04 16:16:33 -08001460}
1461
Chris Craik28ce94a2013-05-31 11:38:03 -07001462/**
1463 * Merged multidraw (such as in drawText and drawBitmaps rely on the fact that no clipping is done
1464 * in the draw path. Instead, clipping is done ahead of time - either as a single clip rect (when at
1465 * least one op is clipped), or disabled entirely (because no merged op is clipped)
1466 *
1467 * This method should be called when restoreDisplayState() won't be restoring the clip
1468 */
1469void OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) {
1470 if (clipRect != NULL) {
1471 mSnapshot->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
1472 } else {
Chris Craik14e51302013-12-30 15:32:54 -08001473 mSnapshot->setClip(0, 0, getWidth(), getHeight());
Chris Craik28ce94a2013-05-31 11:38:03 -07001474 }
Chris Craik527a3aa2013-03-04 10:19:31 -08001475 dirtyClip();
Chris Craik28ce94a2013-05-31 11:38:03 -07001476 mCaches.setScissorEnabled(clipRect != NULL || mScissorOptimizationDisabled);
Chris Craik527a3aa2013-03-04 10:19:31 -08001477}
1478
Chris Craikc3566d02013-02-04 16:16:33 -08001479///////////////////////////////////////////////////////////////////////////////
Romain Guyf6a11b82010-06-23 17:47:49 -07001480// Clipping
1481///////////////////////////////////////////////////////////////////////////////
1482
Romain Guybb9524b2010-06-22 18:56:38 -07001483void OpenGLRenderer::setScissorFromClip() {
Chris Craikd6b65f62014-01-01 14:45:21 -08001484 Rect clip(*currentClipRect());
Romain Guye5ebcb02010-10-15 13:57:28 -07001485 clip.snapToPixelBoundaries();
Romain Guy8f85e802011-12-14 19:23:32 -08001486
Chris Craika64a2be2014-05-14 14:17:01 -07001487 if (mCaches.setScissor(clip.left, getViewportHeight() - clip.bottom,
Romain Guy8a4ac612012-07-17 17:32:48 -07001488 clip.getWidth(), clip.getHeight())) {
1489 mDirtyClip = false;
1490 }
Romain Guy9d5316e2010-06-24 19:30:36 -07001491}
1492
Romain Guy8ce00302013-01-15 18:51:42 -08001493void OpenGLRenderer::ensureStencilBuffer() {
1494 // Thanks to the mismatch between EGL and OpenGL ES FBO we
1495 // cannot attach a stencil buffer to fbo0 dynamically. Let's
1496 // just hope we have one when hasLayer() returns false.
1497 if (hasLayer()) {
Chris Craikd6b65f62014-01-01 14:45:21 -08001498 attachStencilBufferToLayer(currentSnapshot()->layer);
Romain Guy8ce00302013-01-15 18:51:42 -08001499 }
1500}
1501
1502void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) {
1503 // The layer's FBO is already bound when we reach this stage
1504 if (!layer->getStencilRenderBuffer()) {
Romain Guyc3fedaf2013-01-29 17:26:25 -08001505 // GL_QCOM_tiled_rendering doesn't like it if a renderbuffer
1506 // is attached after we initiated tiling. We must turn it off,
1507 // attach the new render buffer then turn tiling back on
1508 endTiling();
1509
Romain Guy8d4aeb72013-02-12 16:08:55 -08001510 RenderBuffer* buffer = mCaches.renderBufferCache.get(
Romain Guy3bbacf22013-02-06 16:51:04 -08001511 Stencil::getSmallestStencilFormat(), layer->getWidth(), layer->getHeight());
Romain Guy8ce00302013-01-15 18:51:42 -08001512 layer->setStencilRenderBuffer(buffer);
Romain Guyc3fedaf2013-01-29 17:26:25 -08001513
Romain Guyf735c8e2013-01-31 17:45:55 -08001514 startTiling(layer->clipRect, layer->layer.getHeight());
Romain Guy8ce00302013-01-15 18:51:42 -08001515 }
1516}
1517
1518void OpenGLRenderer::setStencilFromClip() {
1519 if (!mCaches.debugOverdraw) {
Chris Craikd6b65f62014-01-01 14:45:21 -08001520 if (!currentSnapshot()->clipRegion->isEmpty()) {
Chris Craik62d307c2014-07-29 10:35:13 -07001521 EVENT_LOGD("setStencilFromClip - enabling");
1522
Romain Guy8ce00302013-01-15 18:51:42 -08001523 // NOTE: The order here is important, we must set dirtyClip to false
1524 // before any draw call to avoid calling back into this method
1525 mDirtyClip = false;
1526
1527 ensureStencilBuffer();
1528
1529 mCaches.stencil.enableWrite();
1530
Chris Craikdeeda3d2014-05-05 19:09:33 -07001531 // Clear and update the stencil, but first make sure we restrict drawing
Romain Guy8ce00302013-01-15 18:51:42 -08001532 // to the region's bounds
1533 bool resetScissor = mCaches.enableScissor();
1534 if (resetScissor) {
1535 // The scissor was not set so we now need to update it
1536 setScissorFromClip();
1537 }
1538 mCaches.stencil.clear();
Chris Craikdeeda3d2014-05-05 19:09:33 -07001539
1540 // stash and disable the outline clip state, since stencil doesn't account for outline
1541 bool storedSkipOutlineClip = mSkipOutlineClip;
1542 mSkipOutlineClip = true;
Romain Guy8ce00302013-01-15 18:51:42 -08001543
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05001544 SkPaint paint;
Chris Craik98d608d2014-07-17 12:25:11 -07001545 paint.setColor(SK_ColorBLACK);
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05001546 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
1547
Romain Guy8ce00302013-01-15 18:51:42 -08001548 // NOTE: We could use the region contour path to generate a smaller mesh
1549 // Since we are using the stencil we could use the red book path
1550 // drawing technique. It might increase bandwidth usage though.
1551
1552 // The last parameter is important: we are not drawing in the color buffer
1553 // so we don't want to dirty the current layer, if any
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05001554 drawRegionRects(*(currentSnapshot()->clipRegion), paint, false);
Chris Craikdeeda3d2014-05-05 19:09:33 -07001555 if (resetScissor) mCaches.disableScissor();
1556 mSkipOutlineClip = storedSkipOutlineClip;
Romain Guy8ce00302013-01-15 18:51:42 -08001557
1558 mCaches.stencil.enableTest();
Romain Guy3ff0bfd2013-02-25 14:15:37 -08001559
1560 // Draw the region used to generate the stencil if the appropriate debug
1561 // mode is enabled
1562 if (mCaches.debugStencilClip == Caches::kStencilShowRegion) {
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05001563 paint.setColor(0x7f0000ff);
1564 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
1565 drawRegionRects(*(currentSnapshot()->clipRegion), paint);
Romain Guy3ff0bfd2013-02-25 14:15:37 -08001566 }
Romain Guy8ce00302013-01-15 18:51:42 -08001567 } else {
Chris Craik62d307c2014-07-29 10:35:13 -07001568 EVENT_LOGD("setStencilFromClip - disabling");
Romain Guy8ce00302013-01-15 18:51:42 -08001569 mCaches.stencil.disable();
1570 }
1571 }
1572}
1573
Chris Craikf0a59072013-11-19 18:00:46 -08001574/**
1575 * Returns false and sets scissor enable based upon bounds if drawing won't be clipped out.
1576 *
1577 * @param paint if not null, the bounds will be expanded to account for stroke depending on paint
1578 * style, and tessellated AA ramp
1579 */
1580bool OpenGLRenderer::quickRejectSetupScissor(float left, float top, float right, float bottom,
Chris Craikd218a922014-01-02 17:13:34 -08001581 const SkPaint* paint) {
Chris Craikf0a59072013-11-19 18:00:46 -08001582 bool snapOut = paint && paint->isAntiAlias();
1583
1584 if (paint && paint->getStyle() != SkPaint::kFill_Style) {
1585 float outset = paint->getStrokeWidth() * 0.5f;
1586 left -= outset;
1587 top -= outset;
1588 right += outset;
1589 bottom += outset;
1590 }
1591
Chris Craikdeeda3d2014-05-05 19:09:33 -07001592 bool clipRequired = false;
1593 bool roundRectClipRequired = false;
1594 if (calculateQuickRejectForScissor(left, top, right, bottom,
1595 &clipRequired, &roundRectClipRequired, snapOut)) {
Romain Guydbc26d22010-10-11 17:58:29 -07001596 return true;
1597 }
1598
Chris Craikf23b25a2014-06-26 15:46:20 -07001599 // not quick rejected, so enable the scissor if clipRequired
1600 mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
1601 mSkipOutlineClip = !roundRectClipRequired;
Chris Craik39a908c2013-06-13 14:39:01 -07001602 return false;
Romain Guyc7d53492010-06-25 13:41:57 -07001603}
1604
Romain Guy8ce00302013-01-15 18:51:42 -08001605void OpenGLRenderer::debugClip() {
1606#if DEBUG_CLIP_REGIONS
Chris Craikf23b25a2014-06-26 15:46:20 -07001607 if (!currentSnapshot()->clipRegion->isEmpty()) {
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05001608 SkPaint paint;
1609 paint.setColor(0x7f00ff00);
1610 drawRegionRects(*(currentSnapshot()->clipRegion, paint);
1611
Romain Guy8ce00302013-01-15 18:51:42 -08001612 }
1613#endif
1614}
1615
Romain Guyf6a11b82010-06-23 17:47:49 -07001616///////////////////////////////////////////////////////////////////////////////
Romain Guy70ca14e2010-12-13 18:24:33 -08001617// Drawing commands
1618///////////////////////////////////////////////////////////////////////////////
1619
Chris Craik62d307c2014-07-29 10:35:13 -07001620void OpenGLRenderer::setupDraw(bool clearLayer) {
Chris Craikf0a59072013-11-19 18:00:46 -08001621 // TODO: It would be best if we could do this before quickRejectSetupScissor()
Romain Guy8a4ac612012-07-17 17:32:48 -07001622 // changes the scissor test state
Chris Craik62d307c2014-07-29 10:35:13 -07001623 if (clearLayer) clearLayerRegions();
Romain Guy8ce00302013-01-15 18:51:42 -08001624 // Make sure setScissor & setStencil happen at the beginning of
1625 // this method
Chris Craikb98a0162013-02-21 11:30:22 -08001626 if (mDirtyClip) {
1627 if (mCaches.scissorEnabled) {
1628 setScissorFromClip();
1629 }
Chris Craik62d307c2014-07-29 10:35:13 -07001630
1631 if (clearLayer) {
1632 setStencilFromClip();
1633 } else {
1634 // While clearing layer, force disable stencil buffer, since
1635 // it's invalid to stencil-clip *during* the layer clear
1636 mCaches.stencil.disable();
1637 }
Romain Guy70ca14e2010-12-13 18:24:33 -08001638 }
Romain Guy3ff0bfd2013-02-25 14:15:37 -08001639
Romain Guy70ca14e2010-12-13 18:24:33 -08001640 mDescription.reset();
Romain Guy3ff0bfd2013-02-25 14:15:37 -08001641
Romain Guy70ca14e2010-12-13 18:24:33 -08001642 mSetShaderColor = false;
1643 mColorSet = false;
1644 mColorA = mColorR = mColorG = mColorB = 0.0f;
1645 mTextureUnit = 0;
1646 mTrackDirtyRegions = true;
Romain Guy3ff0bfd2013-02-25 14:15:37 -08001647
1648 // Enable debug highlight when what we're about to draw is tested against
1649 // the stencil buffer and if stencil highlight debugging is on
1650 mDescription.hasDebugHighlight = !mCaches.debugOverdraw &&
1651 mCaches.debugStencilClip == Caches::kStencilShowHighlight &&
1652 mCaches.stencil.isTestEnabled();
Romain Guy78dd96d2013-05-03 14:24:16 -07001653
1654 mDescription.emulateStencil = mCountOverdraw;
Romain Guy70ca14e2010-12-13 18:24:33 -08001655}
1656
1657void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
1658 mDescription.hasTexture = true;
1659 mDescription.hasAlpha8Texture = isAlpha8;
1660}
1661
Romain Guyff316ec2013-02-13 18:39:43 -08001662void OpenGLRenderer::setupDrawWithTextureAndColor(bool isAlpha8) {
1663 mDescription.hasTexture = true;
1664 mDescription.hasColors = true;
1665 mDescription.hasAlpha8Texture = isAlpha8;
1666}
1667
Romain Guyaa6c24c2011-04-28 18:40:04 -07001668void OpenGLRenderer::setupDrawWithExternalTexture() {
1669 mDescription.hasExternalTexture = true;
1670}
1671
Romain Guy15bc6432011-12-13 13:11:32 -08001672void OpenGLRenderer::setupDrawNoTexture() {
Romain Guyff316ec2013-02-13 18:39:43 -08001673 mCaches.disableTexCoordsVertexArray();
Romain Guy15bc6432011-12-13 13:11:32 -08001674}
1675
Chris Craik91a8c7c2014-08-12 14:31:35 -07001676void OpenGLRenderer::setupDrawVertexAlpha(bool useShadowAlphaInterp) {
1677 mDescription.hasVertexAlpha = true;
1678 mDescription.useShadowAlphaInterp = useShadowAlphaInterp;
Chet Haase5b0200b2011-04-13 17:58:08 -07001679}
1680
Romain Guy8d0d4782010-12-14 20:13:35 -08001681void OpenGLRenderer::setupDrawColor(int color, int alpha) {
1682 mColorA = alpha / 255.0f;
Romain Guy886b2752013-01-04 12:26:18 -08001683 mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f;
1684 mColorG = mColorA * ((color >> 8) & 0xFF) / 255.0f;
1685 mColorB = mColorA * ((color ) & 0xFF) / 255.0f;
Romain Guy70ca14e2010-12-13 18:24:33 -08001686 mColorSet = true;
Chris Craike63f7c622013-10-17 10:30:55 -07001687 mSetShaderColor = mDescription.setColorModulate(mColorA);
Romain Guy70ca14e2010-12-13 18:24:33 -08001688}
1689
Romain Guy86568192010-12-14 15:55:39 -08001690void OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) {
1691 mColorA = alpha / 255.0f;
Romain Guy886b2752013-01-04 12:26:18 -08001692 mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f;
1693 mColorG = mColorA * ((color >> 8) & 0xFF) / 255.0f;
1694 mColorB = mColorA * ((color ) & 0xFF) / 255.0f;
Romain Guy86568192010-12-14 15:55:39 -08001695 mColorSet = true;
Chris Craike63f7c622013-10-17 10:30:55 -07001696 mSetShaderColor = mDescription.setAlpha8ColorModulate(mColorR, mColorG, mColorB, mColorA);
Romain Guy86568192010-12-14 15:55:39 -08001697}
1698
Romain Guy41210632012-07-16 17:04:24 -07001699void OpenGLRenderer::setupDrawTextGamma(const SkPaint* paint) {
1700 mCaches.fontRenderer->describe(mDescription, paint);
1701}
1702
Romain Guy70ca14e2010-12-13 18:24:33 -08001703void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) {
1704 mColorA = a;
1705 mColorR = r;
1706 mColorG = g;
1707 mColorB = b;
1708 mColorSet = true;
Chris Craike63f7c622013-10-17 10:30:55 -07001709 mSetShaderColor = mDescription.setColorModulate(a);
Romain Guy70ca14e2010-12-13 18:24:33 -08001710}
1711
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04001712void OpenGLRenderer::setupDrawShader(const SkShader* shader) {
1713 if (shader != NULL) {
1714 SkiaShader::describe(&mCaches, mDescription, mExtensions, *shader);
Romain Guy70ca14e2010-12-13 18:24:33 -08001715 }
1716}
1717
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05001718void OpenGLRenderer::setupDrawColorFilter(const SkColorFilter* filter) {
1719 if (filter == NULL) {
1720 return;
1721 }
1722
1723 SkXfermode::Mode mode;
1724 if (filter->asColorMode(NULL, &mode)) {
1725 mDescription.colorOp = ProgramDescription::kColorBlend;
1726 mDescription.colorMode = mode;
1727 } else if (filter->asColorMatrix(NULL)) {
1728 mDescription.colorOp = ProgramDescription::kColorMatrix;
Romain Guy70ca14e2010-12-13 18:24:33 -08001729 }
1730}
1731
Romain Guyf09ef512011-05-27 11:43:46 -07001732void OpenGLRenderer::accountForClear(SkXfermode::Mode mode) {
1733 if (mColorSet && mode == SkXfermode::kClear_Mode) {
1734 mColorA = 1.0f;
1735 mColorR = mColorG = mColorB = 0.0f;
Romain Guy54be1cd2011-06-13 19:04:27 -07001736 mSetShaderColor = mDescription.modulate = true;
Romain Guyf09ef512011-05-27 11:43:46 -07001737 }
1738}
1739
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05001740void OpenGLRenderer::setupDrawBlending(const Layer* layer, bool swapSrcDst) {
1741 SkXfermode::Mode mode = layer->getMode();
Romain Guyf09ef512011-05-27 11:43:46 -07001742 // When the blending mode is kClear_Mode, we need to use a modulate color
1743 // argb=1,0,0,0
1744 accountForClear(mode);
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04001745 // TODO: check shader blending, once we have shader drawing support for layers.
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05001746 bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f ||
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04001747 (mColorSet && mColorA < 1.0f) || isBlendedColorFilter(layer->getColorFilter());
Chris Craikc3566d02013-02-04 16:16:33 -08001748 chooseBlending(blend, mode, mDescription, swapSrcDst);
Romain Guy70ca14e2010-12-13 18:24:33 -08001749}
1750
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05001751void OpenGLRenderer::setupDrawBlending(const SkPaint* paint, bool blend, bool swapSrcDst) {
1752 SkXfermode::Mode mode = getXfermodeDirect(paint);
Romain Guyf09ef512011-05-27 11:43:46 -07001753 // When the blending mode is kClear_Mode, we need to use a modulate color
1754 // argb=1,0,0,0
1755 accountForClear(mode);
Chris Craikc3566d02013-02-04 16:16:33 -08001756 blend |= (mColorSet && mColorA < 1.0f) ||
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04001757 (getShader(paint) && !getShader(paint)->isOpaque()) ||
1758 isBlendedColorFilter(getColorFilter(paint));
Chris Craikc3566d02013-02-04 16:16:33 -08001759 chooseBlending(blend, mode, mDescription, swapSrcDst);
Romain Guy70ca14e2010-12-13 18:24:33 -08001760}
1761
1762void OpenGLRenderer::setupDrawProgram() {
1763 useProgram(mCaches.programCache.get(mDescription));
Chris Craikdeeda3d2014-05-05 19:09:33 -07001764 if (mDescription.hasRoundRectClip) {
1765 // TODO: avoid doing this repeatedly, stashing state pointer in program
1766 const RoundRectClipState* state = mSnapshot->roundRectClipState;
Chris Craikaf4d04c2014-07-29 12:50:14 -07001767 const Rect& innerRect = state->innerRect;
Chris Craikdeeda3d2014-05-05 19:09:33 -07001768 glUniform4f(mCaches.currentProgram->getUniform("roundRectInnerRectLTRB"),
Chris Craikaf4d04c2014-07-29 12:50:14 -07001769 innerRect.left, innerRect.top,
1770 innerRect.right, innerRect.bottom);
Chris Craikdeeda3d2014-05-05 19:09:33 -07001771 glUniformMatrix4fv(mCaches.currentProgram->getUniform("roundRectInvTransform"),
1772 1, GL_FALSE, &state->matrix.data[0]);
Chris Craik4340c262014-09-11 18:58:45 -07001773
1774 // add half pixel to round out integer rect space to cover pixel centers
1775 float roundedOutRadius = state->radius + 0.5f;
1776 glUniform1f(mCaches.currentProgram->getUniform("roundRectRadius"),
1777 roundedOutRadius);
Chris Craikdeeda3d2014-05-05 19:09:33 -07001778 }
Romain Guy70ca14e2010-12-13 18:24:33 -08001779}
1780
1781void OpenGLRenderer::setupDrawDirtyRegionsDisabled() {
1782 mTrackDirtyRegions = false;
1783}
1784
Chris Craik4063a0e2013-11-15 16:06:56 -08001785void OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset,
1786 float left, float top, float right, float bottom, bool ignoreTransform) {
Chris Craike10e8272014-05-08 14:28:26 -07001787 mModelViewMatrix.loadTranslate(left, top, 0.0f);
Chris Craik4063a0e2013-11-15 16:06:56 -08001788 if (mode == kModelViewMode_TranslateAndScale) {
Chris Craike10e8272014-05-08 14:28:26 -07001789 mModelViewMatrix.scale(right - left, bottom - top, 1.0f);
Romain Guy70ca14e2010-12-13 18:24:33 -08001790 }
Chris Craik4063a0e2013-11-15 16:06:56 -08001791
Romain Guy86568192010-12-14 15:55:39 -08001792 bool dirty = right - left > 0.0f && bottom - top > 0.0f;
Chris Craika64a2be2014-05-14 14:17:01 -07001793 const Matrix4& transformMatrix = ignoreTransform ? Matrix4::identity() : *currentTransform();
1794 mCaches.currentProgram->set(mSnapshot->getOrthoMatrix(), mModelViewMatrix, transformMatrix, offset);
1795 if (dirty && mTrackDirtyRegions) {
1796 if (!ignoreTransform) {
1797 dirtyLayer(left, top, right, bottom, *currentTransform());
1798 } else {
1799 dirtyLayer(left, top, right, bottom);
1800 }
Romain Guy86568192010-12-14 15:55:39 -08001801 }
Romain Guy70ca14e2010-12-13 18:24:33 -08001802}
1803
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04001804void OpenGLRenderer::setupDrawColorUniforms(bool hasShader) {
1805 if ((mColorSet && !hasShader) || (hasShader && mSetShaderColor)) {
Romain Guy70ca14e2010-12-13 18:24:33 -08001806 mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
1807 }
1808}
1809
Romain Guy86568192010-12-14 15:55:39 -08001810void OpenGLRenderer::setupDrawPureColorUniforms() {
Romain Guy55368412010-12-14 10:59:41 -08001811 if (mSetShaderColor) {
Romain Guy86568192010-12-14 15:55:39 -08001812 mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
Romain Guy55368412010-12-14 10:59:41 -08001813 }
1814}
1815
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04001816void OpenGLRenderer::setupDrawShaderUniforms(const SkShader* shader, bool ignoreTransform) {
1817 if (shader == NULL) {
1818 return;
Romain Guy70ca14e2010-12-13 18:24:33 -08001819 }
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04001820
1821 if (ignoreTransform) {
1822 // if ignoreTransform=true was passed to setupDrawModelView, undo currentTransform()
1823 // because it was built into modelView / the geometry, and the description needs to
1824 // compensate.
1825 mat4 modelViewWithoutTransform;
1826 modelViewWithoutTransform.loadInverse(*currentTransform());
1827 modelViewWithoutTransform.multiply(mModelViewMatrix);
1828 mModelViewMatrix.load(modelViewWithoutTransform);
1829 }
1830
1831 SkiaShader::setupProgram(&mCaches, mModelViewMatrix, &mTextureUnit, mExtensions, *shader);
Romain Guy70ca14e2010-12-13 18:24:33 -08001832}
1833
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05001834void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) {
1835 if (NULL == filter) {
1836 return;
Romain Guy70ca14e2010-12-13 18:24:33 -08001837 }
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05001838
1839 SkColor color;
1840 SkXfermode::Mode mode;
1841 if (filter->asColorMode(&color, &mode)) {
1842 const int alpha = SkColorGetA(color);
1843 const GLfloat a = alpha / 255.0f;
1844 const GLfloat r = a * SkColorGetR(color) / 255.0f;
1845 const GLfloat g = a * SkColorGetG(color) / 255.0f;
1846 const GLfloat b = a * SkColorGetB(color) / 255.0f;
1847 glUniform4f(mCaches.currentProgram->getUniform("colorBlend"), r, g, b, a);
1848 return;
1849 }
1850
1851 SkScalar srcColorMatrix[20];
1852 if (filter->asColorMatrix(srcColorMatrix)) {
1853
1854 float colorMatrix[16];
1855 memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float));
1856 memcpy(&colorMatrix[4], &srcColorMatrix[5], 4 * sizeof(float));
1857 memcpy(&colorMatrix[8], &srcColorMatrix[10], 4 * sizeof(float));
1858 memcpy(&colorMatrix[12], &srcColorMatrix[15], 4 * sizeof(float));
1859
1860 // Skia uses the range [0..255] for the addition vector, but we need
1861 // the [0..1] range to apply the vector in GLSL
1862 float colorVector[4];
1863 colorVector[0] = srcColorMatrix[4] / 255.0f;
1864 colorVector[1] = srcColorMatrix[9] / 255.0f;
1865 colorVector[2] = srcColorMatrix[14] / 255.0f;
1866 colorVector[3] = srcColorMatrix[19] / 255.0f;
1867
1868 glUniformMatrix4fv(mCaches.currentProgram->getUniform("colorMatrix"), 1,
1869 GL_FALSE, colorMatrix);
1870 glUniform4fv(mCaches.currentProgram->getUniform("colorMatrixVector"), 1, colorVector);
1871 return;
1872 }
1873
1874 // it is an error if we ever get here
Romain Guy70ca14e2010-12-13 18:24:33 -08001875}
1876
Romain Guy41210632012-07-16 17:04:24 -07001877void OpenGLRenderer::setupDrawTextGammaUniforms() {
1878 mCaches.fontRenderer->setupProgram(mDescription, mCaches.currentProgram);
1879}
1880
Romain Guy70ca14e2010-12-13 18:24:33 -08001881void OpenGLRenderer::setupDrawSimpleMesh() {
Romain Guyf3a910b42011-12-12 20:35:21 -08001882 bool force = mCaches.bindMeshBuffer();
Chris Craikcb4d6002012-09-25 12:00:29 -07001883 mCaches.bindPositionVertexPointer(force, 0);
Romain Guy15bc6432011-12-13 13:11:32 -08001884 mCaches.unbindIndicesBuffer();
Romain Guy70ca14e2010-12-13 18:24:33 -08001885}
1886
1887void OpenGLRenderer::setupDrawTexture(GLuint texture) {
Romain Guy257ae352013-03-20 16:31:12 -07001888 if (texture) bindTexture(texture);
Romain Guy2d4fd362011-12-13 22:00:19 -08001889 mTextureUnit++;
Romain Guy15bc6432011-12-13 13:11:32 -08001890 mCaches.enableTexCoordsVertexArray();
Romain Guy70ca14e2010-12-13 18:24:33 -08001891}
1892
Romain Guyaa6c24c2011-04-28 18:40:04 -07001893void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) {
1894 bindExternalTexture(texture);
Romain Guy2d4fd362011-12-13 22:00:19 -08001895 mTextureUnit++;
Romain Guy15bc6432011-12-13 13:11:32 -08001896 mCaches.enableTexCoordsVertexArray();
Romain Guyaa6c24c2011-04-28 18:40:04 -07001897}
1898
Romain Guy8f0095c2011-05-02 17:24:22 -07001899void OpenGLRenderer::setupDrawTextureTransform() {
1900 mDescription.hasTextureTransform = true;
1901}
1902
1903void OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) {
Romain Guyaa6c24c2011-04-28 18:40:04 -07001904 glUniformMatrix4fv(mCaches.currentProgram->getUniform("mainTextureTransform"), 1,
1905 GL_FALSE, &transform.data[0]);
1906}
1907
Chris Craik564acf72014-01-02 16:46:18 -08001908void OpenGLRenderer::setupDrawMesh(const GLvoid* vertices,
1909 const GLvoid* texCoords, GLuint vbo) {
Romain Guyf3a910b42011-12-12 20:35:21 -08001910 bool force = false;
Romain Guy3b748a42013-04-17 18:54:38 -07001911 if (!vertices || vbo) {
Romain Guyf3a910b42011-12-12 20:35:21 -08001912 force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
Romain Guy70ca14e2010-12-13 18:24:33 -08001913 } else {
Romain Guyf3a910b42011-12-12 20:35:21 -08001914 force = mCaches.unbindMeshBuffer();
Romain Guy70ca14e2010-12-13 18:24:33 -08001915 }
Romain Guyd71dd362011-12-12 19:03:35 -08001916
Chris Craikcb4d6002012-09-25 12:00:29 -07001917 mCaches.bindPositionVertexPointer(force, vertices);
Romain Guy15bc6432011-12-13 13:11:32 -08001918 if (mCaches.currentProgram->texCoords >= 0) {
Chris Craikcb4d6002012-09-25 12:00:29 -07001919 mCaches.bindTexCoordsVertexPointer(force, texCoords);
Romain Guy15bc6432011-12-13 13:11:32 -08001920 }
1921
1922 mCaches.unbindIndicesBuffer();
1923}
1924
Chris Craik564acf72014-01-02 16:46:18 -08001925void OpenGLRenderer::setupDrawMesh(const GLvoid* vertices,
1926 const GLvoid* texCoords, const GLvoid* colors) {
Romain Guyff316ec2013-02-13 18:39:43 -08001927 bool force = mCaches.unbindMeshBuffer();
1928 GLsizei stride = sizeof(ColorTextureVertex);
1929
1930 mCaches.bindPositionVertexPointer(force, vertices, stride);
1931 if (mCaches.currentProgram->texCoords >= 0) {
1932 mCaches.bindTexCoordsVertexPointer(force, texCoords, stride);
1933 }
1934 int slot = mCaches.currentProgram->getAttrib("colors");
1935 if (slot >= 0) {
1936 glEnableVertexAttribArray(slot);
1937 glVertexAttribPointer(slot, 4, GL_FLOAT, GL_FALSE, stride, colors);
1938 }
1939
1940 mCaches.unbindIndicesBuffer();
1941}
1942
Chris Craik564acf72014-01-02 16:46:18 -08001943void OpenGLRenderer::setupDrawMeshIndices(const GLvoid* vertices,
1944 const GLvoid* texCoords, GLuint vbo) {
Romain Guy3b748a42013-04-17 18:54:38 -07001945 bool force = false;
1946 // If vbo is != 0 we want to treat the vertices parameter as an offset inside
1947 // a VBO. However, if vertices is set to NULL and vbo == 0 then we want to
1948 // use the default VBO found in Caches
1949 if (!vertices || vbo) {
1950 force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
1951 } else {
1952 force = mCaches.unbindMeshBuffer();
1953 }
ztenghui63d41ab2014-02-14 13:13:41 -08001954 mCaches.bindQuadIndicesBuffer();
Romain Guy3b748a42013-04-17 18:54:38 -07001955
Chris Craikcb4d6002012-09-25 12:00:29 -07001956 mCaches.bindPositionVertexPointer(force, vertices);
Romain Guy15bc6432011-12-13 13:11:32 -08001957 if (mCaches.currentProgram->texCoords >= 0) {
Chris Craikcb4d6002012-09-25 12:00:29 -07001958 mCaches.bindTexCoordsVertexPointer(force, texCoords);
Romain Guy8d0d4782010-12-14 20:13:35 -08001959 }
Romain Guy70ca14e2010-12-13 18:24:33 -08001960}
1961
Romain Guy448455f2013-07-22 13:57:50 -07001962void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) {
Romain Guyf3a910b42011-12-12 20:35:21 -08001963 bool force = mCaches.unbindMeshBuffer();
ztenghui63d41ab2014-02-14 13:13:41 -08001964 mCaches.bindQuadIndicesBuffer();
Chris Craikcb4d6002012-09-25 12:00:29 -07001965 mCaches.bindPositionVertexPointer(force, vertices, gVertexStride);
Chet Haase5b0200b2011-04-13 17:58:08 -07001966}
1967
Romain Guy70ca14e2010-12-13 18:24:33 -08001968///////////////////////////////////////////////////////////////////////////////
Romain Guyf6a11b82010-06-23 17:47:49 -07001969// Drawing
1970///////////////////////////////////////////////////////////////////////////////
1971
Chris Craika7090e02014-06-20 16:01:00 -07001972status_t OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags) {
Chet Haase58d110a2013-04-10 07:43:29 -07001973 status_t status;
Romain Guy0fe478e2010-11-08 12:08:41 -08001974 // All the usual checks and setup operations (quickReject, setupDraw, etc.)
1975 // will be performed by the display list itself
Chris Craika7090e02014-06-20 16:01:00 -07001976 if (renderNode && renderNode->isRenderable()) {
Chris Craikf57776b2013-10-25 18:30:17 -07001977 // compute 3d ordering
Chris Craika7090e02014-06-20 16:01:00 -07001978 renderNode->computeOrdering();
Chris Craikd90144d2013-03-19 15:03:48 -07001979 if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
Chet Haase58d110a2013-04-10 07:43:29 -07001980 status = startFrame();
Chris Craikff785832013-03-08 13:12:16 -08001981 ReplayStateStruct replayStruct(*this, dirty, replayFlags);
Chris Craika7090e02014-06-20 16:01:00 -07001982 renderNode->replay(replayStruct, 0);
Chet Haase58d110a2013-04-10 07:43:29 -07001983 return status | replayStruct.mDrawGlStatus;
Chris Craikc3566d02013-02-04 16:16:33 -08001984 }
1985
Chris Craik28ce94a2013-05-31 11:38:03 -07001986 bool avoidOverdraw = !mCaches.debugOverdraw && !mCountOverdraw; // shh, don't tell devs!
Chris Craikd6b65f62014-01-01 14:45:21 -08001987 DeferredDisplayList deferredList(*currentClipRect(), avoidOverdraw);
Chris Craikff785832013-03-08 13:12:16 -08001988 DeferStateStruct deferStruct(deferredList, *this, replayFlags);
Chris Craika7090e02014-06-20 16:01:00 -07001989 renderNode->defer(deferStruct, 0);
Romain Guy96885eb2013-03-26 15:05:58 -07001990
1991 flushLayers();
Chet Haase58d110a2013-04-10 07:43:29 -07001992 status = startFrame();
Romain Guy96885eb2013-03-26 15:05:58 -07001993
Chris Craikf57776b2013-10-25 18:30:17 -07001994 return deferredList.flush(*this, dirty) | status;
Romain Guy0fe478e2010-11-08 12:08:41 -08001995 }
Romain Guy7b5b6ab2011-03-14 18:05:08 -07001996
henry.uh_chen3a1bffa2014-07-03 18:01:37 +08001997 // Even if there is no drawing command(Ex: invisible),
1998 // it still needs startFrame to clear buffer and start tiling.
1999 return startFrame();
Romain Guy0fe478e2010-11-08 12:08:41 -08002000}
2001
Chris Craikd218a922014-01-02 17:13:34 -08002002void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, const SkPaint* paint) {
Romain Guy886b2752013-01-04 12:26:18 -08002003 int color = paint != NULL ? paint->getColor() : 0;
2004
Romain Guya168d732011-03-18 16:50:13 -07002005 float x = left;
2006 float y = top;
2007
Romain Guy886b2752013-01-04 12:26:18 -08002008 texture->setWrap(GL_CLAMP_TO_EDGE, true);
2009
Romain Guya168d732011-03-18 16:50:13 -07002010 bool ignoreTransform = false;
Chris Craikd6b65f62014-01-01 14:45:21 -08002011 if (currentTransform()->isPureTranslate()) {
2012 x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f);
2013 y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f);
Romain Guya168d732011-03-18 16:50:13 -07002014 ignoreTransform = true;
Romain Guy886b2752013-01-04 12:26:18 -08002015
2016 texture->setFilter(GL_NEAREST, true);
Romain Guyd21b6e12011-11-30 20:21:23 -08002017 } else {
Chris Craik678625242014-02-28 12:26:34 -08002018 texture->setFilter(getFilter(paint), true);
Romain Guya168d732011-03-18 16:50:13 -07002019 }
2020
Romain Guy3b748a42013-04-17 18:54:38 -07002021 // No need to check for a UV mapper on the texture object, only ARGB_8888
2022 // bitmaps get packed in the atlas
Romain Guy886b2752013-01-04 12:26:18 -08002023 drawAlpha8TextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05002024 paint, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset,
Romain Guy3b748a42013-04-17 18:54:38 -07002025 GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
Romain Guya168d732011-03-18 16:50:13 -07002026}
2027
Romain Guy03c00b52013-06-20 18:30:28 -07002028/**
2029 * Important note: this method is intended to draw batches of bitmaps and
2030 * will not set the scissor enable or dirty the current layer, if any.
2031 * The caller is responsible for properly dirtying the current layer.
2032 */
Chris Craikd218a922014-01-02 17:13:34 -08002033status_t OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
2034 int bitmapCount, TextureVertex* vertices, bool pureTranslate,
2035 const Rect& bounds, const SkPaint* paint) {
Chris Craik527a3aa2013-03-04 10:19:31 -08002036 mCaches.activeTexture(0);
Romain Guy55b6f952013-06-27 15:27:09 -07002037 Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
Chris Craik527a3aa2013-03-04 10:19:31 -08002038 if (!texture) return DrawGlInfo::kStatusDone;
Romain Guy3b748a42013-04-17 18:54:38 -07002039
Chris Craik527a3aa2013-03-04 10:19:31 -08002040 const AutoTexture autoCleanup(texture);
2041
Chris Craik527a3aa2013-03-04 10:19:31 -08002042 texture->setWrap(GL_CLAMP_TO_EDGE, true);
Chris Craik678625242014-02-28 12:26:34 -08002043 texture->setFilter(pureTranslate ? GL_NEAREST : getFilter(paint), true);
Chris Craik527a3aa2013-03-04 10:19:31 -08002044
2045 const float x = (int) floorf(bounds.left + 0.5f);
2046 const float y = (int) floorf(bounds.top + 0.5f);
Mike Reed1103b322014-07-08 12:36:44 -04002047 if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
Chris Craik527a3aa2013-03-04 10:19:31 -08002048 drawAlpha8TextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05002049 texture->id, paint, &vertices[0].x, &vertices[0].u,
Chris Craik4063a0e2013-11-15 16:06:56 -08002050 GL_TRIANGLES, bitmapCount * 6, true,
2051 kModelViewMode_Translate, false);
Chris Craik527a3aa2013-03-04 10:19:31 -08002052 } else {
2053 drawTextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05002054 texture->id, paint, texture->blend, &vertices[0].x, &vertices[0].u,
Chris Craik4063a0e2013-11-15 16:06:56 -08002055 GL_TRIANGLES, bitmapCount * 6, false, true, 0,
2056 kModelViewMode_Translate, false);
Chris Craik527a3aa2013-03-04 10:19:31 -08002057 }
2058
2059 return DrawGlInfo::kStatusDrew;
2060}
2061
Chris Craik79647502014-08-06 13:42:24 -07002062status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
2063 if (quickRejectSetupScissor(0, 0, bitmap->width(), bitmap->height())) {
Chet Haase48659092012-05-31 15:21:51 -07002064 return DrawGlInfo::kStatusDone;
Romain Guy6926c722010-07-12 20:20:03 -07002065 }
2066
Romain Guya1d3c912011-12-13 14:55:06 -08002067 mCaches.activeTexture(0);
Romain Guy3b748a42013-04-17 18:54:38 -07002068 Texture* texture = getTexture(bitmap);
Chet Haase48659092012-05-31 15:21:51 -07002069 if (!texture) return DrawGlInfo::kStatusDone;
Romain Guy22158e12010-08-06 11:18:34 -07002070 const AutoTexture autoCleanup(texture);
2071
Mike Reed1103b322014-07-08 12:36:44 -04002072 if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
Chris Craik79647502014-08-06 13:42:24 -07002073 drawAlphaBitmap(texture, 0, 0, paint);
Romain Guya168d732011-03-18 16:50:13 -07002074 } else {
Chris Craik79647502014-08-06 13:42:24 -07002075 drawTextureRect(0, 0, bitmap->width(), bitmap->height(), texture, paint);
Romain Guya168d732011-03-18 16:50:13 -07002076 }
Chet Haase48659092012-05-31 15:21:51 -07002077
2078 return DrawGlInfo::kStatusDrew;
Romain Guyce0537b2010-06-29 21:05:21 -07002079}
2080
Chris Craik79647502014-08-06 13:42:24 -07002081status_t OpenGLRenderer::drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint) {
2082 if (quickRejectSetupScissor(0, 0, bitmap->width(), bitmap->height())) {
Chet Haase48659092012-05-31 15:21:51 -07002083 return DrawGlInfo::kStatusDone;
Romain Guye651cc62012-05-14 19:44:40 -07002084 }
2085
2086 mCaches.activeTexture(0);
2087 Texture* texture = mCaches.textureCache.getTransient(bitmap);
2088 const AutoTexture autoCleanup(texture);
2089
Mike Reed1103b322014-07-08 12:36:44 -04002090 if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
Chris Craik79647502014-08-06 13:42:24 -07002091 drawAlphaBitmap(texture, 0, 0, paint);
Romain Guy886b2752013-01-04 12:26:18 -08002092 } else {
Chris Craik79647502014-08-06 13:42:24 -07002093 drawTextureRect(0, 0, bitmap->width(), bitmap->height(), texture, paint);
Romain Guy886b2752013-01-04 12:26:18 -08002094 }
Chet Haase48659092012-05-31 15:21:51 -07002095
2096 return DrawGlInfo::kStatusDrew;
Romain Guye651cc62012-05-14 19:44:40 -07002097}
2098
Chris Craikd218a922014-01-02 17:13:34 -08002099status_t OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
2100 const float* vertices, const int* colors, const SkPaint* paint) {
Chris Craikd6b65f62014-01-01 14:45:21 -08002101 if (!vertices || currentSnapshot()->isIgnored()) {
Chet Haase48659092012-05-31 15:21:51 -07002102 return DrawGlInfo::kStatusDone;
Romain Guy5a7b4662011-01-20 19:09:30 -08002103 }
2104
Chris Craik39a908c2013-06-13 14:39:01 -07002105 // TODO: use quickReject on bounds from vertices
2106 mCaches.enableScissor();
2107
Romain Guyb18d2d02011-02-10 15:52:54 -08002108 float left = FLT_MAX;
2109 float top = FLT_MAX;
2110 float right = FLT_MIN;
2111 float bottom = FLT_MIN;
2112
Romain Guya92bb4d2012-10-16 11:08:44 -07002113 const uint32_t count = meshWidth * meshHeight * 6;
Romain Guyb18d2d02011-02-10 15:52:54 -08002114
Chris Craik564acf72014-01-02 16:46:18 -08002115 Vector<ColorTextureVertex> mesh; // TODO: use C++11 unique_ptr
2116 mesh.setCapacity(count);
2117 ColorTextureVertex* vertex = mesh.editArray();
Romain Guyff316ec2013-02-13 18:39:43 -08002118
2119 bool cleanupColors = false;
2120 if (!colors) {
2121 uint32_t colorsCount = (meshWidth + 1) * (meshHeight + 1);
Chris Craikd218a922014-01-02 17:13:34 -08002122 int* newColors = new int[colorsCount];
2123 memset(newColors, 0xff, colorsCount * sizeof(int));
2124 colors = newColors;
Romain Guyff316ec2013-02-13 18:39:43 -08002125 cleanupColors = true;
2126 }
Romain Guya92bb4d2012-10-16 11:08:44 -07002127
Romain Guy3b748a42013-04-17 18:54:38 -07002128 mCaches.activeTexture(0);
2129 Texture* texture = mCaches.assetAtlas.getEntryTexture(bitmap);
2130 const UvMapper& mapper(getMapper(texture));
2131
Romain Guy5a7b4662011-01-20 19:09:30 -08002132 for (int32_t y = 0; y < meshHeight; y++) {
2133 for (int32_t x = 0; x < meshWidth; x++) {
2134 uint32_t i = (y * (meshWidth + 1) + x) * 2;
2135
2136 float u1 = float(x) / meshWidth;
2137 float u2 = float(x + 1) / meshWidth;
2138 float v1 = float(y) / meshHeight;
2139 float v2 = float(y + 1) / meshHeight;
2140
Romain Guy3b748a42013-04-17 18:54:38 -07002141 mapper.map(u1, v1, u2, v2);
2142
Romain Guy5a7b4662011-01-20 19:09:30 -08002143 int ax = i + (meshWidth + 1) * 2;
2144 int ay = ax + 1;
2145 int bx = i;
2146 int by = bx + 1;
2147 int cx = i + 2;
2148 int cy = cx + 1;
2149 int dx = i + (meshWidth + 1) * 2 + 2;
2150 int dy = dx + 1;
2151
Romain Guyff316ec2013-02-13 18:39:43 -08002152 ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
2153 ColorTextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2, colors[ax / 2]);
2154 ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
Romain Guy5a7b4662011-01-20 19:09:30 -08002155
Romain Guyff316ec2013-02-13 18:39:43 -08002156 ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
2157 ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
2158 ColorTextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1, colors[cx / 2]);
Romain Guyb18d2d02011-02-10 15:52:54 -08002159
Romain Guya92bb4d2012-10-16 11:08:44 -07002160 left = fminf(left, fminf(vertices[ax], fminf(vertices[bx], vertices[cx])));
2161 top = fminf(top, fminf(vertices[ay], fminf(vertices[by], vertices[cy])));
2162 right = fmaxf(right, fmaxf(vertices[ax], fmaxf(vertices[bx], vertices[cx])));
2163 bottom = fmaxf(bottom, fmaxf(vertices[ay], fmaxf(vertices[by], vertices[cy])));
Romain Guy5a7b4662011-01-20 19:09:30 -08002164 }
2165 }
2166
Chris Craikf0a59072013-11-19 18:00:46 -08002167 if (quickRejectSetupScissor(left, top, right, bottom)) {
Romain Guyff316ec2013-02-13 18:39:43 -08002168 if (cleanupColors) delete[] colors;
Romain Guya92bb4d2012-10-16 11:08:44 -07002169 return DrawGlInfo::kStatusDone;
2170 }
2171
Romain Guyff316ec2013-02-13 18:39:43 -08002172 if (!texture) {
Romain Guy3b748a42013-04-17 18:54:38 -07002173 texture = mCaches.textureCache.get(bitmap);
2174 if (!texture) {
2175 if (cleanupColors) delete[] colors;
2176 return DrawGlInfo::kStatusDone;
2177 }
Romain Guyff316ec2013-02-13 18:39:43 -08002178 }
Romain Guya92bb4d2012-10-16 11:08:44 -07002179 const AutoTexture autoCleanup(texture);
2180
2181 texture->setWrap(GL_CLAMP_TO_EDGE, true);
Chris Craik678625242014-02-28 12:26:34 -08002182 texture->setFilter(getFilter(paint), true);
Romain Guya92bb4d2012-10-16 11:08:44 -07002183
2184 int alpha;
2185 SkXfermode::Mode mode;
2186 getAlphaAndMode(paint, &alpha, &mode);
2187
Romain Guyff316ec2013-02-13 18:39:43 -08002188 float a = alpha / 255.0f;
2189
Romain Guya92bb4d2012-10-16 11:08:44 -07002190 if (hasLayer()) {
Chris Craikd6b65f62014-01-01 14:45:21 -08002191 dirtyLayer(left, top, right, bottom, *currentTransform());
Romain Guyb18d2d02011-02-10 15:52:54 -08002192 }
Romain Guyb18d2d02011-02-10 15:52:54 -08002193
Romain Guyff316ec2013-02-13 18:39:43 -08002194 setupDraw();
2195 setupDrawWithTextureAndColor();
2196 setupDrawColor(a, a, a, a);
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05002197 setupDrawColorFilter(getColorFilter(paint));
2198 setupDrawBlending(paint, true);
Romain Guyff316ec2013-02-13 18:39:43 -08002199 setupDrawProgram();
2200 setupDrawDirtyRegionsDisabled();
Chris Craik4063a0e2013-11-15 16:06:56 -08002201 setupDrawModelView(kModelViewMode_TranslateAndScale, false, 0.0f, 0.0f, 1.0f, 1.0f);
Romain Guyff316ec2013-02-13 18:39:43 -08002202 setupDrawTexture(texture->id);
2203 setupDrawPureColorUniforms();
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05002204 setupDrawColorFilterUniforms(getColorFilter(paint));
Romain Guy3380cfd2013-08-15 16:57:57 -07002205 setupDrawMesh(&mesh[0].x, &mesh[0].u, &mesh[0].r);
Romain Guyff316ec2013-02-13 18:39:43 -08002206
2207 glDrawArrays(GL_TRIANGLES, 0, count);
2208
Romain Guyff316ec2013-02-13 18:39:43 -08002209 int slot = mCaches.currentProgram->getAttrib("colors");
2210 if (slot >= 0) {
2211 glDisableVertexAttribArray(slot);
2212 }
2213
2214 if (cleanupColors) delete[] colors;
Chet Haase48659092012-05-31 15:21:51 -07002215
2216 return DrawGlInfo::kStatusDrew;
Romain Guy5a7b4662011-01-20 19:09:30 -08002217}
2218
Chris Craikd218a922014-01-02 17:13:34 -08002219status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap,
Romain Guy8ba548f2010-06-30 19:21:21 -07002220 float srcLeft, float srcTop, float srcRight, float srcBottom,
2221 float dstLeft, float dstTop, float dstRight, float dstBottom,
Chris Craikd218a922014-01-02 17:13:34 -08002222 const SkPaint* paint) {
Chris Craikf0a59072013-11-19 18:00:46 -08002223 if (quickRejectSetupScissor(dstLeft, dstTop, dstRight, dstBottom)) {
Chet Haase48659092012-05-31 15:21:51 -07002224 return DrawGlInfo::kStatusDone;
Romain Guy6926c722010-07-12 20:20:03 -07002225 }
2226
Romain Guya1d3c912011-12-13 14:55:06 -08002227 mCaches.activeTexture(0);
Romain Guy3b748a42013-04-17 18:54:38 -07002228 Texture* texture = getTexture(bitmap);
Chet Haase48659092012-05-31 15:21:51 -07002229 if (!texture) return DrawGlInfo::kStatusDone;
Romain Guy22158e12010-08-06 11:18:34 -07002230 const AutoTexture autoCleanup(texture);
Romain Guy8ba548f2010-06-30 19:21:21 -07002231
Romain Guy8ba548f2010-06-30 19:21:21 -07002232 const float width = texture->width;
2233 const float height = texture->height;
2234
Romain Guy3b748a42013-04-17 18:54:38 -07002235 float u1 = fmax(0.0f, srcLeft / width);
2236 float v1 = fmax(0.0f, srcTop / height);
2237 float u2 = fmin(1.0f, srcRight / width);
2238 float v2 = fmin(1.0f, srcBottom / height);
2239
2240 getMapper(texture).map(u1, v1, u2, v2);
Romain Guy8ba548f2010-06-30 19:21:21 -07002241
Romain Guy03750a02010-10-18 14:06:08 -07002242 mCaches.unbindMeshBuffer();
Romain Guy8ba548f2010-06-30 19:21:21 -07002243 resetDrawTextureTexCoords(u1, v1, u2, v2);
2244
Romain Guyd21b6e12011-11-30 20:21:23 -08002245 texture->setWrap(GL_CLAMP_TO_EDGE, true);
2246
Romain Guy886b2752013-01-04 12:26:18 -08002247 float scaleX = (dstRight - dstLeft) / (srcRight - srcLeft);
2248 float scaleY = (dstBottom - dstTop) / (srcBottom - srcTop);
Romain Guy6620c6d2010-12-06 18:07:02 -08002249
Romain Guy886b2752013-01-04 12:26:18 -08002250 bool scaled = scaleX != 1.0f || scaleY != 1.0f;
2251 // Apply a scale transform on the canvas only when a shader is in use
2252 // Skia handles the ratio between the dst and src rects as a scale factor
2253 // when a shader is set
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04002254 bool useScaleTransform = getShader(paint) && scaled;
Romain Guy886b2752013-01-04 12:26:18 -08002255 bool ignoreTransform = false;
Romain Guyb5014982011-07-28 15:39:12 -07002256
Chris Craikd6b65f62014-01-01 14:45:21 -08002257 if (CC_LIKELY(currentTransform()->isPureTranslate() && !useScaleTransform)) {
2258 float x = (int) floorf(dstLeft + currentTransform()->getTranslateX() + 0.5f);
2259 float y = (int) floorf(dstTop + currentTransform()->getTranslateY() + 0.5f);
Romain Guy886b2752013-01-04 12:26:18 -08002260
2261 dstRight = x + (dstRight - dstLeft);
2262 dstBottom = y + (dstBottom - dstTop);
2263
2264 dstLeft = x;
2265 dstTop = y;
2266
Chris Craik678625242014-02-28 12:26:34 -08002267 texture->setFilter(scaled ? getFilter(paint) : GL_NEAREST, true);
Romain Guy886b2752013-01-04 12:26:18 -08002268 ignoreTransform = true;
Romain Guy6620c6d2010-12-06 18:07:02 -08002269 } else {
Chris Craik678625242014-02-28 12:26:34 -08002270 texture->setFilter(getFilter(paint), true);
Romain Guy886b2752013-01-04 12:26:18 -08002271 }
2272
2273 if (CC_UNLIKELY(useScaleTransform)) {
2274 save(SkCanvas::kMatrix_SaveFlag);
2275 translate(dstLeft, dstTop);
2276 scale(scaleX, scaleY);
2277
2278 dstLeft = 0.0f;
2279 dstTop = 0.0f;
2280
2281 dstRight = srcRight - srcLeft;
2282 dstBottom = srcBottom - srcTop;
2283 }
2284
Mike Reed1103b322014-07-08 12:36:44 -04002285 if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
Romain Guy886b2752013-01-04 12:26:18 -08002286 drawAlpha8TextureMesh(dstLeft, dstTop, dstRight, dstBottom,
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05002287 texture->id, paint,
Romain Guy3380cfd2013-08-15 16:57:57 -07002288 &mMeshVertices[0].x, &mMeshVertices[0].u,
Romain Guy886b2752013-01-04 12:26:18 -08002289 GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
2290 } else {
2291 drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom,
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05002292 texture->id, paint, texture->blend,
Romain Guy3380cfd2013-08-15 16:57:57 -07002293 &mMeshVertices[0].x, &mMeshVertices[0].u,
Romain Guy886b2752013-01-04 12:26:18 -08002294 GL_TRIANGLE_STRIP, gMeshCount, false, ignoreTransform);
2295 }
2296
2297 if (CC_UNLIKELY(useScaleTransform)) {
2298 restore();
Romain Guy6620c6d2010-12-06 18:07:02 -08002299 }
Romain Guy8ba548f2010-06-30 19:21:21 -07002300
2301 resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
Chet Haase48659092012-05-31 15:21:51 -07002302
2303 return DrawGlInfo::kStatusDrew;
Romain Guy8ba548f2010-06-30 19:21:21 -07002304}
2305
Chris Craikd218a922014-01-02 17:13:34 -08002306status_t OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
2307 float left, float top, float right, float bottom, const SkPaint* paint) {
Chris Craikf0a59072013-11-19 18:00:46 -08002308 if (quickRejectSetupScissor(left, top, right, bottom)) {
Chet Haase48659092012-05-31 15:21:51 -07002309 return DrawGlInfo::kStatusDone;
Romain Guy6926c722010-07-12 20:20:03 -07002310 }
2311
Romain Guy4c2547f2013-06-11 16:19:24 -07002312 AssetAtlas::Entry* entry = mCaches.assetAtlas.getEntry(bitmap);
Romain Guy3b748a42013-04-17 18:54:38 -07002313 const Patch* mesh = mCaches.patchCache.get(entry, bitmap->width(), bitmap->height(),
2314 right - left, bottom - top, patch);
Romain Guyf7f93552010-07-08 19:17:03 -07002315
Romain Guy03c00b52013-06-20 18:30:28 -07002316 return drawPatch(bitmap, mesh, entry, left, top, right, bottom, paint);
Romain Guy4c2547f2013-06-11 16:19:24 -07002317}
2318
Chris Craikd218a922014-01-02 17:13:34 -08002319status_t OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh,
2320 AssetAtlas::Entry* entry, float left, float top, float right, float bottom,
2321 const SkPaint* paint) {
Chris Craikf0a59072013-11-19 18:00:46 -08002322 if (quickRejectSetupScissor(left, top, right, bottom)) {
Romain Guy4c2547f2013-06-11 16:19:24 -07002323 return DrawGlInfo::kStatusDone;
2324 }
2325
Romain Guy211370f2012-02-01 16:10:55 -08002326 if (CC_LIKELY(mesh && mesh->verticesCount > 0)) {
Romain Guya4adcf02013-02-28 12:15:35 -08002327 mCaches.activeTexture(0);
Romain Guya404e162013-05-24 16:19:19 -07002328 Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
Romain Guya4adcf02013-02-28 12:15:35 -08002329 if (!texture) return DrawGlInfo::kStatusDone;
2330 const AutoTexture autoCleanup(texture);
Romain Guy3b748a42013-04-17 18:54:38 -07002331
Romain Guya4adcf02013-02-28 12:15:35 -08002332 texture->setWrap(GL_CLAMP_TO_EDGE, true);
2333 texture->setFilter(GL_LINEAR, true);
2334
Chris Craikd6b65f62014-01-01 14:45:21 -08002335 const bool pureTranslate = currentTransform()->isPureTranslate();
Romain Guy5b3b3522010-10-27 18:57:51 -07002336 // Mark the current layer dirty where we are going to draw the patch
Romain Guy81683962011-01-24 20:40:18 -08002337 if (hasLayer() && mesh->hasEmptyQuads) {
Chris Craikd6b65f62014-01-01 14:45:21 -08002338 const float offsetX = left + currentTransform()->getTranslateX();
2339 const float offsetY = top + currentTransform()->getTranslateY();
Romain Guy5b3b3522010-10-27 18:57:51 -07002340 const size_t count = mesh->quads.size();
2341 for (size_t i = 0; i < count; i++) {
Romain Guy8ab40792010-12-07 13:30:10 -08002342 const Rect& bounds = mesh->quads.itemAt(i);
Romain Guy211370f2012-02-01 16:10:55 -08002343 if (CC_LIKELY(pureTranslate)) {
Romain Guyc78b5d52011-02-04 14:00:42 -08002344 const float x = (int) floorf(bounds.left + offsetX + 0.5f);
2345 const float y = (int) floorf(bounds.top + offsetY + 0.5f);
2346 dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight());
Romain Guy6620c6d2010-12-06 18:07:02 -08002347 } else {
Romain Guyc78b5d52011-02-04 14:00:42 -08002348 dirtyLayer(left + bounds.left, top + bounds.top,
Chris Craikd6b65f62014-01-01 14:45:21 -08002349 left + bounds.right, top + bounds.bottom, *currentTransform());
Romain Guy6620c6d2010-12-06 18:07:02 -08002350 }
Romain Guy5b3b3522010-10-27 18:57:51 -07002351 }
2352 }
2353
Chris Craik4063a0e2013-11-15 16:06:56 -08002354 bool ignoreTransform = false;
Romain Guy211370f2012-02-01 16:10:55 -08002355 if (CC_LIKELY(pureTranslate)) {
Chris Craikd6b65f62014-01-01 14:45:21 -08002356 const float x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f);
2357 const float y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f);
Romain Guy6620c6d2010-12-06 18:07:02 -08002358
Romain Guy3b748a42013-04-17 18:54:38 -07002359 right = x + right - left;
2360 bottom = y + bottom - top;
Chris Craik4063a0e2013-11-15 16:06:56 -08002361 left = x;
2362 top = y;
2363 ignoreTransform = true;
Romain Guy6620c6d2010-12-06 18:07:02 -08002364 }
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05002365 drawIndexedTextureMesh(left, top, right, bottom, texture->id, paint,
2366 texture->blend, (GLvoid*) mesh->offset, (GLvoid*) mesh->textureOffset,
Chris Craik4063a0e2013-11-15 16:06:56 -08002367 GL_TRIANGLES, mesh->indexCount, false, ignoreTransform,
2368 mCaches.patchCache.getMeshBuffer(), kModelViewMode_Translate, !mesh->hasEmptyQuads);
Romain Guy054dc182010-10-15 17:55:25 -07002369 }
Chet Haase48659092012-05-31 15:21:51 -07002370
2371 return DrawGlInfo::kStatusDrew;
Romain Guyf7f93552010-07-08 19:17:03 -07002372}
2373
Romain Guy03c00b52013-06-20 18:30:28 -07002374/**
2375 * Important note: this method is intended to draw batches of 9-patch objects and
2376 * will not set the scissor enable or dirty the current layer, if any.
2377 * The caller is responsible for properly dirtying the current layer.
2378 */
Chris Craikd218a922014-01-02 17:13:34 -08002379status_t OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
2380 TextureVertex* vertices, uint32_t indexCount, const SkPaint* paint) {
Romain Guy03c00b52013-06-20 18:30:28 -07002381 mCaches.activeTexture(0);
2382 Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
2383 if (!texture) return DrawGlInfo::kStatusDone;
2384 const AutoTexture autoCleanup(texture);
2385
2386 texture->setWrap(GL_CLAMP_TO_EDGE, true);
2387 texture->setFilter(GL_LINEAR, true);
2388
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05002389 drawIndexedTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, paint,
2390 texture->blend, &vertices[0].x, &vertices[0].u,
Chris Craik4063a0e2013-11-15 16:06:56 -08002391 GL_TRIANGLES, indexCount, false, true, 0, kModelViewMode_Translate, false);
Romain Guy03c00b52013-06-20 18:30:28 -07002392
2393 return DrawGlInfo::kStatusDrew;
2394}
2395
Chris Craik05f3d6e2014-06-02 16:27:04 -07002396status_t OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
Chris Craikbf759452014-08-11 16:00:44 -07002397 const VertexBuffer& vertexBuffer, const SkPaint* paint, int displayFlags) {
Chris Craik4063a0e2013-11-15 16:06:56 -08002398 // not missing call to quickReject/dirtyLayer, always done at a higher level
Chris Craik6d29c8d2013-05-08 18:35:44 -07002399 if (!vertexBuffer.getVertexCount()) {
Chris Craik65cd6122012-12-10 17:56:27 -08002400 // no vertices to draw
2401 return DrawGlInfo::kStatusDone;
2402 }
2403
Chris Craik0d5ac952014-07-15 13:01:02 -07002404 Rect bounds(vertexBuffer.getBounds());
2405 bounds.translate(translateX, translateY);
Chris Craik05f3d6e2014-06-02 16:27:04 -07002406 dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform());
2407
Chris Craikcb4d6002012-09-25 12:00:29 -07002408 int color = paint->getColor();
Chris Craikcb4d6002012-09-25 12:00:29 -07002409 bool isAA = paint->isAntiAlias();
2410
Chris Craik710f46d2012-09-17 17:25:49 -07002411 setupDraw();
2412 setupDrawNoTexture();
Chris Craik91a8c7c2014-08-12 14:31:35 -07002413 if (isAA) setupDrawVertexAlpha((displayFlags & kVertexBuffer_ShadowInterp));
Chris Craik710f46d2012-09-17 17:25:49 -07002414 setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05002415 setupDrawColorFilter(getColorFilter(paint));
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04002416 setupDrawShader(getShader(paint));
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05002417 setupDrawBlending(paint, isAA);
Chris Craik710f46d2012-09-17 17:25:49 -07002418 setupDrawProgram();
Chris Craikbf759452014-08-11 16:00:44 -07002419 setupDrawModelView(kModelViewMode_Translate, (displayFlags & kVertexBuffer_Offset),
2420 translateX, translateY, 0, 0);
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04002421 setupDrawColorUniforms(getShader(paint));
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05002422 setupDrawColorFilterUniforms(getColorFilter(paint));
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04002423 setupDrawShaderUniforms(getShader(paint));
Chet Haase858aa932011-05-12 09:06:00 -07002424
ztenghui55bfb4e2013-12-03 10:38:55 -08002425 const void* vertices = vertexBuffer.getBuffer();
Chris Craik710f46d2012-09-17 17:25:49 -07002426 bool force = mCaches.unbindMeshBuffer();
Chris Craikcb4d6002012-09-25 12:00:29 -07002427 mCaches.bindPositionVertexPointer(true, vertices, isAA ? gAlphaVertexStride : gVertexStride);
Chris Craik710f46d2012-09-17 17:25:49 -07002428 mCaches.resetTexCoordsVertexPointer();
ztenghui63d41ab2014-02-14 13:13:41 -08002429
Chris Craik710f46d2012-09-17 17:25:49 -07002430 int alphaSlot = -1;
2431 if (isAA) {
2432 void* alphaCoords = ((GLbyte*) vertices) + gVertexAlphaOffset;
2433 alphaSlot = mCaches.currentProgram->getAttrib("vtxAlpha");
Chris Craik710f46d2012-09-17 17:25:49 -07002434 // TODO: avoid enable/disable in back to back uses of the alpha attribute
Chris Craik6ebdc112012-08-31 18:24:33 -07002435 glEnableVertexAttribArray(alphaSlot);
2436 glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords);
Chris Craik710f46d2012-09-17 17:25:49 -07002437 }
Romain Guy04299382012-07-18 17:15:41 -07002438
Chris Craik05f3d6e2014-06-02 16:27:04 -07002439 const VertexBuffer::Mode mode = vertexBuffer.getMode();
2440 if (mode == VertexBuffer::kStandard) {
ztenghui63d41ab2014-02-14 13:13:41 -08002441 mCaches.unbindIndicesBuffer();
2442 glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
Chris Craik05f3d6e2014-06-02 16:27:04 -07002443 } else if (mode == VertexBuffer::kOnePolyRingShadow) {
ztenghui63d41ab2014-02-14 13:13:41 -08002444 mCaches.bindShadowIndicesBuffer();
ztenghui50ecf842014-03-11 16:52:30 -07002445 glDrawElements(GL_TRIANGLE_STRIP, ONE_POLY_RING_SHADOW_INDEX_COUNT, GL_UNSIGNED_SHORT, 0);
Chris Craik05f3d6e2014-06-02 16:27:04 -07002446 } else if (mode == VertexBuffer::kTwoPolyRingShadow) {
ztenghui50ecf842014-03-11 16:52:30 -07002447 mCaches.bindShadowIndicesBuffer();
2448 glDrawElements(GL_TRIANGLE_STRIP, TWO_POLY_RING_SHADOW_INDEX_COUNT, GL_UNSIGNED_SHORT, 0);
ztenghuid5e8ade2014-08-13 15:48:02 -07002449 } else if (mode == VertexBuffer::kIndices) {
2450 mCaches.unbindIndicesBuffer();
2451 glDrawElements(GL_TRIANGLE_STRIP, vertexBuffer.getIndexCount(), GL_UNSIGNED_SHORT,
2452 vertexBuffer.getIndices());
ztenghui63d41ab2014-02-14 13:13:41 -08002453 }
Romain Guy04299382012-07-18 17:15:41 -07002454
Chris Craik710f46d2012-09-17 17:25:49 -07002455 if (isAA) {
Chris Craik6ebdc112012-08-31 18:24:33 -07002456 glDisableVertexAttribArray(alphaSlot);
Romain Guy04299382012-07-18 17:15:41 -07002457 }
Chris Craik65cd6122012-12-10 17:56:27 -08002458
2459 return DrawGlInfo::kStatusDrew;
Chet Haase858aa932011-05-12 09:06:00 -07002460}
2461
2462/**
Chris Craik65cd6122012-12-10 17:56:27 -08002463 * Renders a convex path via tessellation. For AA paths, this function uses a similar approach to
2464 * that of AA lines in the drawLines() function. We expand the convex path by a half pixel in
2465 * screen space in all directions. However, instead of using a fragment shader to compute the
2466 * translucency of the color from its position, we simply use a varying parameter to define how far
2467 * a given pixel is from the edge. For non-AA paths, the expansion and alpha varying are not used.
2468 *
2469 * Doesn't yet support joins, caps, or path effects.
2470 */
Chris Craikd218a922014-01-02 17:13:34 -08002471status_t OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint) {
Chris Craik65cd6122012-12-10 17:56:27 -08002472 VertexBuffer vertexBuffer;
2473 // TODO: try clipping large paths to viewport
Chris Craikd6b65f62014-01-01 14:45:21 -08002474 PathTessellator::tessellatePath(path, paint, *currentTransform(), vertexBuffer);
Chris Craik05f3d6e2014-06-02 16:27:04 -07002475 return drawVertexBuffer(vertexBuffer, paint);
Chris Craik65cd6122012-12-10 17:56:27 -08002476}
2477
2478/**
2479 * We create tristrips for the lines much like shape stroke tessellation, using a per-vertex alpha
2480 * and additional geometry for defining an alpha slope perimeter.
2481 *
2482 * Using GL_LINES can be difficult because the rasterization rules for those lines produces some
2483 * unexpected results, and may vary between hardware devices. Previously we used a varying-base
2484 * in-shader alpha region, but found it to be taxing on some GPUs.
2485 *
2486 * TODO: try using a fixed input buffer for non-capped lines as in text rendering. this may reduce
2487 * memory transfer by removing need for degenerate vertices.
Chet Haase99ecdc42011-05-06 12:06:34 -07002488 */
Chris Craikd218a922014-01-02 17:13:34 -08002489status_t OpenGLRenderer::drawLines(const float* points, int count, const SkPaint* paint) {
Chris Craikd6b65f62014-01-01 14:45:21 -08002490 if (currentSnapshot()->isIgnored() || count < 4) return DrawGlInfo::kStatusDone;
Chet Haase8a5cc922011-04-26 07:28:09 -07002491
Chris Craik65cd6122012-12-10 17:56:27 -08002492 count &= ~0x3; // round down to nearest four
Romain Guy7b631422012-04-04 11:38:54 -07002493
Chris Craik65cd6122012-12-10 17:56:27 -08002494 VertexBuffer buffer;
Chris Craik05f3d6e2014-06-02 16:27:04 -07002495 PathTessellator::tessellateLines(points, count, paint, *currentTransform(), buffer);
2496 const Rect& bounds = buffer.getBounds();
Romain Guyd71ff91d2013-02-08 13:46:40 -08002497
Chris Craik05f3d6e2014-06-02 16:27:04 -07002498 if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
Romain Guyd71ff91d2013-02-08 13:46:40 -08002499 return DrawGlInfo::kStatusDone;
2500 }
2501
Chris Craikbf759452014-08-11 16:00:44 -07002502 int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset;
2503 return drawVertexBuffer(buffer, paint, displayFlags);
Chet Haase5b0200b2011-04-13 17:58:08 -07002504}
2505
Chris Craikd218a922014-01-02 17:13:34 -08002506status_t OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) {
Chris Craikd6b65f62014-01-01 14:45:21 -08002507 if (currentSnapshot()->isIgnored() || count < 2) return DrawGlInfo::kStatusDone;
Romain Guyed6fcb02011-03-21 13:11:28 -07002508
Chris Craik6d29c8d2013-05-08 18:35:44 -07002509 count &= ~0x1; // round down to nearest two
Romain Guyed6fcb02011-03-21 13:11:28 -07002510
Chris Craik6d29c8d2013-05-08 18:35:44 -07002511 VertexBuffer buffer;
Chris Craik05f3d6e2014-06-02 16:27:04 -07002512 PathTessellator::tessellatePoints(points, count, paint, *currentTransform(), buffer);
Romain Guyd71ff91d2013-02-08 13:46:40 -08002513
Chris Craik05f3d6e2014-06-02 16:27:04 -07002514 const Rect& bounds = buffer.getBounds();
2515 if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
Chris Craik6d29c8d2013-05-08 18:35:44 -07002516 return DrawGlInfo::kStatusDone;
Romain Guyed6fcb02011-03-21 13:11:28 -07002517 }
2518
Chris Craikbf759452014-08-11 16:00:44 -07002519 int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset;
2520 return drawVertexBuffer(buffer, paint, displayFlags);
Romain Guyed6fcb02011-03-21 13:11:28 -07002521}
2522
Chet Haase48659092012-05-31 15:21:51 -07002523status_t OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
Romain Guye45362c2010-11-03 19:58:32 -07002524 // No need to check against the clip, we fill the clip region
Chris Craikd6b65f62014-01-01 14:45:21 -08002525 if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
Romain Guye45362c2010-11-03 19:58:32 -07002526
Chris Craikd6b65f62014-01-01 14:45:21 -08002527 Rect clip(*currentClipRect());
Romain Guyae88e5e2010-10-22 17:49:18 -07002528 clip.snapToPixelBoundaries();
Romain Guy70ca14e2010-12-13 18:24:33 -08002529
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05002530 SkPaint paint;
2531 paint.setColor(color);
2532 paint.setXfermodeMode(mode);
2533
2534 drawColorRect(clip.left, clip.top, clip.right, clip.bottom, &paint, true);
Chet Haase48659092012-05-31 15:21:51 -07002535
2536 return DrawGlInfo::kStatusDrew;
Romain Guyc7d53492010-06-25 13:41:57 -07002537}
Romain Guy9d5316e2010-06-24 19:30:36 -07002538
Chet Haase48659092012-05-31 15:21:51 -07002539status_t OpenGLRenderer::drawShape(float left, float top, const PathTexture* texture,
Chris Craikd218a922014-01-02 17:13:34 -08002540 const SkPaint* paint) {
Chet Haase48659092012-05-31 15:21:51 -07002541 if (!texture) return DrawGlInfo::kStatusDone;
Romain Guy01d58e42011-01-19 21:54:02 -08002542 const AutoTexture autoCleanup(texture);
2543
2544 const float x = left + texture->left - texture->offset;
2545 const float y = top + texture->top - texture->offset;
2546
2547 drawPathTexture(texture, x, y, paint);
Chet Haase48659092012-05-31 15:21:51 -07002548
2549 return DrawGlInfo::kStatusDrew;
Romain Guy01d58e42011-01-19 21:54:02 -08002550}
2551
Chet Haase48659092012-05-31 15:21:51 -07002552status_t OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
Chris Craikd218a922014-01-02 17:13:34 -08002553 float rx, float ry, const SkPaint* p) {
Chris Craik947eabf2014-08-19 10:21:12 -07002554 if (currentSnapshot()->isIgnored()
2555 || quickRejectSetupScissor(left, top, right, bottom, p)
2556 || paintWillNotDraw(*p)) {
Chris Craik710f46d2012-09-17 17:25:49 -07002557 return DrawGlInfo::kStatusDone;
2558 }
Romain Guyc1cd9ba32011-01-23 14:18:41 -08002559
Chris Craikcb4d6002012-09-25 12:00:29 -07002560 if (p->getPathEffect() != 0) {
Chris Craik710f46d2012-09-17 17:25:49 -07002561 mCaches.activeTexture(0);
Romain Guyc46d07a2013-03-15 19:06:39 -07002562 const PathTexture* texture = mCaches.pathCache.getRoundRect(
Chris Craik710f46d2012-09-17 17:25:49 -07002563 right - left, bottom - top, rx, ry, p);
2564 return drawShape(left, top, texture, p);
2565 }
2566
Chris Craik6ac174b2014-06-17 13:47:05 -07002567 const VertexBuffer* vertexBuffer = mCaches.tessellationCache.getRoundRect(
2568 *currentTransform(), *p, right - left, bottom - top, rx, ry);
Chris Craik05f3d6e2014-06-02 16:27:04 -07002569 return drawVertexBuffer(left, top, *vertexBuffer, p);
Romain Guyc1cd9ba32011-01-23 14:18:41 -08002570}
2571
Chris Craikd218a922014-01-02 17:13:34 -08002572status_t OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p) {
Chris Craik947eabf2014-08-19 10:21:12 -07002573 if (currentSnapshot()->isIgnored()
2574 || quickRejectSetupScissor(x - radius, y - radius, x + radius, y + radius, p)
2575 || paintWillNotDraw(*p)) {
Chris Craik710f46d2012-09-17 17:25:49 -07002576 return DrawGlInfo::kStatusDone;
2577 }
Chris Craikcb4d6002012-09-25 12:00:29 -07002578 if (p->getPathEffect() != 0) {
Chris Craik710f46d2012-09-17 17:25:49 -07002579 mCaches.activeTexture(0);
Romain Guyc46d07a2013-03-15 19:06:39 -07002580 const PathTexture* texture = mCaches.pathCache.getCircle(radius, p);
Chris Craik710f46d2012-09-17 17:25:49 -07002581 return drawShape(x - radius, y - radius, texture, p);
2582 }
2583
2584 SkPath path;
Chris Craikcb4d6002012-09-25 12:00:29 -07002585 if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2586 path.addCircle(x, y, radius + p->getStrokeWidth() / 2);
2587 } else {
2588 path.addCircle(x, y, radius);
2589 }
Chris Craik65cd6122012-12-10 17:56:27 -08002590 return drawConvexPath(path, p);
Romain Guyc1cd9ba32011-01-23 14:18:41 -08002591}
Romain Guy01d58e42011-01-19 21:54:02 -08002592
Chet Haase48659092012-05-31 15:21:51 -07002593status_t OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
Chris Craikd218a922014-01-02 17:13:34 -08002594 const SkPaint* p) {
Chris Craik947eabf2014-08-19 10:21:12 -07002595 if (currentSnapshot()->isIgnored()
2596 || quickRejectSetupScissor(left, top, right, bottom, p)
2597 || paintWillNotDraw(*p)) {
Chris Craik710f46d2012-09-17 17:25:49 -07002598 return DrawGlInfo::kStatusDone;
2599 }
Romain Guy01d58e42011-01-19 21:54:02 -08002600
Chris Craikcb4d6002012-09-25 12:00:29 -07002601 if (p->getPathEffect() != 0) {
Chris Craik710f46d2012-09-17 17:25:49 -07002602 mCaches.activeTexture(0);
Romain Guyc46d07a2013-03-15 19:06:39 -07002603 const PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p);
Chris Craik710f46d2012-09-17 17:25:49 -07002604 return drawShape(left, top, texture, p);
2605 }
2606
2607 SkPath path;
2608 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
Chris Craikcb4d6002012-09-25 12:00:29 -07002609 if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2610 rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
2611 }
Chris Craik710f46d2012-09-17 17:25:49 -07002612 path.addOval(rect);
Chris Craik65cd6122012-12-10 17:56:27 -08002613 return drawConvexPath(path, p);
Romain Guyc1cd9ba32011-01-23 14:18:41 -08002614}
2615
Chet Haase48659092012-05-31 15:21:51 -07002616status_t OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
Chris Craikd218a922014-01-02 17:13:34 -08002617 float startAngle, float sweepAngle, bool useCenter, const SkPaint* p) {
Chris Craik947eabf2014-08-19 10:21:12 -07002618 if (currentSnapshot()->isIgnored()
2619 || quickRejectSetupScissor(left, top, right, bottom, p)
2620 || paintWillNotDraw(*p)) {
Chris Craik780c1282012-10-04 14:10:49 -07002621 return DrawGlInfo::kStatusDone;
Romain Guy8b2f5262011-01-23 16:15:02 -08002622 }
2623
Chris Craik780c1282012-10-04 14:10:49 -07002624 // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
Chris Craik65cd6122012-12-10 17:56:27 -08002625 if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != 0 || useCenter) {
Chris Craik780c1282012-10-04 14:10:49 -07002626 mCaches.activeTexture(0);
Romain Guyc46d07a2013-03-15 19:06:39 -07002627 const PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top,
Chris Craik780c1282012-10-04 14:10:49 -07002628 startAngle, sweepAngle, useCenter, p);
2629 return drawShape(left, top, texture, p);
2630 }
2631
2632 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2633 if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2634 rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
2635 }
2636
2637 SkPath path;
2638 if (useCenter) {
2639 path.moveTo(rect.centerX(), rect.centerY());
2640 }
2641 path.arcTo(rect, startAngle, sweepAngle, !useCenter);
2642 if (useCenter) {
2643 path.close();
2644 }
Chris Craik65cd6122012-12-10 17:56:27 -08002645 return drawConvexPath(path, p);
Romain Guy8b2f5262011-01-23 16:15:02 -08002646}
2647
Romain Guycf8675e2012-10-02 12:32:25 -07002648// See SkPaintDefaults.h
2649#define SkPaintDefaults_MiterLimit SkIntToScalar(4)
2650
Chris Craikd218a922014-01-02 17:13:34 -08002651status_t OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
2652 const SkPaint* p) {
Chris Craik947eabf2014-08-19 10:21:12 -07002653 if (currentSnapshot()->isIgnored()
2654 || quickRejectSetupScissor(left, top, right, bottom, p)
2655 || paintWillNotDraw(*p)) {
Chet Haase48659092012-05-31 15:21:51 -07002656 return DrawGlInfo::kStatusDone;
Romain Guy6926c722010-07-12 20:20:03 -07002657 }
2658
Chris Craik710f46d2012-09-17 17:25:49 -07002659 if (p->getStyle() != SkPaint::kFill_Style) {
Romain Guycf8675e2012-10-02 12:32:25 -07002660 // only fill style is supported by drawConvexPath, since others have to handle joins
2661 if (p->getPathEffect() != 0 || p->getStrokeJoin() != SkPaint::kMiter_Join ||
2662 p->getStrokeMiter() != SkPaintDefaults_MiterLimit) {
2663 mCaches.activeTexture(0);
2664 const PathTexture* texture =
Romain Guyc46d07a2013-03-15 19:06:39 -07002665 mCaches.pathCache.getRect(right - left, bottom - top, p);
Romain Guycf8675e2012-10-02 12:32:25 -07002666 return drawShape(left, top, texture, p);
2667 }
2668
2669 SkPath path;
2670 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
2671 if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
2672 rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
2673 }
2674 path.addRect(rect);
Chris Craik65cd6122012-12-10 17:56:27 -08002675 return drawConvexPath(path, p);
Romain Guy026c5e162010-06-28 17:12:22 -07002676 }
2677
Chris Craikd6b65f62014-01-01 14:45:21 -08002678 if (p->isAntiAlias() && !currentTransform()->isSimple()) {
Chris Craik710f46d2012-09-17 17:25:49 -07002679 SkPath path;
2680 path.addRect(left, top, right, bottom);
Chris Craik65cd6122012-12-10 17:56:27 -08002681 return drawConvexPath(path, p);
Chet Haase858aa932011-05-12 09:06:00 -07002682 } else {
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05002683 drawColorRect(left, top, right, bottom, p);
Chris Craik65cd6122012-12-10 17:56:27 -08002684 return DrawGlInfo::kStatusDrew;
Chet Haase858aa932011-05-12 09:06:00 -07002685 }
Romain Guyc7d53492010-06-25 13:41:57 -07002686}
Romain Guy9d5316e2010-06-24 19:30:36 -07002687
Chris Craikd218a922014-01-02 17:13:34 -08002688void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text,
2689 int bytesCount, int count, const float* positions,
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05002690 FontRenderer& fontRenderer, int alpha, float x, float y) {
Raph Levien416a8472012-07-19 22:48:17 -07002691 mCaches.activeTexture(0);
2692
Derek Sollenbergerc29a0a42014-03-31 13:52:39 -04002693 TextShadow textShadow;
2694 if (!getTextShadow(paint, &textShadow)) {
2695 LOG_ALWAYS_FATAL("failed to query shadow attributes");
2696 }
2697
Raph Levien416a8472012-07-19 22:48:17 -07002698 // NOTE: The drop shadow will not perform gamma correction
2699 // if shader-based correction is enabled
2700 mCaches.dropShadowCache.setFontRenderer(fontRenderer);
2701 const ShadowTexture* shadow = mCaches.dropShadowCache.get(
Derek Sollenbergerc29a0a42014-03-31 13:52:39 -04002702 paint, text, bytesCount, count, textShadow.radius, positions);
Romain Guycf51a412013-04-08 19:40:31 -07002703 // If the drop shadow exceeds the max texture size or couldn't be
2704 // allocated, skip drawing
2705 if (!shadow) return;
Raph Levien416a8472012-07-19 22:48:17 -07002706 const AutoTexture autoCleanup(shadow);
2707
Derek Sollenbergerc29a0a42014-03-31 13:52:39 -04002708 const float sx = x - shadow->left + textShadow.dx;
2709 const float sy = y - shadow->top + textShadow.dy;
Raph Levien416a8472012-07-19 22:48:17 -07002710
Derek Sollenbergerc29a0a42014-03-31 13:52:39 -04002711 const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * mSnapshot->alpha;
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04002712 if (getShader(paint)) {
Derek Sollenbergerc29a0a42014-03-31 13:52:39 -04002713 textShadow.color = SK_ColorWHITE;
Raph Levien416a8472012-07-19 22:48:17 -07002714 }
2715
2716 setupDraw();
2717 setupDrawWithTexture(true);
Derek Sollenbergerc29a0a42014-03-31 13:52:39 -04002718 setupDrawAlpha8Color(textShadow.color, shadowAlpha < 255 ? shadowAlpha : alpha);
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05002719 setupDrawColorFilter(getColorFilter(paint));
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04002720 setupDrawShader(getShader(paint));
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05002721 setupDrawBlending(paint, true);
Raph Levien416a8472012-07-19 22:48:17 -07002722 setupDrawProgram();
Chris Craik4063a0e2013-11-15 16:06:56 -08002723 setupDrawModelView(kModelViewMode_TranslateAndScale, false,
2724 sx, sy, sx + shadow->width, sy + shadow->height);
Raph Levien416a8472012-07-19 22:48:17 -07002725 setupDrawTexture(shadow->id);
2726 setupDrawPureColorUniforms();
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05002727 setupDrawColorFilterUniforms(getColorFilter(paint));
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04002728 setupDrawShaderUniforms(getShader(paint));
Raph Levien416a8472012-07-19 22:48:17 -07002729 setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
2730
2731 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
2732}
2733
Romain Guy768bffc2013-02-27 13:50:45 -08002734bool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
Derek Sollenbergerc29a0a42014-03-31 13:52:39 -04002735 float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * mSnapshot->alpha;
Romain Guy768bffc2013-02-27 13:50:45 -08002736 return alpha == 0.0f && getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
2737}
2738
Chet Haase48659092012-05-31 15:21:51 -07002739status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
Chris Craikd218a922014-01-02 17:13:34 -08002740 const float* positions, const SkPaint* paint) {
Chris Craikd6b65f62014-01-01 14:45:21 -08002741 if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint)) {
Chet Haase48659092012-05-31 15:21:51 -07002742 return DrawGlInfo::kStatusDone;
Romain Guyeb9a5362012-01-17 17:39:26 -08002743 }
Romain Guyeb9a5362012-01-17 17:39:26 -08002744
Romain Guy671d6cf2012-01-18 12:39:17 -08002745 // NOTE: Skia does not support perspective transform on drawPosText yet
Chris Craikd6b65f62014-01-01 14:45:21 -08002746 if (!currentTransform()->isSimple()) {
Chet Haase48659092012-05-31 15:21:51 -07002747 return DrawGlInfo::kStatusDone;
Romain Guy671d6cf2012-01-18 12:39:17 -08002748 }
2749
Chris Craik39a908c2013-06-13 14:39:01 -07002750 mCaches.enableScissor();
2751
Romain Guy671d6cf2012-01-18 12:39:17 -08002752 float x = 0.0f;
2753 float y = 0.0f;
Chris Craikd6b65f62014-01-01 14:45:21 -08002754 const bool pureTranslate = currentTransform()->isPureTranslate();
Romain Guy671d6cf2012-01-18 12:39:17 -08002755 if (pureTranslate) {
Chris Craikd6b65f62014-01-01 14:45:21 -08002756 x = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f);
2757 y = (int) floorf(y + currentTransform()->getTranslateY() + 0.5f);
Romain Guy671d6cf2012-01-18 12:39:17 -08002758 }
2759
Romain Guyb1d0a4e2012-07-13 18:25:35 -07002760 FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
Chris Craik59744b72014-07-01 17:56:52 -07002761 fontRenderer.setFont(paint, SkMatrix::I());
Romain Guy671d6cf2012-01-18 12:39:17 -08002762
2763 int alpha;
2764 SkXfermode::Mode mode;
2765 getAlphaAndMode(paint, &alpha, &mode);
2766
Derek Sollenbergerc29a0a42014-03-31 13:52:39 -04002767 if (CC_UNLIKELY(hasTextShadow(paint))) {
Romain Guye3a9b242013-01-08 11:15:30 -08002768 drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05002769 alpha, 0.0f, 0.0f);
Raph Levien416a8472012-07-19 22:48:17 -07002770 }
2771
Romain Guy671d6cf2012-01-18 12:39:17 -08002772 // Pick the appropriate texture filtering
Chris Craikd6b65f62014-01-01 14:45:21 -08002773 bool linearFilter = currentTransform()->changesBounds();
Romain Guy671d6cf2012-01-18 12:39:17 -08002774 if (pureTranslate && !linearFilter) {
2775 linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f;
2776 }
Romain Guy257ae352013-03-20 16:31:12 -07002777 fontRenderer.setTextureFiltering(linearFilter);
Romain Guy671d6cf2012-01-18 12:39:17 -08002778
2779 const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip();
2780 Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2781
Romain Guy211370f2012-02-01 16:10:55 -08002782 const bool hasActiveLayer = hasLayer();
Romain Guy671d6cf2012-01-18 12:39:17 -08002783
Victoria Lease1e546812013-06-25 14:25:17 -07002784 TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
Romain Guy671d6cf2012-01-18 12:39:17 -08002785 if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
Romain Guy257ae352013-03-20 16:31:12 -07002786 positions, hasActiveLayer ? &bounds : NULL, &functor)) {
Romain Guy671d6cf2012-01-18 12:39:17 -08002787 if (hasActiveLayer) {
2788 if (!pureTranslate) {
Chris Craikd6b65f62014-01-01 14:45:21 -08002789 currentTransform()->mapRect(bounds);
Romain Guy671d6cf2012-01-18 12:39:17 -08002790 }
2791 dirtyLayerUnchecked(bounds, getRegion());
2792 }
Romain Guy671d6cf2012-01-18 12:39:17 -08002793 }
Chet Haase48659092012-05-31 15:21:51 -07002794
2795 return DrawGlInfo::kStatusDrew;
Romain Guyeb9a5362012-01-17 17:39:26 -08002796}
2797
Chris Craik59744b72014-07-01 17:56:52 -07002798bool OpenGLRenderer::findBestFontTransform(const mat4& transform, SkMatrix* outMatrix) const {
Romain Guy624234f2013-03-05 16:43:31 -08002799 if (CC_LIKELY(transform.isPureTranslate())) {
Chris Craik59744b72014-07-01 17:56:52 -07002800 outMatrix->setIdentity();
2801 return false;
2802 } else if (CC_UNLIKELY(transform.isPerspective())) {
2803 outMatrix->setIdentity();
2804 return true;
Romain Guy624234f2013-03-05 16:43:31 -08002805 }
Chris Craik59744b72014-07-01 17:56:52 -07002806
2807 /**
Chris Craika736cd92014-08-04 13:18:38 -07002808 * Input is a non-perspective, scaling transform. Generate a scale-only transform,
2809 * with values rounded to the nearest int.
Chris Craik59744b72014-07-01 17:56:52 -07002810 */
2811 float sx, sy;
2812 transform.decomposeScale(sx, sy);
Chris Craika736cd92014-08-04 13:18:38 -07002813 outMatrix->setScale(
2814 roundf(fmaxf(1.0f, sx)),
2815 roundf(fmaxf(1.0f, sy)));
2816 return true;
Romain Guy624234f2013-03-05 16:43:31 -08002817}
2818
Chris Craik41541822013-05-03 16:35:54 -07002819status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float x, float y,
Chris Craikd218a922014-01-02 17:13:34 -08002820 const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
Chris Craik527a3aa2013-03-04 10:19:31 -08002821 DrawOpMode drawOpMode) {
2822
Chris Craik527a3aa2013-03-04 10:19:31 -08002823 if (drawOpMode == kDrawOpMode_Immediate) {
Chris Craik28ce94a2013-05-31 11:38:03 -07002824 // The checks for corner-case ignorable text and quick rejection is only done for immediate
2825 // drawing as ops from DeferredDisplayList are already filtered for these
Chris Craikd6b65f62014-01-01 14:45:21 -08002826 if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint) ||
Chris Craikf0a59072013-11-19 18:00:46 -08002827 quickRejectSetupScissor(bounds)) {
Chris Craik28ce94a2013-05-31 11:38:03 -07002828 return DrawGlInfo::kStatusDone;
2829 }
Romain Guycac5fd32011-12-01 20:08:50 -08002830 }
2831
Romain Guy3a3fa1b2010-12-06 18:47:50 -08002832 const float oldX = x;
2833 const float oldY = y;
Romain Guy624234f2013-03-05 16:43:31 -08002834
Chris Craikd6b65f62014-01-01 14:45:21 -08002835 const mat4& transform = *currentTransform();
Romain Guy624234f2013-03-05 16:43:31 -08002836 const bool pureTranslate = transform.isPureTranslate();
Romain Guyc74f45a2013-02-26 19:10:14 -08002837
Romain Guy211370f2012-02-01 16:10:55 -08002838 if (CC_LIKELY(pureTranslate)) {
Romain Guy624234f2013-03-05 16:43:31 -08002839 x = (int) floorf(x + transform.getTranslateX() + 0.5f);
2840 y = (int) floorf(y + transform.getTranslateY() + 0.5f);
Romain Guy6620c6d2010-12-06 18:07:02 -08002841 }
2842
Romain Guy86568192010-12-14 15:55:39 -08002843 int alpha;
2844 SkXfermode::Mode mode;
2845 getAlphaAndMode(paint, &alpha, &mode);
Romain Guy9d13fe252010-10-15 16:06:03 -07002846
Romain Guyc74f45a2013-02-26 19:10:14 -08002847 FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
2848
Derek Sollenbergerc29a0a42014-03-31 13:52:39 -04002849 if (CC_UNLIKELY(hasTextShadow(paint))) {
Chris Craik59744b72014-07-01 17:56:52 -07002850 fontRenderer.setFont(paint, SkMatrix::I());
Romain Guyc74f45a2013-02-26 19:10:14 -08002851 drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05002852 alpha, oldX, oldY);
Romain Guy1e45aae2010-08-13 19:39:53 -07002853 }
2854
Romain Guy19d4dd82013-03-04 11:14:26 -08002855 const bool hasActiveLayer = hasLayer();
2856
Romain Guy624234f2013-03-05 16:43:31 -08002857 // We only pass a partial transform to the font renderer. That partial
2858 // matrix defines how glyphs are rasterized. Typically we want glyphs
2859 // to be rasterized at their final size on screen, which means the partial
2860 // matrix needs to take the scale factor into account.
2861 // When a partial matrix is used to transform glyphs during rasterization,
2862 // the mesh is generated with the inverse transform (in the case of scale,
2863 // the mesh is generated at 1.0 / scale for instance.) This allows us to
2864 // apply the full transform matrix at draw time in the vertex shader.
2865 // Applying the full matrix in the shader is the easiest way to handle
2866 // rotation and perspective and allows us to always generated quads in the
2867 // font renderer which greatly simplifies the code, clipping in particular.
Chris Craik59744b72014-07-01 17:56:52 -07002868 SkMatrix fontTransform;
2869 bool linearFilter = findBestFontTransform(transform, &fontTransform)
2870 || fabs(y - (int) y) > 0.0f
2871 || fabs(x - (int) x) > 0.0f;
Romain Guy3b753822013-03-05 10:27:35 -08002872 fontRenderer.setFont(paint, fontTransform);
Romain Guy257ae352013-03-20 16:31:12 -07002873 fontRenderer.setTextureFiltering(linearFilter);
Romain Guy06f96e22010-07-30 19:18:16 -07002874
Romain Guy624234f2013-03-05 16:43:31 -08002875 // TODO: Implement better clipping for scaled/rotated text
Chris Craikd6b65f62014-01-01 14:45:21 -08002876 const Rect* clip = !pureTranslate ? NULL : currentClipRect();
Chris Craik41541822013-05-03 16:35:54 -07002877 Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
Romain Guy5b3b3522010-10-27 18:57:51 -07002878
Raph Levien996e57c2012-07-23 15:22:52 -07002879 bool status;
Victoria Lease1e546812013-06-25 14:25:17 -07002880 TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
Chris Craik527a3aa2013-03-04 10:19:31 -08002881
2882 // don't call issuedrawcommand, do it at end of batch
2883 bool forceFinish = (drawOpMode != kDrawOpMode_Defer);
Romain Guya3dc55f2012-09-28 13:55:44 -07002884 if (CC_UNLIKELY(paint->getTextAlign() != SkPaint::kLeft_Align)) {
Raph Levien8b4072d2012-07-30 15:50:00 -07002885 SkPaint paintCopy(*paint);
2886 paintCopy.setTextAlign(SkPaint::kLeft_Align);
2887 status = fontRenderer.renderPosText(&paintCopy, clip, text, 0, bytesCount, count, x, y,
Chris Craik41541822013-05-03 16:35:54 -07002888 positions, hasActiveLayer ? &layerBounds : NULL, &functor, forceFinish);
Raph Levien996e57c2012-07-23 15:22:52 -07002889 } else {
Raph Levien8b4072d2012-07-30 15:50:00 -07002890 status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
Chris Craik41541822013-05-03 16:35:54 -07002891 positions, hasActiveLayer ? &layerBounds : NULL, &functor, forceFinish);
Raph Levien996e57c2012-07-23 15:22:52 -07002892 }
Romain Guy4ff0cf42012-08-06 14:51:10 -07002893
Chris Craik527a3aa2013-03-04 10:19:31 -08002894 if ((status || drawOpMode != kDrawOpMode_Immediate) && hasActiveLayer) {
Romain Guy624234f2013-03-05 16:43:31 -08002895 if (!pureTranslate) {
Chris Craik41541822013-05-03 16:35:54 -07002896 transform.mapRect(layerBounds);
Romain Guya4adcf02013-02-28 12:15:35 -08002897 }
Chris Craik41541822013-05-03 16:35:54 -07002898 dirtyLayerUnchecked(layerBounds, getRegion());
Romain Guy5b3b3522010-10-27 18:57:51 -07002899 }
Romain Guy694b5192010-07-21 21:33:20 -07002900
Chris Craike63f7c622013-10-17 10:30:55 -07002901 drawTextDecorations(totalAdvance, oldX, oldY, paint);
Chet Haase48659092012-05-31 15:21:51 -07002902
2903 return DrawGlInfo::kStatusDrew;
Romain Guy694b5192010-07-21 21:33:20 -07002904}
2905
Chris Craikd218a922014-01-02 17:13:34 -08002906status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
2907 const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) {
Chris Craikd6b65f62014-01-01 14:45:21 -08002908 if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint)) {
Chet Haase48659092012-05-31 15:21:51 -07002909 return DrawGlInfo::kStatusDone;
Romain Guy03d58522012-02-24 17:54:07 -08002910 }
2911
Chris Craik39a908c2013-06-13 14:39:01 -07002912 // TODO: avoid scissor by calculating maximum bounds using path bounds + font metrics
2913 mCaches.enableScissor();
2914
Romain Guyb1d0a4e2012-07-13 18:25:35 -07002915 FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
Chris Craik59744b72014-07-01 17:56:52 -07002916 fontRenderer.setFont(paint, SkMatrix::I());
Romain Guy257ae352013-03-20 16:31:12 -07002917 fontRenderer.setTextureFiltering(true);
Romain Guy03d58522012-02-24 17:54:07 -08002918
2919 int alpha;
2920 SkXfermode::Mode mode;
2921 getAlphaAndMode(paint, &alpha, &mode);
Victoria Lease1e546812013-06-25 14:25:17 -07002922 TextSetupFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint);
Romain Guy03d58522012-02-24 17:54:07 -08002923
Romain Guy97771732012-02-28 18:17:02 -08002924 const Rect* clip = &mSnapshot->getLocalClip();
2925 Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
Romain Guy03d58522012-02-24 17:54:07 -08002926
Romain Guy97771732012-02-28 18:17:02 -08002927 const bool hasActiveLayer = hasLayer();
Romain Guy97771732012-02-28 18:17:02 -08002928
2929 if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path,
Victoria Lease1e546812013-06-25 14:25:17 -07002930 hOffset, vOffset, hasActiveLayer ? &bounds : NULL, &functor)) {
Romain Guy97771732012-02-28 18:17:02 -08002931 if (hasActiveLayer) {
Chris Craikd6b65f62014-01-01 14:45:21 -08002932 currentTransform()->mapRect(bounds);
Romain Guy97771732012-02-28 18:17:02 -08002933 dirtyLayerUnchecked(bounds, getRegion());
2934 }
Romain Guy97771732012-02-28 18:17:02 -08002935 }
Chet Haase48659092012-05-31 15:21:51 -07002936
2937 return DrawGlInfo::kStatusDrew;
Romain Guy325740f2012-02-24 16:48:34 -08002938}
2939
Chris Craikd218a922014-01-02 17:13:34 -08002940status_t OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
Chris Craikd6b65f62014-01-01 14:45:21 -08002941 if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
Romain Guydbc26d22010-10-11 17:58:29 -07002942
Romain Guya1d3c912011-12-13 14:55:06 -08002943 mCaches.activeTexture(0);
Romain Guy7fbcc042010-08-04 15:40:07 -07002944
Romain Guyfb8b7632010-08-23 21:05:08 -07002945 const PathTexture* texture = mCaches.pathCache.get(path, paint);
Chet Haase48659092012-05-31 15:21:51 -07002946 if (!texture) return DrawGlInfo::kStatusDone;
Romain Guy22158e12010-08-06 11:18:34 -07002947 const AutoTexture autoCleanup(texture);
Romain Guy7fbcc042010-08-04 15:40:07 -07002948
Romain Guy8b55f372010-08-18 17:10:07 -07002949 const float x = texture->left - texture->offset;
2950 const float y = texture->top - texture->offset;
2951
Romain Guy01d58e42011-01-19 21:54:02 -08002952 drawPathTexture(texture, x, y, paint);
Chet Haase48659092012-05-31 15:21:51 -07002953
2954 return DrawGlInfo::kStatusDrew;
Romain Guy7fbcc042010-08-04 15:40:07 -07002955}
2956
Chris Craika08f95c2013-03-15 17:24:33 -07002957status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
Romain Guy35643dd2012-09-18 15:40:58 -07002958 if (!layer) {
2959 return DrawGlInfo::kStatusDone;
2960 }
2961
Romain Guyb2e2f242012-10-17 18:18:35 -07002962 mat4* transform = NULL;
2963 if (layer->isTextureLayer()) {
2964 transform = &layer->getTransform();
2965 if (!transform->isIdentity()) {
Chris Craik3f0854292014-04-15 16:18:08 -07002966 save(SkCanvas::kMatrix_SaveFlag);
Chris Craik14e51302013-12-30 15:32:54 -08002967 concatMatrix(*transform);
Romain Guyb2e2f242012-10-17 18:18:35 -07002968 }
2969 }
2970
Chris Craik39a908c2013-06-13 14:39:01 -07002971 bool clipRequired = false;
Chris Craikf0a59072013-11-19 18:00:46 -08002972 const bool rejected = calculateQuickRejectForScissor(x, y,
Chris Craikdeeda3d2014-05-05 19:09:33 -07002973 x + layer->layer.getWidth(), y + layer->layer.getHeight(), &clipRequired, NULL, false);
Romain Guy35643dd2012-09-18 15:40:58 -07002974
2975 if (rejected) {
Romain Guyb2e2f242012-10-17 18:18:35 -07002976 if (transform && !transform->isIdentity()) {
2977 restore();
2978 }
Chet Haase48659092012-05-31 15:21:51 -07002979 return DrawGlInfo::kStatusDone;
Romain Guy6c319ca2011-01-11 14:29:25 -08002980 }
2981
Chris Craik62d307c2014-07-29 10:35:13 -07002982 EVENT_LOGD("drawLayer," RECT_STRING ", clipRequired %d", x, y,
2983 x + layer->layer.getWidth(), y + layer->layer.getHeight(), clipRequired);
2984
Romain Guy5bb3c732012-11-29 17:52:58 -08002985 updateLayer(layer, true);
Romain Guy2bf68f02012-03-02 13:37:47 -08002986
Chris Craik39a908c2013-06-13 14:39:01 -07002987 mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
Romain Guya1d3c912011-12-13 14:55:06 -08002988 mCaches.activeTexture(0);
Romain Guy6c319ca2011-01-11 14:29:25 -08002989
Romain Guy211370f2012-02-01 16:10:55 -08002990 if (CC_LIKELY(!layer->region.isEmpty())) {
Romain Guyc88e3572011-01-22 00:32:12 -08002991 if (layer->region.isRect()) {
Chris Craik34416ea2013-04-15 16:08:28 -07002992 DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
2993 composeLayerRect(layer, layer->regionRect));
Romain Guyc88e3572011-01-22 00:32:12 -08002994 } else if (layer->mesh) {
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05002995
Chris Craik16ecda52013-03-29 10:59:59 -07002996 const float a = getLayerAlpha(layer);
Romain Guyc88e3572011-01-22 00:32:12 -08002997 setupDraw();
2998 setupDrawWithTexture();
Romain Guy81683962011-01-24 20:40:18 -08002999 setupDrawColor(a, a, a, a);
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003000 setupDrawColorFilter(layer->getColorFilter());
3001 setupDrawBlending(layer);
Romain Guyc88e3572011-01-22 00:32:12 -08003002 setupDrawProgram();
Romain Guyc88e3572011-01-22 00:32:12 -08003003 setupDrawPureColorUniforms();
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003004 setupDrawColorFilterUniforms(layer->getColorFilter());
Romain Guy9ace8f52011-07-07 20:50:11 -07003005 setupDrawTexture(layer->getTexture());
Chris Craikd6b65f62014-01-01 14:45:21 -08003006 if (CC_LIKELY(currentTransform()->isPureTranslate())) {
3007 int tx = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f);
3008 int ty = (int) floorf(y + currentTransform()->getTranslateY() + 0.5f);
Romain Guy9ace8f52011-07-07 20:50:11 -07003009
Romain Guyd21b6e12011-11-30 20:21:23 -08003010 layer->setFilter(GL_NEAREST);
Chris Craik4063a0e2013-11-15 16:06:56 -08003011 setupDrawModelView(kModelViewMode_Translate, false, tx, ty,
Romain Guy4ff0cf42012-08-06 14:51:10 -07003012 tx + layer->layer.getWidth(), ty + layer->layer.getHeight(), true);
Romain Guy9ace8f52011-07-07 20:50:11 -07003013 } else {
Romain Guyd21b6e12011-11-30 20:21:23 -08003014 layer->setFilter(GL_LINEAR);
Chris Craik4063a0e2013-11-15 16:06:56 -08003015 setupDrawModelView(kModelViewMode_Translate, false, x, y,
Romain Guy9ace8f52011-07-07 20:50:11 -07003016 x + layer->layer.getWidth(), y + layer->layer.getHeight());
3017 }
Romain Guyf219da52011-01-16 12:54:25 -08003018
Romain Guy448455f2013-07-22 13:57:50 -07003019 TextureVertex* mesh = &layer->mesh[0];
3020 GLsizei elementsCount = layer->meshElementCount;
3021
3022 while (elementsCount > 0) {
3023 GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6);
3024
Romain Guy3380cfd2013-08-15 16:57:57 -07003025 setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
Romain Guy448455f2013-07-22 13:57:50 -07003026 DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
3027 glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, NULL));
3028
3029 elementsCount -= drawCount;
3030 // Though there are 4 vertices in a quad, we use 6 indices per
3031 // quad to draw with GL_TRIANGLES
3032 mesh += (drawCount / 6) * 4;
3033 }
Romain Guyf219da52011-01-16 12:54:25 -08003034
Romain Guy3a3133d2011-02-01 22:59:58 -08003035#if DEBUG_LAYERS_AS_REGIONS
Chris Craike63f7c622013-10-17 10:30:55 -07003036 drawRegionRectsDebug(layer->region);
Romain Guy3a3133d2011-02-01 22:59:58 -08003037#endif
Romain Guyc88e3572011-01-22 00:32:12 -08003038 }
Romain Guy4ff0cf42012-08-06 14:51:10 -07003039
Romain Guy5bb3c732012-11-29 17:52:58 -08003040 if (layer->debugDrawUpdate) {
3041 layer->debugDrawUpdate = false;
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003042
3043 SkPaint paint;
3044 paint.setColor(0x7f00ff00);
3045 drawColorRect(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(), &paint);
Romain Guy4ff0cf42012-08-06 14:51:10 -07003046 }
Romain Guyf219da52011-01-16 12:54:25 -08003047 }
Chris Craik34416ea2013-04-15 16:08:28 -07003048 layer->hasDrawnSinceUpdate = true;
Chet Haase48659092012-05-31 15:21:51 -07003049
Romain Guyb2e2f242012-10-17 18:18:35 -07003050 if (transform && !transform->isIdentity()) {
3051 restore();
3052 }
3053
Chet Haase48659092012-05-31 15:21:51 -07003054 return DrawGlInfo::kStatusDrew;
Romain Guy6c319ca2011-01-11 14:29:25 -08003055}
3056
Romain Guy6926c722010-07-12 20:20:03 -07003057///////////////////////////////////////////////////////////////////////////////
Romain Guy5ff9df62012-01-23 17:09:05 -08003058// Draw filters
3059///////////////////////////////////////////////////////////////////////////////
Derek Sollenberger09c2d4f2014-10-15 09:21:10 -04003060void OpenGLRenderer::setDrawFilter(SkDrawFilter* filter) {
3061 // We should never get here since we apply the draw filter when stashing
3062 // the paints in the DisplayList.
3063 LOG_ALWAYS_FATAL("OpenGLRenderer does not directly support DrawFilters");
Romain Guy5ff9df62012-01-23 17:09:05 -08003064}
3065
3066///////////////////////////////////////////////////////////////////////////////
Romain Guy6926c722010-07-12 20:20:03 -07003067// Drawing implementation
3068///////////////////////////////////////////////////////////////////////////////
3069
Chris Craikd218a922014-01-02 17:13:34 -08003070Texture* OpenGLRenderer::getTexture(const SkBitmap* bitmap) {
Romain Guy3b748a42013-04-17 18:54:38 -07003071 Texture* texture = mCaches.assetAtlas.getEntryTexture(bitmap);
3072 if (!texture) {
3073 return mCaches.textureCache.get(bitmap);
3074 }
3075 return texture;
3076}
3077
Romain Guy01d58e42011-01-19 21:54:02 -08003078void OpenGLRenderer::drawPathTexture(const PathTexture* texture,
Chris Craikd218a922014-01-02 17:13:34 -08003079 float x, float y, const SkPaint* paint) {
Chris Craikf0a59072013-11-19 18:00:46 -08003080 if (quickRejectSetupScissor(x, y, x + texture->width, y + texture->height)) {
Romain Guy01d58e42011-01-19 21:54:02 -08003081 return;
3082 }
3083
3084 int alpha;
3085 SkXfermode::Mode mode;
3086 getAlphaAndMode(paint, &alpha, &mode);
3087
3088 setupDraw();
3089 setupDrawWithTexture(true);
3090 setupDrawAlpha8Color(paint->getColor(), alpha);
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003091 setupDrawColorFilter(getColorFilter(paint));
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04003092 setupDrawShader(getShader(paint));
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003093 setupDrawBlending(paint, true);
Romain Guy01d58e42011-01-19 21:54:02 -08003094 setupDrawProgram();
Chris Craik4063a0e2013-11-15 16:06:56 -08003095 setupDrawModelView(kModelViewMode_TranslateAndScale, false,
3096 x, y, x + texture->width, y + texture->height);
Romain Guy01d58e42011-01-19 21:54:02 -08003097 setupDrawTexture(texture->id);
3098 setupDrawPureColorUniforms();
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003099 setupDrawColorFilterUniforms(getColorFilter(paint));
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04003100 setupDrawShaderUniforms(getShader(paint));
Romain Guy01d58e42011-01-19 21:54:02 -08003101 setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
3102
3103 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
Romain Guy01d58e42011-01-19 21:54:02 -08003104}
3105
Romain Guyf607bdc2010-09-10 19:20:06 -07003106// Same values used by Skia
Romain Guy0a417492010-08-16 20:26:20 -07003107#define kStdStrikeThru_Offset (-6.0f / 21.0f)
3108#define kStdUnderline_Offset (1.0f / 9.0f)
3109#define kStdUnderline_Thickness (1.0f / 18.0f)
3110
Chris Craikd218a922014-01-02 17:13:34 -08003111void OpenGLRenderer::drawTextDecorations(float underlineWidth, float x, float y,
3112 const SkPaint* paint) {
Romain Guy0a417492010-08-16 20:26:20 -07003113 // Handle underline and strike-through
3114 uint32_t flags = paint->getFlags();
3115 if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
Romain Guy726aeba2011-06-01 14:52:00 -07003116 SkPaint paintCopy(*paint);
Romain Guy0a417492010-08-16 20:26:20 -07003117
Romain Guy211370f2012-02-01 16:10:55 -08003118 if (CC_LIKELY(underlineWidth > 0.0f)) {
Romain Guy726aeba2011-06-01 14:52:00 -07003119 const float textSize = paintCopy.getTextSize();
Romain Guyf6834472011-01-23 13:32:12 -08003120 const float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
Romain Guy0a417492010-08-16 20:26:20 -07003121
Raph Levien8b4072d2012-07-30 15:50:00 -07003122 const float left = x;
Romain Guy0a417492010-08-16 20:26:20 -07003123 float top = 0.0f;
Romain Guye20ecbd2010-09-22 19:49:04 -07003124
Romain Guyf6834472011-01-23 13:32:12 -08003125 int linesCount = 0;
3126 if (flags & SkPaint::kUnderlineText_Flag) linesCount++;
3127 if (flags & SkPaint::kStrikeThruText_Flag) linesCount++;
3128
3129 const int pointsCount = 4 * linesCount;
Romain Guye20ecbd2010-09-22 19:49:04 -07003130 float points[pointsCount];
3131 int currentPoint = 0;
Romain Guy0a417492010-08-16 20:26:20 -07003132
3133 if (flags & SkPaint::kUnderlineText_Flag) {
3134 top = y + textSize * kStdUnderline_Offset;
Romain Guye20ecbd2010-09-22 19:49:04 -07003135 points[currentPoint++] = left;
3136 points[currentPoint++] = top;
3137 points[currentPoint++] = left + underlineWidth;
3138 points[currentPoint++] = top;
Romain Guy0a417492010-08-16 20:26:20 -07003139 }
3140
3141 if (flags & SkPaint::kStrikeThruText_Flag) {
3142 top = y + textSize * kStdStrikeThru_Offset;
Romain Guye20ecbd2010-09-22 19:49:04 -07003143 points[currentPoint++] = left;
3144 points[currentPoint++] = top;
3145 points[currentPoint++] = left + underlineWidth;
3146 points[currentPoint++] = top;
Romain Guy0a417492010-08-16 20:26:20 -07003147 }
Romain Guye20ecbd2010-09-22 19:49:04 -07003148
Romain Guy726aeba2011-06-01 14:52:00 -07003149 paintCopy.setStrokeWidth(strokeWidth);
Romain Guye20ecbd2010-09-22 19:49:04 -07003150
Romain Guy726aeba2011-06-01 14:52:00 -07003151 drawLines(&points[0], pointsCount, &paintCopy);
Romain Guy0a417492010-08-16 20:26:20 -07003152 }
3153 }
3154}
3155
Chris Craikd218a922014-01-02 17:13:34 -08003156status_t OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
Chris Craikd6b65f62014-01-01 14:45:21 -08003157 if (currentSnapshot()->isIgnored()) {
Romain Guy672433d2013-01-04 19:05:13 -08003158 return DrawGlInfo::kStatusDone;
3159 }
3160
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003161 return drawColorRects(rects, count, paint, false, true, true);
Romain Guy735738c2012-12-03 12:34:51 -08003162}
3163
Chris Craikb79a3e32014-03-11 12:20:17 -07003164static void mapPointFakeZ(Vector3& point, const mat4& transformXY, const mat4& transformZ) {
3165 // map z coordinate with true 3d matrix
3166 point.z = transformZ.mapZ(point);
3167
3168 // map x,y coordinates with draw/Skia matrix
3169 transformXY.mapPoint(point.x, point.y);
3170}
3171
Chris Craik05f3d6e2014-06-02 16:27:04 -07003172status_t OpenGLRenderer::drawShadow(float casterAlpha,
3173 const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) {
Chris Craikd6b65f62014-01-01 14:45:21 -08003174 if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
Chris Craikf57776b2013-10-25 18:30:17 -07003175
Chris Craik15a07a22014-01-26 13:43:53 -08003176 // TODO: use quickRejectWithScissor. For now, always force enable scissor.
Chris Craikf57776b2013-10-25 18:30:17 -07003177 mCaches.enableScissor();
3178
3179 SkPaint paint;
Chris Craikba9b6132013-12-15 17:10:19 -08003180 paint.setAntiAlias(true); // want to use AlphaVertex
Chris Craikf57776b2013-10-25 18:30:17 -07003181
ztenghui14a4e352014-08-13 10:44:39 -07003182 // The caller has made sure casterAlpha > 0.
3183 float ambientShadowAlpha = mAmbientShadowAlpha;
3184 if (CC_UNLIKELY(mCaches.propertyAmbientShadowStrength >= 0)) {
3185 ambientShadowAlpha = mCaches.propertyAmbientShadowStrength;
3186 }
3187 if (ambientShadowVertexBuffer && ambientShadowAlpha > 0) {
3188 paint.setARGB(casterAlpha * ambientShadowAlpha, 0, 0, 0);
Chris Craik91a8c7c2014-08-12 14:31:35 -07003189 drawVertexBuffer(*ambientShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp);
ztenghuief94c6f2014-02-13 17:09:45 -08003190 }
ztenghui7b4516e2014-01-07 10:42:55 -08003191
ztenghui14a4e352014-08-13 10:44:39 -07003192 float spotShadowAlpha = mSpotShadowAlpha;
3193 if (CC_UNLIKELY(mCaches.propertySpotShadowStrength >= 0)) {
3194 spotShadowAlpha = mCaches.propertySpotShadowStrength;
3195 }
3196 if (spotShadowVertexBuffer && spotShadowAlpha > 0) {
3197 paint.setARGB(casterAlpha * spotShadowAlpha, 0, 0, 0);
Chris Craik91a8c7c2014-08-12 14:31:35 -07003198 drawVertexBuffer(*spotShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp);
ztenghuief94c6f2014-02-13 17:09:45 -08003199 }
ztenghui7b4516e2014-01-07 10:42:55 -08003200
3201 return DrawGlInfo::kStatusDrew;
Chris Craikf57776b2013-10-25 18:30:17 -07003202}
3203
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003204status_t OpenGLRenderer::drawColorRects(const float* rects, int count, const SkPaint* paint,
3205 bool ignoreTransform, bool dirty, bool clip) {
Romain Guy3b753822013-03-05 10:27:35 -08003206 if (count == 0) {
3207 return DrawGlInfo::kStatusDone;
3208 }
Romain Guy735738c2012-12-03 12:34:51 -08003209
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003210 int color = paint->getColor();
3211 // If a shader is set, preserve only the alpha
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04003212 if (getShader(paint)) {
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003213 color |= 0x00ffffff;
3214 }
3215
Romain Guy672433d2013-01-04 19:05:13 -08003216 float left = FLT_MAX;
3217 float top = FLT_MAX;
3218 float right = FLT_MIN;
3219 float bottom = FLT_MIN;
3220
Romain Guy448455f2013-07-22 13:57:50 -07003221 Vertex mesh[count];
Romain Guy672433d2013-01-04 19:05:13 -08003222 Vertex* vertex = mesh;
3223
Chris Craik2af46352012-11-26 18:30:17 -08003224 for (int index = 0; index < count; index += 4) {
Romain Guy672433d2013-01-04 19:05:13 -08003225 float l = rects[index + 0];
3226 float t = rects[index + 1];
3227 float r = rects[index + 2];
3228 float b = rects[index + 3];
3229
Romain Guy3b753822013-03-05 10:27:35 -08003230 Vertex::set(vertex++, l, t);
3231 Vertex::set(vertex++, r, t);
3232 Vertex::set(vertex++, l, b);
Romain Guy3b753822013-03-05 10:27:35 -08003233 Vertex::set(vertex++, r, b);
Romain Guy672433d2013-01-04 19:05:13 -08003234
Romain Guy3b753822013-03-05 10:27:35 -08003235 left = fminf(left, l);
3236 top = fminf(top, t);
3237 right = fmaxf(right, r);
3238 bottom = fmaxf(bottom, b);
Romain Guy672433d2013-01-04 19:05:13 -08003239 }
3240
Chris Craikf0a59072013-11-19 18:00:46 -08003241 if (clip && quickRejectSetupScissor(left, top, right, bottom)) {
Romain Guya362c692013-02-04 13:50:16 -08003242 return DrawGlInfo::kStatusDone;
3243 }
Romain Guy672433d2013-01-04 19:05:13 -08003244
Romain Guy672433d2013-01-04 19:05:13 -08003245 setupDraw();
3246 setupDrawNoTexture();
Chris Craikd6b65f62014-01-01 14:45:21 -08003247 setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04003248 setupDrawShader(getShader(paint));
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003249 setupDrawColorFilter(getColorFilter(paint));
3250 setupDrawBlending(paint);
Romain Guy672433d2013-01-04 19:05:13 -08003251 setupDrawProgram();
3252 setupDrawDirtyRegionsDisabled();
Chris Craik4063a0e2013-11-15 16:06:56 -08003253 setupDrawModelView(kModelViewMode_Translate, false,
3254 0.0f, 0.0f, 0.0f, 0.0f, ignoreTransform);
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04003255 setupDrawColorUniforms(getShader(paint));
3256 setupDrawShaderUniforms(getShader(paint));
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003257 setupDrawColorFilterUniforms(getColorFilter(paint));
Romain Guy672433d2013-01-04 19:05:13 -08003258
Romain Guy8ce00302013-01-15 18:51:42 -08003259 if (dirty && hasLayer()) {
Chris Craikd6b65f62014-01-01 14:45:21 -08003260 dirtyLayer(left, top, right, bottom, *currentTransform());
Romain Guy672433d2013-01-04 19:05:13 -08003261 }
3262
Chris Craik4063a0e2013-11-15 16:06:56 -08003263 issueIndexedQuadDraw(&mesh[0], count / 4);
Romain Guy672433d2013-01-04 19:05:13 -08003264
3265 return DrawGlInfo::kStatusDrew;
3266}
3267
Romain Guy026c5e162010-06-28 17:12:22 -07003268void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003269 const SkPaint* paint, bool ignoreTransform) {
3270 int color = paint->getColor();
Romain Guyd27977d2010-07-14 19:18:51 -07003271 // If a shader is set, preserve only the alpha
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04003272 if (getShader(paint)) {
Romain Guyd27977d2010-07-14 19:18:51 -07003273 color |= 0x00ffffff;
3274 }
3275
Romain Guy70ca14e2010-12-13 18:24:33 -08003276 setupDraw();
Romain Guy15bc6432011-12-13 13:11:32 -08003277 setupDrawNoTexture();
Chris Craikd6b65f62014-01-01 14:45:21 -08003278 setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04003279 setupDrawShader(getShader(paint));
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003280 setupDrawColorFilter(getColorFilter(paint));
3281 setupDrawBlending(paint);
Romain Guy70ca14e2010-12-13 18:24:33 -08003282 setupDrawProgram();
Chris Craik4063a0e2013-11-15 16:06:56 -08003283 setupDrawModelView(kModelViewMode_TranslateAndScale, false,
3284 left, top, right, bottom, ignoreTransform);
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04003285 setupDrawColorUniforms(getShader(paint));
3286 setupDrawShaderUniforms(getShader(paint), ignoreTransform);
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003287 setupDrawColorFilterUniforms(getColorFilter(paint));
Romain Guy70ca14e2010-12-13 18:24:33 -08003288 setupDrawSimpleMesh();
Romain Guyc0ac1932010-07-19 18:43:02 -07003289
Romain Guyc95c8d62010-09-17 15:31:32 -07003290 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
3291}
3292
Romain Guy82ba8142010-07-09 13:25:56 -07003293void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
Chris Craikd218a922014-01-02 17:13:34 -08003294 Texture* texture, const SkPaint* paint) {
Romain Guyd21b6e12011-11-30 20:21:23 -08003295 texture->setWrap(GL_CLAMP_TO_EDGE, true);
Romain Guy8164c2d2010-10-25 18:03:28 -07003296
Romain Guy3b748a42013-04-17 18:54:38 -07003297 GLvoid* vertices = (GLvoid*) NULL;
3298 GLvoid* texCoords = (GLvoid*) gMeshTextureOffset;
3299
3300 if (texture->uvMapper) {
Romain Guy3380cfd2013-08-15 16:57:57 -07003301 vertices = &mMeshVertices[0].x;
3302 texCoords = &mMeshVertices[0].u;
Romain Guy3b748a42013-04-17 18:54:38 -07003303
3304 Rect uvs(0.0f, 0.0f, 1.0f, 1.0f);
3305 texture->uvMapper->map(uvs);
3306
3307 resetDrawTextureTexCoords(uvs.left, uvs.top, uvs.right, uvs.bottom);
3308 }
3309
Chris Craikd6b65f62014-01-01 14:45:21 -08003310 if (CC_LIKELY(currentTransform()->isPureTranslate())) {
3311 const float x = (int) floorf(left + currentTransform()->getTranslateX() + 0.5f);
3312 const float y = (int) floorf(top + currentTransform()->getTranslateY() + 0.5f);
Romain Guy6620c6d2010-12-06 18:07:02 -08003313
Romain Guyd21b6e12011-11-30 20:21:23 -08003314 texture->setFilter(GL_NEAREST, true);
Romain Guy6620c6d2010-12-06 18:07:02 -08003315 drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003316 paint, texture->blend, vertices, texCoords,
Romain Guy3b748a42013-04-17 18:54:38 -07003317 GL_TRIANGLE_STRIP, gMeshCount, false, true);
Romain Guy6620c6d2010-12-06 18:07:02 -08003318 } else {
Chris Craik678625242014-02-28 12:26:34 -08003319 texture->setFilter(getFilter(paint), true);
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003320 drawTextureMesh(left, top, right, bottom, texture->id, paint,
Romain Guy3b748a42013-04-17 18:54:38 -07003321 texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, gMeshCount);
3322 }
3323
3324 if (texture->uvMapper) {
3325 resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
Romain Guy6620c6d2010-12-06 18:07:02 -08003326 }
Romain Guy85bf02f2010-06-22 13:11:24 -07003327}
3328
Romain Guyf7f93552010-07-08 19:17:03 -07003329void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003330 GLuint texture, const SkPaint* paint, bool blend,
Romain Guy6820ac82010-09-15 18:11:50 -07003331 GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
Chris Craik4063a0e2013-11-15 16:06:56 -08003332 bool swapSrcDst, bool ignoreTransform, GLuint vbo,
3333 ModelViewMode modelViewMode, bool dirty) {
Romain Guy70ca14e2010-12-13 18:24:33 -08003334
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003335 int a;
3336 SkXfermode::Mode mode;
3337 getAlphaAndMode(paint, &a, &mode);
3338 const float alpha = a / 255.0f;
3339
Romain Guy746b7402010-10-26 16:27:31 -07003340 setupDraw();
Romain Guy70ca14e2010-12-13 18:24:33 -08003341 setupDrawWithTexture();
3342 setupDrawColor(alpha, alpha, alpha, alpha);
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003343 setupDrawColorFilter(getColorFilter(paint));
3344 setupDrawBlending(paint, blend, swapSrcDst);
Romain Guy70ca14e2010-12-13 18:24:33 -08003345 setupDrawProgram();
Romain Guy886b2752013-01-04 12:26:18 -08003346 if (!dirty) setupDrawDirtyRegionsDisabled();
Chris Craik4063a0e2013-11-15 16:06:56 -08003347 setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
Romain Guy886b2752013-01-04 12:26:18 -08003348 setupDrawTexture(texture);
Romain Guy86568192010-12-14 15:55:39 -08003349 setupDrawPureColorUniforms();
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003350 setupDrawColorFilterUniforms(getColorFilter(paint));
Romain Guy70ca14e2010-12-13 18:24:33 -08003351 setupDrawMesh(vertices, texCoords, vbo);
Romain Guydb1938e2010-08-02 18:50:22 -07003352
Romain Guy6820ac82010-09-15 18:11:50 -07003353 glDrawArrays(drawMode, 0, elementsCount);
Romain Guy82ba8142010-07-09 13:25:56 -07003354}
3355
Romain Guy3b748a42013-04-17 18:54:38 -07003356void OpenGLRenderer::drawIndexedTextureMesh(float left, float top, float right, float bottom,
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003357 GLuint texture, const SkPaint* paint, bool blend,
Romain Guy3b748a42013-04-17 18:54:38 -07003358 GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
Chris Craik4063a0e2013-11-15 16:06:56 -08003359 bool swapSrcDst, bool ignoreTransform, GLuint vbo,
3360 ModelViewMode modelViewMode, bool dirty) {
Romain Guy3b748a42013-04-17 18:54:38 -07003361
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003362 int a;
3363 SkXfermode::Mode mode;
3364 getAlphaAndMode(paint, &a, &mode);
3365 const float alpha = a / 255.0f;
3366
Romain Guy3b748a42013-04-17 18:54:38 -07003367 setupDraw();
3368 setupDrawWithTexture();
3369 setupDrawColor(alpha, alpha, alpha, alpha);
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003370 setupDrawColorFilter(getColorFilter(paint));
3371 setupDrawBlending(paint, blend, swapSrcDst);
Romain Guy3b748a42013-04-17 18:54:38 -07003372 setupDrawProgram();
3373 if (!dirty) setupDrawDirtyRegionsDisabled();
Chris Craik4063a0e2013-11-15 16:06:56 -08003374 setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
Romain Guy3b748a42013-04-17 18:54:38 -07003375 setupDrawTexture(texture);
3376 setupDrawPureColorUniforms();
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003377 setupDrawColorFilterUniforms(getColorFilter(paint));
Romain Guy3b748a42013-04-17 18:54:38 -07003378 setupDrawMeshIndices(vertices, texCoords, vbo);
3379
3380 glDrawElements(drawMode, elementsCount, GL_UNSIGNED_SHORT, NULL);
Romain Guy3b748a42013-04-17 18:54:38 -07003381}
3382
Romain Guy886b2752013-01-04 12:26:18 -08003383void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom,
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003384 GLuint texture, const SkPaint* paint,
Romain Guy886b2752013-01-04 12:26:18 -08003385 GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
Chris Craik4063a0e2013-11-15 16:06:56 -08003386 bool ignoreTransform, ModelViewMode modelViewMode, bool dirty) {
Romain Guy886b2752013-01-04 12:26:18 -08003387
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003388 int color = paint != NULL ? paint->getColor() : 0;
3389 int alpha;
3390 SkXfermode::Mode mode;
3391 getAlphaAndMode(paint, &alpha, &mode);
3392
Romain Guy886b2752013-01-04 12:26:18 -08003393 setupDraw();
3394 setupDrawWithTexture(true);
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003395 if (paint != NULL) {
Romain Guy886b2752013-01-04 12:26:18 -08003396 setupDrawAlpha8Color(color, alpha);
3397 }
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003398 setupDrawColorFilter(getColorFilter(paint));
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04003399 setupDrawShader(getShader(paint));
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003400 setupDrawBlending(paint, true);
Romain Guy886b2752013-01-04 12:26:18 -08003401 setupDrawProgram();
3402 if (!dirty) setupDrawDirtyRegionsDisabled();
Chris Craik4063a0e2013-11-15 16:06:56 -08003403 setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
Romain Guy886b2752013-01-04 12:26:18 -08003404 setupDrawTexture(texture);
3405 setupDrawPureColorUniforms();
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003406 setupDrawColorFilterUniforms(getColorFilter(paint));
Leon Scroggins IIId1ad5e62014-05-05 12:50:38 -04003407 setupDrawShaderUniforms(getShader(paint), ignoreTransform);
Romain Guy886b2752013-01-04 12:26:18 -08003408 setupDrawMesh(vertices, texCoords);
3409
3410 glDrawArrays(drawMode, 0, elementsCount);
Romain Guy886b2752013-01-04 12:26:18 -08003411}
3412
Romain Guya5aed0d2010-09-09 14:42:43 -07003413void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
Romain Guyf607bdc2010-09-10 19:20:06 -07003414 ProgramDescription& description, bool swapSrcDst) {
Chris Craikdeeda3d2014-05-05 19:09:33 -07003415
3416 if (mSnapshot->roundRectClipState != NULL /*&& !mSkipOutlineClip*/) {
3417 blend = true;
3418 mDescription.hasRoundRectClip = true;
3419 }
3420 mSkipOutlineClip = true;
3421
Romain Guy78dd96d2013-05-03 14:24:16 -07003422 if (mCountOverdraw) {
3423 if (!mCaches.blend) glEnable(GL_BLEND);
3424 if (mCaches.lastSrcMode != GL_ONE || mCaches.lastDstMode != GL_ONE) {
3425 glBlendFunc(GL_ONE, GL_ONE);
3426 }
3427
3428 mCaches.blend = true;
3429 mCaches.lastSrcMode = GL_ONE;
3430 mCaches.lastDstMode = GL_ONE;
3431
3432 return;
3433 }
3434
Romain Guy82ba8142010-07-09 13:25:56 -07003435 blend = blend || mode != SkXfermode::kSrcOver_Mode;
Romain Guyc189ef52012-04-25 20:02:53 -07003436
Romain Guy82ba8142010-07-09 13:25:56 -07003437 if (blend) {
Romain Guy82bc7a72012-01-03 14:13:39 -08003438 // These blend modes are not supported by OpenGL directly and have
3439 // to be implemented using shaders. Since the shader will perform
3440 // the blending, turn blending off here
3441 // If the blend mode cannot be implemented using shaders, fall
3442 // back to the default SrcOver blend mode instead
Romain Guy33fa1f72012-08-07 19:09:57 -07003443 if (CC_UNLIKELY(mode > SkXfermode::kScreen_Mode)) {
Romain Guy3bbacf22013-02-06 16:51:04 -08003444 if (CC_UNLIKELY(mExtensions.hasFramebufferFetch())) {
Romain Guya5aed0d2010-09-09 14:42:43 -07003445 description.framebufferMode = mode;
Romain Guyf607bdc2010-09-10 19:20:06 -07003446 description.swapSrcDst = swapSrcDst;
Romain Guya5aed0d2010-09-09 14:42:43 -07003447
Romain Guy82bc7a72012-01-03 14:13:39 -08003448 if (mCaches.blend) {
3449 glDisable(GL_BLEND);
3450 mCaches.blend = false;
3451 }
3452
3453 return;
3454 } else {
3455 mode = SkXfermode::kSrcOver_Mode;
Romain Guya5aed0d2010-09-09 14:42:43 -07003456 }
Romain Guy82bc7a72012-01-03 14:13:39 -08003457 }
3458
3459 if (!mCaches.blend) {
3460 glEnable(GL_BLEND);
3461 }
3462
3463 GLenum sourceMode = swapSrcDst ? gBlendsSwap[mode].src : gBlends[mode].src;
3464 GLenum destMode = swapSrcDst ? gBlendsSwap[mode].dst : gBlends[mode].dst;
3465
3466 if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) {
3467 glBlendFunc(sourceMode, destMode);
3468 mCaches.lastSrcMode = sourceMode;
3469 mCaches.lastDstMode = destMode;
Romain Guy82ba8142010-07-09 13:25:56 -07003470 }
Romain Guyfb8b7632010-08-23 21:05:08 -07003471 } else if (mCaches.blend) {
Romain Guy82ba8142010-07-09 13:25:56 -07003472 glDisable(GL_BLEND);
3473 }
Romain Guyfb8b7632010-08-23 21:05:08 -07003474 mCaches.blend = blend;
Romain Guybd6b79b2010-06-26 00:13:53 -07003475}
3476
Romain Guy889f8d12010-07-29 14:37:42 -07003477bool OpenGLRenderer::useProgram(Program* program) {
Romain Guyd27977d2010-07-14 19:18:51 -07003478 if (!program->isInUse()) {
Romain Guyfb8b7632010-08-23 21:05:08 -07003479 if (mCaches.currentProgram != NULL) mCaches.currentProgram->remove();
Romain Guyd27977d2010-07-14 19:18:51 -07003480 program->use();
Romain Guyfb8b7632010-08-23 21:05:08 -07003481 mCaches.currentProgram = program;
Romain Guy6926c722010-07-12 20:20:03 -07003482 return false;
Romain Guy260e1022010-07-12 14:41:06 -07003483 }
Romain Guy6926c722010-07-12 20:20:03 -07003484 return true;
Romain Guy260e1022010-07-12 14:41:06 -07003485}
3486
Romain Guy026c5e162010-06-28 17:12:22 -07003487void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
Romain Guyac670c02010-07-27 17:39:27 -07003488 TextureVertex* v = &mMeshVertices[0];
Romain Guy82ba8142010-07-09 13:25:56 -07003489 TextureVertex::setUV(v++, u1, v1);
3490 TextureVertex::setUV(v++, u2, v1);
3491 TextureVertex::setUV(v++, u1, v2);
3492 TextureVertex::setUV(v++, u2, v2);
Romain Guy8ba548f2010-06-30 19:21:21 -07003493}
3494
Chris Craikd218a922014-01-02 17:13:34 -08003495void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) const {
Romain Guybe6f9dc2012-07-16 12:41:17 -07003496 getAlphaAndModeDirect(paint, alpha, mode);
Chris Craik16ecda52013-03-29 10:59:59 -07003497 if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
3498 // if drawing a layer, ignore the paint's alpha
Romain Guy87b515c2013-05-03 17:42:27 -07003499 *alpha = mDrawModifiers.mOverrideLayerAlpha * 255;
Chris Craik16ecda52013-03-29 10:59:59 -07003500 }
Chris Craikd6b65f62014-01-01 14:45:21 -08003501 *alpha *= currentSnapshot()->alpha;
Romain Guy026c5e162010-06-28 17:12:22 -07003502}
3503
Derek Sollenberger76d3a1b2013-12-10 12:28:58 -05003504float OpenGLRenderer::getLayerAlpha(const Layer* layer) const {
Chris Craik16ecda52013-03-29 10:59:59 -07003505 float alpha;
3506 if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
3507 alpha = mDrawModifiers.mOverrideLayerAlpha;
3508 } else {
3509 alpha = layer->getAlpha() / 255.0f;
3510 }
Chris Craikd6b65f62014-01-01 14:45:21 -08003511 return alpha * currentSnapshot()->alpha;
Chris Craik16ecda52013-03-29 10:59:59 -07003512}
3513
Romain Guy9d5316e2010-06-24 19:30:36 -07003514}; // namespace uirenderer
Romain Guye4d01122010-06-16 18:44:05 -07003515}; // namespace android