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 #include <GpuMemoryTracker.h>
18 #include "OpenGLRenderer.h"
19
20 #include "DeferredDisplayList.h"
21 #include "GammaFontRenderer.h"
22 #include "Glop.h"
23 #include "GlopBuilder.h"
24 #include "Patch.h"
25 #include "PathTessellator.h"
26 #include "Properties.h"
27 #include "RenderNode.h"
28 #include "renderstate/MeshState.h"
29 #include "renderstate/RenderState.h"
30 #include "ShadowTessellator.h"
31 #include "SkiaShader.h"
32 #include "Vector.h"
33 #include "VertexBuffer.h"
34 #include "hwui/Canvas.h"
35 #include "utils/GLUtils.h"
36 #include "utils/PaintUtils.h"
37 #include "utils/TraceUtils.h"
38
39 #include <stdlib.h>
40 #include <stdint.h>
41 #include <sys/types.h>
42
43 #include <SkColor.h>
44 #include <SkPaintDefaults.h>
45 #include <SkPathOps.h>
46 #include <SkShader.h>
47 #include <SkTypeface.h>
48
49 #include <utils/Log.h>
50 #include <utils/StopWatch.h>
51
52 #include <private/hwui/DrawGlInfo.h>
53
54 #include <ui/Rect.h>
55
56 #if DEBUG_DETAILED_EVENTS
57 #define EVENT_LOGD(...) eventMarkDEBUG(__VA_ARGS__)
58 #else
59 #define EVENT_LOGD(...)
60 #endif
61
62 namespace android {
63 namespace uirenderer {
64
65 ///////////////////////////////////////////////////////////////////////////////
66 // Constructors/destructor
67 ///////////////////////////////////////////////////////////////////////////////
68
OpenGLRenderer(RenderState & renderState)69 OpenGLRenderer::OpenGLRenderer(RenderState& renderState)
70 : mState(*this)
71 , mCaches(Caches::getInstance())
72 , mRenderState(renderState)
73 , mFrameStarted(false)
74 , mScissorOptimizationDisabled(false)
75 , mDirty(false)
76 , mLightCenter((Vector3){FLT_MIN, FLT_MIN, FLT_MIN})
77 , mLightRadius(FLT_MIN)
78 , mAmbientShadowAlpha(0)
79 , mSpotShadowAlpha(0) {
80 }
81
~OpenGLRenderer()82 OpenGLRenderer::~OpenGLRenderer() {
83 // The context has already been destroyed at this point, do not call
84 // GL APIs. All GL state should be kept in Caches.h
85 }
86
initProperties()87 void OpenGLRenderer::initProperties() {
88 char property[PROPERTY_VALUE_MAX];
89 if (property_get(PROPERTY_DISABLE_SCISSOR_OPTIMIZATION, property, "false")) {
90 mScissorOptimizationDisabled = !strcasecmp(property, "true");
91 INIT_LOGD(" Scissor optimization %s",
92 mScissorOptimizationDisabled ? "disabled" : "enabled");
93 } else {
94 INIT_LOGD(" Scissor optimization enabled");
95 }
96 }
97
initLight(float lightRadius,uint8_t ambientShadowAlpha,uint8_t spotShadowAlpha)98 void OpenGLRenderer::initLight(float lightRadius, uint8_t ambientShadowAlpha,
99 uint8_t spotShadowAlpha) {
100 mLightRadius = lightRadius;
101 mAmbientShadowAlpha = ambientShadowAlpha;
102 mSpotShadowAlpha = spotShadowAlpha;
103 }
104
setLightCenter(const Vector3 & lightCenter)105 void OpenGLRenderer::setLightCenter(const Vector3& lightCenter) {
106 mLightCenter = lightCenter;
107 }
108
109 ///////////////////////////////////////////////////////////////////////////////
110 // Setup
111 ///////////////////////////////////////////////////////////////////////////////
112
onViewportInitialized()113 void OpenGLRenderer::onViewportInitialized() {
114 glDisable(GL_DITHER);
115 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
116 }
117
setupFrameState(int viewportWidth,int viewportHeight,float left,float top,float right,float bottom,bool opaque)118 void OpenGLRenderer::setupFrameState(int viewportWidth, int viewportHeight,
119 float left, float top, float right, float bottom, bool opaque) {
120 mCaches.clearGarbage();
121 mState.initializeSaveStack(viewportWidth, viewportHeight,
122 left, top, right, bottom, mLightCenter);
123 mOpaque = opaque;
124 mTilingClip.set(left, top, right, bottom);
125 }
126
startFrame()127 void OpenGLRenderer::startFrame() {
128 if (mFrameStarted) return;
129 mFrameStarted = true;
130
131 mState.setDirtyClip(true);
132
133 discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom);
134
135 mRenderState.setViewport(mState.getWidth(), mState.getHeight());
136
137 debugOverdraw(true, true);
138
139 clear(mTilingClip.left, mTilingClip.top,
140 mTilingClip.right, mTilingClip.bottom, mOpaque);
141 }
142
prepareDirty(int viewportWidth,int viewportHeight,float left,float top,float right,float bottom,bool opaque)143 void OpenGLRenderer::prepareDirty(int viewportWidth, int viewportHeight,
144 float left, float top, float right, float bottom, bool opaque) {
145
146 setupFrameState(viewportWidth, viewportHeight, left, top, right, bottom, opaque);
147
148 // Layer renderers will start the frame immediately
149 // The framebuffer renderer will first defer the display list
150 // for each layer and wait until the first drawing command
151 // to start the frame
152 if (currentSnapshot()->fbo == 0) {
153 mRenderState.blend().syncEnabled();
154 updateLayers();
155 } else {
156 startFrame();
157 }
158 }
159
discardFramebuffer(float left,float top,float right,float bottom)160 void OpenGLRenderer::discardFramebuffer(float left, float top, float right, float bottom) {
161 // If we know that we are going to redraw the entire framebuffer,
162 // perform a discard to let the driver know we don't need to preserve
163 // the back buffer for this frame.
164 if (mCaches.extensions().hasDiscardFramebuffer() &&
165 left <= 0.0f && top <= 0.0f && right >= mState.getWidth() && bottom >= mState.getHeight()) {
166 const bool isFbo = getTargetFbo() == 0;
167 const GLenum attachments[] = {
168 isFbo ? (const GLenum) GL_COLOR_EXT : (const GLenum) GL_COLOR_ATTACHMENT0,
169 isFbo ? (const GLenum) GL_STENCIL_EXT : (const GLenum) GL_STENCIL_ATTACHMENT };
170 glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, attachments);
171 }
172 }
173
clear(float left,float top,float right,float bottom,bool opaque)174 void OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
175 if (!opaque) {
176 mRenderState.scissor().setEnabled(true);
177 mRenderState.scissor().set(left, getViewportHeight() - bottom, right - left, bottom - top);
178 glClear(GL_COLOR_BUFFER_BIT);
179 mDirty = true;
180 return;
181 }
182
183 mRenderState.scissor().reset();
184 }
185
finish()186 bool OpenGLRenderer::finish() {
187 renderOverdraw();
188 mTempPaths.clear();
189
190 // When finish() is invoked on FBO 0 we've reached the end
191 // of the current frame
192 if (getTargetFbo() == 0) {
193 mCaches.pathCache.trim();
194 mCaches.tessellationCache.trim();
195 }
196
197 if (!suppressErrorChecks()) {
198 GL_CHECKPOINT(MODERATE);
199
200 #if DEBUG_MEMORY_USAGE
201 mCaches.dumpMemoryUsage();
202 GPUMemoryTracker::dump();
203 #else
204 if (Properties::debugLevel & kDebugMemory) {
205 mCaches.dumpMemoryUsage();
206 }
207 #endif
208 }
209
210 mFrameStarted = false;
211
212 return reportAndClearDirty();
213 }
214
resumeAfterLayer()215 void OpenGLRenderer::resumeAfterLayer() {
216 mRenderState.setViewport(getViewportWidth(), getViewportHeight());
217 mRenderState.bindFramebuffer(currentSnapshot()->fbo);
218 debugOverdraw(true, false);
219
220 mRenderState.scissor().reset();
221 dirtyClip();
222 }
223
callDrawGLFunction(Functor * functor,Rect & dirty)224 void OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
225 if (mState.currentlyIgnored()) return;
226
227 Rect clip(mState.currentRenderTargetClip());
228 clip.snapToPixelBoundaries();
229
230 // Since we don't know what the functor will draw, let's dirty
231 // the entire clip region
232 if (hasLayer()) {
233 dirtyLayerUnchecked(clip, getRegion());
234 }
235
236 DrawGlInfo info;
237 info.clipLeft = clip.left;
238 info.clipTop = clip.top;
239 info.clipRight = clip.right;
240 info.clipBottom = clip.bottom;
241 info.isLayer = hasLayer();
242 info.width = getViewportWidth();
243 info.height = getViewportHeight();
244 currentTransform()->copyTo(&info.transform[0]);
245
246 bool prevDirtyClip = mState.getDirtyClip();
247 // setup GL state for functor
248 if (mState.getDirtyClip()) {
249 setStencilFromClip(); // can issue draws, so must precede enableScissor()/interrupt()
250 }
251 if (mRenderState.scissor().setEnabled(true) || prevDirtyClip) {
252 setScissorFromClip();
253 }
254
255 mRenderState.invokeFunctor(functor, DrawGlInfo::kModeDraw, &info);
256 // Scissor may have been modified, reset dirty clip
257 dirtyClip();
258
259 mDirty = true;
260 }
261
262 ///////////////////////////////////////////////////////////////////////////////
263 // Debug
264 ///////////////////////////////////////////////////////////////////////////////
265
eventMarkDEBUG(const char * fmt,...) const266 void OpenGLRenderer::eventMarkDEBUG(const char* fmt, ...) const {
267 #if DEBUG_DETAILED_EVENTS
268 const int BUFFER_SIZE = 256;
269 va_list ap;
270 char buf[BUFFER_SIZE];
271
272 va_start(ap, fmt);
273 vsnprintf(buf, BUFFER_SIZE, fmt, ap);
274 va_end(ap);
275
276 eventMark(buf);
277 #endif
278 }
279
280
eventMark(const char * name) const281 void OpenGLRenderer::eventMark(const char* name) const {
282 mCaches.eventMark(0, name);
283 }
284
startMark(const char * name) const285 void OpenGLRenderer::startMark(const char* name) const {
286 mCaches.startMark(0, name);
287 }
288
endMark() const289 void OpenGLRenderer::endMark() const {
290 mCaches.endMark();
291 }
292
debugOverdraw(bool enable,bool clear)293 void OpenGLRenderer::debugOverdraw(bool enable, bool clear) {
294 mRenderState.debugOverdraw(enable, clear);
295 }
296
renderOverdraw()297 void OpenGLRenderer::renderOverdraw() {
298 if (Properties::debugOverdraw && getTargetFbo() == 0) {
299 const Rect* clip = &mTilingClip;
300
301 mRenderState.scissor().setEnabled(true);
302 mRenderState.scissor().set(clip->left,
303 mState.firstSnapshot()->getViewportHeight() - clip->bottom,
304 clip->right - clip->left,
305 clip->bottom - clip->top);
306
307 // 1x overdraw
308 mRenderState.stencil().enableDebugTest(2);
309 drawColor(mCaches.getOverdrawColor(1), SkXfermode::kSrcOver_Mode);
310
311 // 2x overdraw
312 mRenderState.stencil().enableDebugTest(3);
313 drawColor(mCaches.getOverdrawColor(2), SkXfermode::kSrcOver_Mode);
314
315 // 3x overdraw
316 mRenderState.stencil().enableDebugTest(4);
317 drawColor(mCaches.getOverdrawColor(3), SkXfermode::kSrcOver_Mode);
318
319 // 4x overdraw and higher
320 mRenderState.stencil().enableDebugTest(4, true);
321 drawColor(mCaches.getOverdrawColor(4), SkXfermode::kSrcOver_Mode);
322
323 mRenderState.stencil().disable();
324 }
325 }
326
327 ///////////////////////////////////////////////////////////////////////////////
328 // Layers
329 ///////////////////////////////////////////////////////////////////////////////
330
updateLayer(Layer * layer,bool inFrame)331 bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) {
332 if (layer->deferredUpdateScheduled && layer->renderer
333 && layer->renderNode.get() && layer->renderNode->isRenderable()) {
334
335 if (inFrame) {
336 debugOverdraw(false, false);
337 }
338
339 if (CC_UNLIKELY(inFrame || Properties::drawDeferDisabled)) {
340 layer->render(*this);
341 } else {
342 layer->defer(*this);
343 }
344
345 if (inFrame) {
346 resumeAfterLayer();
347 }
348
349 layer->debugDrawUpdate = Properties::debugLayersUpdates;
350 layer->hasDrawnSinceUpdate = false;
351
352 return true;
353 }
354
355 return false;
356 }
357
updateLayers()358 void OpenGLRenderer::updateLayers() {
359 // If draw deferring is enabled this method will simply defer
360 // the display list of each individual layer. The layers remain
361 // in the layer updates list which will be cleared by flushLayers().
362 int count = mLayerUpdates.size();
363 if (count > 0) {
364 if (CC_UNLIKELY(Properties::drawDeferDisabled)) {
365 startMark("Layer Updates");
366 } else {
367 startMark("Defer Layer Updates");
368 }
369
370 // Note: it is very important to update the layers in order
371 for (int i = 0; i < count; i++) {
372 Layer* layer = mLayerUpdates[i].get();
373 updateLayer(layer, false);
374 }
375
376 if (CC_UNLIKELY(Properties::drawDeferDisabled)) {
377 mLayerUpdates.clear();
378 mRenderState.bindFramebuffer(getTargetFbo());
379 }
380 endMark();
381 }
382 }
383
flushLayers()384 void OpenGLRenderer::flushLayers() {
385 int count = mLayerUpdates.size();
386 if (count > 0) {
387 startMark("Apply Layer Updates");
388
389 // Note: it is very important to update the layers in order
390 for (int i = 0; i < count; i++) {
391 mLayerUpdates[i]->flush();
392 }
393
394 mLayerUpdates.clear();
395 mRenderState.bindFramebuffer(getTargetFbo());
396
397 endMark();
398 }
399 }
400
pushLayerUpdate(Layer * layer)401 void OpenGLRenderer::pushLayerUpdate(Layer* layer) {
402 if (layer) {
403 // Make sure we don't introduce duplicates.
404 // SortedVector would do this automatically but we need to respect
405 // the insertion order. The linear search is not an issue since
406 // this list is usually very short (typically one item, at most a few)
407 for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
408 if (mLayerUpdates[i] == layer) {
409 return;
410 }
411 }
412 mLayerUpdates.push_back(layer);
413 }
414 }
415
cancelLayerUpdate(Layer * layer)416 void OpenGLRenderer::cancelLayerUpdate(Layer* layer) {
417 if (layer) {
418 for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
419 if (mLayerUpdates[i] == layer) {
420 mLayerUpdates.erase(mLayerUpdates.begin() + i);
421 break;
422 }
423 }
424 }
425 }
426
flushLayerUpdates()427 void OpenGLRenderer::flushLayerUpdates() {
428 ATRACE_NAME("Update HW Layers");
429 mRenderState.blend().syncEnabled();
430 updateLayers();
431 flushLayers();
432 // Wait for all the layer updates to be executed
433 glFinish();
434 }
435
markLayersAsBuildLayers()436 void OpenGLRenderer::markLayersAsBuildLayers() {
437 for (size_t i = 0; i < mLayerUpdates.size(); i++) {
438 mLayerUpdates[i]->wasBuildLayered = true;
439 }
440 }
441
442 ///////////////////////////////////////////////////////////////////////////////
443 // State management
444 ///////////////////////////////////////////////////////////////////////////////
445
onSnapshotRestored(const Snapshot & removed,const Snapshot & restored)446 void OpenGLRenderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
447 bool restoreViewport = removed.flags & Snapshot::kFlagIsFboLayer;
448 bool restoreClip = removed.flags & Snapshot::kFlagClipSet;
449 bool restoreLayer = removed.flags & Snapshot::kFlagIsLayer;
450
451 if (restoreViewport) {
452 mRenderState.setViewport(getViewportWidth(), getViewportHeight());
453 }
454
455 if (restoreClip) {
456 dirtyClip();
457 }
458
459 if (restoreLayer) {
460 endMark(); // Savelayer
461 ATRACE_END(); // SaveLayer
462 startMark("ComposeLayer");
463 composeLayer(removed, restored);
464 endMark();
465 }
466 }
467
468 ///////////////////////////////////////////////////////////////////////////////
469 // Layers
470 ///////////////////////////////////////////////////////////////////////////////
471
saveLayer(float left,float top,float right,float bottom,const SkPaint * paint,int flags,const SkPath * convexMask)472 int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
473 const SkPaint* paint, int flags, const SkPath* convexMask) {
474 // force matrix/clip isolation for layer
475 flags |= SaveFlags::MatrixClip;
476
477 const int count = mState.saveSnapshot(flags);
478
479 if (!mState.currentlyIgnored()) {
480 createLayer(left, top, right, bottom, paint, flags, convexMask);
481 }
482
483 return count;
484 }
485
calculateLayerBoundsAndClip(Rect & bounds,Rect & clip,bool fboLayer)486 void OpenGLRenderer::calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool fboLayer) {
487 const Rect untransformedBounds(bounds);
488
489 currentTransform()->mapRect(bounds);
490
491 // Layers only make sense if they are in the framebuffer's bounds
492 bounds.doIntersect(mState.currentRenderTargetClip());
493 if (!bounds.isEmpty()) {
494 // We cannot work with sub-pixels in this case
495 bounds.snapToPixelBoundaries();
496
497 // When the layer is not an FBO, we may use glCopyTexImage so we
498 // need to make sure the layer does not extend outside the bounds
499 // of the framebuffer
500 const Snapshot& previous = *(currentSnapshot()->previous);
501 Rect previousViewport(0, 0, previous.getViewportWidth(), previous.getViewportHeight());
502
503 bounds.doIntersect(previousViewport);
504 if (!bounds.isEmpty() && fboLayer) {
505 clip.set(bounds);
506 mat4 inverse;
507 inverse.loadInverse(*currentTransform());
508 inverse.mapRect(clip);
509 clip.snapToPixelBoundaries();
510 clip.doIntersect(untransformedBounds);
511 if (!clip.isEmpty()) {
512 clip.translate(-untransformedBounds.left, -untransformedBounds.top);
513 bounds.set(untransformedBounds);
514 }
515 }
516 }
517 }
518
updateSnapshotIgnoreForLayer(const Rect & bounds,const Rect & clip,bool fboLayer,int alpha)519 void OpenGLRenderer::updateSnapshotIgnoreForLayer(const Rect& bounds, const Rect& clip,
520 bool fboLayer, int alpha) {
521 if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize ||
522 bounds.getHeight() > mCaches.maxTextureSize ||
523 (fboLayer && clip.isEmpty())) {
524 writableSnapshot()->empty = fboLayer;
525 } else {
526 writableSnapshot()->invisible = writableSnapshot()->invisible || (alpha <= 0 && fboLayer);
527 }
528 }
529
saveLayerDeferred(float left,float top,float right,float bottom,const SkPaint * paint,int flags)530 int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float bottom,
531 const SkPaint* paint, int flags) {
532 const int count = mState.saveSnapshot(flags);
533
534 if (!mState.currentlyIgnored() && (flags & SaveFlags::ClipToLayer)) {
535 // initialize the snapshot as though it almost represents an FBO layer so deferred draw
536 // operations will be able to store and restore the current clip and transform info, and
537 // quick rejection will be correct (for display lists)
538
539 Rect bounds(left, top, right, bottom);
540 Rect clip;
541 calculateLayerBoundsAndClip(bounds, clip, true);
542 updateSnapshotIgnoreForLayer(bounds, clip, true, PaintUtils::getAlphaDirect(paint));
543
544 if (!mState.currentlyIgnored()) {
545 writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f);
546 writableSnapshot()->resetClip(clip.left, clip.top, clip.right, clip.bottom);
547 writableSnapshot()->initializeViewport(bounds.getWidth(), bounds.getHeight());
548 writableSnapshot()->roundRectClipState = nullptr;
549 }
550 }
551
552 return count;
553 }
554
555 /**
556 * Layers are viewed by Skia are slightly different than layers in image editing
557 * programs (for instance.) When a layer is created, previously created layers
558 * and the frame buffer still receive every drawing command. For instance, if a
559 * layer is created and a shape intersecting the bounds of the layers and the
560 * framebuffer is draw, the shape will be drawn on both (unless the layer was
561 * created with the SaveFlags::ClipToLayer flag.)
562 *
563 * A way to implement layers is to create an FBO for each layer, backed by an RGBA
564 * texture. Unfortunately, this is inefficient as it requires every primitive to
565 * be drawn n + 1 times, where n is the number of active layers. In practice this
566 * means, for every primitive:
567 * - Switch active frame buffer
568 * - Change viewport, clip and projection matrix
569 * - Issue the drawing
570 *
571 * Switching rendering target n + 1 times per drawn primitive is extremely costly.
572 * To avoid this, layers are implemented in a different way here, at least in the
573 * general case. FBOs are used, as an optimization, when the "clip to layer" flag
574 * is set. When this flag is set we can redirect all drawing operations into a
575 * single FBO.
576 *
577 * This implementation relies on the frame buffer being at least RGBA 8888. When
578 * a layer is created, only a texture is created, not an FBO. The content of the
579 * frame buffer contained within the layer's bounds is copied into this texture
580 * using glCopyTexImage2D(). The layer's region is then cleared(1) in the frame
581 * buffer and drawing continues as normal. This technique therefore treats the
582 * frame buffer as a scratch buffer for the layers.
583 *
584 * To compose the layers back onto the frame buffer, each layer texture
585 * (containing the original frame buffer data) is drawn as a simple quad over
586 * the frame buffer. The trick is that the quad is set as the composition
587 * destination in the blending equation, and the frame buffer becomes the source
588 * of the composition.
589 *
590 * Drawing layers with an alpha value requires an extra step before composition.
591 * An empty quad is drawn over the layer's region in the frame buffer. This quad
592 * is drawn with the rgba color (0,0,0,alpha). The alpha value offered by the
593 * quad is used to multiply the colors in the frame buffer. This is achieved by
594 * changing the GL blend functions for the GL_FUNC_ADD blend equation to
595 * GL_ZERO, GL_SRC_ALPHA.
596 *
597 * Because glCopyTexImage2D() can be slow, an alternative implementation might
598 * be use to draw a single clipped layer. The implementation described above
599 * is correct in every case.
600 *
601 * (1) The frame buffer is actually not cleared right away. To allow the GPU
602 * to potentially optimize series of calls to glCopyTexImage2D, the frame
603 * buffer is left untouched until the first drawing operation. Only when
604 * something actually gets drawn are the layers regions cleared.
605 */
createLayer(float left,float top,float right,float bottom,const SkPaint * paint,int flags,const SkPath * convexMask)606 bool OpenGLRenderer::createLayer(float left, float top, float right, float bottom,
607 const SkPaint* paint, int flags, const SkPath* convexMask) {
608 LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top);
609 LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
610
611 const bool fboLayer = flags & SaveFlags::ClipToLayer;
612
613 // Window coordinates of the layer
614 Rect clip;
615 Rect bounds(left, top, right, bottom);
616 calculateLayerBoundsAndClip(bounds, clip, fboLayer);
617 updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, PaintUtils::getAlphaDirect(paint));
618
619 // Bail out if we won't draw in this snapshot
620 if (mState.currentlyIgnored()) {
621 return false;
622 }
623
624 mCaches.textureState().activateTexture(0);
625 Layer* layer = mCaches.layerCache.get(mRenderState, bounds.getWidth(), bounds.getHeight());
626 if (!layer) {
627 return false;
628 }
629
630 layer->setPaint(paint);
631 layer->layer.set(bounds);
632 layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()),
633 bounds.getWidth() / float(layer->getWidth()), 0.0f);
634
635 layer->setBlend(true);
636 layer->setDirty(false);
637 layer->setConvexMask(convexMask); // note: the mask must be cleared before returning to the cache
638
639 // Save the layer in the snapshot
640 writableSnapshot()->flags |= Snapshot::kFlagIsLayer;
641 writableSnapshot()->layer = layer;
642
643 ATRACE_FORMAT_BEGIN("%ssaveLayer %ux%u",
644 fboLayer ? "" : "unclipped ",
645 layer->getWidth(), layer->getHeight());
646 startMark("SaveLayer");
647 if (fboLayer) {
648 return createFboLayer(layer, bounds, clip);
649 } else {
650 // Copy the framebuffer into the layer
651 layer->bindTexture();
652 if (!bounds.isEmpty()) {
653 if (layer->isEmpty()) {
654 // Workaround for some GL drivers. When reading pixels lying outside
655 // of the window we should get undefined values for those pixels.
656 // Unfortunately some drivers will turn the entire target texture black
657 // when reading outside of the window.
658 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->getWidth(), layer->getHeight(),
659 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
660 layer->setEmpty(false);
661 }
662
663 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
664 bounds.left, getViewportHeight() - bounds.bottom,
665 bounds.getWidth(), bounds.getHeight());
666
667 // Enqueue the buffer coordinates to clear the corresponding region later
668 mLayers.push_back(Rect(bounds));
669 }
670 }
671
672 return true;
673 }
674
createFboLayer(Layer * layer,Rect & bounds,Rect & clip)675 bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {
676 layer->clipRect.set(clip);
677 layer->setFbo(mRenderState.createFramebuffer());
678
679 writableSnapshot()->region = &writableSnapshot()->layer->region;
680 writableSnapshot()->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
681 writableSnapshot()->fbo = layer->getFbo();
682 writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f);
683 writableSnapshot()->resetClip(clip.left, clip.top, clip.right, clip.bottom);
684 writableSnapshot()->initializeViewport(bounds.getWidth(), bounds.getHeight());
685 writableSnapshot()->roundRectClipState = nullptr;
686
687 debugOverdraw(false, false);
688 // Bind texture to FBO
689 mRenderState.bindFramebuffer(layer->getFbo());
690 layer->bindTexture();
691
692 // Initialize the texture if needed
693 if (layer->isEmpty()) {
694 layer->allocateTexture();
695 layer->setEmpty(false);
696 }
697
698 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
699 layer->getTextureId(), 0);
700
701 // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
702 mRenderState.scissor().setEnabled(true);
703 mRenderState.scissor().set(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
704 clip.getWidth() + 2.0f, clip.getHeight() + 2.0f);
705 glClear(GL_COLOR_BUFFER_BIT);
706
707 dirtyClip();
708
709 // Change the ortho projection
710 mRenderState.setViewport(bounds.getWidth(), bounds.getHeight());
711 return true;
712 }
713
714 /**
715 * Read the documentation of createLayer() before doing anything in this method.
716 */
composeLayer(const Snapshot & removed,const Snapshot & restored)717 void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& restored) {
718 if (!removed.layer) {
719 ALOGE("Attempting to compose a layer that does not exist");
720 return;
721 }
722
723 Layer* layer = removed.layer;
724 const Rect& rect = layer->layer;
725 const bool fboLayer = removed.flags & Snapshot::kFlagIsFboLayer;
726
727 bool clipRequired = false;
728 mState.calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom,
729 &clipRequired, nullptr, false); // safely ignore return, should never be rejected
730 mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
731
732 if (fboLayer) {
733 // Detach the texture from the FBO
734 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
735
736 layer->removeFbo(false);
737
738 // Unbind current FBO and restore previous one
739 mRenderState.bindFramebuffer(restored.fbo);
740 debugOverdraw(true, false);
741 }
742
743 if (!fboLayer && layer->getAlpha() < 255) {
744 SkPaint layerPaint;
745 layerPaint.setAlpha(layer->getAlpha());
746 layerPaint.setXfermodeMode(SkXfermode::kDstIn_Mode);
747 layerPaint.setColorFilter(layer->getColorFilter());
748
749 drawColorRect(rect.left, rect.top, rect.right, rect.bottom, &layerPaint, true);
750 // Required below, composeLayerRect() will divide by 255
751 layer->setAlpha(255);
752 }
753
754 mRenderState.meshState().unbindMeshBuffer();
755
756 mCaches.textureState().activateTexture(0);
757
758 // When the layer is stored in an FBO, we can save a bit of fillrate by
759 // drawing only the dirty region
760 if (fboLayer) {
761 dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *restored.transform);
762 composeLayerRegion(layer, rect);
763 } else if (!rect.isEmpty()) {
764 dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
765
766 save(0);
767 // the layer contains screen buffer content that shouldn't be alpha modulated
768 // (and any necessary alpha modulation was handled drawing into the layer)
769 writableSnapshot()->alpha = 1.0f;
770 composeLayerRectSwapped(layer, rect);
771 restore();
772 }
773
774 dirtyClip();
775
776 // Failing to add the layer to the cache should happen only if the layer is too large
777 layer->setConvexMask(nullptr);
778 if (!mCaches.layerCache.put(layer)) {
779 LAYER_LOGD("Deleting layer");
780 layer->decStrong(nullptr);
781 }
782 }
783
drawTextureLayer(Layer * layer,const Rect & rect)784 void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
785 const bool tryToSnap = !layer->getForceFilter()
786 && layer->getWidth() == (uint32_t) rect.getWidth()
787 && layer->getHeight() == (uint32_t) rect.getHeight();
788 Glop glop;
789 GlopBuilder(mRenderState, mCaches, &glop)
790 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
791 .setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
792 .setFillTextureLayer(*layer, getLayerAlpha(layer))
793 .setTransform(*currentSnapshot(), TransformFlags::None)
794 .setModelViewMapUnitToRectOptionalSnap(tryToSnap, rect)
795 .build();
796 renderGlop(glop);
797 }
798
composeLayerRectSwapped(Layer * layer,const Rect & rect)799 void OpenGLRenderer::composeLayerRectSwapped(Layer* layer, const Rect& rect) {
800 Glop glop;
801 GlopBuilder(mRenderState, mCaches, &glop)
802 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
803 .setMeshTexturedUvQuad(nullptr, layer->texCoords)
804 .setFillLayer(layer->getTexture(), layer->getColorFilter(),
805 getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::Swap)
806 .setTransform(*currentSnapshot(), TransformFlags::MeshIgnoresCanvasTransform)
807 .setModelViewMapUnitToRect(rect)
808 .build();
809 renderGlop(glop);
810 }
811
composeLayerRect(Layer * layer,const Rect & rect)812 void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect) {
813 if (layer->isTextureLayer()) {
814 EVENT_LOGD("composeTextureLayerRect");
815 drawTextureLayer(layer, rect);
816 } else {
817 EVENT_LOGD("composeHardwareLayerRect");
818
819 const bool tryToSnap = layer->getWidth() == static_cast<uint32_t>(rect.getWidth())
820 && layer->getHeight() == static_cast<uint32_t>(rect.getHeight());
821 Glop glop;
822 GlopBuilder(mRenderState, mCaches, &glop)
823 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
824 .setMeshTexturedUvQuad(nullptr, layer->texCoords)
825 .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
826 .setTransform(*currentSnapshot(), TransformFlags::None)
827 .setModelViewMapUnitToRectOptionalSnap(tryToSnap, rect)
828 .build();
829 renderGlop(glop);
830 }
831 }
832
833 /**
834 * Issues the command X, and if we're composing a save layer to the fbo or drawing a newly updated
835 * hardware layer with overdraw debug on, draws again to the stencil only, so that these draw
836 * operations are correctly counted twice for overdraw. NOTE: assumes composeLayerRegion only used
837 * by saveLayer's restore
838 */
839 #define DRAW_DOUBLE_STENCIL_IF(COND, DRAW_COMMAND) { \
840 DRAW_COMMAND; \
841 if (CC_UNLIKELY(Properties::debugOverdraw && getTargetFbo() == 0 && COND)) { \
842 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); \
843 DRAW_COMMAND; \
844 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); \
845 } \
846 }
847
848 #define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND)
849
850 // This class is purely for inspection. It inherits from SkShader, but Skia does not know how to
851 // use it. The OpenGLRenderer will look at it to find its Layer and whether it is opaque.
852 class LayerShader : public SkShader {
853 public:
LayerShader(Layer * layer,const SkMatrix * localMatrix)854 LayerShader(Layer* layer, const SkMatrix* localMatrix)
855 : INHERITED(localMatrix)
856 , mLayer(layer) {
857 }
858
asACustomShader(void ** data) const859 virtual bool asACustomShader(void** data) const override {
860 if (data) {
861 *data = static_cast<void*>(mLayer);
862 }
863 return true;
864 }
865
isOpaque() const866 virtual bool isOpaque() const override {
867 return !mLayer->isBlend();
868 }
869
870 protected:
shadeSpan(int x,int y,SkPMColor[],int count)871 virtual void shadeSpan(int x, int y, SkPMColor[], int count) {
872 LOG_ALWAYS_FATAL("LayerShader should never be drawn with raster backend.");
873 }
874
flatten(SkWriteBuffer &) const875 virtual void flatten(SkWriteBuffer&) const override {
876 LOG_ALWAYS_FATAL("LayerShader should never be flattened.");
877 }
878
getFactory() const879 virtual Factory getFactory() const override {
880 LOG_ALWAYS_FATAL("LayerShader should never be created from a stream.");
881 return nullptr;
882 }
883 private:
884 // Unowned.
885 Layer* mLayer;
886 typedef SkShader INHERITED;
887 };
888
composeLayerRegion(Layer * layer,const Rect & rect)889 void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
890 if (CC_UNLIKELY(layer->region.isEmpty())) return; // nothing to draw
891
892 if (layer->getConvexMask()) {
893 save(SaveFlags::MatrixClip);
894
895 // clip to the area of the layer the mask can be larger
896 clipRect(rect.left, rect.top, rect.right, rect.bottom, SkRegion::kIntersect_Op);
897
898 SkPaint paint;
899 paint.setAntiAlias(true);
900 paint.setColor(SkColorSetARGB(int(getLayerAlpha(layer) * 255), 0, 0, 0));
901
902 // create LayerShader to map SaveLayer content into subsequent draw
903 SkMatrix shaderMatrix;
904 shaderMatrix.setTranslate(rect.left, rect.bottom);
905 shaderMatrix.preScale(1, -1);
906 LayerShader layerShader(layer, &shaderMatrix);
907 paint.setShader(&layerShader);
908
909 // Since the drawing primitive is defined in local drawing space,
910 // we don't need to modify the draw matrix
911 const SkPath* maskPath = layer->getConvexMask();
912 DRAW_DOUBLE_STENCIL(drawConvexPath(*maskPath, &paint));
913
914 paint.setShader(nullptr);
915 restore();
916
917 return;
918 }
919
920 if (layer->region.isRect()) {
921 layer->setRegionAsRect();
922
923 DRAW_DOUBLE_STENCIL(composeLayerRect(layer, layer->regionRect));
924
925 layer->region.clear();
926 return;
927 }
928
929 EVENT_LOGD("composeLayerRegion");
930 // standard Region based draw
931 size_t count;
932 const android::Rect* rects;
933 Region safeRegion;
934 if (CC_LIKELY(hasRectToRectTransform())) {
935 rects = layer->region.getArray(&count);
936 } else {
937 safeRegion = Region::createTJunctionFreeRegion(layer->region);
938 rects = safeRegion.getArray(&count);
939 }
940
941 const float texX = 1.0f / float(layer->getWidth());
942 const float texY = 1.0f / float(layer->getHeight());
943 const float height = rect.getHeight();
944
945 TextureVertex quadVertices[count * 4];
946 TextureVertex* mesh = &quadVertices[0];
947 for (size_t i = 0; i < count; i++) {
948 const android::Rect* r = &rects[i];
949
950 const float u1 = r->left * texX;
951 const float v1 = (height - r->top) * texY;
952 const float u2 = r->right * texX;
953 const float v2 = (height - r->bottom) * texY;
954
955 // TODO: Reject quads outside of the clip
956 TextureVertex::set(mesh++, r->left, r->top, u1, v1);
957 TextureVertex::set(mesh++, r->right, r->top, u2, v1);
958 TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
959 TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
960 }
961 Rect modelRect = Rect(rect.getWidth(), rect.getHeight());
962 Glop glop;
963 GlopBuilder(mRenderState, mCaches, &glop)
964 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
965 .setMeshTexturedIndexedQuads(&quadVertices[0], count * 6)
966 .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
967 .setTransform(*currentSnapshot(), TransformFlags::None)
968 .setModelViewOffsetRectSnap(rect.left, rect.top, modelRect)
969 .build();
970 DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
971
972 #if DEBUG_LAYERS_AS_REGIONS
973 drawRegionRectsDebug(layer->region);
974 #endif
975
976 layer->region.clear();
977 }
978
979 #if DEBUG_LAYERS_AS_REGIONS
drawRegionRectsDebug(const Region & region)980 void OpenGLRenderer::drawRegionRectsDebug(const Region& region) {
981 size_t count;
982 const android::Rect* rects = region.getArray(&count);
983
984 uint32_t colors[] = {
985 0x7fff0000, 0x7f00ff00,
986 0x7f0000ff, 0x7fff00ff,
987 };
988
989 int offset = 0;
990 int32_t top = rects[0].top;
991
992 for (size_t i = 0; i < count; i++) {
993 if (top != rects[i].top) {
994 offset ^= 0x2;
995 top = rects[i].top;
996 }
997
998 SkPaint paint;
999 paint.setColor(colors[offset + (i & 0x1)]);
1000 Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom);
1001 drawColorRect(r.left, r.top, r.right, r.bottom, paint);
1002 }
1003 }
1004 #endif
1005
drawRegionRects(const SkRegion & region,const SkPaint & paint,bool dirty)1006 void OpenGLRenderer::drawRegionRects(const SkRegion& region, const SkPaint& paint, bool dirty) {
1007 Vector<float> rects;
1008
1009 SkRegion::Iterator it(region);
1010 while (!it.done()) {
1011 const SkIRect& r = it.rect();
1012 rects.push(r.fLeft);
1013 rects.push(r.fTop);
1014 rects.push(r.fRight);
1015 rects.push(r.fBottom);
1016 it.next();
1017 }
1018
1019 drawColorRects(rects.array(), rects.size(), &paint, true, dirty, false);
1020 }
1021
dirtyLayer(const float left,const float top,const float right,const float bottom,const Matrix4 & transform)1022 void OpenGLRenderer::dirtyLayer(const float left, const float top,
1023 const float right, const float bottom, const Matrix4& transform) {
1024 if (hasLayer()) {
1025 Rect bounds(left, top, right, bottom);
1026 transform.mapRect(bounds);
1027 dirtyLayerUnchecked(bounds, getRegion());
1028 }
1029 }
1030
dirtyLayer(const float left,const float top,const float right,const float bottom)1031 void OpenGLRenderer::dirtyLayer(const float left, const float top,
1032 const float right, const float bottom) {
1033 if (hasLayer()) {
1034 Rect bounds(left, top, right, bottom);
1035 dirtyLayerUnchecked(bounds, getRegion());
1036 }
1037 }
1038
dirtyLayerUnchecked(Rect & bounds,Region * region)1039 void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) {
1040 bounds.doIntersect(mState.currentRenderTargetClip());
1041 if (!bounds.isEmpty()) {
1042 bounds.snapToPixelBoundaries();
1043 android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
1044 if (!dirty.isEmpty()) {
1045 region->orSelf(dirty);
1046 }
1047 }
1048 }
1049
clearLayerRegions()1050 void OpenGLRenderer::clearLayerRegions() {
1051 const size_t quadCount = mLayers.size();
1052 if (quadCount == 0) return;
1053
1054 if (!mState.currentlyIgnored()) {
1055 EVENT_LOGD("clearLayerRegions");
1056 // Doing several glScissor/glClear here can negatively impact
1057 // GPUs with a tiler architecture, instead we draw quads with
1058 // the Clear blending mode
1059
1060 // The list contains bounds that have already been clipped
1061 // against their initial clip rect, and the current clip
1062 // is likely different so we need to disable clipping here
1063 bool scissorChanged = mRenderState.scissor().setEnabled(false);
1064
1065 Vertex mesh[quadCount * 4];
1066 Vertex* vertex = mesh;
1067
1068 for (uint32_t i = 0; i < quadCount; i++) {
1069 const Rect& bounds = mLayers[i];
1070
1071 Vertex::set(vertex++, bounds.left, bounds.top);
1072 Vertex::set(vertex++, bounds.right, bounds.top);
1073 Vertex::set(vertex++, bounds.left, bounds.bottom);
1074 Vertex::set(vertex++, bounds.right, bounds.bottom);
1075 }
1076 // We must clear the list of dirty rects before we
1077 // call clearLayerRegions() in renderGlop to prevent
1078 // stencil setup from doing the same thing again
1079 mLayers.clear();
1080
1081 const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform;
1082 Glop glop;
1083 GlopBuilder(mRenderState, mCaches, &glop)
1084 .setRoundRectClipState(nullptr) // clear ignores clip state
1085 .setMeshIndexedQuads(&mesh[0], quadCount)
1086 .setFillClear()
1087 .setTransform(*currentSnapshot(), transformFlags)
1088 .setModelViewOffsetRect(0, 0, Rect(currentSnapshot()->getRenderTargetClip()))
1089 .build();
1090 renderGlop(glop, GlopRenderType::LayerClear);
1091
1092 if (scissorChanged) mRenderState.scissor().setEnabled(true);
1093 } else {
1094 mLayers.clear();
1095 }
1096 }
1097
1098 ///////////////////////////////////////////////////////////////////////////////
1099 // State Deferral
1100 ///////////////////////////////////////////////////////////////////////////////
1101
storeDisplayState(DeferredDisplayState & state,int stateDeferFlags)1102 bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) {
1103 const Rect& currentClip = mState.currentRenderTargetClip();
1104 const mat4* currentMatrix = currentTransform();
1105
1106 if (stateDeferFlags & kStateDeferFlag_Draw) {
1107 // state has bounds initialized in local coordinates
1108 if (!state.mBounds.isEmpty()) {
1109 currentMatrix->mapRect(state.mBounds);
1110 Rect clippedBounds(state.mBounds);
1111 // NOTE: if we ever want to use this clipping info to drive whether the scissor
1112 // is used, it should more closely duplicate the quickReject logic (in how it uses
1113 // snapToPixelBoundaries)
1114
1115 clippedBounds.doIntersect(currentClip);
1116 if (clippedBounds.isEmpty()) {
1117 // quick rejected
1118 return true;
1119 }
1120
1121 state.mClipSideFlags = kClipSide_None;
1122 if (!currentClip.contains(state.mBounds)) {
1123 int& flags = state.mClipSideFlags;
1124 // op partially clipped, so record which sides are clipped for clip-aware merging
1125 if (currentClip.left > state.mBounds.left) flags |= kClipSide_Left;
1126 if (currentClip.top > state.mBounds.top) flags |= kClipSide_Top;
1127 if (currentClip.right < state.mBounds.right) flags |= kClipSide_Right;
1128 if (currentClip.bottom < state.mBounds.bottom) flags |= kClipSide_Bottom;
1129 }
1130 state.mBounds.set(clippedBounds);
1131 } else {
1132 // Empty bounds implies size unknown. Label op as conservatively clipped to disable
1133 // overdraw avoidance (since we don't know what it overlaps)
1134 state.mClipSideFlags = kClipSide_ConservativeFull;
1135 state.mBounds.set(currentClip);
1136 }
1137 }
1138
1139 state.mClipValid = (stateDeferFlags & kStateDeferFlag_Clip);
1140 if (state.mClipValid) {
1141 state.mClip.set(currentClip);
1142 }
1143
1144 // Transform and alpha always deferred, since they are used by state operations
1145 // (Note: saveLayer/restore use colorFilter and alpha, so we just save restore everything)
1146 state.mMatrix = *currentMatrix;
1147 state.mAlpha = currentSnapshot()->alpha;
1148
1149 // always store/restore, since these are just pointers
1150 state.mRoundRectClipState = currentSnapshot()->roundRectClipState;
1151 #if !HWUI_NEW_OPS
1152 state.mProjectionPathMask = currentSnapshot()->projectionPathMask;
1153 #endif
1154 return false;
1155 }
1156
restoreDisplayState(const DeferredDisplayState & state,bool skipClipRestore)1157 void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) {
1158 setGlobalMatrix(state.mMatrix);
1159 writableSnapshot()->alpha = state.mAlpha;
1160 writableSnapshot()->roundRectClipState = state.mRoundRectClipState;
1161 #if !HWUI_NEW_OPS
1162 writableSnapshot()->projectionPathMask = state.mProjectionPathMask;
1163 #endif
1164
1165 if (state.mClipValid && !skipClipRestore) {
1166 writableSnapshot()->setClip(state.mClip.left, state.mClip.top,
1167 state.mClip.right, state.mClip.bottom);
1168 dirtyClip();
1169 }
1170 }
1171
1172 /**
1173 * Merged multidraw (such as in drawText and drawBitmaps rely on the fact that no clipping is done
1174 * in the draw path. Instead, clipping is done ahead of time - either as a single clip rect (when at
1175 * least one op is clipped), or disabled entirely (because no merged op is clipped)
1176 *
1177 * This method should be called when restoreDisplayState() won't be restoring the clip
1178 */
setupMergedMultiDraw(const Rect * clipRect)1179 void OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) {
1180 if (clipRect != nullptr) {
1181 writableSnapshot()->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
1182 } else {
1183 writableSnapshot()->setClip(0, 0, mState.getWidth(), mState.getHeight());
1184 }
1185 dirtyClip();
1186 bool enableScissor = (clipRect != nullptr) || mScissorOptimizationDisabled;
1187 mRenderState.scissor().setEnabled(enableScissor);
1188 }
1189
1190 ///////////////////////////////////////////////////////////////////////////////
1191 // Clipping
1192 ///////////////////////////////////////////////////////////////////////////////
1193
setScissorFromClip()1194 void OpenGLRenderer::setScissorFromClip() {
1195 Rect clip(mState.currentRenderTargetClip());
1196 clip.snapToPixelBoundaries();
1197
1198 if (mRenderState.scissor().set(clip.left, getViewportHeight() - clip.bottom,
1199 clip.getWidth(), clip.getHeight())) {
1200 mState.setDirtyClip(false);
1201 }
1202 }
1203
ensureStencilBuffer()1204 void OpenGLRenderer::ensureStencilBuffer() {
1205 // Thanks to the mismatch between EGL and OpenGL ES FBO we
1206 // cannot attach a stencil buffer to fbo0 dynamically. Let's
1207 // just hope we have one when hasLayer() returns false.
1208 if (hasLayer()) {
1209 attachStencilBufferToLayer(currentSnapshot()->layer);
1210 }
1211 }
1212
attachStencilBufferToLayer(Layer * layer)1213 void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) {
1214 // The layer's FBO is already bound when we reach this stage
1215 if (!layer->getStencilRenderBuffer()) {
1216 RenderBuffer* buffer = mCaches.renderBufferCache.get(
1217 Stencil::getLayerStencilFormat(),
1218 layer->getWidth(), layer->getHeight());
1219 layer->setStencilRenderBuffer(buffer);
1220 }
1221 }
1222
handlePoint(std::vector<Vertex> & rectangleVertices,const Matrix4 & transform,float x,float y)1223 static void handlePoint(std::vector<Vertex>& rectangleVertices, const Matrix4& transform,
1224 float x, float y) {
1225 Vertex v;
1226 v.x = x;
1227 v.y = y;
1228 transform.mapPoint(v.x, v.y);
1229 rectangleVertices.push_back(v);
1230 }
1231
handlePointNoTransform(std::vector<Vertex> & rectangleVertices,float x,float y)1232 static void handlePointNoTransform(std::vector<Vertex>& rectangleVertices, float x, float y) {
1233 Vertex v;
1234 v.x = x;
1235 v.y = y;
1236 rectangleVertices.push_back(v);
1237 }
1238
drawRectangleList(const RectangleList & rectangleList)1239 void OpenGLRenderer::drawRectangleList(const RectangleList& rectangleList) {
1240 int quadCount = rectangleList.getTransformedRectanglesCount();
1241 std::vector<Vertex> rectangleVertices(quadCount * 4);
1242 Rect scissorBox = rectangleList.calculateBounds();
1243 scissorBox.snapToPixelBoundaries();
1244 for (int i = 0; i < quadCount; ++i) {
1245 const TransformedRectangle& tr(rectangleList.getTransformedRectangle(i));
1246 const Matrix4& transform = tr.getTransform();
1247 Rect bounds = tr.getBounds();
1248 if (transform.rectToRect()) {
1249 transform.mapRect(bounds);
1250 bounds.doIntersect(scissorBox);
1251 if (!bounds.isEmpty()) {
1252 handlePointNoTransform(rectangleVertices, bounds.left, bounds.top);
1253 handlePointNoTransform(rectangleVertices, bounds.right, bounds.top);
1254 handlePointNoTransform(rectangleVertices, bounds.left, bounds.bottom);
1255 handlePointNoTransform(rectangleVertices, bounds.right, bounds.bottom);
1256 }
1257 } else {
1258 handlePoint(rectangleVertices, transform, bounds.left, bounds.top);
1259 handlePoint(rectangleVertices, transform, bounds.right, bounds.top);
1260 handlePoint(rectangleVertices, transform, bounds.left, bounds.bottom);
1261 handlePoint(rectangleVertices, transform, bounds.right, bounds.bottom);
1262 }
1263 }
1264
1265 mRenderState.scissor().set(scissorBox.left, getViewportHeight() - scissorBox.bottom,
1266 scissorBox.getWidth(), scissorBox.getHeight());
1267 const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform;
1268 Glop glop;
1269 Vertex* vertices = &rectangleVertices[0];
1270 GlopBuilder(mRenderState, mCaches, &glop)
1271 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
1272 .setMeshIndexedQuads(vertices, rectangleVertices.size() / 4)
1273 .setFillBlack()
1274 .setTransform(*currentSnapshot(), transformFlags)
1275 .setModelViewOffsetRect(0, 0, scissorBox)
1276 .build();
1277 renderGlop(glop);
1278 }
1279
setStencilFromClip()1280 void OpenGLRenderer::setStencilFromClip() {
1281 if (!Properties::debugOverdraw) {
1282 if (!currentSnapshot()->clipIsSimple()) {
1283 int incrementThreshold;
1284 EVENT_LOGD("setStencilFromClip - enabling");
1285
1286 // NOTE: The order here is important, we must set dirtyClip to false
1287 // before any draw call to avoid calling back into this method
1288 mState.setDirtyClip(false);
1289
1290 ensureStencilBuffer();
1291
1292 const ClipArea& clipArea = currentSnapshot()->getClipArea();
1293
1294 bool isRectangleList = clipArea.isRectangleList();
1295 if (isRectangleList) {
1296 incrementThreshold = clipArea.getRectangleList().getTransformedRectanglesCount();
1297 } else {
1298 incrementThreshold = 0;
1299 }
1300
1301 mRenderState.stencil().enableWrite(incrementThreshold);
1302
1303 // Clean and update the stencil, but first make sure we restrict drawing
1304 // to the region's bounds
1305 bool resetScissor = mRenderState.scissor().setEnabled(true);
1306 if (resetScissor) {
1307 // The scissor was not set so we now need to update it
1308 setScissorFromClip();
1309 }
1310
1311 mRenderState.stencil().clear();
1312
1313 // stash and disable the outline clip state, since stencil doesn't account for outline
1314 bool storedSkipOutlineClip = mSkipOutlineClip;
1315 mSkipOutlineClip = true;
1316
1317 SkPaint paint;
1318 paint.setColor(SK_ColorBLACK);
1319 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
1320
1321 if (isRectangleList) {
1322 drawRectangleList(clipArea.getRectangleList());
1323 } else {
1324 // NOTE: We could use the region contour path to generate a smaller mesh
1325 // Since we are using the stencil we could use the red book path
1326 // drawing technique. It might increase bandwidth usage though.
1327
1328 // The last parameter is important: we are not drawing in the color buffer
1329 // so we don't want to dirty the current layer, if any
1330 drawRegionRects(clipArea.getClipRegion(), paint, false);
1331 }
1332 if (resetScissor) mRenderState.scissor().setEnabled(false);
1333 mSkipOutlineClip = storedSkipOutlineClip;
1334
1335 mRenderState.stencil().enableTest(incrementThreshold);
1336
1337 // Draw the region used to generate the stencil if the appropriate debug
1338 // mode is enabled
1339 // TODO: Implement for rectangle list clip areas
1340 if (Properties::debugStencilClip == StencilClipDebug::ShowRegion
1341 && !clipArea.isRectangleList()) {
1342 paint.setColor(0x7f0000ff);
1343 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
1344 drawRegionRects(currentSnapshot()->getClipRegion(), paint);
1345 }
1346 } else {
1347 EVENT_LOGD("setStencilFromClip - disabling");
1348 mRenderState.stencil().disable();
1349 }
1350 }
1351 }
1352
1353 /**
1354 * Returns false and sets scissor enable based upon bounds if drawing won't be clipped out.
1355 *
1356 * @param paint if not null, the bounds will be expanded to account for stroke depending on paint
1357 * style, and tessellated AA ramp
1358 */
quickRejectSetupScissor(float left,float top,float right,float bottom,const SkPaint * paint)1359 bool OpenGLRenderer::quickRejectSetupScissor(float left, float top, float right, float bottom,
1360 const SkPaint* paint) {
1361 bool snapOut = paint && paint->isAntiAlias();
1362
1363 if (paint && paint->getStyle() != SkPaint::kFill_Style) {
1364 float outset = paint->getStrokeWidth() * 0.5f;
1365 left -= outset;
1366 top -= outset;
1367 right += outset;
1368 bottom += outset;
1369 }
1370
1371 bool clipRequired = false;
1372 bool roundRectClipRequired = false;
1373 if (mState.calculateQuickRejectForScissor(left, top, right, bottom,
1374 &clipRequired, &roundRectClipRequired, snapOut)) {
1375 return true;
1376 }
1377
1378 // not quick rejected, so enable the scissor if clipRequired
1379 mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
1380 mSkipOutlineClip = !roundRectClipRequired;
1381 return false;
1382 }
1383
debugClip()1384 void OpenGLRenderer::debugClip() {
1385 #if DEBUG_CLIP_REGIONS
1386 if (!currentSnapshot()->clipRegion->isEmpty()) {
1387 SkPaint paint;
1388 paint.setColor(0x7f00ff00);
1389 drawRegionRects(*(currentSnapshot()->clipRegion, paint);
1390
1391 }
1392 #endif
1393 }
1394
1395 void OpenGLRenderer::renderGlop(const Glop& glop, GlopRenderType type) {
1396 // TODO: It would be best if we could do this before quickRejectSetupScissor()
1397 // changes the scissor test state
1398 if (type != GlopRenderType::LayerClear) {
1399 // Regular draws need to clear the dirty area on the layer before they start drawing on top
1400 // of it. If this draw *is* a layer clear, it skips the clear step (since it would
1401 // infinitely recurse)
1402 clearLayerRegions();
1403 }
1404
1405 if (mState.getDirtyClip()) {
1406 if (mRenderState.scissor().isEnabled()) {
1407 setScissorFromClip();
1408 }
1409
1410 setStencilFromClip();
1411 }
1412 mRenderState.render(glop, currentSnapshot()->getOrthoMatrix());
1413 if (type == GlopRenderType::Standard && !mRenderState.stencil().isWriteEnabled()) {
1414 // TODO: specify more clearly when a draw should dirty the layer.
1415 // is writing to the stencil the only time we should ignore this?
1416 #if !HWUI_NEW_OPS
1417 dirtyLayer(glop.bounds.left, glop.bounds.top, glop.bounds.right, glop.bounds.bottom);
1418 #endif
1419 mDirty = true;
1420 }
1421 }
1422
1423 ///////////////////////////////////////////////////////////////////////////////
1424 // Drawing
1425 ///////////////////////////////////////////////////////////////////////////////
1426
1427 void OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags) {
1428 // All the usual checks and setup operations (quickReject, setupDraw, etc.)
1429 // will be performed by the display list itself
1430 if (renderNode && renderNode->isRenderable()) {
1431 // compute 3d ordering
1432 renderNode->computeOrdering();
1433 if (CC_UNLIKELY(Properties::drawDeferDisabled)) {
1434 startFrame();
1435 ReplayStateStruct replayStruct(*this, dirty, replayFlags);
1436 renderNode->replay(replayStruct, 0);
1437 return;
1438 }
1439
1440 DeferredDisplayList deferredList(mState.currentRenderTargetClip());
1441 DeferStateStruct deferStruct(deferredList, *this, replayFlags);
1442 renderNode->defer(deferStruct, 0);
1443
1444 flushLayers();
1445 startFrame();
1446
1447 deferredList.flush(*this, dirty);
1448 } else {
1449 // Even if there is no drawing command(Ex: invisible),
1450 // it still needs startFrame to clear buffer and start tiling.
1451 startFrame();
1452 }
1453 }
1454
1455 /**
1456 * Important note: this method is intended to draw batches of bitmaps and
1457 * will not set the scissor enable or dirty the current layer, if any.
1458 * The caller is responsible for properly dirtying the current layer.
1459 */
1460 void OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
1461 int bitmapCount, TextureVertex* vertices, bool pureTranslate,
1462 const Rect& bounds, const SkPaint* paint) {
1463 Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
1464 if (!texture) return;
1465
1466 const AutoTexture autoCleanup(texture);
1467
1468 // TODO: remove layer dirty in multi-draw callers
1469 // TODO: snap doesn't need to touch transform, only texture filter.
1470 bool snap = pureTranslate;
1471 const float x = floorf(bounds.left + 0.5f);
1472 const float y = floorf(bounds.top + 0.5f);
1473
1474 const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType)
1475 ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
1476 const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform;
1477 Glop glop;
1478 GlopBuilder(mRenderState, mCaches, &glop)
1479 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
1480 .setMeshTexturedMesh(vertices, bitmapCount * 6)
1481 .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
1482 .setTransform(*currentSnapshot(), transformFlags)
1483 .setModelViewOffsetRectOptionalSnap(snap, x, y, Rect(bounds.getWidth(), bounds.getHeight()))
1484 .build();
1485 renderGlop(glop, GlopRenderType::Multi);
1486 }
1487
1488 void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
1489 if (quickRejectSetupScissor(0, 0, bitmap->width(), bitmap->height())) {
1490 return;
1491 }
1492
1493 mCaches.textureState().activateTexture(0);
1494 Texture* texture = getTexture(bitmap);
1495 if (!texture) return;
1496 const AutoTexture autoCleanup(texture);
1497
1498 const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType)
1499 ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
1500 Glop glop;
1501 GlopBuilder(mRenderState, mCaches, &glop)
1502 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
1503 .setMeshTexturedUnitQuad(texture->uvMapper)
1504 .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
1505 .setTransform(*currentSnapshot(), TransformFlags::None)
1506 .setModelViewMapUnitToRectSnap(Rect(texture->width(), texture->height()))
1507 .build();
1508 renderGlop(glop);
1509 }
1510
1511 void OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
1512 const float* vertices, const int* colors, const SkPaint* paint) {
1513 if (!vertices || mState.currentlyIgnored()) {
1514 return;
1515 }
1516
1517 float left = FLT_MAX;
1518 float top = FLT_MAX;
1519 float right = FLT_MIN;
1520 float bottom = FLT_MIN;
1521
1522 const uint32_t elementCount = meshWidth * meshHeight * 6;
1523
1524 std::unique_ptr<ColorTextureVertex[]> mesh(new ColorTextureVertex[elementCount]);
1525 ColorTextureVertex* vertex = &mesh[0];
1526
1527 std::unique_ptr<int[]> tempColors;
1528 if (!colors) {
1529 uint32_t colorsCount = (meshWidth + 1) * (meshHeight + 1);
1530 tempColors.reset(new int[colorsCount]);
1531 memset(tempColors.get(), 0xff, colorsCount * sizeof(int));
1532 colors = tempColors.get();
1533 }
1534
1535 Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap->pixelRef());
1536 const UvMapper& mapper(getMapper(texture));
1537
1538 for (int32_t y = 0; y < meshHeight; y++) {
1539 for (int32_t x = 0; x < meshWidth; x++) {
1540 uint32_t i = (y * (meshWidth + 1) + x) * 2;
1541
1542 float u1 = float(x) / meshWidth;
1543 float u2 = float(x + 1) / meshWidth;
1544 float v1 = float(y) / meshHeight;
1545 float v2 = float(y + 1) / meshHeight;
1546
1547 mapper.map(u1, v1, u2, v2);
1548
1549 int ax = i + (meshWidth + 1) * 2;
1550 int ay = ax + 1;
1551 int bx = i;
1552 int by = bx + 1;
1553 int cx = i + 2;
1554 int cy = cx + 1;
1555 int dx = i + (meshWidth + 1) * 2 + 2;
1556 int dy = dx + 1;
1557
1558 ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
1559 ColorTextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2, colors[ax / 2]);
1560 ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
1561
1562 ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
1563 ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
1564 ColorTextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1, colors[cx / 2]);
1565
1566 left = std::min(left, std::min(vertices[ax], std::min(vertices[bx], vertices[cx])));
1567 top = std::min(top, std::min(vertices[ay], std::min(vertices[by], vertices[cy])));
1568 right = std::max(right, std::max(vertices[ax], std::max(vertices[bx], vertices[cx])));
1569 bottom = std::max(bottom, std::max(vertices[ay], std::max(vertices[by], vertices[cy])));
1570 }
1571 }
1572
1573 if (quickRejectSetupScissor(left, top, right, bottom)) {
1574 return;
1575 }
1576
1577 if (!texture) {
1578 texture = mCaches.textureCache.get(bitmap);
1579 if (!texture) {
1580 return;
1581 }
1582 }
1583 const AutoTexture autoCleanup(texture);
1584
1585 /*
1586 * TODO: handle alpha_8 textures correctly by applying paint color, but *not*
1587 * shader in that case to mimic the behavior in SkiaCanvas::drawBitmapMesh.
1588 */
1589 const int textureFillFlags = TextureFillFlags::None;
1590 Glop glop;
1591 GlopBuilder(mRenderState, mCaches, &glop)
1592 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
1593 .setMeshColoredTexturedMesh(mesh.get(), elementCount)
1594 .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
1595 .setTransform(*currentSnapshot(), TransformFlags::None)
1596 .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
1597 .build();
1598 renderGlop(glop);
1599 }
1600
1601 void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, Rect src, Rect dst, const SkPaint* paint) {
1602 if (quickRejectSetupScissor(dst)) {
1603 return;
1604 }
1605
1606 Texture* texture = getTexture(bitmap);
1607 if (!texture) return;
1608 const AutoTexture autoCleanup(texture);
1609
1610 Rect uv(std::max(0.0f, src.left / texture->width()),
1611 std::max(0.0f, src.top / texture->height()),
1612 std::min(1.0f, src.right / texture->width()),
1613 std::min(1.0f, src.bottom / texture->height()));
1614
1615 const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType)
1616 ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
1617 const bool tryToSnap = MathUtils::areEqual(src.getWidth(), dst.getWidth())
1618 && MathUtils::areEqual(src.getHeight(), dst.getHeight());
1619 Glop glop;
1620 GlopBuilder(mRenderState, mCaches, &glop)
1621 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
1622 .setMeshTexturedUvQuad(texture->uvMapper, uv)
1623 .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
1624 .setTransform(*currentSnapshot(), TransformFlags::None)
1625 .setModelViewMapUnitToRectOptionalSnap(tryToSnap, dst)
1626 .build();
1627 renderGlop(glop);
1628 }
1629
1630 void OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh,
1631 AssetAtlas::Entry* entry, float left, float top, float right, float bottom,
1632 const SkPaint* paint) {
1633 if (!mesh || !mesh->verticesCount || quickRejectSetupScissor(left, top, right, bottom)) {
1634 return;
1635 }
1636
1637 Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
1638 if (!texture) return;
1639 const AutoTexture autoCleanup(texture);
1640
1641 // 9 patches are built for stretching - always filter
1642 int textureFillFlags = TextureFillFlags::ForceFilter;
1643 if (bitmap->colorType() == kAlpha_8_SkColorType) {
1644 textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture;
1645 }
1646 Glop glop;
1647 GlopBuilder(mRenderState, mCaches, &glop)
1648 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
1649 .setMeshPatchQuads(*mesh)
1650 .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
1651 .setTransform(*currentSnapshot(), TransformFlags::None)
1652 .setModelViewOffsetRectSnap(left, top, Rect(right - left, bottom - top)) // TODO: get minimal bounds from patch
1653 .build();
1654 renderGlop(glop);
1655 }
1656
1657 /**
1658 * Important note: this method is intended to draw batches of 9-patch objects and
1659 * will not set the scissor enable or dirty the current layer, if any.
1660 * The caller is responsible for properly dirtying the current layer.
1661 */
1662 void OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
1663 TextureVertex* vertices, uint32_t elementCount, const SkPaint* paint) {
1664 mCaches.textureState().activateTexture(0);
1665 Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
1666 if (!texture) return;
1667 const AutoTexture autoCleanup(texture);
1668
1669 // TODO: get correct bounds from caller
1670 const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform;
1671 // 9 patches are built for stretching - always filter
1672 int textureFillFlags = TextureFillFlags::ForceFilter;
1673 if (bitmap->colorType() == kAlpha_8_SkColorType) {
1674 textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture;
1675 }
1676 Glop glop;
1677 GlopBuilder(mRenderState, mCaches, &glop)
1678 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
1679 .setMeshTexturedIndexedQuads(vertices, elementCount)
1680 .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
1681 .setTransform(*currentSnapshot(), transformFlags)
1682 .setModelViewOffsetRect(0, 0, Rect())
1683 .build();
1684 renderGlop(glop, GlopRenderType::Multi);
1685 }
1686
1687 void OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
1688 const VertexBuffer& vertexBuffer, const SkPaint* paint, int displayFlags) {
1689 // not missing call to quickReject/dirtyLayer, always done at a higher level
1690 if (!vertexBuffer.getVertexCount()) {
1691 // no vertices to draw
1692 return;
1693 }
1694
1695 bool shadowInterp = displayFlags & kVertexBuffer_ShadowInterp;
1696 const int transformFlags = TransformFlags::OffsetByFudgeFactor;
1697 Glop glop;
1698 GlopBuilder(mRenderState, mCaches, &glop)
1699 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
1700 .setMeshVertexBuffer(vertexBuffer)
1701 .setFillPaint(*paint, currentSnapshot()->alpha, shadowInterp)
1702 .setTransform(*currentSnapshot(), transformFlags)
1703 .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds())
1704 .build();
1705 renderGlop(glop);
1706 }
1707
1708 /**
1709 * Renders a convex path via tessellation. For AA paths, this function uses a similar approach to
1710 * that of AA lines in the drawLines() function. We expand the convex path by a half pixel in
1711 * screen space in all directions. However, instead of using a fragment shader to compute the
1712 * translucency of the color from its position, we simply use a varying parameter to define how far
1713 * a given pixel is from the edge. For non-AA paths, the expansion and alpha varying are not used.
1714 *
1715 * Doesn't yet support joins, caps, or path effects.
1716 */
1717 void OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint) {
1718 VertexBuffer vertexBuffer;
1719 // TODO: try clipping large paths to viewport
1720
1721 PathTessellator::tessellatePath(path, paint, *currentTransform(), vertexBuffer);
1722 drawVertexBuffer(vertexBuffer, paint);
1723 }
1724
1725 /**
1726 * We create tristrips for the lines much like shape stroke tessellation, using a per-vertex alpha
1727 * and additional geometry for defining an alpha slope perimeter.
1728 *
1729 * Using GL_LINES can be difficult because the rasterization rules for those lines produces some
1730 * unexpected results, and may vary between hardware devices. Previously we used a varying-base
1731 * in-shader alpha region, but found it to be taxing on some GPUs.
1732 *
1733 * TODO: try using a fixed input buffer for non-capped lines as in text rendering. this may reduce
1734 * memory transfer by removing need for degenerate vertices.
1735 */
1736 void OpenGLRenderer::drawLines(const float* points, int count, const SkPaint* paint) {
1737 if (mState.currentlyIgnored() || count < 4) return;
1738
1739 count &= ~0x3; // round down to nearest four
1740
1741 VertexBuffer buffer;
1742 PathTessellator::tessellateLines(points, count, paint, *currentTransform(), buffer);
1743 const Rect& bounds = buffer.getBounds();
1744
1745 if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
1746 return;
1747 }
1748
1749 int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset;
1750 drawVertexBuffer(buffer, paint, displayFlags);
1751 }
1752
1753 void OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) {
1754 if (mState.currentlyIgnored() || count < 2) return;
1755
1756 count &= ~0x1; // round down to nearest two
1757
1758 VertexBuffer buffer;
1759 PathTessellator::tessellatePoints(points, count, paint, *currentTransform(), buffer);
1760
1761 const Rect& bounds = buffer.getBounds();
1762 if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
1763 return;
1764 }
1765
1766 int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset;
1767 drawVertexBuffer(buffer, paint, displayFlags);
1768
1769 mDirty = true;
1770 }
1771
1772 void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
1773 // No need to check against the clip, we fill the clip region
1774 if (mState.currentlyIgnored()) return;
1775
1776 Rect clip(mState.currentRenderTargetClip());
1777 clip.snapToPixelBoundaries();
1778
1779 SkPaint paint;
1780 paint.setColor(color);
1781 paint.setXfermodeMode(mode);
1782
1783 drawColorRect(clip.left, clip.top, clip.right, clip.bottom, &paint, true);
1784
1785 mDirty = true;
1786 }
1787
1788 void OpenGLRenderer::drawShape(float left, float top, PathTexture* texture,
1789 const SkPaint* paint) {
1790 if (!texture) return;
1791 const AutoTexture autoCleanup(texture);
1792
1793 const float x = left + texture->left - texture->offset;
1794 const float y = top + texture->top - texture->offset;
1795
1796 drawPathTexture(texture, x, y, paint);
1797
1798 mDirty = true;
1799 }
1800
1801 void OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
1802 float rx, float ry, const SkPaint* p) {
1803 if (mState.currentlyIgnored()
1804 || quickRejectSetupScissor(left, top, right, bottom, p)
1805 || PaintUtils::paintWillNotDraw(*p)) {
1806 return;
1807 }
1808
1809 if (p->getPathEffect() != nullptr) {
1810 mCaches.textureState().activateTexture(0);
1811 PathTexture* texture = mCaches.pathCache.getRoundRect(
1812 right - left, bottom - top, rx, ry, p);
1813 drawShape(left, top, texture, p);
1814 } else {
1815 const VertexBuffer* vertexBuffer = mCaches.tessellationCache.getRoundRect(
1816 *currentTransform(), *p, right - left, bottom - top, rx, ry);
1817 drawVertexBuffer(left, top, *vertexBuffer, p);
1818 }
1819 }
1820
1821 void OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p) {
1822 if (mState.currentlyIgnored()
1823 || quickRejectSetupScissor(x - radius, y - radius, x + radius, y + radius, p)
1824 || PaintUtils::paintWillNotDraw(*p)) {
1825 return;
1826 }
1827
1828 if (p->getPathEffect() != nullptr) {
1829 mCaches.textureState().activateTexture(0);
1830 PathTexture* texture = mCaches.pathCache.getCircle(radius, p);
1831 drawShape(x - radius, y - radius, texture, p);
1832 return;
1833 }
1834
1835 SkPath path;
1836 if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
1837 path.addCircle(x, y, radius + p->getStrokeWidth() / 2);
1838 } else {
1839 path.addCircle(x, y, radius);
1840 }
1841
1842 #if !HWUI_NEW_OPS
1843 if (CC_UNLIKELY(currentSnapshot()->projectionPathMask != nullptr)) {
1844 // mask ripples with projection mask
1845 SkPath maskPath = *(currentSnapshot()->projectionPathMask->projectionMask);
1846
1847 Matrix4 screenSpaceTransform;
1848 currentSnapshot()->buildScreenSpaceTransform(&screenSpaceTransform);
1849
1850 Matrix4 totalTransform;
1851 totalTransform.loadInverse(screenSpaceTransform);
1852 totalTransform.multiply(currentSnapshot()->projectionPathMask->projectionMaskTransform);
1853
1854 SkMatrix skTotalTransform;
1855 totalTransform.copyTo(skTotalTransform);
1856 maskPath.transform(skTotalTransform);
1857
1858 // Mask the ripple path by the projection mask, now that it's
1859 // in local space. Note that this can create CCW paths.
1860 Op(path, maskPath, kIntersect_SkPathOp, &path);
1861 }
1862 #endif
1863 drawConvexPath(path, p);
1864 }
1865
1866 void OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
1867 const SkPaint* p) {
1868 if (mState.currentlyIgnored()
1869 || quickRejectSetupScissor(left, top, right, bottom, p)
1870 || PaintUtils::paintWillNotDraw(*p)) {
1871 return;
1872 }
1873
1874 if (p->getPathEffect() != nullptr) {
1875 mCaches.textureState().activateTexture(0);
1876 PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p);
1877 drawShape(left, top, texture, p);
1878 } else {
1879 SkPath path;
1880 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
1881 if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
1882 rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
1883 }
1884 path.addOval(rect);
1885 drawConvexPath(path, p);
1886 }
1887 }
1888
1889 void OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
1890 float startAngle, float sweepAngle, bool useCenter, const SkPaint* p) {
1891 if (mState.currentlyIgnored()
1892 || quickRejectSetupScissor(left, top, right, bottom, p)
1893 || PaintUtils::paintWillNotDraw(*p)) {
1894 return;
1895 }
1896
1897 // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
1898 if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != nullptr || useCenter) {
1899 mCaches.textureState().activateTexture(0);
1900 PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top,
1901 startAngle, sweepAngle, useCenter, p);
1902 drawShape(left, top, texture, p);
1903 return;
1904 }
1905 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
1906 if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
1907 rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
1908 }
1909
1910 SkPath path;
1911 if (useCenter) {
1912 path.moveTo(rect.centerX(), rect.centerY());
1913 }
1914 path.arcTo(rect, startAngle, sweepAngle, !useCenter);
1915 if (useCenter) {
1916 path.close();
1917 }
1918 drawConvexPath(path, p);
1919 }
1920
1921 void OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
1922 const SkPaint* p) {
1923 if (mState.currentlyIgnored()
1924 || quickRejectSetupScissor(left, top, right, bottom, p)
1925 || PaintUtils::paintWillNotDraw(*p)) {
1926 return;
1927 }
1928
1929 if (p->getStyle() != SkPaint::kFill_Style) {
1930 // only fill style is supported by drawConvexPath, since others have to handle joins
1931 static_assert(SkPaintDefaults_MiterLimit == 4.0f, "Miter limit has changed");
1932 if (p->getPathEffect() != nullptr || p->getStrokeJoin() != SkPaint::kMiter_Join ||
1933 p->getStrokeMiter() != SkPaintDefaults_MiterLimit) {
1934 mCaches.textureState().activateTexture(0);
1935 PathTexture* texture =
1936 mCaches.pathCache.getRect(right - left, bottom - top, p);
1937 drawShape(left, top, texture, p);
1938 } else {
1939 SkPath path;
1940 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
1941 if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
1942 rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
1943 }
1944 path.addRect(rect);
1945 drawConvexPath(path, p);
1946 }
1947 } else {
1948 if (p->isAntiAlias() && !currentTransform()->isSimple()) {
1949 SkPath path;
1950 path.addRect(left, top, right, bottom);
1951 drawConvexPath(path, p);
1952 } else {
1953 drawColorRect(left, top, right, bottom, p);
1954
1955 mDirty = true;
1956 }
1957 }
1958 }
1959
1960 void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const glyph_t* glyphs,
1961 int count, const float* positions,
1962 FontRenderer& fontRenderer, int alpha, float x, float y) {
1963 mCaches.textureState().activateTexture(0);
1964
1965 PaintUtils::TextShadow textShadow;
1966 if (!PaintUtils::getTextShadow(paint, &textShadow)) {
1967 LOG_ALWAYS_FATAL("failed to query shadow attributes");
1968 }
1969
1970 // NOTE: The drop shadow will not perform gamma correction
1971 // if shader-based correction is enabled
1972 mCaches.dropShadowCache.setFontRenderer(fontRenderer);
1973 ShadowTexture* texture = mCaches.dropShadowCache.get(
1974 paint, glyphs, count, textShadow.radius, positions);
1975 // If the drop shadow exceeds the max texture size or couldn't be
1976 // allocated, skip drawing
1977 if (!texture) return;
1978 const AutoTexture autoCleanup(texture);
1979
1980 const float sx = x - texture->left + textShadow.dx;
1981 const float sy = y - texture->top + textShadow.dy;
1982
1983 Glop glop;
1984 GlopBuilder(mRenderState, mCaches, &glop)
1985 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
1986 .setMeshTexturedUnitQuad(nullptr)
1987 .setFillShadowTexturePaint(*texture, textShadow.color, *paint, currentSnapshot()->alpha)
1988 .setTransform(*currentSnapshot(), TransformFlags::None)
1989 .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width(), sy + texture->height()))
1990 .build();
1991 renderGlop(glop);
1992 }
1993
1994 // TODO: remove this, once mState.currentlyIgnored captures snapshot alpha
1995 bool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
1996 float alpha = (PaintUtils::hasTextShadow(paint)
1997 ? 1.0f : paint->getAlpha()) * currentSnapshot()->alpha;
1998 return MathUtils::isZero(alpha)
1999 && PaintUtils::getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
2000 }
2001
2002 bool OpenGLRenderer::findBestFontTransform(const mat4& transform, SkMatrix* outMatrix) const {
2003 if (CC_LIKELY(transform.isPureTranslate())) {
2004 outMatrix->setIdentity();
2005 return false;
2006 } else if (CC_UNLIKELY(transform.isPerspective())) {
2007 outMatrix->setIdentity();
2008 return true;
2009 }
2010
2011 /**
2012 * Input is a non-perspective, scaling transform. Generate a scale-only transform,
2013 * with values rounded to the nearest int.
2014 */
2015 float sx, sy;
2016 transform.decomposeScale(sx, sy);
2017 outMatrix->setScale(
2018 roundf(std::max(1.0f, sx)),
2019 roundf(std::max(1.0f, sy)));
2020 return true;
2021 }
2022
2023 int OpenGLRenderer::getSaveCount() const {
2024 return mState.getSaveCount();
2025 }
2026
2027 int OpenGLRenderer::save(int flags) {
2028 return mState.save(flags);
2029 }
2030
2031 void OpenGLRenderer::restore() {
2032 mState.restore();
2033 }
2034
2035 void OpenGLRenderer::restoreToCount(int saveCount) {
2036 mState.restoreToCount(saveCount);
2037 }
2038
2039
2040 void OpenGLRenderer::translate(float dx, float dy, float dz) {
2041 mState.translate(dx, dy, dz);
2042 }
2043
2044 void OpenGLRenderer::rotate(float degrees) {
2045 mState.rotate(degrees);
2046 }
2047
2048 void OpenGLRenderer::scale(float sx, float sy) {
2049 mState.scale(sx, sy);
2050 }
2051
2052 void OpenGLRenderer::skew(float sx, float sy) {
2053 mState.skew(sx, sy);
2054 }
2055
2056 void OpenGLRenderer::setLocalMatrix(const Matrix4& matrix) {
2057 mState.setMatrix(mBaseTransform);
2058 mState.concatMatrix(matrix);
2059 }
2060
2061 void OpenGLRenderer::setLocalMatrix(const SkMatrix& matrix) {
2062 mState.setMatrix(mBaseTransform);
2063 mState.concatMatrix(matrix);
2064 }
2065
2066 void OpenGLRenderer::concatMatrix(const Matrix4& matrix) {
2067 mState.concatMatrix(matrix);
2068 }
2069
2070 bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
2071 return mState.clipRect(left, top, right, bottom, op);
2072 }
2073
2074 bool OpenGLRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
2075 return mState.clipPath(path, op);
2076 }
2077
2078 bool OpenGLRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
2079 return mState.clipRegion(region, op);
2080 }
2081
2082 void OpenGLRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
2083 mState.setClippingOutline(allocator, outline);
2084 }
2085
2086 void OpenGLRenderer::setClippingRoundRect(LinearAllocator& allocator,
2087 const Rect& rect, float radius, bool highPriority) {
2088 mState.setClippingRoundRect(allocator, rect, radius, highPriority);
2089 }
2090
2091 void OpenGLRenderer::setProjectionPathMask(LinearAllocator& allocator, const SkPath* path) {
2092 mState.setProjectionPathMask(allocator, path);
2093 }
2094
2095 void OpenGLRenderer::drawText(const glyph_t* glyphs, int bytesCount, int count, float x, float y,
2096 const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
2097 DrawOpMode drawOpMode) {
2098
2099 if (drawOpMode == DrawOpMode::kImmediate) {
2100 // The checks for corner-case ignorable text and quick rejection is only done for immediate
2101 // drawing as ops from DeferredDisplayList are already filtered for these
2102 if (glyphs == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint) ||
2103 quickRejectSetupScissor(bounds)) {
2104 return;
2105 }
2106 }
2107
2108 const float oldX = x;
2109 const float oldY = y;
2110
2111 const mat4& transform = *currentTransform();
2112 const bool pureTranslate = transform.isPureTranslate();
2113
2114 if (CC_LIKELY(pureTranslate)) {
2115 x = floorf(x + transform.getTranslateX() + 0.5f);
2116 y = floorf(y + transform.getTranslateY() + 0.5f);
2117 }
2118
2119 int alpha = PaintUtils::getAlphaDirect(paint) * currentSnapshot()->alpha;
2120 SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(paint);
2121
2122 FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer();
2123
2124 if (CC_UNLIKELY(PaintUtils::hasTextShadow(paint))) {
2125 fontRenderer.setFont(paint, SkMatrix::I());
2126 drawTextShadow(paint, glyphs, count, positions, fontRenderer,
2127 alpha, oldX, oldY);
2128 }
2129
2130 const bool hasActiveLayer = hasLayer();
2131
2132 // We only pass a partial transform to the font renderer. That partial
2133 // matrix defines how glyphs are rasterized. Typically we want glyphs
2134 // to be rasterized at their final size on screen, which means the partial
2135 // matrix needs to take the scale factor into account.
2136 // When a partial matrix is used to transform glyphs during rasterization,
2137 // the mesh is generated with the inverse transform (in the case of scale,
2138 // the mesh is generated at 1.0 / scale for instance.) This allows us to
2139 // apply the full transform matrix at draw time in the vertex shader.
2140 // Applying the full matrix in the shader is the easiest way to handle
2141 // rotation and perspective and allows us to always generated quads in the
2142 // font renderer which greatly simplifies the code, clipping in particular.
2143 SkMatrix fontTransform;
2144 bool linearFilter = findBestFontTransform(transform, &fontTransform)
2145 || fabs(y - (int) y) > 0.0f
2146 || fabs(x - (int) x) > 0.0f;
2147 fontRenderer.setFont(paint, fontTransform);
2148 fontRenderer.setTextureFiltering(linearFilter);
2149
2150 // TODO: Implement better clipping for scaled/rotated text
2151 const Rect* clip = !pureTranslate ? nullptr : &mState.currentRenderTargetClip();
2152 Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2153
2154 bool status;
2155 #if HWUI_NEW_OPS
2156 LOG_ALWAYS_FATAL("unsupported");
2157 TextDrawFunctor functor(nullptr, nullptr, nullptr, x, y, pureTranslate, alpha, mode, paint);
2158 #else
2159 TextDrawFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
2160 #endif
2161
2162 // don't call issuedrawcommand, do it at end of batch
2163 bool forceFinish = (drawOpMode != DrawOpMode::kDefer);
2164 if (CC_UNLIKELY(paint->getTextAlign() != SkPaint::kLeft_Align)) {
2165 SkPaint paintCopy(*paint);
2166 paintCopy.setTextAlign(SkPaint::kLeft_Align);
2167 status = fontRenderer.renderPosText(&paintCopy, clip, glyphs, count, x, y,
2168 positions, hasActiveLayer ? &layerBounds : nullptr, &functor, forceFinish);
2169 } else {
2170 status = fontRenderer.renderPosText(paint, clip, glyphs, count, x, y,
2171 positions, hasActiveLayer ? &layerBounds : nullptr, &functor, forceFinish);
2172 }
2173
2174 if ((status || drawOpMode != DrawOpMode::kImmediate) && hasActiveLayer) {
2175 if (!pureTranslate) {
2176 transform.mapRect(layerBounds);
2177 }
2178 dirtyLayerUnchecked(layerBounds, getRegion());
2179 }
2180
2181 mDirty = true;
2182 }
2183
2184 void OpenGLRenderer::drawTextOnPath(const glyph_t* glyphs, int bytesCount, int count,
2185 const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) {
2186 if (glyphs == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) {
2187 return;
2188 }
2189
2190 // TODO: avoid scissor by calculating maximum bounds using path bounds + font metrics
2191 mRenderState.scissor().setEnabled(true);
2192
2193 FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer();
2194 fontRenderer.setFont(paint, SkMatrix::I());
2195 fontRenderer.setTextureFiltering(true);
2196
2197 int alpha = PaintUtils::getAlphaDirect(paint) * currentSnapshot()->alpha;
2198 SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(paint);
2199 #if HWUI_NEW_OPS
2200 LOG_ALWAYS_FATAL("unsupported");
2201 TextDrawFunctor functor(nullptr, nullptr, nullptr, 0.0f, 0.0f, false, alpha, mode, paint);
2202 #else
2203 TextDrawFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint);
2204 #endif
2205
2206 const Rect* clip = &writableSnapshot()->getLocalClip();
2207 Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
2208
2209 if (fontRenderer.renderTextOnPath(paint, clip, glyphs, count, path,
2210 hOffset, vOffset, hasLayer() ? &bounds : nullptr, &functor)) {
2211 dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform());
2212 mDirty = true;
2213 }
2214 }
2215
2216 void OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
2217 if (mState.currentlyIgnored()) return;
2218
2219 mCaches.textureState().activateTexture(0);
2220
2221 PathTexture* texture = mCaches.pathCache.get(path, paint);
2222 if (!texture) return;
2223
2224 const float x = texture->left - texture->offset;
2225 const float y = texture->top - texture->offset;
2226
2227 drawPathTexture(texture, x, y, paint);
2228
2229 if (texture->cleanup) {
2230 mCaches.pathCache.remove(path, paint);
2231 }
2232 mDirty = true;
2233 }
2234
2235 void OpenGLRenderer::drawLayer(Layer* layer) {
2236 if (!layer) {
2237 return;
2238 }
2239
2240 mat4* transform = nullptr;
2241 if (layer->isTextureLayer()) {
2242 transform = &layer->getTransform();
2243 if (!transform->isIdentity()) {
2244 save(SaveFlags::Matrix);
2245 concatMatrix(*transform);
2246 }
2247 }
2248
2249 bool clipRequired = false;
2250 const bool rejected = mState.calculateQuickRejectForScissor(
2251 0, 0, layer->layer.getWidth(), layer->layer.getHeight(),
2252 &clipRequired, nullptr, false);
2253
2254 if (rejected) {
2255 if (transform && !transform->isIdentity()) {
2256 restore();
2257 }
2258 return;
2259 }
2260
2261 EVENT_LOGD("drawLayer," RECT_STRING ", clipRequired %d", x, y,
2262 x + layer->layer.getWidth(), y + layer->layer.getHeight(), clipRequired);
2263
2264 updateLayer(layer, true);
2265
2266 mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
2267 mCaches.textureState().activateTexture(0);
2268
2269 if (CC_LIKELY(!layer->region.isEmpty())) {
2270 if (layer->region.isRect()) {
2271 DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
2272 composeLayerRect(layer, layer->regionRect));
2273 } else if (layer->mesh) {
2274 Glop glop;
2275 GlopBuilder(mRenderState, mCaches, &glop)
2276 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
2277 .setMeshTexturedIndexedQuads(layer->mesh, layer->meshElementCount)
2278 .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
2279 .setTransform(*currentSnapshot(), TransformFlags::None)
2280 .setModelViewOffsetRectSnap(0, 0, Rect(layer->layer.getWidth(), layer->layer.getHeight()))
2281 .build();
2282 DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
2283 #if DEBUG_LAYERS_AS_REGIONS
2284 drawRegionRectsDebug(layer->region);
2285 #endif
2286 }
2287
2288 if (layer->debugDrawUpdate) {
2289 layer->debugDrawUpdate = false;
2290
2291 SkPaint paint;
2292 paint.setColor(0x7f00ff00);
2293 drawColorRect(0, 0, layer->layer.getWidth(), layer->layer.getHeight(), &paint);
2294 }
2295 }
2296 layer->hasDrawnSinceUpdate = true;
2297
2298 if (transform && !transform->isIdentity()) {
2299 restore();
2300 }
2301
2302 mDirty = true;
2303 }
2304
2305 ///////////////////////////////////////////////////////////////////////////////
2306 // Draw filters
2307 ///////////////////////////////////////////////////////////////////////////////
2308 void OpenGLRenderer::setDrawFilter(SkDrawFilter* filter) {
2309 // We should never get here since we apply the draw filter when stashing
2310 // the paints in the DisplayList.
2311 LOG_ALWAYS_FATAL("OpenGLRenderer does not directly support DrawFilters");
2312 }
2313
2314 ///////////////////////////////////////////////////////////////////////////////
2315 // Drawing implementation
2316 ///////////////////////////////////////////////////////////////////////////////
2317
2318 Texture* OpenGLRenderer::getTexture(const SkBitmap* bitmap) {
2319 Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap->pixelRef());
2320 if (!texture) {
2321 return mCaches.textureCache.get(bitmap);
2322 }
2323 return texture;
2324 }
2325
2326 void OpenGLRenderer::drawPathTexture(PathTexture* texture, float x, float y,
2327 const SkPaint* paint) {
2328 if (quickRejectSetupScissor(x, y, x + texture->width(), y + texture->height())) {
2329 return;
2330 }
2331
2332 Glop glop;
2333 GlopBuilder(mRenderState, mCaches, &glop)
2334 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
2335 .setMeshTexturedUnitQuad(nullptr)
2336 .setFillPathTexturePaint(*texture, *paint, currentSnapshot()->alpha)
2337 .setTransform(*currentSnapshot(), TransformFlags::None)
2338 .setModelViewMapUnitToRect(Rect(x, y, x + texture->width(), y + texture->height()))
2339 .build();
2340 renderGlop(glop);
2341 }
2342
2343 void OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
2344 if (mState.currentlyIgnored()) {
2345 return;
2346 }
2347
2348 drawColorRects(rects, count, paint, false, true, true);
2349 }
2350
2351 void OpenGLRenderer::drawShadow(float casterAlpha,
2352 const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) {
2353 if (mState.currentlyIgnored()) return;
2354
2355 // TODO: use quickRejectWithScissor. For now, always force enable scissor.
2356 mRenderState.scissor().setEnabled(true);
2357
2358 SkPaint paint;
2359 paint.setAntiAlias(true); // want to use AlphaVertex
2360
2361 // The caller has made sure casterAlpha > 0.
2362 float ambientShadowAlpha = mAmbientShadowAlpha;
2363 if (CC_UNLIKELY(Properties::overrideAmbientShadowStrength >= 0)) {
2364 ambientShadowAlpha = Properties::overrideAmbientShadowStrength;
2365 }
2366 if (ambientShadowVertexBuffer && ambientShadowAlpha > 0) {
2367 paint.setARGB(casterAlpha * ambientShadowAlpha, 0, 0, 0);
2368 drawVertexBuffer(*ambientShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp);
2369 }
2370
2371 float spotShadowAlpha = mSpotShadowAlpha;
2372 if (CC_UNLIKELY(Properties::overrideSpotShadowStrength >= 0)) {
2373 spotShadowAlpha = Properties::overrideSpotShadowStrength;
2374 }
2375 if (spotShadowVertexBuffer && spotShadowAlpha > 0) {
2376 paint.setARGB(casterAlpha * spotShadowAlpha, 0, 0, 0);
2377 drawVertexBuffer(*spotShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp);
2378 }
2379
2380 mDirty=true;
2381 }
2382
2383 void OpenGLRenderer::drawColorRects(const float* rects, int count, const SkPaint* paint,
2384 bool ignoreTransform, bool dirty, bool clip) {
2385 if (count == 0) {
2386 return;
2387 }
2388
2389 float left = FLT_MAX;
2390 float top = FLT_MAX;
2391 float right = FLT_MIN;
2392 float bottom = FLT_MIN;
2393
2394 Vertex mesh[count];
2395 Vertex* vertex = mesh;
2396
2397 for (int index = 0; index < count; index += 4) {
2398 float l = rects[index + 0];
2399 float t = rects[index + 1];
2400 float r = rects[index + 2];
2401 float b = rects[index + 3];
2402
2403 Vertex::set(vertex++, l, t);
2404 Vertex::set(vertex++, r, t);
2405 Vertex::set(vertex++, l, b);
2406 Vertex::set(vertex++, r, b);
2407
2408 left = std::min(left, l);
2409 top = std::min(top, t);
2410 right = std::max(right, r);
2411 bottom = std::max(bottom, b);
2412 }
2413
2414 if (clip && quickRejectSetupScissor(left, top, right, bottom)) {
2415 return;
2416 }
2417
2418 const int transformFlags = ignoreTransform
2419 ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
2420 Glop glop;
2421 GlopBuilder(mRenderState, mCaches, &glop)
2422 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
2423 .setMeshIndexedQuads(&mesh[0], count / 4)
2424 .setFillPaint(*paint, currentSnapshot()->alpha)
2425 .setTransform(*currentSnapshot(), transformFlags)
2426 .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
2427 .build();
2428 renderGlop(glop);
2429 }
2430
2431 void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
2432 const SkPaint* paint, bool ignoreTransform) {
2433 const int transformFlags = ignoreTransform
2434 ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
2435 Glop glop;
2436 GlopBuilder(mRenderState, mCaches, &glop)
2437 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
2438 .setMeshUnitQuad()
2439 .setFillPaint(*paint, currentSnapshot()->alpha)
2440 .setTransform(*currentSnapshot(), transformFlags)
2441 .setModelViewMapUnitToRect(Rect(left, top, right, bottom))
2442 .build();
2443 renderGlop(glop);
2444 }
2445
2446 float OpenGLRenderer::getLayerAlpha(const Layer* layer) const {
2447 return (layer->getAlpha() / 255.0f) * currentSnapshot()->alpha;
2448 }
2449
2450 }; // namespace uirenderer
2451 }; // namespace android
2452