• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 #define LOG_TAG "OpenGLRenderer"
18 
19 #include <stdlib.h>
20 #include <stdint.h>
21 #include <sys/types.h>
22 
23 #include <SkCanvas.h>
24 #include <SkPathMeasure.h>
25 #include <SkTypeface.h>
26 
27 #include <utils/Log.h>
28 #include <utils/StopWatch.h>
29 
30 #include <private/hwui/DrawGlInfo.h>
31 
32 #include <ui/Rect.h>
33 
34 #include "OpenGLRenderer.h"
35 #include "DisplayListRenderer.h"
36 #include "Vector.h"
37 
38 namespace android {
39 namespace uirenderer {
40 
41 ///////////////////////////////////////////////////////////////////////////////
42 // Defines
43 ///////////////////////////////////////////////////////////////////////////////
44 
45 #define RAD_TO_DEG (180.0f / 3.14159265f)
46 #define MIN_ANGLE 0.001f
47 
48 // TODO: This should be set in properties
49 #define ALPHA_THRESHOLD (0x7f / PANEL_BIT_DEPTH)
50 
51 #define FILTER(paint) (paint && paint->isFilterBitmap() ? GL_LINEAR : GL_NEAREST)
52 
53 ///////////////////////////////////////////////////////////////////////////////
54 // Globals
55 ///////////////////////////////////////////////////////////////////////////////
56 
57 /**
58  * Structure mapping Skia xfermodes to OpenGL blending factors.
59  */
60 struct Blender {
61     SkXfermode::Mode mode;
62     GLenum src;
63     GLenum dst;
64 }; // struct Blender
65 
66 // In this array, the index of each Blender equals the value of the first
67 // entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
68 static const Blender gBlends[] = {
69     { SkXfermode::kClear_Mode,    GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
70     { SkXfermode::kSrc_Mode,      GL_ONE,                 GL_ZERO },
71     { SkXfermode::kDst_Mode,      GL_ZERO,                GL_ONE },
72     { SkXfermode::kSrcOver_Mode,  GL_ONE,                 GL_ONE_MINUS_SRC_ALPHA },
73     { SkXfermode::kDstOver_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_ONE },
74     { SkXfermode::kSrcIn_Mode,    GL_DST_ALPHA,           GL_ZERO },
75     { SkXfermode::kDstIn_Mode,    GL_ZERO,                GL_SRC_ALPHA },
76     { SkXfermode::kSrcOut_Mode,   GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
77     { SkXfermode::kDstOut_Mode,   GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
78     { SkXfermode::kSrcATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
79     { SkXfermode::kDstATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
80     { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
81     { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
82     { SkXfermode::kMultiply_Mode, GL_ZERO,                GL_SRC_COLOR },
83     { SkXfermode::kScreen_Mode,   GL_ONE,                 GL_ONE_MINUS_SRC_COLOR }
84 };
85 
86 // This array contains the swapped version of each SkXfermode. For instance
87 // this array's SrcOver blending mode is actually DstOver. You can refer to
88 // createLayer() for more information on the purpose of this array.
89 static const Blender gBlendsSwap[] = {
90     { SkXfermode::kClear_Mode,    GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
91     { SkXfermode::kSrc_Mode,      GL_ZERO,                GL_ONE },
92     { SkXfermode::kDst_Mode,      GL_ONE,                 GL_ZERO },
93     { SkXfermode::kSrcOver_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_ONE },
94     { SkXfermode::kDstOver_Mode,  GL_ONE,                 GL_ONE_MINUS_SRC_ALPHA },
95     { SkXfermode::kSrcIn_Mode,    GL_ZERO,                GL_SRC_ALPHA },
96     { SkXfermode::kDstIn_Mode,    GL_DST_ALPHA,           GL_ZERO },
97     { SkXfermode::kSrcOut_Mode,   GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
98     { SkXfermode::kDstOut_Mode,   GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
99     { SkXfermode::kSrcATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
100     { SkXfermode::kDstATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
101     { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
102     { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
103     { SkXfermode::kMultiply_Mode, GL_DST_COLOR,           GL_ZERO },
104     { SkXfermode::kScreen_Mode,   GL_ONE_MINUS_DST_COLOR, GL_ONE }
105 };
106 
107 ///////////////////////////////////////////////////////////////////////////////
108 // Constructors/destructor
109 ///////////////////////////////////////////////////////////////////////////////
110 
OpenGLRenderer()111 OpenGLRenderer::OpenGLRenderer(): mCaches(Caches::getInstance()) {
112     mShader = NULL;
113     mColorFilter = NULL;
114     mHasShadow = false;
115     mHasDrawFilter = false;
116 
117     memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
118 
119     mFirstSnapshot = new Snapshot;
120 }
121 
~OpenGLRenderer()122 OpenGLRenderer::~OpenGLRenderer() {
123     // The context has already been destroyed at this point, do not call
124     // GL APIs. All GL state should be kept in Caches.h
125 }
126 
127 ///////////////////////////////////////////////////////////////////////////////
128 // Debug
129 ///////////////////////////////////////////////////////////////////////////////
130 
startMark(const char * name) const131 void OpenGLRenderer::startMark(const char* name) const {
132     mCaches.startMark(0, name);
133 }
134 
endMark() const135 void OpenGLRenderer::endMark() const {
136     mCaches.endMark();
137 }
138 
139 ///////////////////////////////////////////////////////////////////////////////
140 // Setup
141 ///////////////////////////////////////////////////////////////////////////////
142 
getStencilSize()143 uint32_t OpenGLRenderer::getStencilSize() {
144     return STENCIL_BUFFER_SIZE;
145 }
146 
isDeferred()147 bool OpenGLRenderer::isDeferred() {
148     return false;
149 }
150 
setViewport(int width,int height)151 void OpenGLRenderer::setViewport(int width, int height) {
152     mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
153 
154     mWidth = width;
155     mHeight = height;
156 
157     mFirstSnapshot->height = height;
158     mFirstSnapshot->viewport.set(0, 0, width, height);
159 
160     glDisable(GL_DITHER);
161     glEnable(GL_SCISSOR_TEST);
162     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
163 
164     glEnableVertexAttribArray(Program::kBindingPosition);
165 }
166 
prepare(bool opaque)167 int OpenGLRenderer::prepare(bool opaque) {
168     return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque);
169 }
170 
prepareDirty(float left,float top,float right,float bottom,bool opaque)171 int OpenGLRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) {
172     mCaches.clearGarbage();
173 
174     mSnapshot = new Snapshot(mFirstSnapshot,
175             SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
176     mSnapshot->fbo = getTargetFbo();
177     mSaveCount = 1;
178 
179     mSnapshot->setClip(left, top, right, bottom);
180     mDirtyClip = opaque;
181 
182     syncState();
183 
184     if (!opaque) {
185         mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top);
186         glClear(GL_COLOR_BUFFER_BIT);
187         return DrawGlInfo::kStatusDrew;
188     } else {
189         mCaches.resetScissor();
190     }
191 
192     return DrawGlInfo::kStatusDone;
193 }
194 
syncState()195 void OpenGLRenderer::syncState() {
196     glViewport(0, 0, mWidth, mHeight);
197 
198     if (mCaches.blend) {
199         glEnable(GL_BLEND);
200     } else {
201         glDisable(GL_BLEND);
202     }
203 }
204 
finish()205 void OpenGLRenderer::finish() {
206 #if DEBUG_OPENGL
207     GLenum status = GL_NO_ERROR;
208     while ((status = glGetError()) != GL_NO_ERROR) {
209         ALOGD("GL error from OpenGLRenderer: 0x%x", status);
210         switch (status) {
211             case GL_INVALID_ENUM:
212                 ALOGE("  GL_INVALID_ENUM");
213                 break;
214             case GL_INVALID_VALUE:
215                 ALOGE("  GL_INVALID_VALUE");
216                 break;
217             case GL_INVALID_OPERATION:
218                 ALOGE("  GL_INVALID_OPERATION");
219                 break;
220             case GL_OUT_OF_MEMORY:
221                 ALOGE("  Out of memory!");
222                 break;
223         }
224     }
225 #endif
226 #if DEBUG_MEMORY_USAGE
227     mCaches.dumpMemoryUsage();
228 #else
229     if (mCaches.getDebugLevel() & kDebugMemory) {
230         mCaches.dumpMemoryUsage();
231     }
232 #endif
233 }
234 
interrupt()235 void OpenGLRenderer::interrupt() {
236     if (mCaches.currentProgram) {
237         if (mCaches.currentProgram->isInUse()) {
238             mCaches.currentProgram->remove();
239             mCaches.currentProgram = NULL;
240         }
241     }
242     mCaches.unbindMeshBuffer();
243     mCaches.unbindIndicesBuffer();
244     mCaches.resetVertexPointers();
245     mCaches.disbaleTexCoordsVertexArray();
246 }
247 
resume()248 void OpenGLRenderer::resume() {
249     sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot;
250 
251     glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
252     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
253 
254     glEnable(GL_SCISSOR_TEST);
255     mCaches.resetScissor();
256     dirtyClip();
257 
258     mCaches.activeTexture(0);
259     glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
260 
261     mCaches.blend = true;
262     glEnable(GL_BLEND);
263     glBlendFunc(mCaches.lastSrcMode, mCaches.lastDstMode);
264     glBlendEquation(GL_FUNC_ADD);
265 }
266 
detachFunctor(Functor * functor)267 void OpenGLRenderer::detachFunctor(Functor* functor) {
268     mFunctors.remove(functor);
269 }
270 
attachFunctor(Functor * functor)271 void OpenGLRenderer::attachFunctor(Functor* functor) {
272     mFunctors.add(functor);
273 }
274 
invokeFunctors(Rect & dirty)275 status_t OpenGLRenderer::invokeFunctors(Rect& dirty) {
276     status_t result = DrawGlInfo::kStatusDone;
277     size_t count = mFunctors.size();
278 
279     if (count > 0) {
280         SortedVector<Functor*> functors(mFunctors);
281         mFunctors.clear();
282 
283         DrawGlInfo info;
284         info.clipLeft = 0;
285         info.clipTop = 0;
286         info.clipRight = 0;
287         info.clipBottom = 0;
288         info.isLayer = false;
289         info.width = 0;
290         info.height = 0;
291         memset(info.transform, 0, sizeof(float) * 16);
292 
293         for (size_t i = 0; i < count; i++) {
294             Functor* f = functors.itemAt(i);
295             result |= (*f)(DrawGlInfo::kModeProcess, &info);
296 
297             if (result & DrawGlInfo::kStatusDraw) {
298                 Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom);
299                 dirty.unionWith(localDirty);
300             }
301 
302             if (result & DrawGlInfo::kStatusInvoke) {
303                 mFunctors.add(f);
304             }
305         }
306     }
307 
308     mCaches.activeTexture(0);
309 
310     return result;
311 }
312 
callDrawGLFunction(Functor * functor,Rect & dirty)313 status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
314     interrupt();
315     detachFunctor(functor);
316 
317     if (mDirtyClip) {
318         setScissorFromClip();
319     }
320 
321     Rect clip(*mSnapshot->clipRect);
322     clip.snapToPixelBoundaries();
323 
324 #if RENDER_LAYERS_AS_REGIONS
325     // Since we don't know what the functor will draw, let's dirty
326     // tne entire clip region
327     if (hasLayer()) {
328         dirtyLayerUnchecked(clip, getRegion());
329     }
330 #endif
331 
332     DrawGlInfo info;
333     info.clipLeft = clip.left;
334     info.clipTop = clip.top;
335     info.clipRight = clip.right;
336     info.clipBottom = clip.bottom;
337     info.isLayer = hasLayer();
338     info.width = getSnapshot()->viewport.getWidth();
339     info.height = getSnapshot()->height;
340     getSnapshot()->transform->copyTo(&info.transform[0]);
341 
342     status_t result = (*functor)(DrawGlInfo::kModeDraw, &info) | DrawGlInfo::kStatusDrew;
343 
344     if (result != DrawGlInfo::kStatusDone) {
345         Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom);
346         dirty.unionWith(localDirty);
347 
348         if (result & DrawGlInfo::kStatusInvoke) {
349             mFunctors.add(functor);
350         }
351     }
352 
353     resume();
354     return result;
355 }
356 
357 ///////////////////////////////////////////////////////////////////////////////
358 // State management
359 ///////////////////////////////////////////////////////////////////////////////
360 
getSaveCount() const361 int OpenGLRenderer::getSaveCount() const {
362     return mSaveCount;
363 }
364 
save(int flags)365 int OpenGLRenderer::save(int flags) {
366     return saveSnapshot(flags);
367 }
368 
restore()369 void OpenGLRenderer::restore() {
370     if (mSaveCount > 1) {
371         restoreSnapshot();
372     }
373 }
374 
restoreToCount(int saveCount)375 void OpenGLRenderer::restoreToCount(int saveCount) {
376     if (saveCount < 1) saveCount = 1;
377 
378     while (mSaveCount > saveCount) {
379         restoreSnapshot();
380     }
381 }
382 
saveSnapshot(int flags)383 int OpenGLRenderer::saveSnapshot(int flags) {
384     mSnapshot = new Snapshot(mSnapshot, flags);
385     return mSaveCount++;
386 }
387 
restoreSnapshot()388 bool OpenGLRenderer::restoreSnapshot() {
389     bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet;
390     bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer;
391     bool restoreOrtho = mSnapshot->flags & Snapshot::kFlagDirtyOrtho;
392 
393     sp<Snapshot> current = mSnapshot;
394     sp<Snapshot> previous = mSnapshot->previous;
395 
396     if (restoreOrtho) {
397         Rect& r = previous->viewport;
398         glViewport(r.left, r.top, r.right, r.bottom);
399         mOrthoMatrix.load(current->orthoMatrix);
400     }
401 
402     mSaveCount--;
403     mSnapshot = previous;
404 
405     if (restoreClip) {
406         dirtyClip();
407     }
408 
409     if (restoreLayer) {
410         composeLayer(current, previous);
411     }
412 
413     return restoreClip;
414 }
415 
416 ///////////////////////////////////////////////////////////////////////////////
417 // Layers
418 ///////////////////////////////////////////////////////////////////////////////
419 
saveLayer(float left,float top,float right,float bottom,SkPaint * p,int flags)420 int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
421         SkPaint* p, int flags) {
422     const GLuint previousFbo = mSnapshot->fbo;
423     const int count = saveSnapshot(flags);
424 
425     if (!mSnapshot->isIgnored()) {
426         int alpha = 255;
427         SkXfermode::Mode mode;
428 
429         if (p) {
430             alpha = p->getAlpha();
431             if (!mCaches.extensions.hasFramebufferFetch()) {
432                 const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode);
433                 if (!isMode) {
434                     // Assume SRC_OVER
435                     mode = SkXfermode::kSrcOver_Mode;
436                 }
437             } else {
438                 mode = getXfermode(p->getXfermode());
439             }
440         } else {
441             mode = SkXfermode::kSrcOver_Mode;
442         }
443 
444         createLayer(mSnapshot, left, top, right, bottom, alpha, mode, flags, previousFbo);
445     }
446 
447     return count;
448 }
449 
saveLayerAlpha(float left,float top,float right,float bottom,int alpha,int flags)450 int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom,
451         int alpha, int flags) {
452     if (alpha >= 255 - ALPHA_THRESHOLD) {
453         return saveLayer(left, top, right, bottom, NULL, flags);
454     } else {
455         SkPaint paint;
456         paint.setAlpha(alpha);
457         return saveLayer(left, top, right, bottom, &paint, flags);
458     }
459 }
460 
461 /**
462  * Layers are viewed by Skia are slightly different than layers in image editing
463  * programs (for instance.) When a layer is created, previously created layers
464  * and the frame buffer still receive every drawing command. For instance, if a
465  * layer is created and a shape intersecting the bounds of the layers and the
466  * framebuffer is draw, the shape will be drawn on both (unless the layer was
467  * created with the SkCanvas::kClipToLayer_SaveFlag flag.)
468  *
469  * A way to implement layers is to create an FBO for each layer, backed by an RGBA
470  * texture. Unfortunately, this is inefficient as it requires every primitive to
471  * be drawn n + 1 times, where n is the number of active layers. In practice this
472  * means, for every primitive:
473  *   - Switch active frame buffer
474  *   - Change viewport, clip and projection matrix
475  *   - Issue the drawing
476  *
477  * Switching rendering target n + 1 times per drawn primitive is extremely costly.
478  * To avoid this, layers are implemented in a different way here, at least in the
479  * general case. FBOs are used, as an optimization, when the "clip to layer" flag
480  * is set. When this flag is set we can redirect all drawing operations into a
481  * single FBO.
482  *
483  * This implementation relies on the frame buffer being at least RGBA 8888. When
484  * a layer is created, only a texture is created, not an FBO. The content of the
485  * frame buffer contained within the layer's bounds is copied into this texture
486  * using glCopyTexImage2D(). The layer's region is then cleared(1) in the frame
487  * buffer and drawing continues as normal. This technique therefore treats the
488  * frame buffer as a scratch buffer for the layers.
489  *
490  * To compose the layers back onto the frame buffer, each layer texture
491  * (containing the original frame buffer data) is drawn as a simple quad over
492  * the frame buffer. The trick is that the quad is set as the composition
493  * destination in the blending equation, and the frame buffer becomes the source
494  * of the composition.
495  *
496  * Drawing layers with an alpha value requires an extra step before composition.
497  * An empty quad is drawn over the layer's region in the frame buffer. This quad
498  * is drawn with the rgba color (0,0,0,alpha). The alpha value offered by the
499  * quad is used to multiply the colors in the frame buffer. This is achieved by
500  * changing the GL blend functions for the GL_FUNC_ADD blend equation to
501  * GL_ZERO, GL_SRC_ALPHA.
502  *
503  * Because glCopyTexImage2D() can be slow, an alternative implementation might
504  * be use to draw a single clipped layer. The implementation described above
505  * is correct in every case.
506  *
507  * (1) The frame buffer is actually not cleared right away. To allow the GPU
508  *     to potentially optimize series of calls to glCopyTexImage2D, the frame
509  *     buffer is left untouched until the first drawing operation. Only when
510  *     something actually gets drawn are the layers regions cleared.
511  */
createLayer(sp<Snapshot> snapshot,float left,float top,float right,float bottom,int alpha,SkXfermode::Mode mode,int flags,GLuint previousFbo)512 bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
513         float right, float bottom, int alpha, SkXfermode::Mode mode,
514         int flags, GLuint previousFbo) {
515     LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top);
516     LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
517 
518     const bool fboLayer = flags & SkCanvas::kClipToLayer_SaveFlag;
519 
520     // Window coordinates of the layer
521     Rect bounds(left, top, right, bottom);
522     if (!fboLayer) {
523         mSnapshot->transform->mapRect(bounds);
524 
525         // Layers only make sense if they are in the framebuffer's bounds
526         if (bounds.intersect(*snapshot->clipRect)) {
527             // We cannot work with sub-pixels in this case
528             bounds.snapToPixelBoundaries();
529 
530             // When the layer is not an FBO, we may use glCopyTexImage so we
531             // need to make sure the layer does not extend outside the bounds
532             // of the framebuffer
533             if (!bounds.intersect(snapshot->previous->viewport)) {
534                 bounds.setEmpty();
535             }
536         } else {
537             bounds.setEmpty();
538         }
539     }
540 
541     if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize ||
542             bounds.getHeight() > mCaches.maxTextureSize) {
543         snapshot->empty = fboLayer;
544     } else {
545         snapshot->invisible = snapshot->invisible || (alpha <= ALPHA_THRESHOLD && fboLayer);
546     }
547 
548     // Bail out if we won't draw in this snapshot
549     if (snapshot->invisible || snapshot->empty) {
550         return false;
551     }
552 
553     mCaches.activeTexture(0);
554     Layer* layer = mCaches.layerCache.get(bounds.getWidth(), bounds.getHeight());
555     if (!layer) {
556         return false;
557     }
558 
559     layer->setAlpha(alpha, mode);
560     layer->layer.set(bounds);
561     layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()),
562             bounds.getWidth() / float(layer->getWidth()), 0.0f);
563     layer->setColorFilter(mColorFilter);
564     layer->setBlend(true);
565 
566     // Save the layer in the snapshot
567     snapshot->flags |= Snapshot::kFlagIsLayer;
568     snapshot->layer = layer;
569 
570     if (fboLayer) {
571         return createFboLayer(layer, bounds, snapshot, previousFbo);
572     } else {
573         // Copy the framebuffer into the layer
574         layer->bindTexture();
575         if (!bounds.isEmpty()) {
576             if (layer->isEmpty()) {
577                 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
578                         bounds.left, snapshot->height - bounds.bottom,
579                         layer->getWidth(), layer->getHeight(), 0);
580                 layer->setEmpty(false);
581             } else {
582                 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left,
583                         snapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight());
584             }
585 
586             // Enqueue the buffer coordinates to clear the corresponding region later
587             mLayers.push(new Rect(bounds));
588         }
589     }
590 
591     return true;
592 }
593 
createFboLayer(Layer * layer,Rect & bounds,sp<Snapshot> snapshot,GLuint previousFbo)594 bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, sp<Snapshot> snapshot,
595         GLuint previousFbo) {
596     layer->setFbo(mCaches.fboCache.get());
597 
598 #if RENDER_LAYERS_AS_REGIONS
599     snapshot->region = &snapshot->layer->region;
600     snapshot->flags |= Snapshot::kFlagFboTarget;
601 #endif
602 
603     Rect clip(bounds);
604     snapshot->transform->mapRect(clip);
605     clip.intersect(*snapshot->clipRect);
606     clip.snapToPixelBoundaries();
607     clip.intersect(snapshot->previous->viewport);
608 
609     mat4 inverse;
610     inverse.loadInverse(*mSnapshot->transform);
611 
612     inverse.mapRect(clip);
613     clip.snapToPixelBoundaries();
614     clip.intersect(bounds);
615     clip.translate(-bounds.left, -bounds.top);
616 
617     snapshot->flags |= Snapshot::kFlagIsFboLayer;
618     snapshot->fbo = layer->getFbo();
619     snapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
620     snapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
621     snapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
622     snapshot->height = bounds.getHeight();
623     snapshot->flags |= Snapshot::kFlagDirtyOrtho;
624     snapshot->orthoMatrix.load(mOrthoMatrix);
625 
626     // Bind texture to FBO
627     glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo());
628     layer->bindTexture();
629 
630     // Initialize the texture if needed
631     if (layer->isEmpty()) {
632         layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE);
633         layer->setEmpty(false);
634     }
635 
636     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
637             layer->getTexture(), 0);
638 
639 #if DEBUG_LAYERS_AS_REGIONS
640     GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
641     if (status != GL_FRAMEBUFFER_COMPLETE) {
642         ALOGE("Framebuffer incomplete (GL error code 0x%x)", status);
643 
644         glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
645         layer->deleteTexture();
646         mCaches.fboCache.put(layer->getFbo());
647 
648         delete layer;
649 
650         return false;
651     }
652 #endif
653 
654     // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
655     mCaches.setScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
656             clip.getWidth() + 2.0f, clip.getHeight() + 2.0f);
657     glClear(GL_COLOR_BUFFER_BIT);
658 
659     dirtyClip();
660 
661     // Change the ortho projection
662     glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
663     mOrthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
664 
665     return true;
666 }
667 
668 /**
669  * Read the documentation of createLayer() before doing anything in this method.
670  */
composeLayer(sp<Snapshot> current,sp<Snapshot> previous)671 void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
672     if (!current->layer) {
673         ALOGE("Attempting to compose a layer that does not exist");
674         return;
675     }
676 
677     const bool fboLayer = current->flags & Snapshot::kFlagIsFboLayer;
678 
679     if (fboLayer) {
680         // Detach the texture from the FBO
681         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
682 
683         // Unbind current FBO and restore previous one
684         glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);
685     }
686 
687     Layer* layer = current->layer;
688     const Rect& rect = layer->layer;
689 
690     if (!fboLayer && layer->getAlpha() < 255) {
691         drawColorRect(rect.left, rect.top, rect.right, rect.bottom,
692                 layer->getAlpha() << 24, SkXfermode::kDstIn_Mode, true);
693         // Required below, composeLayerRect() will divide by 255
694         layer->setAlpha(255);
695     }
696 
697     mCaches.unbindMeshBuffer();
698 
699     mCaches.activeTexture(0);
700 
701     // When the layer is stored in an FBO, we can save a bit of fillrate by
702     // drawing only the dirty region
703     if (fboLayer) {
704         dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *previous->transform);
705         if (layer->getColorFilter()) {
706             setupColorFilter(layer->getColorFilter());
707         }
708         composeLayerRegion(layer, rect);
709         if (layer->getColorFilter()) {
710             resetColorFilter();
711         }
712     } else if (!rect.isEmpty()) {
713         dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
714         composeLayerRect(layer, rect, true);
715     }
716 
717     if (fboLayer) {
718         // Note: No need to use glDiscardFramebufferEXT() since we never
719         //       create/compose layers that are not on screen with this
720         //       code path
721         // See LayerRenderer::destroyLayer(Layer*)
722 
723         // Put the FBO name back in the cache, if it doesn't fit, it will be destroyed
724         mCaches.fboCache.put(current->fbo);
725         layer->setFbo(0);
726     }
727 
728     dirtyClip();
729 
730     // Failing to add the layer to the cache should happen only if the layer is too large
731     if (!mCaches.layerCache.put(layer)) {
732         LAYER_LOGD("Deleting layer");
733         layer->deleteTexture();
734         delete layer;
735     }
736 }
737 
drawTextureLayer(Layer * layer,const Rect & rect)738 void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
739     float alpha = layer->getAlpha() / 255.0f;
740 
741     mat4& transform = layer->getTransform();
742     if (!transform.isIdentity()) {
743         save(0);
744         mSnapshot->transform->multiply(transform);
745     }
746 
747     setupDraw();
748     if (layer->getRenderTarget() == GL_TEXTURE_2D) {
749         setupDrawWithTexture();
750     } else {
751         setupDrawWithExternalTexture();
752     }
753     setupDrawTextureTransform();
754     setupDrawColor(alpha, alpha, alpha, alpha);
755     setupDrawColorFilter();
756     setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode());
757     setupDrawProgram();
758     setupDrawPureColorUniforms();
759     setupDrawColorFilterUniforms();
760     if (layer->getRenderTarget() == GL_TEXTURE_2D) {
761         setupDrawTexture(layer->getTexture());
762     } else {
763         setupDrawExternalTexture(layer->getTexture());
764     }
765     if (mSnapshot->transform->isPureTranslate() &&
766             layer->getWidth() == (uint32_t) rect.getWidth() &&
767             layer->getHeight() == (uint32_t) rect.getHeight()) {
768         const float x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f);
769         const float y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f);
770 
771         layer->setFilter(GL_NEAREST);
772         setupDrawModelView(x, y, x + rect.getWidth(), y + rect.getHeight(), true);
773     } else {
774         layer->setFilter(GL_LINEAR);
775         setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom);
776     }
777     setupDrawTextureTransformUniforms(layer->getTexTransform());
778     setupDrawMesh(&mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]);
779 
780     glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
781 
782     finishDrawTexture();
783 
784     if (!transform.isIdentity()) {
785         restore();
786     }
787 }
788 
composeLayerRect(Layer * layer,const Rect & rect,bool swap)789 void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
790     if (!layer->isTextureLayer()) {
791         const Rect& texCoords = layer->texCoords;
792         resetDrawTextureTexCoords(texCoords.left, texCoords.top,
793                 texCoords.right, texCoords.bottom);
794 
795         float x = rect.left;
796         float y = rect.top;
797         bool simpleTransform = mSnapshot->transform->isPureTranslate() &&
798                 layer->getWidth() == (uint32_t) rect.getWidth() &&
799                 layer->getHeight() == (uint32_t) rect.getHeight();
800 
801         if (simpleTransform) {
802             // When we're swapping, the layer is already in screen coordinates
803             if (!swap) {
804                 x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f);
805                 y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f);
806             }
807 
808             layer->setFilter(GL_NEAREST, true);
809         } else {
810             layer->setFilter(GL_LINEAR, true);
811         }
812 
813         drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
814                 layer->getTexture(), layer->getAlpha() / 255.0f,
815                 layer->getMode(), layer->isBlend(),
816                 &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
817                 GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform);
818 
819         resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
820     } else {
821         resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
822         drawTextureLayer(layer, rect);
823         resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
824     }
825 }
826 
composeLayerRegion(Layer * layer,const Rect & rect)827 void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
828 #if RENDER_LAYERS_AS_REGIONS
829     if (layer->region.isRect()) {
830         layer->setRegionAsRect();
831 
832         composeLayerRect(layer, layer->regionRect);
833 
834         layer->region.clear();
835         return;
836     }
837 
838     // TODO: See LayerRenderer.cpp::generateMesh() for important
839     //       information about this implementation
840     if (CC_LIKELY(!layer->region.isEmpty())) {
841         size_t count;
842         const android::Rect* rects = layer->region.getArray(&count);
843 
844         const float alpha = layer->getAlpha() / 255.0f;
845         const float texX = 1.0f / float(layer->getWidth());
846         const float texY = 1.0f / float(layer->getHeight());
847         const float height = rect.getHeight();
848 
849         TextureVertex* mesh = mCaches.getRegionMesh();
850         GLsizei numQuads = 0;
851 
852         setupDraw();
853         setupDrawWithTexture();
854         setupDrawColor(alpha, alpha, alpha, alpha);
855         setupDrawColorFilter();
856         setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode(), false);
857         setupDrawProgram();
858         setupDrawDirtyRegionsDisabled();
859         setupDrawPureColorUniforms();
860         setupDrawColorFilterUniforms();
861         setupDrawTexture(layer->getTexture());
862         if (mSnapshot->transform->isPureTranslate()) {
863             const float x = (int) floorf(rect.left + mSnapshot->transform->getTranslateX() + 0.5f);
864             const float y = (int) floorf(rect.top + mSnapshot->transform->getTranslateY() + 0.5f);
865 
866             layer->setFilter(GL_NEAREST);
867             setupDrawModelViewTranslate(x, y, x + rect.getWidth(), y + rect.getHeight(), true);
868         } else {
869             layer->setFilter(GL_LINEAR);
870             setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom);
871         }
872         setupDrawMeshIndices(&mesh[0].position[0], &mesh[0].texture[0]);
873 
874         for (size_t i = 0; i < count; i++) {
875             const android::Rect* r = &rects[i];
876 
877             const float u1 = r->left * texX;
878             const float v1 = (height - r->top) * texY;
879             const float u2 = r->right * texX;
880             const float v2 = (height - r->bottom) * texY;
881 
882             // TODO: Reject quads outside of the clip
883             TextureVertex::set(mesh++, r->left, r->top, u1, v1);
884             TextureVertex::set(mesh++, r->right, r->top, u2, v1);
885             TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
886             TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
887 
888             numQuads++;
889 
890             if (numQuads >= REGION_MESH_QUAD_COUNT) {
891                 glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, NULL);
892                 numQuads = 0;
893                 mesh = mCaches.getRegionMesh();
894             }
895         }
896 
897         if (numQuads > 0) {
898             glDrawElements(GL_TRIANGLES, numQuads * 6, GL_UNSIGNED_SHORT, NULL);
899         }
900 
901         finishDrawTexture();
902 
903 #if DEBUG_LAYERS_AS_REGIONS
904         drawRegionRects(layer->region);
905 #endif
906 
907         layer->region.clear();
908     }
909 #else
910     composeLayerRect(layer, rect);
911 #endif
912 }
913 
drawRegionRects(const Region & region)914 void OpenGLRenderer::drawRegionRects(const Region& region) {
915 #if DEBUG_LAYERS_AS_REGIONS
916     size_t count;
917     const android::Rect* rects = region.getArray(&count);
918 
919     uint32_t colors[] = {
920             0x7fff0000, 0x7f00ff00,
921             0x7f0000ff, 0x7fff00ff,
922     };
923 
924     int offset = 0;
925     int32_t top = rects[0].top;
926 
927     for (size_t i = 0; i < count; i++) {
928         if (top != rects[i].top) {
929             offset ^= 0x2;
930             top = rects[i].top;
931         }
932 
933         Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom);
934         drawColorRect(r.left, r.top, r.right, r.bottom, colors[offset + (i & 0x1)],
935                 SkXfermode::kSrcOver_Mode);
936     }
937 #endif
938 }
939 
dirtyLayer(const float left,const float top,const float right,const float bottom,const mat4 transform)940 void OpenGLRenderer::dirtyLayer(const float left, const float top,
941         const float right, const float bottom, const mat4 transform) {
942 #if RENDER_LAYERS_AS_REGIONS
943     if (hasLayer()) {
944         Rect bounds(left, top, right, bottom);
945         transform.mapRect(bounds);
946         dirtyLayerUnchecked(bounds, getRegion());
947     }
948 #endif
949 }
950 
dirtyLayer(const float left,const float top,const float right,const float bottom)951 void OpenGLRenderer::dirtyLayer(const float left, const float top,
952         const float right, const float bottom) {
953 #if RENDER_LAYERS_AS_REGIONS
954     if (hasLayer()) {
955         Rect bounds(left, top, right, bottom);
956         dirtyLayerUnchecked(bounds, getRegion());
957     }
958 #endif
959 }
960 
dirtyLayerUnchecked(Rect & bounds,Region * region)961 void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) {
962 #if RENDER_LAYERS_AS_REGIONS
963     if (bounds.intersect(*mSnapshot->clipRect)) {
964         bounds.snapToPixelBoundaries();
965         android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
966         if (!dirty.isEmpty()) {
967             region->orSelf(dirty);
968         }
969     }
970 #endif
971 }
972 
clearLayerRegions()973 void OpenGLRenderer::clearLayerRegions() {
974     const size_t count = mLayers.size();
975     if (count == 0) return;
976 
977     if (!mSnapshot->isIgnored()) {
978         // Doing several glScissor/glClear here can negatively impact
979         // GPUs with a tiler architecture, instead we draw quads with
980         // the Clear blending mode
981 
982         // The list contains bounds that have already been clipped
983         // against their initial clip rect, and the current clip
984         // is likely different so we need to disable clipping here
985         glDisable(GL_SCISSOR_TEST);
986 
987         Vertex mesh[count * 6];
988         Vertex* vertex = mesh;
989 
990         for (uint32_t i = 0; i < count; i++) {
991             Rect* bounds = mLayers.itemAt(i);
992 
993             Vertex::set(vertex++, bounds->left, bounds->bottom);
994             Vertex::set(vertex++, bounds->left, bounds->top);
995             Vertex::set(vertex++, bounds->right, bounds->top);
996             Vertex::set(vertex++, bounds->left, bounds->bottom);
997             Vertex::set(vertex++, bounds->right, bounds->top);
998             Vertex::set(vertex++, bounds->right, bounds->bottom);
999 
1000             delete bounds;
1001         }
1002 
1003         setupDraw(false);
1004         setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f);
1005         setupDrawBlending(true, SkXfermode::kClear_Mode);
1006         setupDrawProgram();
1007         setupDrawPureColorUniforms();
1008         setupDrawModelViewTranslate(0.0f, 0.0f, 0.0f, 0.0f, true);
1009         setupDrawVertices(&mesh[0].position[0]);
1010 
1011         glDrawArrays(GL_TRIANGLES, 0, count * 6);
1012 
1013         glEnable(GL_SCISSOR_TEST);
1014     } else {
1015         for (uint32_t i = 0; i < count; i++) {
1016             delete mLayers.itemAt(i);
1017         }
1018     }
1019 
1020     mLayers.clear();
1021 }
1022 
1023 ///////////////////////////////////////////////////////////////////////////////
1024 // Transforms
1025 ///////////////////////////////////////////////////////////////////////////////
1026 
translate(float dx,float dy)1027 void OpenGLRenderer::translate(float dx, float dy) {
1028     mSnapshot->transform->translate(dx, dy, 0.0f);
1029 }
1030 
rotate(float degrees)1031 void OpenGLRenderer::rotate(float degrees) {
1032     mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f);
1033 }
1034 
scale(float sx,float sy)1035 void OpenGLRenderer::scale(float sx, float sy) {
1036     mSnapshot->transform->scale(sx, sy, 1.0f);
1037 }
1038 
skew(float sx,float sy)1039 void OpenGLRenderer::skew(float sx, float sy) {
1040     mSnapshot->transform->skew(sx, sy);
1041 }
1042 
setMatrix(SkMatrix * matrix)1043 void OpenGLRenderer::setMatrix(SkMatrix* matrix) {
1044     if (matrix) {
1045         mSnapshot->transform->load(*matrix);
1046     } else {
1047         mSnapshot->transform->loadIdentity();
1048     }
1049 }
1050 
getMatrix(SkMatrix * matrix)1051 void OpenGLRenderer::getMatrix(SkMatrix* matrix) {
1052     mSnapshot->transform->copyTo(*matrix);
1053 }
1054 
concatMatrix(SkMatrix * matrix)1055 void OpenGLRenderer::concatMatrix(SkMatrix* matrix) {
1056     SkMatrix transform;
1057     mSnapshot->transform->copyTo(transform);
1058     transform.preConcat(*matrix);
1059     mSnapshot->transform->load(transform);
1060 }
1061 
1062 ///////////////////////////////////////////////////////////////////////////////
1063 // Clipping
1064 ///////////////////////////////////////////////////////////////////////////////
1065 
setScissorFromClip()1066 void OpenGLRenderer::setScissorFromClip() {
1067     Rect clip(*mSnapshot->clipRect);
1068     clip.snapToPixelBoundaries();
1069 
1070     mCaches.setScissor(clip.left, mSnapshot->height - clip.bottom,
1071             clip.getWidth(), clip.getHeight());
1072 
1073     mDirtyClip = false;
1074 }
1075 
getClipBounds()1076 const Rect& OpenGLRenderer::getClipBounds() {
1077     return mSnapshot->getLocalClip();
1078 }
1079 
quickReject(float left,float top,float right,float bottom)1080 bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) {
1081     if (mSnapshot->isIgnored()) {
1082         return true;
1083     }
1084 
1085     Rect r(left, top, right, bottom);
1086     mSnapshot->transform->mapRect(r);
1087     r.snapToPixelBoundaries();
1088 
1089     Rect clipRect(*mSnapshot->clipRect);
1090     clipRect.snapToPixelBoundaries();
1091 
1092     return !clipRect.intersects(r);
1093 }
1094 
clipRect(float left,float top,float right,float bottom,SkRegion::Op op)1095 bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
1096     bool clipped = mSnapshot->clip(left, top, right, bottom, op);
1097     if (clipped) {
1098         dirtyClip();
1099     }
1100     return !mSnapshot->clipRect->isEmpty();
1101 }
1102 
getClipRect()1103 Rect* OpenGLRenderer::getClipRect() {
1104     return mSnapshot->clipRect;
1105 }
1106 
1107 ///////////////////////////////////////////////////////////////////////////////
1108 // Drawing commands
1109 ///////////////////////////////////////////////////////////////////////////////
1110 
setupDraw(bool clear)1111 void OpenGLRenderer::setupDraw(bool clear) {
1112     if (clear) clearLayerRegions();
1113     if (mDirtyClip) {
1114         setScissorFromClip();
1115     }
1116     mDescription.reset();
1117     mSetShaderColor = false;
1118     mColorSet = false;
1119     mColorA = mColorR = mColorG = mColorB = 0.0f;
1120     mTextureUnit = 0;
1121     mTrackDirtyRegions = true;
1122 }
1123 
setupDrawWithTexture(bool isAlpha8)1124 void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
1125     mDescription.hasTexture = true;
1126     mDescription.hasAlpha8Texture = isAlpha8;
1127 }
1128 
setupDrawWithExternalTexture()1129 void OpenGLRenderer::setupDrawWithExternalTexture() {
1130     mDescription.hasExternalTexture = true;
1131 }
1132 
setupDrawNoTexture()1133 void OpenGLRenderer::setupDrawNoTexture() {
1134     mCaches.disbaleTexCoordsVertexArray();
1135 }
1136 
setupDrawAALine()1137 void OpenGLRenderer::setupDrawAALine() {
1138     mDescription.isAA = true;
1139 }
1140 
setupDrawPoint(float pointSize)1141 void OpenGLRenderer::setupDrawPoint(float pointSize) {
1142     mDescription.isPoint = true;
1143     mDescription.pointSize = pointSize;
1144 }
1145 
setupDrawColor(int color)1146 void OpenGLRenderer::setupDrawColor(int color) {
1147     setupDrawColor(color, (color >> 24) & 0xFF);
1148 }
1149 
setupDrawColor(int color,int alpha)1150 void OpenGLRenderer::setupDrawColor(int color, int alpha) {
1151     mColorA = alpha / 255.0f;
1152     mColorA *= mSnapshot->alpha;
1153     // Second divide of a by 255 is an optimization, allowing us to simply multiply
1154     // the rgb values by a instead of also dividing by 255
1155     const float a = mColorA / 255.0f;
1156     mColorR = a * ((color >> 16) & 0xFF);
1157     mColorG = a * ((color >>  8) & 0xFF);
1158     mColorB = a * ((color      ) & 0xFF);
1159     mColorSet = true;
1160     mSetShaderColor = mDescription.setColor(mColorR, mColorG, mColorB, mColorA);
1161 }
1162 
setupDrawAlpha8Color(int color,int alpha)1163 void OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) {
1164     mColorA = alpha / 255.0f;
1165     // Double-divide of a by 255 is an optimization, allowing us to simply multiply
1166     // the rgb values by a instead of also dividing by 255
1167     const float a = mColorA / 255.0f;
1168     mColorR = a * ((color >> 16) & 0xFF);
1169     mColorG = a * ((color >>  8) & 0xFF);
1170     mColorB = a * ((color      ) & 0xFF);
1171     mColorSet = true;
1172     mSetShaderColor = mDescription.setAlpha8Color(mColorR, mColorG, mColorB, mColorA);
1173 }
1174 
setupDrawColor(float r,float g,float b,float a)1175 void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) {
1176     mColorA = a;
1177     mColorR = r;
1178     mColorG = g;
1179     mColorB = b;
1180     mColorSet = true;
1181     mSetShaderColor = mDescription.setColor(r, g, b, a);
1182 }
1183 
setupDrawAlpha8Color(float r,float g,float b,float a)1184 void OpenGLRenderer::setupDrawAlpha8Color(float r, float g, float b, float a) {
1185     mColorA = a;
1186     mColorR = r;
1187     mColorG = g;
1188     mColorB = b;
1189     mColorSet = true;
1190     mSetShaderColor = mDescription.setAlpha8Color(r, g, b, a);
1191 }
1192 
setupDrawShader()1193 void OpenGLRenderer::setupDrawShader() {
1194     if (mShader) {
1195         mShader->describe(mDescription, mCaches.extensions);
1196     }
1197 }
1198 
setupDrawColorFilter()1199 void OpenGLRenderer::setupDrawColorFilter() {
1200     if (mColorFilter) {
1201         mColorFilter->describe(mDescription, mCaches.extensions);
1202     }
1203 }
1204 
accountForClear(SkXfermode::Mode mode)1205 void OpenGLRenderer::accountForClear(SkXfermode::Mode mode) {
1206     if (mColorSet && mode == SkXfermode::kClear_Mode) {
1207         mColorA = 1.0f;
1208         mColorR = mColorG = mColorB = 0.0f;
1209         mSetShaderColor = mDescription.modulate = true;
1210     }
1211 }
1212 
setupDrawBlending(SkXfermode::Mode mode,bool swapSrcDst)1213 void OpenGLRenderer::setupDrawBlending(SkXfermode::Mode mode, bool swapSrcDst) {
1214     // When the blending mode is kClear_Mode, we need to use a modulate color
1215     // argb=1,0,0,0
1216     accountForClear(mode);
1217     chooseBlending((mColorSet && mColorA < 1.0f) || (mShader && mShader->blend()), mode,
1218             mDescription, swapSrcDst);
1219 }
1220 
setupDrawBlending(bool blend,SkXfermode::Mode mode,bool swapSrcDst)1221 void OpenGLRenderer::setupDrawBlending(bool blend, SkXfermode::Mode mode, bool swapSrcDst) {
1222     // When the blending mode is kClear_Mode, we need to use a modulate color
1223     // argb=1,0,0,0
1224     accountForClear(mode);
1225     chooseBlending(blend || (mColorSet && mColorA < 1.0f) || (mShader && mShader->blend()), mode,
1226             mDescription, swapSrcDst);
1227 }
1228 
setupDrawProgram()1229 void OpenGLRenderer::setupDrawProgram() {
1230     useProgram(mCaches.programCache.get(mDescription));
1231 }
1232 
setupDrawDirtyRegionsDisabled()1233 void OpenGLRenderer::setupDrawDirtyRegionsDisabled() {
1234     mTrackDirtyRegions = false;
1235 }
1236 
setupDrawModelViewTranslate(float left,float top,float right,float bottom,bool ignoreTransform)1237 void OpenGLRenderer::setupDrawModelViewTranslate(float left, float top, float right, float bottom,
1238         bool ignoreTransform) {
1239     mModelView.loadTranslate(left, top, 0.0f);
1240     if (!ignoreTransform) {
1241         mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
1242         if (mTrackDirtyRegions) dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
1243     } else {
1244         mCaches.currentProgram->set(mOrthoMatrix, mModelView, mIdentity);
1245         if (mTrackDirtyRegions) dirtyLayer(left, top, right, bottom);
1246     }
1247 }
1248 
setupDrawModelViewIdentity(bool offset)1249 void OpenGLRenderer::setupDrawModelViewIdentity(bool offset) {
1250     mCaches.currentProgram->set(mOrthoMatrix, mIdentity, *mSnapshot->transform, offset);
1251 }
1252 
setupDrawModelView(float left,float top,float right,float bottom,bool ignoreTransform,bool ignoreModelView)1253 void OpenGLRenderer::setupDrawModelView(float left, float top, float right, float bottom,
1254         bool ignoreTransform, bool ignoreModelView) {
1255     if (!ignoreModelView) {
1256         mModelView.loadTranslate(left, top, 0.0f);
1257         mModelView.scale(right - left, bottom - top, 1.0f);
1258     } else {
1259         mModelView.loadIdentity();
1260     }
1261     bool dirty = right - left > 0.0f && bottom - top > 0.0f;
1262     if (!ignoreTransform) {
1263         mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
1264         if (mTrackDirtyRegions && dirty) {
1265             dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
1266         }
1267     } else {
1268         mCaches.currentProgram->set(mOrthoMatrix, mModelView, mIdentity);
1269         if (mTrackDirtyRegions && dirty) dirtyLayer(left, top, right, bottom);
1270     }
1271 }
1272 
setupDrawPointUniforms()1273 void OpenGLRenderer::setupDrawPointUniforms() {
1274     int slot = mCaches.currentProgram->getUniform("pointSize");
1275     glUniform1f(slot, mDescription.pointSize);
1276 }
1277 
setupDrawColorUniforms()1278 void OpenGLRenderer::setupDrawColorUniforms() {
1279     if ((mColorSet && !mShader) || (mShader && mSetShaderColor)) {
1280         mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
1281     }
1282 }
1283 
setupDrawPureColorUniforms()1284 void OpenGLRenderer::setupDrawPureColorUniforms() {
1285     if (mSetShaderColor) {
1286         mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
1287     }
1288 }
1289 
setupDrawShaderUniforms(bool ignoreTransform)1290 void OpenGLRenderer::setupDrawShaderUniforms(bool ignoreTransform) {
1291     if (mShader) {
1292         if (ignoreTransform) {
1293             mModelView.loadInverse(*mSnapshot->transform);
1294         }
1295         mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &mTextureUnit);
1296     }
1297 }
1298 
setupDrawShaderIdentityUniforms()1299 void OpenGLRenderer::setupDrawShaderIdentityUniforms() {
1300     if (mShader) {
1301         mShader->setupProgram(mCaches.currentProgram, mIdentity, *mSnapshot, &mTextureUnit);
1302     }
1303 }
1304 
setupDrawColorFilterUniforms()1305 void OpenGLRenderer::setupDrawColorFilterUniforms() {
1306     if (mColorFilter) {
1307         mColorFilter->setupProgram(mCaches.currentProgram);
1308     }
1309 }
1310 
setupDrawSimpleMesh()1311 void OpenGLRenderer::setupDrawSimpleMesh() {
1312     bool force = mCaches.bindMeshBuffer();
1313     mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, 0);
1314     mCaches.unbindIndicesBuffer();
1315 }
1316 
setupDrawTexture(GLuint texture)1317 void OpenGLRenderer::setupDrawTexture(GLuint texture) {
1318     bindTexture(texture);
1319     mTextureUnit++;
1320     mCaches.enableTexCoordsVertexArray();
1321 }
1322 
setupDrawExternalTexture(GLuint texture)1323 void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) {
1324     bindExternalTexture(texture);
1325     mTextureUnit++;
1326     mCaches.enableTexCoordsVertexArray();
1327 }
1328 
setupDrawTextureTransform()1329 void OpenGLRenderer::setupDrawTextureTransform() {
1330     mDescription.hasTextureTransform = true;
1331 }
1332 
setupDrawTextureTransformUniforms(mat4 & transform)1333 void OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) {
1334     glUniformMatrix4fv(mCaches.currentProgram->getUniform("mainTextureTransform"), 1,
1335             GL_FALSE, &transform.data[0]);
1336 }
1337 
setupDrawMesh(GLvoid * vertices,GLvoid * texCoords,GLuint vbo)1338 void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLuint vbo) {
1339     bool force = false;
1340     if (!vertices) {
1341         force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
1342     } else {
1343         force = mCaches.unbindMeshBuffer();
1344     }
1345 
1346     mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, vertices);
1347     if (mCaches.currentProgram->texCoords >= 0) {
1348         mCaches.bindTexCoordsVertexPointer(force, mCaches.currentProgram->texCoords, texCoords);
1349     }
1350 
1351     mCaches.unbindIndicesBuffer();
1352 }
1353 
setupDrawMeshIndices(GLvoid * vertices,GLvoid * texCoords)1354 void OpenGLRenderer::setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords) {
1355     bool force = mCaches.unbindMeshBuffer();
1356     mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position, vertices);
1357     if (mCaches.currentProgram->texCoords >= 0) {
1358         mCaches.bindTexCoordsVertexPointer(force, mCaches.currentProgram->texCoords, texCoords);
1359     }
1360 }
1361 
setupDrawVertices(GLvoid * vertices)1362 void OpenGLRenderer::setupDrawVertices(GLvoid* vertices) {
1363     bool force = mCaches.unbindMeshBuffer();
1364     mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position,
1365             vertices, gVertexStride);
1366     mCaches.unbindIndicesBuffer();
1367 }
1368 
1369 /**
1370  * Sets up the shader to draw an AA line. We draw AA lines with quads, where there is an
1371  * outer boundary that fades out to 0. The variables set in the shader define the proportion of
1372  * the width and length of the primitive occupied by the AA region. The vtxWidth and vtxLength
1373  * attributes (one per vertex) are values from zero to one that tells the fragment
1374  * shader where the fragment is in relation to the line width/length overall; these values are
1375  * then used to compute the proper color, based on whether the fragment lies in the fading AA
1376  * region of the line.
1377  * Note that we only pass down the width values in this setup function. The length coordinates
1378  * are set up for each individual segment.
1379  */
setupDrawAALine(GLvoid * vertices,GLvoid * widthCoords,GLvoid * lengthCoords,float boundaryWidthProportion,int & widthSlot,int & lengthSlot)1380 void OpenGLRenderer::setupDrawAALine(GLvoid* vertices, GLvoid* widthCoords,
1381         GLvoid* lengthCoords, float boundaryWidthProportion, int& widthSlot, int& lengthSlot) {
1382     bool force = mCaches.unbindMeshBuffer();
1383     mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position,
1384             vertices, gAAVertexStride);
1385     mCaches.resetTexCoordsVertexPointer();
1386     mCaches.unbindIndicesBuffer();
1387 
1388     widthSlot = mCaches.currentProgram->getAttrib("vtxWidth");
1389     glEnableVertexAttribArray(widthSlot);
1390     glVertexAttribPointer(widthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, widthCoords);
1391 
1392     lengthSlot = mCaches.currentProgram->getAttrib("vtxLength");
1393     glEnableVertexAttribArray(lengthSlot);
1394     glVertexAttribPointer(lengthSlot, 1, GL_FLOAT, GL_FALSE, gAAVertexStride, lengthCoords);
1395 
1396     int boundaryWidthSlot = mCaches.currentProgram->getUniform("boundaryWidth");
1397     glUniform1f(boundaryWidthSlot, boundaryWidthProportion);
1398 
1399     // Setting the inverse value saves computations per-fragment in the shader
1400     int inverseBoundaryWidthSlot = mCaches.currentProgram->getUniform("inverseBoundaryWidth");
1401     glUniform1f(inverseBoundaryWidthSlot, 1.0f / boundaryWidthProportion);
1402 }
1403 
finishDrawAALine(const int widthSlot,const int lengthSlot)1404 void OpenGLRenderer::finishDrawAALine(const int widthSlot, const int lengthSlot) {
1405     glDisableVertexAttribArray(widthSlot);
1406     glDisableVertexAttribArray(lengthSlot);
1407 }
1408 
finishDrawTexture()1409 void OpenGLRenderer::finishDrawTexture() {
1410 }
1411 
1412 ///////////////////////////////////////////////////////////////////////////////
1413 // Drawing
1414 ///////////////////////////////////////////////////////////////////////////////
1415 
drawDisplayList(DisplayList * displayList,Rect & dirty,int32_t flags,uint32_t level)1416 status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList,
1417         Rect& dirty, int32_t flags, uint32_t level) {
1418 
1419     // All the usual checks and setup operations (quickReject, setupDraw, etc.)
1420     // will be performed by the display list itself
1421     if (displayList && displayList->isRenderable()) {
1422         return displayList->replay(*this, dirty, flags, level);
1423     }
1424 
1425     return DrawGlInfo::kStatusDone;
1426 }
1427 
outputDisplayList(DisplayList * displayList,uint32_t level)1428 void OpenGLRenderer::outputDisplayList(DisplayList* displayList, uint32_t level) {
1429     if (displayList) {
1430         displayList->output(*this, level);
1431     }
1432 }
1433 
drawAlphaBitmap(Texture * texture,float left,float top,SkPaint * paint)1434 void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint) {
1435     int alpha;
1436     SkXfermode::Mode mode;
1437     getAlphaAndMode(paint, &alpha, &mode);
1438 
1439     float x = left;
1440     float y = top;
1441 
1442     GLenum filter = GL_LINEAR;
1443     bool ignoreTransform = false;
1444     if (mSnapshot->transform->isPureTranslate()) {
1445         x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f);
1446         y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f);
1447         ignoreTransform = true;
1448         filter = GL_NEAREST;
1449     } else {
1450         filter = FILTER(paint);
1451     }
1452 
1453     setupDraw();
1454     setupDrawWithTexture(true);
1455     if (paint) {
1456         setupDrawAlpha8Color(paint->getColor(), alpha);
1457     }
1458     setupDrawColorFilter();
1459     setupDrawShader();
1460     setupDrawBlending(true, mode);
1461     setupDrawProgram();
1462     setupDrawModelView(x, y, x + texture->width, y + texture->height, ignoreTransform);
1463 
1464     setupDrawTexture(texture->id);
1465     texture->setWrap(GL_CLAMP_TO_EDGE);
1466     texture->setFilter(filter);
1467 
1468     setupDrawPureColorUniforms();
1469     setupDrawColorFilterUniforms();
1470     setupDrawShaderUniforms();
1471     setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
1472 
1473     glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
1474 
1475     finishDrawTexture();
1476 }
1477 
drawBitmap(SkBitmap * bitmap,float left,float top,SkPaint * paint)1478 status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
1479     const float right = left + bitmap->width();
1480     const float bottom = top + bitmap->height();
1481 
1482     if (quickReject(left, top, right, bottom)) {
1483         return DrawGlInfo::kStatusDone;
1484     }
1485 
1486     mCaches.activeTexture(0);
1487     Texture* texture = mCaches.textureCache.get(bitmap);
1488     if (!texture) return DrawGlInfo::kStatusDone;
1489     const AutoTexture autoCleanup(texture);
1490 
1491     if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) {
1492         drawAlphaBitmap(texture, left, top, paint);
1493     } else {
1494         drawTextureRect(left, top, right, bottom, texture, paint);
1495     }
1496 
1497     return DrawGlInfo::kStatusDrew;
1498 }
1499 
drawBitmap(SkBitmap * bitmap,SkMatrix * matrix,SkPaint * paint)1500 status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint) {
1501     Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height());
1502     const mat4 transform(*matrix);
1503     transform.mapRect(r);
1504 
1505     if (quickReject(r.left, r.top, r.right, r.bottom)) {
1506         return DrawGlInfo::kStatusDone;
1507     }
1508 
1509     mCaches.activeTexture(0);
1510     Texture* texture = mCaches.textureCache.get(bitmap);
1511     if (!texture) return DrawGlInfo::kStatusDone;
1512     const AutoTexture autoCleanup(texture);
1513 
1514     // This could be done in a cheaper way, all we need is pass the matrix
1515     // to the vertex shader. The save/restore is a bit overkill.
1516     save(SkCanvas::kMatrix_SaveFlag);
1517     concatMatrix(matrix);
1518     drawTextureRect(0.0f, 0.0f, bitmap->width(), bitmap->height(), texture, paint);
1519     restore();
1520 
1521     return DrawGlInfo::kStatusDrew;
1522 }
1523 
drawBitmapData(SkBitmap * bitmap,float left,float top,SkPaint * paint)1524 status_t OpenGLRenderer::drawBitmapData(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
1525     const float right = left + bitmap->width();
1526     const float bottom = top + bitmap->height();
1527 
1528     if (quickReject(left, top, right, bottom)) {
1529         return DrawGlInfo::kStatusDone;
1530     }
1531 
1532     mCaches.activeTexture(0);
1533     Texture* texture = mCaches.textureCache.getTransient(bitmap);
1534     const AutoTexture autoCleanup(texture);
1535 
1536     drawTextureRect(left, top, right, bottom, texture, paint);
1537 
1538     return DrawGlInfo::kStatusDrew;
1539 }
1540 
drawBitmapMesh(SkBitmap * bitmap,int meshWidth,int meshHeight,float * vertices,int * colors,SkPaint * paint)1541 status_t OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
1542         float* vertices, int* colors, SkPaint* paint) {
1543     // TODO: Do a quickReject
1544     if (!vertices || mSnapshot->isIgnored()) {
1545         return DrawGlInfo::kStatusDone;
1546     }
1547 
1548     mCaches.activeTexture(0);
1549     Texture* texture = mCaches.textureCache.get(bitmap);
1550     if (!texture) return DrawGlInfo::kStatusDone;
1551     const AutoTexture autoCleanup(texture);
1552 
1553     texture->setWrap(GL_CLAMP_TO_EDGE, true);
1554     texture->setFilter(FILTER(paint), true);
1555 
1556     int alpha;
1557     SkXfermode::Mode mode;
1558     getAlphaAndMode(paint, &alpha, &mode);
1559 
1560     const uint32_t count = meshWidth * meshHeight * 6;
1561 
1562     float left = FLT_MAX;
1563     float top = FLT_MAX;
1564     float right = FLT_MIN;
1565     float bottom = FLT_MIN;
1566 
1567 #if RENDER_LAYERS_AS_REGIONS
1568     const bool hasActiveLayer = hasLayer();
1569 #else
1570     const bool hasActiveLayer = false;
1571 #endif
1572 
1573     // TODO: Support the colors array
1574     TextureVertex mesh[count];
1575     TextureVertex* vertex = mesh;
1576     for (int32_t y = 0; y < meshHeight; y++) {
1577         for (int32_t x = 0; x < meshWidth; x++) {
1578             uint32_t i = (y * (meshWidth + 1) + x) * 2;
1579 
1580             float u1 = float(x) / meshWidth;
1581             float u2 = float(x + 1) / meshWidth;
1582             float v1 = float(y) / meshHeight;
1583             float v2 = float(y + 1) / meshHeight;
1584 
1585             int ax = i + (meshWidth + 1) * 2;
1586             int ay = ax + 1;
1587             int bx = i;
1588             int by = bx + 1;
1589             int cx = i + 2;
1590             int cy = cx + 1;
1591             int dx = i + (meshWidth + 1) * 2 + 2;
1592             int dy = dx + 1;
1593 
1594             TextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2);
1595             TextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1);
1596             TextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1);
1597 
1598             TextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2);
1599             TextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1);
1600             TextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2);
1601 
1602 #if RENDER_LAYERS_AS_REGIONS
1603             if (hasActiveLayer) {
1604                 // TODO: This could be optimized to avoid unnecessary ops
1605                 left = fminf(left, fminf(vertices[ax], fminf(vertices[bx], vertices[cx])));
1606                 top = fminf(top, fminf(vertices[ay], fminf(vertices[by], vertices[cy])));
1607                 right = fmaxf(right, fmaxf(vertices[ax], fmaxf(vertices[bx], vertices[cx])));
1608                 bottom = fmaxf(bottom, fmaxf(vertices[ay], fmaxf(vertices[by], vertices[cy])));
1609             }
1610 #endif
1611         }
1612     }
1613 
1614 #if RENDER_LAYERS_AS_REGIONS
1615     if (hasActiveLayer) {
1616         dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
1617     }
1618 #endif
1619 
1620     drawTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, alpha / 255.0f,
1621             mode, texture->blend, &mesh[0].position[0], &mesh[0].texture[0],
1622             GL_TRIANGLES, count, false, false, 0, false, false);
1623 
1624     return DrawGlInfo::kStatusDrew;
1625 }
1626 
drawBitmap(SkBitmap * bitmap,float srcLeft,float srcTop,float srcRight,float srcBottom,float dstLeft,float dstTop,float dstRight,float dstBottom,SkPaint * paint)1627 status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
1628          float srcLeft, float srcTop, float srcRight, float srcBottom,
1629          float dstLeft, float dstTop, float dstRight, float dstBottom,
1630          SkPaint* paint) {
1631     if (quickReject(dstLeft, dstTop, dstRight, dstBottom)) {
1632         return DrawGlInfo::kStatusDone;
1633     }
1634 
1635     mCaches.activeTexture(0);
1636     Texture* texture = mCaches.textureCache.get(bitmap);
1637     if (!texture) return DrawGlInfo::kStatusDone;
1638     const AutoTexture autoCleanup(texture);
1639 
1640     const float width = texture->width;
1641     const float height = texture->height;
1642 
1643     const float u1 = fmax(0.0f, srcLeft / width);
1644     const float v1 = fmax(0.0f, srcTop / height);
1645     const float u2 = fmin(1.0f, srcRight / width);
1646     const float v2 = fmin(1.0f, srcBottom / height);
1647 
1648     mCaches.unbindMeshBuffer();
1649     resetDrawTextureTexCoords(u1, v1, u2, v2);
1650 
1651     int alpha;
1652     SkXfermode::Mode mode;
1653     getAlphaAndMode(paint, &alpha, &mode);
1654 
1655     texture->setWrap(GL_CLAMP_TO_EDGE, true);
1656 
1657     if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) {
1658         const float x = (int) floorf(dstLeft + mSnapshot->transform->getTranslateX() + 0.5f);
1659         const float y = (int) floorf(dstTop + mSnapshot->transform->getTranslateY() + 0.5f);
1660 
1661         GLenum filter = GL_NEAREST;
1662         // Enable linear filtering if the source rectangle is scaled
1663         if (srcRight - srcLeft != dstRight - dstLeft || srcBottom - srcTop != dstBottom - dstTop) {
1664             filter = FILTER(paint);
1665         }
1666 
1667         texture->setFilter(filter, true);
1668         drawTextureMesh(x, y, x + (dstRight - dstLeft), y + (dstBottom - dstTop),
1669                 texture->id, alpha / 255.0f, mode, texture->blend,
1670                 &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
1671                 GL_TRIANGLE_STRIP, gMeshCount, false, true);
1672     } else {
1673         texture->setFilter(FILTER(paint), true);
1674         drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom, texture->id, alpha / 255.0f,
1675                 mode, texture->blend, &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
1676                 GL_TRIANGLE_STRIP, gMeshCount);
1677     }
1678 
1679     resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
1680 
1681     return DrawGlInfo::kStatusDrew;
1682 }
1683 
drawPatch(SkBitmap * bitmap,const int32_t * xDivs,const int32_t * yDivs,const uint32_t * colors,uint32_t width,uint32_t height,int8_t numColors,float left,float top,float right,float bottom,SkPaint * paint)1684 status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
1685         const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
1686         float left, float top, float right, float bottom, SkPaint* paint) {
1687     if (quickReject(left, top, right, bottom)) {
1688         return DrawGlInfo::kStatusDone;
1689     }
1690 
1691     mCaches.activeTexture(0);
1692     Texture* texture = mCaches.textureCache.get(bitmap);
1693     if (!texture) return DrawGlInfo::kStatusDone;
1694     const AutoTexture autoCleanup(texture);
1695     texture->setWrap(GL_CLAMP_TO_EDGE, true);
1696     texture->setFilter(GL_LINEAR, true);
1697 
1698     int alpha;
1699     SkXfermode::Mode mode;
1700     getAlphaAndMode(paint, &alpha, &mode);
1701 
1702     const Patch* mesh = mCaches.patchCache.get(bitmap->width(), bitmap->height(),
1703             right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors);
1704 
1705     if (CC_LIKELY(mesh && mesh->verticesCount > 0)) {
1706         const bool pureTranslate = mSnapshot->transform->isPureTranslate();
1707 #if RENDER_LAYERS_AS_REGIONS
1708         // Mark the current layer dirty where we are going to draw the patch
1709         if (hasLayer() && mesh->hasEmptyQuads) {
1710             const float offsetX = left + mSnapshot->transform->getTranslateX();
1711             const float offsetY = top + mSnapshot->transform->getTranslateY();
1712             const size_t count = mesh->quads.size();
1713             for (size_t i = 0; i < count; i++) {
1714                 const Rect& bounds = mesh->quads.itemAt(i);
1715                 if (CC_LIKELY(pureTranslate)) {
1716                     const float x = (int) floorf(bounds.left + offsetX + 0.5f);
1717                     const float y = (int) floorf(bounds.top + offsetY + 0.5f);
1718                     dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight());
1719                 } else {
1720                     dirtyLayer(left + bounds.left, top + bounds.top,
1721                             left + bounds.right, top + bounds.bottom, *mSnapshot->transform);
1722                 }
1723             }
1724         }
1725 #endif
1726 
1727         if (CC_LIKELY(pureTranslate)) {
1728             const float x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f);
1729             const float y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f);
1730 
1731             drawTextureMesh(x, y, x + right - left, y + bottom - top, texture->id, alpha / 255.0f,
1732                     mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset,
1733                     GL_TRIANGLES, mesh->verticesCount, false, true, mesh->meshBuffer,
1734                     true, !mesh->hasEmptyQuads);
1735         } else {
1736             drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f,
1737                     mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset,
1738                     GL_TRIANGLES, mesh->verticesCount, false, false, mesh->meshBuffer,
1739                     true, !mesh->hasEmptyQuads);
1740         }
1741     }
1742 
1743     return DrawGlInfo::kStatusDrew;
1744 }
1745 
1746 /**
1747  * This function uses a similar approach to that of AA lines in the drawLines() function.
1748  * We expand the rectangle by a half pixel in screen space on all sides, and use a fragment
1749  * shader to compute the translucency of the color, determined by whether a given pixel is
1750  * within that boundary region and how far into the region it is.
1751  */
drawAARect(float left,float top,float right,float bottom,int color,SkXfermode::Mode mode)1752 void OpenGLRenderer::drawAARect(float left, float top, float right, float bottom,
1753         int color, SkXfermode::Mode mode) {
1754     float inverseScaleX = 1.0f;
1755     float inverseScaleY = 1.0f;
1756     // The quad that we use needs to account for scaling.
1757     if (CC_UNLIKELY(!mSnapshot->transform->isPureTranslate())) {
1758         Matrix4 *mat = mSnapshot->transform;
1759         float m00 = mat->data[Matrix4::kScaleX];
1760         float m01 = mat->data[Matrix4::kSkewY];
1761         float m02 = mat->data[2];
1762         float m10 = mat->data[Matrix4::kSkewX];
1763         float m11 = mat->data[Matrix4::kScaleX];
1764         float m12 = mat->data[6];
1765         float scaleX = sqrt(m00 * m00 + m01 * m01);
1766         float scaleY = sqrt(m10 * m10 + m11 * m11);
1767         inverseScaleX = (scaleX != 0) ? (inverseScaleX / scaleX) : 0;
1768         inverseScaleY = (scaleY != 0) ? (inverseScaleY / scaleY) : 0;
1769     }
1770 
1771     setupDraw();
1772     setupDrawNoTexture();
1773     setupDrawAALine();
1774     setupDrawColor(color);
1775     setupDrawColorFilter();
1776     setupDrawShader();
1777     setupDrawBlending(true, mode);
1778     setupDrawProgram();
1779     setupDrawModelViewIdentity(true);
1780     setupDrawColorUniforms();
1781     setupDrawColorFilterUniforms();
1782     setupDrawShaderIdentityUniforms();
1783 
1784     AAVertex rects[4];
1785     AAVertex* aaVertices = &rects[0];
1786     void* widthCoords = ((GLbyte*) aaVertices) + gVertexAAWidthOffset;
1787     void* lengthCoords = ((GLbyte*) aaVertices) + gVertexAALengthOffset;
1788 
1789     float boundarySizeX = .5 * inverseScaleX;
1790     float boundarySizeY = .5 * inverseScaleY;
1791 
1792     // Adjust the rect by the AA boundary padding
1793     left -= boundarySizeX;
1794     right += boundarySizeX;
1795     top -= boundarySizeY;
1796     bottom += boundarySizeY;
1797 
1798     float width = right - left;
1799     float height = bottom - top;
1800 
1801     int widthSlot;
1802     int lengthSlot;
1803 
1804     float boundaryWidthProportion = (width != 0) ? (2 * boundarySizeX) / width : 0;
1805     float boundaryHeightProportion = (height != 0) ? (2 * boundarySizeY) / height : 0;
1806     setupDrawAALine((void*) aaVertices, widthCoords, lengthCoords,
1807             boundaryWidthProportion, widthSlot, lengthSlot);
1808 
1809     int boundaryLengthSlot = mCaches.currentProgram->getUniform("boundaryLength");
1810     int inverseBoundaryLengthSlot = mCaches.currentProgram->getUniform("inverseBoundaryLength");
1811     glUniform1f(boundaryLengthSlot, boundaryHeightProportion);
1812     glUniform1f(inverseBoundaryLengthSlot, (1.0f / boundaryHeightProportion));
1813 
1814     if (!quickReject(left, top, right, bottom)) {
1815         AAVertex::set(aaVertices++, left, bottom, 1, 1);
1816         AAVertex::set(aaVertices++, left, top, 1, 0);
1817         AAVertex::set(aaVertices++, right, bottom, 0, 1);
1818         AAVertex::set(aaVertices++, right, top, 0, 0);
1819         dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
1820         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1821     }
1822 
1823     finishDrawAALine(widthSlot, lengthSlot);
1824 }
1825 
1826 /**
1827  * We draw lines as quads (tristrips). Using GL_LINES can be difficult because the rasterization
1828  * rules for those lines produces some unexpected results, and may vary between hardware devices.
1829  * The basics of lines-as-quads is easy; we simply find the normal to the line and position the
1830  * corners of the quads on either side of each line endpoint, separated by the strokeWidth
1831  * of the line. Hairlines are more involved because we need to account for transform scaling
1832  * to end up with a one-pixel-wide line in screen space..
1833  * Anti-aliased lines add another factor to the approach. We use a specialized fragment shader
1834  * in combination with values that we calculate and pass down in this method. The basic approach
1835  * is that the quad we create contains both the core line area plus a bounding area in which
1836  * the translucent/AA pixels are drawn. The values we calculate tell the shader what
1837  * proportion of the width and the length of a given segment is represented by the boundary
1838  * region. The quad ends up being exactly .5 pixel larger in all directions than the non-AA quad.
1839  * The bounding region is actually 1 pixel wide on all sides (half pixel on the outside, half pixel
1840  * on the inside). This ends up giving the result we want, with pixels that are completely
1841  * 'inside' the line area being filled opaquely and the other pixels being filled according to
1842  * how far into the boundary region they are, which is determined by shader interpolation.
1843  */
drawLines(float * points,int count,SkPaint * paint)1844 status_t OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
1845     if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
1846 
1847     const bool isAA = paint->isAntiAlias();
1848     // We use half the stroke width here because we're going to position the quad
1849     // corner vertices half of the width away from the line endpoints
1850     float halfStrokeWidth = paint->getStrokeWidth() * 0.5f;
1851     // A stroke width of 0 has a special meaning in Skia:
1852     // it draws a line 1 px wide regardless of current transform
1853     bool isHairLine = paint->getStrokeWidth() == 0.0f;
1854 
1855     float inverseScaleX = 1.0f;
1856     float inverseScaleY = 1.0f;
1857     bool scaled = false;
1858 
1859     int alpha;
1860     SkXfermode::Mode mode;
1861 
1862     int generatedVerticesCount = 0;
1863     int verticesCount = count;
1864     if (count > 4) {
1865         // Polyline: account for extra vertices needed for continuous tri-strip
1866         verticesCount += (count - 4);
1867     }
1868 
1869     if (isHairLine || isAA) {
1870         // The quad that we use for AA and hairlines needs to account for scaling. For hairlines
1871         // the line on the screen should always be one pixel wide regardless of scale. For
1872         // AA lines, we only want one pixel of translucent boundary around the quad.
1873         if (CC_UNLIKELY(!mSnapshot->transform->isPureTranslate())) {
1874             Matrix4 *mat = mSnapshot->transform;
1875             float m00 = mat->data[Matrix4::kScaleX];
1876             float m01 = mat->data[Matrix4::kSkewY];
1877             float m02 = mat->data[2];
1878             float m10 = mat->data[Matrix4::kSkewX];
1879             float m11 = mat->data[Matrix4::kScaleX];
1880             float m12 = mat->data[6];
1881 
1882             float scaleX = sqrtf(m00 * m00 + m01 * m01);
1883             float scaleY = sqrtf(m10 * m10 + m11 * m11);
1884 
1885             inverseScaleX = (scaleX != 0) ? (inverseScaleX / scaleX) : 0;
1886             inverseScaleY = (scaleY != 0) ? (inverseScaleY / scaleY) : 0;
1887 
1888             if (inverseScaleX != 1.0f || inverseScaleY != 1.0f) {
1889                 scaled = true;
1890             }
1891         }
1892     }
1893 
1894     getAlphaAndMode(paint, &alpha, &mode);
1895     setupDraw();
1896     setupDrawNoTexture();
1897     if (isAA) {
1898         setupDrawAALine();
1899     }
1900     setupDrawColor(paint->getColor(), alpha);
1901     setupDrawColorFilter();
1902     setupDrawShader();
1903     setupDrawBlending(isAA, mode);
1904     setupDrawProgram();
1905     setupDrawModelViewIdentity(true);
1906     setupDrawColorUniforms();
1907     setupDrawColorFilterUniforms();
1908     setupDrawShaderIdentityUniforms();
1909 
1910     if (isHairLine) {
1911         // Set a real stroke width to be used in quad construction
1912         halfStrokeWidth = isAA? 1 : .5;
1913     } else if (isAA && !scaled) {
1914         // Expand boundary to enable AA calculations on the quad border
1915         halfStrokeWidth += .5f;
1916     }
1917 
1918     int widthSlot;
1919     int lengthSlot;
1920 
1921     Vertex lines[verticesCount];
1922     Vertex* vertices = &lines[0];
1923 
1924     AAVertex wLines[verticesCount];
1925     AAVertex* aaVertices = &wLines[0];
1926 
1927     if (CC_UNLIKELY(!isAA)) {
1928         setupDrawVertices(vertices);
1929     } else {
1930         void* widthCoords = ((GLbyte*) aaVertices) + gVertexAAWidthOffset;
1931         void* lengthCoords = ((GLbyte*) aaVertices) + gVertexAALengthOffset;
1932         // innerProportion is the ratio of the inner (non-AA) part of the line to the total
1933         // AA stroke width (the base stroke width expanded by a half pixel on either side).
1934         // This value is used in the fragment shader to determine how to fill fragments.
1935         // We will need to calculate the actual width proportion on each segment for
1936         // scaled non-hairlines, since the boundary proportion may differ per-axis when scaled.
1937         float boundaryWidthProportion = 1 / (2 * halfStrokeWidth);
1938         setupDrawAALine((void*) aaVertices, widthCoords, lengthCoords,
1939                 boundaryWidthProportion, widthSlot, lengthSlot);
1940     }
1941 
1942     AAVertex* prevAAVertex = NULL;
1943     Vertex* prevVertex = NULL;
1944 
1945     int boundaryLengthSlot = -1;
1946     int inverseBoundaryLengthSlot = -1;
1947     int boundaryWidthSlot = -1;
1948     int inverseBoundaryWidthSlot = -1;
1949 
1950     for (int i = 0; i < count; i += 4) {
1951         // a = start point, b = end point
1952         vec2 a(points[i], points[i + 1]);
1953         vec2 b(points[i + 2], points[i + 3]);
1954 
1955         float length = 0;
1956         float boundaryLengthProportion = 0;
1957         float boundaryWidthProportion = 0;
1958 
1959         // Find the normal to the line
1960         vec2 n = (b - a).copyNormalized() * halfStrokeWidth;
1961         if (isHairLine) {
1962             if (isAA) {
1963                 float wideningFactor;
1964                 if (fabs(n.x) >= fabs(n.y)) {
1965                     wideningFactor = fabs(1.0f / n.x);
1966                 } else {
1967                     wideningFactor = fabs(1.0f / n.y);
1968                 }
1969                 n *= wideningFactor;
1970             }
1971 
1972             if (scaled) {
1973                 n.x *= inverseScaleX;
1974                 n.y *= inverseScaleY;
1975             }
1976         } else if (scaled) {
1977             // Extend n by .5 pixel on each side, post-transform
1978             vec2 extendedN = n.copyNormalized();
1979             extendedN /= 2;
1980             extendedN.x *= inverseScaleX;
1981             extendedN.y *= inverseScaleY;
1982 
1983             float extendedNLength = extendedN.length();
1984             // We need to set this value on the shader prior to drawing
1985             boundaryWidthProportion = extendedNLength / (halfStrokeWidth + extendedNLength);
1986             n += extendedN;
1987         }
1988 
1989         float x = n.x;
1990         n.x = -n.y;
1991         n.y = x;
1992 
1993         // aa lines expand the endpoint vertices to encompass the AA boundary
1994         if (isAA) {
1995             vec2 abVector = (b - a);
1996             length = abVector.length();
1997             abVector.normalize();
1998 
1999             if (scaled) {
2000                 abVector.x *= inverseScaleX;
2001                 abVector.y *= inverseScaleY;
2002                 float abLength = abVector.length();
2003                 boundaryLengthProportion = abLength / (length + abLength);
2004             } else {
2005                 boundaryLengthProportion = .5 / (length + 1);
2006             }
2007 
2008             abVector /= 2;
2009             a -= abVector;
2010             b += abVector;
2011         }
2012 
2013         // Four corners of the rectangle defining a thick line
2014         vec2 p1 = a - n;
2015         vec2 p2 = a + n;
2016         vec2 p3 = b + n;
2017         vec2 p4 = b - n;
2018 
2019 
2020         const float left = fmin(p1.x, fmin(p2.x, fmin(p3.x, p4.x)));
2021         const float right = fmax(p1.x, fmax(p2.x, fmax(p3.x, p4.x)));
2022         const float top = fmin(p1.y, fmin(p2.y, fmin(p3.y, p4.y)));
2023         const float bottom = fmax(p1.y, fmax(p2.y, fmax(p3.y, p4.y)));
2024 
2025         if (!quickReject(left, top, right, bottom)) {
2026             if (!isAA) {
2027                 if (prevVertex != NULL) {
2028                     // Issue two repeat vertices to create degenerate triangles to bridge
2029                     // between the previous line and the new one. This is necessary because
2030                     // we are creating a single triangle_strip which will contain
2031                     // potentially discontinuous line segments.
2032                     Vertex::set(vertices++, prevVertex->position[0], prevVertex->position[1]);
2033                     Vertex::set(vertices++, p1.x, p1.y);
2034                     generatedVerticesCount += 2;
2035                 }
2036 
2037                 Vertex::set(vertices++, p1.x, p1.y);
2038                 Vertex::set(vertices++, p2.x, p2.y);
2039                 Vertex::set(vertices++, p4.x, p4.y);
2040                 Vertex::set(vertices++, p3.x, p3.y);
2041 
2042                 prevVertex = vertices - 1;
2043                 generatedVerticesCount += 4;
2044             } else {
2045                 if (!isHairLine && scaled) {
2046                     // Must set width proportions per-segment for scaled non-hairlines to use the
2047                     // correct AA boundary dimensions
2048                     if (boundaryWidthSlot < 0) {
2049                         boundaryWidthSlot =
2050                                 mCaches.currentProgram->getUniform("boundaryWidth");
2051                         inverseBoundaryWidthSlot =
2052                                 mCaches.currentProgram->getUniform("inverseBoundaryWidth");
2053                     }
2054 
2055                     glUniform1f(boundaryWidthSlot, boundaryWidthProportion);
2056                     glUniform1f(inverseBoundaryWidthSlot, (1 / boundaryWidthProportion));
2057                 }
2058 
2059                 if (boundaryLengthSlot < 0) {
2060                     boundaryLengthSlot = mCaches.currentProgram->getUniform("boundaryLength");
2061                     inverseBoundaryLengthSlot =
2062                             mCaches.currentProgram->getUniform("inverseBoundaryLength");
2063                 }
2064 
2065                 glUniform1f(boundaryLengthSlot, boundaryLengthProportion);
2066                 glUniform1f(inverseBoundaryLengthSlot, (1 / boundaryLengthProportion));
2067 
2068                 if (prevAAVertex != NULL) {
2069                     // Issue two repeat vertices to create degenerate triangles to bridge
2070                     // between the previous line and the new one. This is necessary because
2071                     // we are creating a single triangle_strip which will contain
2072                     // potentially discontinuous line segments.
2073                     AAVertex::set(aaVertices++,prevAAVertex->position[0],
2074                             prevAAVertex->position[1], prevAAVertex->width, prevAAVertex->length);
2075                     AAVertex::set(aaVertices++, p4.x, p4.y, 1, 1);
2076                     generatedVerticesCount += 2;
2077                 }
2078 
2079                 AAVertex::set(aaVertices++, p4.x, p4.y, 1, 1);
2080                 AAVertex::set(aaVertices++, p1.x, p1.y, 1, 0);
2081                 AAVertex::set(aaVertices++, p3.x, p3.y, 0, 1);
2082                 AAVertex::set(aaVertices++, p2.x, p2.y, 0, 0);
2083 
2084                 prevAAVertex = aaVertices - 1;
2085                 generatedVerticesCount += 4;
2086             }
2087 
2088             dirtyLayer(a.x == b.x ? left - 1 : left, a.y == b.y ? top - 1 : top,
2089                     a.x == b.x ? right: right, a.y == b.y ? bottom: bottom,
2090                     *mSnapshot->transform);
2091         }
2092     }
2093 
2094     if (generatedVerticesCount > 0) {
2095        glDrawArrays(GL_TRIANGLE_STRIP, 0, generatedVerticesCount);
2096     }
2097 
2098     if (isAA) {
2099         finishDrawAALine(widthSlot, lengthSlot);
2100     }
2101 
2102     return DrawGlInfo::kStatusDrew;
2103 }
2104 
drawPoints(float * points,int count,SkPaint * paint)2105 status_t OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) {
2106     if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
2107 
2108     // TODO: The paint's cap style defines whether the points are square or circular
2109     // TODO: Handle AA for round points
2110 
2111     // A stroke width of 0 has a special meaning in Skia:
2112     // it draws an unscaled 1px point
2113     float strokeWidth = paint->getStrokeWidth();
2114     const bool isHairLine = paint->getStrokeWidth() == 0.0f;
2115     if (isHairLine) {
2116         // Now that we know it's hairline, we can set the effective width, to be used later
2117         strokeWidth = 1.0f;
2118     }
2119     const float halfWidth = strokeWidth / 2;
2120     int alpha;
2121     SkXfermode::Mode mode;
2122     getAlphaAndMode(paint, &alpha, &mode);
2123 
2124     int verticesCount = count >> 1;
2125     int generatedVerticesCount = 0;
2126 
2127     TextureVertex pointsData[verticesCount];
2128     TextureVertex* vertex = &pointsData[0];
2129 
2130     setupDraw();
2131     setupDrawNoTexture();
2132     setupDrawPoint(strokeWidth);
2133     setupDrawColor(paint->getColor(), alpha);
2134     setupDrawColorFilter();
2135     setupDrawShader();
2136     setupDrawBlending(mode);
2137     setupDrawProgram();
2138     setupDrawModelViewIdentity(true);
2139     setupDrawColorUniforms();
2140     setupDrawColorFilterUniforms();
2141     setupDrawPointUniforms();
2142     setupDrawShaderIdentityUniforms();
2143     setupDrawMesh(vertex);
2144 
2145     for (int i = 0; i < count; i += 2) {
2146         TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f);
2147         generatedVerticesCount++;
2148 
2149         float left = points[i] - halfWidth;
2150         float right = points[i] + halfWidth;
2151         float top = points[i + 1] - halfWidth;
2152         float bottom = points [i + 1] + halfWidth;
2153 
2154         dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
2155     }
2156 
2157     glDrawArrays(GL_POINTS, 0, generatedVerticesCount);
2158 
2159     return DrawGlInfo::kStatusDrew;
2160 }
2161 
drawColor(int color,SkXfermode::Mode mode)2162 status_t OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
2163     // No need to check against the clip, we fill the clip region
2164     if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
2165 
2166     Rect& clip(*mSnapshot->clipRect);
2167     clip.snapToPixelBoundaries();
2168 
2169     drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true);
2170 
2171     return DrawGlInfo::kStatusDrew;
2172 }
2173 
drawShape(float left,float top,const PathTexture * texture,SkPaint * paint)2174 status_t OpenGLRenderer::drawShape(float left, float top, const PathTexture* texture,
2175         SkPaint* paint) {
2176     if (!texture) return DrawGlInfo::kStatusDone;
2177     const AutoTexture autoCleanup(texture);
2178 
2179     const float x = left + texture->left - texture->offset;
2180     const float y = top + texture->top - texture->offset;
2181 
2182     drawPathTexture(texture, x, y, paint);
2183 
2184     return DrawGlInfo::kStatusDrew;
2185 }
2186 
drawRoundRect(float left,float top,float right,float bottom,float rx,float ry,SkPaint * paint)2187 status_t OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
2188         float rx, float ry, SkPaint* paint) {
2189     if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
2190 
2191     mCaches.activeTexture(0);
2192     const PathTexture* texture = mCaches.roundRectShapeCache.getRoundRect(
2193             right - left, bottom - top, rx, ry, paint);
2194     return drawShape(left, top, texture, paint);
2195 }
2196 
drawCircle(float x,float y,float radius,SkPaint * paint)2197 status_t OpenGLRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) {
2198     if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
2199 
2200     mCaches.activeTexture(0);
2201     const PathTexture* texture = mCaches.circleShapeCache.getCircle(radius, paint);
2202     return drawShape(x - radius, y - radius, texture, paint);
2203 }
2204 
drawOval(float left,float top,float right,float bottom,SkPaint * paint)2205 status_t OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
2206         SkPaint* paint) {
2207     if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
2208 
2209     mCaches.activeTexture(0);
2210     const PathTexture* texture = mCaches.ovalShapeCache.getOval(right - left, bottom - top, paint);
2211     return drawShape(left, top, texture, paint);
2212 }
2213 
drawArc(float left,float top,float right,float bottom,float startAngle,float sweepAngle,bool useCenter,SkPaint * paint)2214 status_t OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
2215         float startAngle, float sweepAngle, bool useCenter, SkPaint* paint) {
2216     if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
2217 
2218     if (fabs(sweepAngle) >= 360.0f) {
2219         return drawOval(left, top, right, bottom, paint);
2220     }
2221 
2222     mCaches.activeTexture(0);
2223     const PathTexture* texture = mCaches.arcShapeCache.getArc(right - left, bottom - top,
2224             startAngle, sweepAngle, useCenter, paint);
2225     return drawShape(left, top, texture, paint);
2226 }
2227 
drawRectAsShape(float left,float top,float right,float bottom,SkPaint * paint)2228 status_t OpenGLRenderer::drawRectAsShape(float left, float top, float right, float bottom,
2229         SkPaint* paint) {
2230     if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
2231 
2232     mCaches.activeTexture(0);
2233     const PathTexture* texture = mCaches.rectShapeCache.getRect(right - left, bottom - top, paint);
2234     return drawShape(left, top, texture, paint);
2235 }
2236 
drawRect(float left,float top,float right,float bottom,SkPaint * p)2237 status_t OpenGLRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* p) {
2238     if (p->getStyle() != SkPaint::kFill_Style) {
2239         return drawRectAsShape(left, top, right, bottom, p);
2240     }
2241 
2242     if (quickReject(left, top, right, bottom)) {
2243         return DrawGlInfo::kStatusDone;
2244     }
2245 
2246     SkXfermode::Mode mode;
2247     if (!mCaches.extensions.hasFramebufferFetch()) {
2248         const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode);
2249         if (!isMode) {
2250             // Assume SRC_OVER
2251             mode = SkXfermode::kSrcOver_Mode;
2252         }
2253     } else {
2254         mode = getXfermode(p->getXfermode());
2255     }
2256 
2257     int color = p->getColor();
2258     if (p->isAntiAlias() && !mSnapshot->transform->isSimple()) {
2259         drawAARect(left, top, right, bottom, color, mode);
2260     } else {
2261         drawColorRect(left, top, right, bottom, color, mode);
2262     }
2263 
2264     return DrawGlInfo::kStatusDrew;
2265 }
2266 
drawPosText(const char * text,int bytesCount,int count,const float * positions,SkPaint * paint)2267 status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
2268         const float* positions, SkPaint* paint) {
2269     if (text == NULL || count == 0 || mSnapshot->isIgnored() ||
2270             (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) {
2271         return DrawGlInfo::kStatusDone;
2272     }
2273 
2274     // NOTE: Skia does not support perspective transform on drawPosText yet
2275     if (!mSnapshot->transform->isSimple()) {
2276         return DrawGlInfo::kStatusDone;
2277     }
2278 
2279     float x = 0.0f;
2280     float y = 0.0f;
2281     const bool pureTranslate = mSnapshot->transform->isPureTranslate();
2282     if (pureTranslate) {
2283         x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f);
2284         y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f);
2285     }
2286 
2287     FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(paint);
2288     fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()),
2289             paint->getTextSize());
2290 
2291     int alpha;
2292     SkXfermode::Mode mode;
2293     getAlphaAndMode(paint, &alpha, &mode);
2294 
2295     // Pick the appropriate texture filtering
2296     bool linearFilter = mSnapshot->transform->changesBounds();
2297     if (pureTranslate && !linearFilter) {
2298         linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f;
2299     }
2300 
2301     mCaches.activeTexture(0);
2302     setupDraw();
2303     setupDrawDirtyRegionsDisabled();
2304     setupDrawWithTexture(true);
2305     setupDrawAlpha8Color(paint->getColor(), alpha);
2306     setupDrawColorFilter();
2307     setupDrawShader();
2308     setupDrawBlending(true, mode);
2309     setupDrawProgram();
2310     setupDrawModelView(x, y, x, y, pureTranslate, true);
2311     setupDrawTexture(fontRenderer.getTexture(linearFilter));
2312     setupDrawPureColorUniforms();
2313     setupDrawColorFilterUniforms();
2314     setupDrawShaderUniforms(pureTranslate);
2315 
2316     const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip();
2317     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2318 
2319 #if RENDER_LAYERS_AS_REGIONS
2320     const bool hasActiveLayer = hasLayer();
2321 #else
2322     const bool hasActiveLayer = false;
2323 #endif
2324 
2325     if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
2326             positions, hasActiveLayer ? &bounds : NULL)) {
2327 #if RENDER_LAYERS_AS_REGIONS
2328         if (hasActiveLayer) {
2329             if (!pureTranslate) {
2330                 mSnapshot->transform->mapRect(bounds);
2331             }
2332             dirtyLayerUnchecked(bounds, getRegion());
2333         }
2334 #endif
2335     }
2336 
2337     return DrawGlInfo::kStatusDrew;
2338 }
2339 
drawText(const char * text,int bytesCount,int count,float x,float y,SkPaint * paint,float length)2340 status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
2341         float x, float y, SkPaint* paint, float length) {
2342     if (text == NULL || count == 0 || mSnapshot->isIgnored() ||
2343             (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) {
2344         return DrawGlInfo::kStatusDone;
2345     }
2346 
2347     if (length < 0.0f) length = paint->measureText(text, bytesCount);
2348     switch (paint->getTextAlign()) {
2349         case SkPaint::kCenter_Align:
2350             x -= length / 2.0f;
2351             break;
2352         case SkPaint::kRight_Align:
2353             x -= length;
2354             break;
2355         default:
2356             break;
2357     }
2358 
2359     SkPaint::FontMetrics metrics;
2360     paint->getFontMetrics(&metrics, 0.0f);
2361     if (quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom)) {
2362         return DrawGlInfo::kStatusDone;
2363     }
2364 
2365     const float oldX = x;
2366     const float oldY = y;
2367     const bool pureTranslate = mSnapshot->transform->isPureTranslate();
2368     if (CC_LIKELY(pureTranslate)) {
2369         x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f);
2370         y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f);
2371     }
2372 
2373 #if DEBUG_GLYPHS
2374     ALOGD("OpenGLRenderer drawText() with FontID=%d", SkTypeface::UniqueID(paint->getTypeface()));
2375 #endif
2376 
2377     FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(paint);
2378     fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()),
2379             paint->getTextSize());
2380 
2381     int alpha;
2382     SkXfermode::Mode mode;
2383     getAlphaAndMode(paint, &alpha, &mode);
2384 
2385     if (CC_UNLIKELY(mHasShadow)) {
2386         mCaches.activeTexture(0);
2387 
2388         mCaches.dropShadowCache.setFontRenderer(fontRenderer);
2389         const ShadowTexture* shadow = mCaches.dropShadowCache.get(
2390                 paint, text, bytesCount, count, mShadowRadius);
2391         const AutoTexture autoCleanup(shadow);
2392 
2393         const float sx = oldX - shadow->left + mShadowDx;
2394         const float sy = oldY - shadow->top + mShadowDy;
2395 
2396         const int shadowAlpha = ((mShadowColor >> 24) & 0xFF);
2397         int shadowColor = mShadowColor;
2398         if (mShader) {
2399             shadowColor = 0xffffffff;
2400         }
2401 
2402         setupDraw();
2403         setupDrawWithTexture(true);
2404         setupDrawAlpha8Color(shadowColor, shadowAlpha < 255 ? shadowAlpha : alpha);
2405         setupDrawColorFilter();
2406         setupDrawShader();
2407         setupDrawBlending(true, mode);
2408         setupDrawProgram();
2409         setupDrawModelView(sx, sy, sx + shadow->width, sy + shadow->height);
2410         setupDrawTexture(shadow->id);
2411         setupDrawPureColorUniforms();
2412         setupDrawColorFilterUniforms();
2413         setupDrawShaderUniforms();
2414         setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
2415 
2416         glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
2417     }
2418 
2419     // Pick the appropriate texture filtering
2420     bool linearFilter = mSnapshot->transform->changesBounds();
2421     if (pureTranslate && !linearFilter) {
2422         linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f;
2423     }
2424 
2425     // The font renderer will always use texture unit 0
2426     mCaches.activeTexture(0);
2427     setupDraw();
2428     setupDrawDirtyRegionsDisabled();
2429     setupDrawWithTexture(true);
2430     setupDrawAlpha8Color(paint->getColor(), alpha);
2431     setupDrawColorFilter();
2432     setupDrawShader();
2433     setupDrawBlending(true, mode);
2434     setupDrawProgram();
2435     setupDrawModelView(x, y, x, y, pureTranslate, true);
2436     // See comment above; the font renderer must use texture unit 0
2437     // assert(mTextureUnit == 0)
2438     setupDrawTexture(fontRenderer.getTexture(linearFilter));
2439     setupDrawPureColorUniforms();
2440     setupDrawColorFilterUniforms();
2441     setupDrawShaderUniforms(pureTranslate);
2442 
2443     const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip();
2444     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2445 
2446 #if RENDER_LAYERS_AS_REGIONS
2447     const bool hasActiveLayer = hasLayer();
2448 #else
2449     const bool hasActiveLayer = false;
2450 #endif
2451 
2452     if (fontRenderer.renderText(paint, clip, text, 0, bytesCount, count, x, y,
2453             hasActiveLayer ? &bounds : NULL)) {
2454 #if RENDER_LAYERS_AS_REGIONS
2455         if (hasActiveLayer) {
2456             if (!pureTranslate) {
2457                 mSnapshot->transform->mapRect(bounds);
2458             }
2459             dirtyLayerUnchecked(bounds, getRegion());
2460         }
2461 #endif
2462     }
2463 
2464     drawTextDecorations(text, bytesCount, length, oldX, oldY, paint);
2465 
2466     return DrawGlInfo::kStatusDrew;
2467 }
2468 
drawTextOnPath(const char * text,int bytesCount,int count,SkPath * path,float hOffset,float vOffset,SkPaint * paint)2469 status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count, SkPath* path,
2470         float hOffset, float vOffset, SkPaint* paint) {
2471     if (text == NULL || count == 0 || mSnapshot->isIgnored() ||
2472             (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) {
2473         return DrawGlInfo::kStatusDone;
2474     }
2475 
2476     FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(paint);
2477     fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()),
2478             paint->getTextSize());
2479 
2480     int alpha;
2481     SkXfermode::Mode mode;
2482     getAlphaAndMode(paint, &alpha, &mode);
2483 
2484     mCaches.activeTexture(0);
2485     setupDraw();
2486     setupDrawDirtyRegionsDisabled();
2487     setupDrawWithTexture(true);
2488     setupDrawAlpha8Color(paint->getColor(), alpha);
2489     setupDrawColorFilter();
2490     setupDrawShader();
2491     setupDrawBlending(true, mode);
2492     setupDrawProgram();
2493     setupDrawModelView(0.0f, 0.0f, 0.0f, 0.0f, false, true);
2494     setupDrawTexture(fontRenderer.getTexture(true));
2495     setupDrawPureColorUniforms();
2496     setupDrawColorFilterUniforms();
2497     setupDrawShaderUniforms(false);
2498 
2499     const Rect* clip = &mSnapshot->getLocalClip();
2500     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2501 
2502 #if RENDER_LAYERS_AS_REGIONS
2503     const bool hasActiveLayer = hasLayer();
2504 #else
2505     const bool hasActiveLayer = false;
2506 #endif
2507 
2508     if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path,
2509             hOffset, vOffset, hasActiveLayer ? &bounds : NULL)) {
2510 #if RENDER_LAYERS_AS_REGIONS
2511         if (hasActiveLayer) {
2512             mSnapshot->transform->mapRect(bounds);
2513             dirtyLayerUnchecked(bounds, getRegion());
2514         }
2515 #endif
2516     }
2517 
2518     return DrawGlInfo::kStatusDrew;
2519 }
2520 
drawPath(SkPath * path,SkPaint * paint)2521 status_t OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) {
2522     if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
2523 
2524     mCaches.activeTexture(0);
2525 
2526     // TODO: Perform early clip test before we rasterize the path
2527     const PathTexture* texture = mCaches.pathCache.get(path, paint);
2528     if (!texture) return DrawGlInfo::kStatusDone;
2529     const AutoTexture autoCleanup(texture);
2530 
2531     const float x = texture->left - texture->offset;
2532     const float y = texture->top - texture->offset;
2533 
2534     drawPathTexture(texture, x, y, paint);
2535 
2536     return DrawGlInfo::kStatusDrew;
2537 }
2538 
drawLayer(Layer * layer,float x,float y,SkPaint * paint)2539 status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) {
2540     if (!layer || quickReject(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight())) {
2541         return DrawGlInfo::kStatusDone;
2542     }
2543 
2544     if (layer->deferredUpdateScheduled && layer->renderer && layer->displayList) {
2545         OpenGLRenderer* renderer = layer->renderer;
2546         Rect& dirty = layer->dirtyRect;
2547 
2548         interrupt();
2549         renderer->setViewport(layer->layer.getWidth(), layer->layer.getHeight());
2550         renderer->prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, !layer->isBlend());
2551         renderer->drawDisplayList(layer->displayList, dirty, DisplayList::kReplayFlag_ClipChildren);
2552         renderer->finish();
2553         resume();
2554 
2555         dirty.setEmpty();
2556         layer->deferredUpdateScheduled = false;
2557         layer->renderer = NULL;
2558         layer->displayList = NULL;
2559     }
2560 
2561     mCaches.activeTexture(0);
2562 
2563     int alpha;
2564     SkXfermode::Mode mode;
2565     getAlphaAndMode(paint, &alpha, &mode);
2566 
2567     layer->setAlpha(alpha, mode);
2568 
2569 #if RENDER_LAYERS_AS_REGIONS
2570     if (CC_LIKELY(!layer->region.isEmpty())) {
2571         if (layer->region.isRect()) {
2572             composeLayerRect(layer, layer->regionRect);
2573         } else if (layer->mesh) {
2574             const float a = alpha / 255.0f;
2575             const Rect& rect = layer->layer;
2576 
2577             setupDraw();
2578             setupDrawWithTexture();
2579             setupDrawColor(a, a, a, a);
2580             setupDrawColorFilter();
2581             setupDrawBlending(layer->isBlend() || a < 1.0f, layer->getMode(), false);
2582             setupDrawProgram();
2583             setupDrawPureColorUniforms();
2584             setupDrawColorFilterUniforms();
2585             setupDrawTexture(layer->getTexture());
2586             if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) {
2587                 x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f);
2588                 y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f);
2589 
2590                 layer->setFilter(GL_NEAREST);
2591                 setupDrawModelViewTranslate(x, y,
2592                         x + layer->layer.getWidth(), y + layer->layer.getHeight(), true);
2593             } else {
2594                 layer->setFilter(GL_LINEAR);
2595                 setupDrawModelViewTranslate(x, y,
2596                         x + layer->layer.getWidth(), y + layer->layer.getHeight());
2597             }
2598             setupDrawMesh(&layer->mesh[0].position[0], &layer->mesh[0].texture[0]);
2599 
2600             glDrawElements(GL_TRIANGLES, layer->meshElementCount,
2601                     GL_UNSIGNED_SHORT, layer->meshIndices);
2602 
2603             finishDrawTexture();
2604 
2605 #if DEBUG_LAYERS_AS_REGIONS
2606             drawRegionRects(layer->region);
2607 #endif
2608         }
2609     }
2610 #else
2611     const Rect r(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight());
2612     composeLayerRect(layer, r);
2613 #endif
2614 
2615     return DrawGlInfo::kStatusDrew;
2616 }
2617 
2618 ///////////////////////////////////////////////////////////////////////////////
2619 // Shaders
2620 ///////////////////////////////////////////////////////////////////////////////
2621 
resetShader()2622 void OpenGLRenderer::resetShader() {
2623     mShader = NULL;
2624 }
2625 
setupShader(SkiaShader * shader)2626 void OpenGLRenderer::setupShader(SkiaShader* shader) {
2627     mShader = shader;
2628     if (mShader) {
2629         mShader->set(&mCaches.textureCache, &mCaches.gradientCache);
2630     }
2631 }
2632 
2633 ///////////////////////////////////////////////////////////////////////////////
2634 // Color filters
2635 ///////////////////////////////////////////////////////////////////////////////
2636 
resetColorFilter()2637 void OpenGLRenderer::resetColorFilter() {
2638     mColorFilter = NULL;
2639 }
2640 
setupColorFilter(SkiaColorFilter * filter)2641 void OpenGLRenderer::setupColorFilter(SkiaColorFilter* filter) {
2642     mColorFilter = filter;
2643 }
2644 
2645 ///////////////////////////////////////////////////////////////////////////////
2646 // Drop shadow
2647 ///////////////////////////////////////////////////////////////////////////////
2648 
resetShadow()2649 void OpenGLRenderer::resetShadow() {
2650     mHasShadow = false;
2651 }
2652 
setupShadow(float radius,float dx,float dy,int color)2653 void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) {
2654     mHasShadow = true;
2655     mShadowRadius = radius;
2656     mShadowDx = dx;
2657     mShadowDy = dy;
2658     mShadowColor = color;
2659 }
2660 
2661 ///////////////////////////////////////////////////////////////////////////////
2662 // Draw filters
2663 ///////////////////////////////////////////////////////////////////////////////
2664 
resetPaintFilter()2665 void OpenGLRenderer::resetPaintFilter() {
2666     mHasDrawFilter = false;
2667 }
2668 
setupPaintFilter(int clearBits,int setBits)2669 void OpenGLRenderer::setupPaintFilter(int clearBits, int setBits) {
2670     mHasDrawFilter = true;
2671     mPaintFilterClearBits = clearBits & SkPaint::kAllFlags;
2672     mPaintFilterSetBits = setBits & SkPaint::kAllFlags;
2673 }
2674 
filterPaint(SkPaint * paint)2675 SkPaint* OpenGLRenderer::filterPaint(SkPaint* paint) {
2676     if (CC_LIKELY(!mHasDrawFilter || !paint)) return paint;
2677 
2678     uint32_t flags = paint->getFlags();
2679 
2680     mFilteredPaint = *paint;
2681     mFilteredPaint.setFlags((flags & ~mPaintFilterClearBits) | mPaintFilterSetBits);
2682 
2683     return &mFilteredPaint;
2684 }
2685 
2686 ///////////////////////////////////////////////////////////////////////////////
2687 // Drawing implementation
2688 ///////////////////////////////////////////////////////////////////////////////
2689 
drawPathTexture(const PathTexture * texture,float x,float y,SkPaint * paint)2690 void OpenGLRenderer::drawPathTexture(const PathTexture* texture,
2691         float x, float y, SkPaint* paint) {
2692     if (quickReject(x, y, x + texture->width, y + texture->height)) {
2693         return;
2694     }
2695 
2696     int alpha;
2697     SkXfermode::Mode mode;
2698     getAlphaAndMode(paint, &alpha, &mode);
2699 
2700     setupDraw();
2701     setupDrawWithTexture(true);
2702     setupDrawAlpha8Color(paint->getColor(), alpha);
2703     setupDrawColorFilter();
2704     setupDrawShader();
2705     setupDrawBlending(true, mode);
2706     setupDrawProgram();
2707     setupDrawModelView(x, y, x + texture->width, y + texture->height);
2708     setupDrawTexture(texture->id);
2709     setupDrawPureColorUniforms();
2710     setupDrawColorFilterUniforms();
2711     setupDrawShaderUniforms();
2712     setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
2713 
2714     glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
2715 
2716     finishDrawTexture();
2717 }
2718 
2719 // Same values used by Skia
2720 #define kStdStrikeThru_Offset   (-6.0f / 21.0f)
2721 #define kStdUnderline_Offset    (1.0f / 9.0f)
2722 #define kStdUnderline_Thickness (1.0f / 18.0f)
2723 
drawTextDecorations(const char * text,int bytesCount,float length,float x,float y,SkPaint * paint)2724 void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float length,
2725         float x, float y, SkPaint* paint) {
2726     // Handle underline and strike-through
2727     uint32_t flags = paint->getFlags();
2728     if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
2729         SkPaint paintCopy(*paint);
2730         float underlineWidth = length;
2731         // If length is > 0.0f, we already measured the text for the text alignment
2732         if (length <= 0.0f) {
2733             underlineWidth = paintCopy.measureText(text, bytesCount);
2734         }
2735 
2736         float offsetX = 0;
2737         switch (paintCopy.getTextAlign()) {
2738             case SkPaint::kCenter_Align:
2739                 offsetX = underlineWidth * 0.5f;
2740                 break;
2741             case SkPaint::kRight_Align:
2742                 offsetX = underlineWidth;
2743                 break;
2744             default:
2745                 break;
2746         }
2747 
2748         if (CC_LIKELY(underlineWidth > 0.0f)) {
2749             const float textSize = paintCopy.getTextSize();
2750             const float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
2751 
2752             const float left = x - offsetX;
2753             float top = 0.0f;
2754 
2755             int linesCount = 0;
2756             if (flags & SkPaint::kUnderlineText_Flag) linesCount++;
2757             if (flags & SkPaint::kStrikeThruText_Flag) linesCount++;
2758 
2759             const int pointsCount = 4 * linesCount;
2760             float points[pointsCount];
2761             int currentPoint = 0;
2762 
2763             if (flags & SkPaint::kUnderlineText_Flag) {
2764                 top = y + textSize * kStdUnderline_Offset;
2765                 points[currentPoint++] = left;
2766                 points[currentPoint++] = top;
2767                 points[currentPoint++] = left + underlineWidth;
2768                 points[currentPoint++] = top;
2769             }
2770 
2771             if (flags & SkPaint::kStrikeThruText_Flag) {
2772                 top = y + textSize * kStdStrikeThru_Offset;
2773                 points[currentPoint++] = left;
2774                 points[currentPoint++] = top;
2775                 points[currentPoint++] = left + underlineWidth;
2776                 points[currentPoint++] = top;
2777             }
2778 
2779             paintCopy.setStrokeWidth(strokeWidth);
2780 
2781             drawLines(&points[0], pointsCount, &paintCopy);
2782         }
2783     }
2784 }
2785 
drawColorRect(float left,float top,float right,float bottom,int color,SkXfermode::Mode mode,bool ignoreTransform)2786 void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
2787         int color, SkXfermode::Mode mode, bool ignoreTransform) {
2788     // If a shader is set, preserve only the alpha
2789     if (mShader) {
2790         color |= 0x00ffffff;
2791     }
2792 
2793     setupDraw();
2794     setupDrawNoTexture();
2795     setupDrawColor(color);
2796     setupDrawShader();
2797     setupDrawColorFilter();
2798     setupDrawBlending(mode);
2799     setupDrawProgram();
2800     setupDrawModelView(left, top, right, bottom, ignoreTransform);
2801     setupDrawColorUniforms();
2802     setupDrawShaderUniforms(ignoreTransform);
2803     setupDrawColorFilterUniforms();
2804     setupDrawSimpleMesh();
2805 
2806     glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
2807 }
2808 
drawTextureRect(float left,float top,float right,float bottom,Texture * texture,SkPaint * paint)2809 void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
2810         Texture* texture, SkPaint* paint) {
2811     int alpha;
2812     SkXfermode::Mode mode;
2813     getAlphaAndMode(paint, &alpha, &mode);
2814 
2815     texture->setWrap(GL_CLAMP_TO_EDGE, true);
2816 
2817     if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) {
2818         const float x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f);
2819         const float y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f);
2820 
2821         texture->setFilter(GL_NEAREST, true);
2822         drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
2823                 alpha / 255.0f, mode, texture->blend, (GLvoid*) NULL,
2824                 (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount, false, true);
2825     } else {
2826         texture->setFilter(FILTER(paint), true);
2827         drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode,
2828                 texture->blend, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset,
2829                 GL_TRIANGLE_STRIP, gMeshCount);
2830     }
2831 }
2832 
drawTextureRect(float left,float top,float right,float bottom,GLuint texture,float alpha,SkXfermode::Mode mode,bool blend)2833 void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
2834         GLuint texture, float alpha, SkXfermode::Mode mode, bool blend) {
2835     drawTextureMesh(left, top, right, bottom, texture, alpha, mode, blend,
2836             (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount);
2837 }
2838 
drawTextureMesh(float left,float top,float right,float bottom,GLuint texture,float alpha,SkXfermode::Mode mode,bool blend,GLvoid * vertices,GLvoid * texCoords,GLenum drawMode,GLsizei elementsCount,bool swapSrcDst,bool ignoreTransform,GLuint vbo,bool ignoreScale,bool dirty)2839 void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
2840         GLuint texture, float alpha, SkXfermode::Mode mode, bool blend,
2841         GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
2842         bool swapSrcDst, bool ignoreTransform, GLuint vbo, bool ignoreScale, bool dirty) {
2843 
2844     setupDraw();
2845     setupDrawWithTexture();
2846     setupDrawColor(alpha, alpha, alpha, alpha);
2847     setupDrawColorFilter();
2848     setupDrawBlending(blend, mode, swapSrcDst);
2849     setupDrawProgram();
2850     if (!dirty) {
2851         setupDrawDirtyRegionsDisabled();
2852     }
2853     if (!ignoreScale) {
2854         setupDrawModelView(left, top, right, bottom, ignoreTransform);
2855     } else {
2856         setupDrawModelViewTranslate(left, top, right, bottom, ignoreTransform);
2857     }
2858     setupDrawPureColorUniforms();
2859     setupDrawColorFilterUniforms();
2860     setupDrawTexture(texture);
2861     setupDrawMesh(vertices, texCoords, vbo);
2862 
2863     glDrawArrays(drawMode, 0, elementsCount);
2864 
2865     finishDrawTexture();
2866 }
2867 
chooseBlending(bool blend,SkXfermode::Mode mode,ProgramDescription & description,bool swapSrcDst)2868 void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
2869         ProgramDescription& description, bool swapSrcDst) {
2870     blend = blend || mode != SkXfermode::kSrcOver_Mode;
2871 
2872     if (blend) {
2873         // These blend modes are not supported by OpenGL directly and have
2874         // to be implemented using shaders. Since the shader will perform
2875         // the blending, turn blending off here
2876         // If the blend mode cannot be implemented using shaders, fall
2877         // back to the default SrcOver blend mode instead
2878         if CC_UNLIKELY((mode > SkXfermode::kScreen_Mode)) {
2879             if (CC_UNLIKELY(mCaches.extensions.hasFramebufferFetch())) {
2880                 description.framebufferMode = mode;
2881                 description.swapSrcDst = swapSrcDst;
2882 
2883                 if (mCaches.blend) {
2884                     glDisable(GL_BLEND);
2885                     mCaches.blend = false;
2886                 }
2887 
2888                 return;
2889             } else {
2890                 mode = SkXfermode::kSrcOver_Mode;
2891             }
2892         }
2893 
2894         if (!mCaches.blend) {
2895             glEnable(GL_BLEND);
2896         }
2897 
2898         GLenum sourceMode = swapSrcDst ? gBlendsSwap[mode].src : gBlends[mode].src;
2899         GLenum destMode = swapSrcDst ? gBlendsSwap[mode].dst : gBlends[mode].dst;
2900 
2901         if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) {
2902             glBlendFunc(sourceMode, destMode);
2903             mCaches.lastSrcMode = sourceMode;
2904             mCaches.lastDstMode = destMode;
2905         }
2906     } else if (mCaches.blend) {
2907         glDisable(GL_BLEND);
2908     }
2909     mCaches.blend = blend;
2910 }
2911 
useProgram(Program * program)2912 bool OpenGLRenderer::useProgram(Program* program) {
2913     if (!program->isInUse()) {
2914         if (mCaches.currentProgram != NULL) mCaches.currentProgram->remove();
2915         program->use();
2916         mCaches.currentProgram = program;
2917         return false;
2918     }
2919     return true;
2920 }
2921 
resetDrawTextureTexCoords(float u1,float v1,float u2,float v2)2922 void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
2923     TextureVertex* v = &mMeshVertices[0];
2924     TextureVertex::setUV(v++, u1, v1);
2925     TextureVertex::setUV(v++, u2, v1);
2926     TextureVertex::setUV(v++, u1, v2);
2927     TextureVertex::setUV(v++, u2, v2);
2928 }
2929 
getAlphaAndMode(SkPaint * paint,int * alpha,SkXfermode::Mode * mode)2930 void OpenGLRenderer::getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) {
2931     if (paint) {
2932         *mode = getXfermode(paint->getXfermode());
2933 
2934         // Skia draws using the color's alpha channel if < 255
2935         // Otherwise, it uses the paint's alpha
2936         int color = paint->getColor();
2937         *alpha = (color >> 24) & 0xFF;
2938         if (*alpha == 255) {
2939             *alpha = paint->getAlpha();
2940         }
2941     } else {
2942         *mode = SkXfermode::kSrcOver_Mode;
2943         *alpha = 255;
2944     }
2945     *alpha *= mSnapshot->alpha;
2946 }
2947 
getXfermode(SkXfermode * mode)2948 SkXfermode::Mode OpenGLRenderer::getXfermode(SkXfermode* mode) {
2949     SkXfermode::Mode resultMode;
2950     if (!SkXfermode::AsMode(mode, &resultMode)) {
2951         resultMode = SkXfermode::kSrcOver_Mode;
2952     }
2953     return resultMode;
2954 }
2955 
2956 }; // namespace uirenderer
2957 }; // namespace android
2958