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