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 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 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 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 98 void OpenGLRenderer::initLight(float lightRadius, uint8_t ambientShadowAlpha, 99 uint8_t spotShadowAlpha) { 100 mLightRadius = lightRadius; 101 mAmbientShadowAlpha = ambientShadowAlpha; 102 mSpotShadowAlpha = spotShadowAlpha; 103 } 104 105 void OpenGLRenderer::setLightCenter(const Vector3& lightCenter) { 106 mLightCenter = lightCenter; 107 } 108 109 /////////////////////////////////////////////////////////////////////////////// 110 // Setup 111 /////////////////////////////////////////////////////////////////////////////// 112 113 void OpenGLRenderer::onViewportInitialized() { 114 glDisable(GL_DITHER); 115 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 116 } 117 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 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 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 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 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 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 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 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 266 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 281 void OpenGLRenderer::eventMark(const char* name) const { 282 mCaches.eventMark(0, name); 283 } 284 285 void OpenGLRenderer::startMark(const char* name) const { 286 mCaches.startMark(0, name); 287 } 288 289 void OpenGLRenderer::endMark() const { 290 mCaches.endMark(); 291 } 292 293 void OpenGLRenderer::debugOverdraw(bool enable, bool clear) { 294 mRenderState.debugOverdraw(enable, clear); 295 } 296 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 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 */ 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 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 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 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: 854 LayerShader(Layer* layer, const SkMatrix* localMatrix) 855 : INHERITED(localMatrix) 856 , mLayer(layer) { 857 } 858 859 virtual bool asACustomShader(void** data) const override { 860 if (data) { 861 *data = static_cast<void*>(mLayer); 862 } 863 return true; 864 } 865 866 virtual bool isOpaque() const override { 867 return !mLayer->isBlend(); 868 } 869 870 protected: 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 875 virtual void flatten(SkWriteBuffer&) const override { 876 LOG_ALWAYS_FATAL("LayerShader should never be flattened."); 877 } 878 879 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 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 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 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 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 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 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 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 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 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 */ 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 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 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 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 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 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 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 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 */ 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 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