1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "OpenGLRenderer" 18 19 #include <stdlib.h> 20 #include <stdint.h> 21 #include <sys/types.h> 22 23 #include <SkCanvas.h> 24 #include <SkPathMeasure.h> 25 #include <SkTypeface.h> 26 27 #include <utils/Log.h> 28 #include <utils/StopWatch.h> 29 30 #include <private/hwui/DrawGlInfo.h> 31 32 #include <ui/Rect.h> 33 34 #include "OpenGLRenderer.h" 35 #include "DeferredDisplayList.h" 36 #include "DisplayListRenderer.h" 37 #include "PathTessellator.h" 38 #include "Properties.h" 39 #include "Vector.h" 40 41 namespace android { 42 namespace uirenderer { 43 44 /////////////////////////////////////////////////////////////////////////////// 45 // Defines 46 /////////////////////////////////////////////////////////////////////////////// 47 48 #define RAD_TO_DEG (180.0f / 3.14159265f) 49 #define MIN_ANGLE 0.001f 50 51 #define ALPHA_THRESHOLD 0 52 53 #define FILTER(paint) (!paint || paint->isFilterBitmap() ? GL_LINEAR : GL_NEAREST) 54 55 /////////////////////////////////////////////////////////////////////////////// 56 // Globals 57 /////////////////////////////////////////////////////////////////////////////// 58 59 /** 60 * Structure mapping Skia xfermodes to OpenGL blending factors. 61 */ 62 struct Blender { 63 SkXfermode::Mode mode; 64 GLenum src; 65 GLenum dst; 66 }; // struct Blender 67 68 // In this array, the index of each Blender equals the value of the first 69 // entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode] 70 static const Blender gBlends[] = { 71 { SkXfermode::kClear_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, 72 { SkXfermode::kSrc_Mode, GL_ONE, GL_ZERO }, 73 { SkXfermode::kDst_Mode, GL_ZERO, GL_ONE }, 74 { SkXfermode::kSrcOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, 75 { SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE }, 76 { SkXfermode::kSrcIn_Mode, GL_DST_ALPHA, GL_ZERO }, 77 { SkXfermode::kDstIn_Mode, GL_ZERO, GL_SRC_ALPHA }, 78 { SkXfermode::kSrcOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, 79 { SkXfermode::kDstOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, 80 { SkXfermode::kSrcATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, 81 { SkXfermode::kDstATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, 82 { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, 83 { SkXfermode::kPlus_Mode, GL_ONE, GL_ONE }, 84 { SkXfermode::kModulate_Mode, GL_ZERO, GL_SRC_COLOR }, 85 { SkXfermode::kScreen_Mode, GL_ONE, GL_ONE_MINUS_SRC_COLOR } 86 }; 87 88 // This array contains the swapped version of each SkXfermode. For instance 89 // this array's SrcOver blending mode is actually DstOver. You can refer to 90 // createLayer() for more information on the purpose of this array. 91 static const Blender gBlendsSwap[] = { 92 { SkXfermode::kClear_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, 93 { SkXfermode::kSrc_Mode, GL_ZERO, GL_ONE }, 94 { SkXfermode::kDst_Mode, GL_ONE, GL_ZERO }, 95 { SkXfermode::kSrcOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE }, 96 { SkXfermode::kDstOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, 97 { SkXfermode::kSrcIn_Mode, GL_ZERO, GL_SRC_ALPHA }, 98 { SkXfermode::kDstIn_Mode, GL_DST_ALPHA, GL_ZERO }, 99 { SkXfermode::kSrcOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, 100 { SkXfermode::kDstOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, 101 { SkXfermode::kSrcATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, 102 { SkXfermode::kDstATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, 103 { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, 104 { SkXfermode::kPlus_Mode, GL_ONE, GL_ONE }, 105 { SkXfermode::kModulate_Mode, GL_DST_COLOR, GL_ZERO }, 106 { SkXfermode::kScreen_Mode, GL_ONE_MINUS_DST_COLOR, GL_ONE } 107 }; 108 109 /////////////////////////////////////////////////////////////////////////////// 110 // Constructors/destructor 111 /////////////////////////////////////////////////////////////////////////////// 112 113 OpenGLRenderer::OpenGLRenderer(): 114 mCaches(Caches::getInstance()), mExtensions(Extensions::getInstance()) { 115 // *set* draw modifiers to be 0 116 memset(&mDrawModifiers, 0, sizeof(mDrawModifiers)); 117 mDrawModifiers.mOverrideLayerAlpha = 1.0f; 118 119 memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices)); 120 121 mFirstSnapshot = new Snapshot; 122 mFrameStarted = false; 123 124 mScissorOptimizationDisabled = false; 125 } 126 127 OpenGLRenderer::~OpenGLRenderer() { 128 // The context has already been destroyed at this point, do not call 129 // GL APIs. All GL state should be kept in Caches.h 130 } 131 132 void OpenGLRenderer::initProperties() { 133 char property[PROPERTY_VALUE_MAX]; 134 if (property_get(PROPERTY_DISABLE_SCISSOR_OPTIMIZATION, property, "false")) { 135 mScissorOptimizationDisabled = !strcasecmp(property, "true"); 136 INIT_LOGD(" Scissor optimization %s", 137 mScissorOptimizationDisabled ? "disabled" : "enabled"); 138 } else { 139 INIT_LOGD(" Scissor optimization enabled"); 140 } 141 } 142 143 /////////////////////////////////////////////////////////////////////////////// 144 // Setup 145 /////////////////////////////////////////////////////////////////////////////// 146 147 void OpenGLRenderer::setName(const char* name) { 148 if (name) { 149 mName.setTo(name); 150 } else { 151 mName.clear(); 152 } 153 } 154 155 const char* OpenGLRenderer::getName() const { 156 return mName.string(); 157 } 158 159 bool OpenGLRenderer::isDeferred() { 160 return false; 161 } 162 163 void OpenGLRenderer::setViewport(int width, int height) { 164 initViewport(width, height); 165 166 glDisable(GL_DITHER); 167 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 168 169 glEnableVertexAttribArray(Program::kBindingPosition); 170 } 171 172 void OpenGLRenderer::initViewport(int width, int height) { 173 mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1); 174 175 mWidth = width; 176 mHeight = height; 177 178 mFirstSnapshot->height = height; 179 mFirstSnapshot->viewport.set(0, 0, width, height); 180 } 181 182 void OpenGLRenderer::setupFrameState(float left, float top, 183 float right, float bottom, bool opaque) { 184 mCaches.clearGarbage(); 185 186 mOpaque = opaque; 187 mSnapshot = new Snapshot(mFirstSnapshot, 188 SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); 189 mSnapshot->fbo = getTargetFbo(); 190 mSaveCount = 1; 191 192 mSnapshot->setClip(left, top, right, bottom); 193 mTilingClip.set(left, top, right, bottom); 194 } 195 196 status_t OpenGLRenderer::startFrame() { 197 if (mFrameStarted) return DrawGlInfo::kStatusDone; 198 mFrameStarted = true; 199 200 mDirtyClip = true; 201 202 discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom); 203 204 glViewport(0, 0, mWidth, mHeight); 205 206 // Functors break the tiling extension in pretty spectacular ways 207 // This ensures we don't use tiling when a functor is going to be 208 // invoked during the frame 209 mSuppressTiling = mCaches.hasRegisteredFunctors(); 210 211 startTiling(mSnapshot, true); 212 213 debugOverdraw(true, true); 214 215 return clear(mTilingClip.left, mTilingClip.top, 216 mTilingClip.right, mTilingClip.bottom, mOpaque); 217 } 218 219 status_t OpenGLRenderer::prepare(bool opaque) { 220 return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque); 221 } 222 223 status_t OpenGLRenderer::prepareDirty(float left, float top, 224 float right, float bottom, bool opaque) { 225 setupFrameState(left, top, right, bottom, opaque); 226 227 // Layer renderers will start the frame immediately 228 // The framebuffer renderer will first defer the display list 229 // for each layer and wait until the first drawing command 230 // to start the frame 231 if (mSnapshot->fbo == 0) { 232 syncState(); 233 updateLayers(); 234 } else { 235 return startFrame(); 236 } 237 238 return DrawGlInfo::kStatusDone; 239 } 240 241 void OpenGLRenderer::discardFramebuffer(float left, float top, float right, float bottom) { 242 // If we know that we are going to redraw the entire framebuffer, 243 // perform a discard to let the driver know we don't need to preserve 244 // the back buffer for this frame. 245 if (mExtensions.hasDiscardFramebuffer() && 246 left <= 0.0f && top <= 0.0f && right >= mWidth && bottom >= mHeight) { 247 const bool isFbo = getTargetFbo() == 0; 248 const GLenum attachments[] = { 249 isFbo ? (const GLenum) GL_COLOR_EXT : (const GLenum) GL_COLOR_ATTACHMENT0, 250 isFbo ? (const GLenum) GL_STENCIL_EXT : (const GLenum) GL_STENCIL_ATTACHMENT }; 251 glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, attachments); 252 } 253 } 254 255 status_t OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) { 256 if (!opaque) { 257 mCaches.enableScissor(); 258 mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top); 259 glClear(GL_COLOR_BUFFER_BIT); 260 return DrawGlInfo::kStatusDrew; 261 } 262 263 mCaches.resetScissor(); 264 return DrawGlInfo::kStatusDone; 265 } 266 267 void OpenGLRenderer::syncState() { 268 if (mCaches.blend) { 269 glEnable(GL_BLEND); 270 } else { 271 glDisable(GL_BLEND); 272 } 273 } 274 275 void OpenGLRenderer::startTiling(const sp<Snapshot>& s, bool opaque) { 276 if (!mSuppressTiling) { 277 Rect* clip = &mTilingClip; 278 if (s->flags & Snapshot::kFlagFboTarget) { 279 clip = &(s->layer->clipRect); 280 } 281 282 startTiling(*clip, s->height, opaque); 283 } 284 } 285 286 void OpenGLRenderer::startTiling(const Rect& clip, int windowHeight, bool opaque) { 287 if (!mSuppressTiling) { 288 mCaches.startTiling(clip.left, windowHeight - clip.bottom, 289 clip.right - clip.left, clip.bottom - clip.top, opaque); 290 } 291 } 292 293 void OpenGLRenderer::endTiling() { 294 if (!mSuppressTiling) mCaches.endTiling(); 295 } 296 297 void OpenGLRenderer::finish() { 298 renderOverdraw(); 299 endTiling(); 300 301 // When finish() is invoked on FBO 0 we've reached the end 302 // of the current frame 303 if (getTargetFbo() == 0) { 304 mCaches.pathCache.trim(); 305 } 306 307 if (!suppressErrorChecks()) { 308 #if DEBUG_OPENGL 309 GLenum status = GL_NO_ERROR; 310 while ((status = glGetError()) != GL_NO_ERROR) { 311 ALOGD("GL error from OpenGLRenderer: 0x%x", status); 312 switch (status) { 313 case GL_INVALID_ENUM: 314 ALOGE(" GL_INVALID_ENUM"); 315 break; 316 case GL_INVALID_VALUE: 317 ALOGE(" GL_INVALID_VALUE"); 318 break; 319 case GL_INVALID_OPERATION: 320 ALOGE(" GL_INVALID_OPERATION"); 321 break; 322 case GL_OUT_OF_MEMORY: 323 ALOGE(" Out of memory!"); 324 break; 325 } 326 } 327 #endif 328 329 #if DEBUG_MEMORY_USAGE 330 mCaches.dumpMemoryUsage(); 331 #else 332 if (mCaches.getDebugLevel() & kDebugMemory) { 333 mCaches.dumpMemoryUsage(); 334 } 335 #endif 336 } 337 338 mFrameStarted = false; 339 } 340 341 void OpenGLRenderer::interrupt() { 342 if (mCaches.currentProgram) { 343 if (mCaches.currentProgram->isInUse()) { 344 mCaches.currentProgram->remove(); 345 mCaches.currentProgram = NULL; 346 } 347 } 348 mCaches.unbindMeshBuffer(); 349 mCaches.unbindIndicesBuffer(); 350 mCaches.resetVertexPointers(); 351 mCaches.disableTexCoordsVertexArray(); 352 debugOverdraw(false, false); 353 } 354 355 void OpenGLRenderer::resume() { 356 sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot; 357 glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight()); 358 glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo); 359 debugOverdraw(true, false); 360 361 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 362 363 mCaches.scissorEnabled = glIsEnabled(GL_SCISSOR_TEST); 364 mCaches.enableScissor(); 365 mCaches.resetScissor(); 366 dirtyClip(); 367 368 mCaches.activeTexture(0); 369 370 mCaches.blend = true; 371 glEnable(GL_BLEND); 372 glBlendFunc(mCaches.lastSrcMode, mCaches.lastDstMode); 373 glBlendEquation(GL_FUNC_ADD); 374 } 375 376 void OpenGLRenderer::resumeAfterLayer() { 377 sp<Snapshot> snapshot = (mSnapshot != NULL) ? mSnapshot : mFirstSnapshot; 378 glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight()); 379 glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo); 380 debugOverdraw(true, false); 381 382 mCaches.resetScissor(); 383 dirtyClip(); 384 } 385 386 void OpenGLRenderer::detachFunctor(Functor* functor) { 387 mFunctors.remove(functor); 388 } 389 390 void OpenGLRenderer::attachFunctor(Functor* functor) { 391 mFunctors.add(functor); 392 } 393 394 status_t OpenGLRenderer::invokeFunctors(Rect& dirty) { 395 status_t result = DrawGlInfo::kStatusDone; 396 size_t count = mFunctors.size(); 397 398 if (count > 0) { 399 interrupt(); 400 SortedVector<Functor*> functors(mFunctors); 401 mFunctors.clear(); 402 403 DrawGlInfo info; 404 info.clipLeft = 0; 405 info.clipTop = 0; 406 info.clipRight = 0; 407 info.clipBottom = 0; 408 info.isLayer = false; 409 info.width = 0; 410 info.height = 0; 411 memset(info.transform, 0, sizeof(float) * 16); 412 413 for (size_t i = 0; i < count; i++) { 414 Functor* f = functors.itemAt(i); 415 result |= (*f)(DrawGlInfo::kModeProcess, &info); 416 417 if (result & DrawGlInfo::kStatusDraw) { 418 Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom); 419 dirty.unionWith(localDirty); 420 } 421 422 if (result & DrawGlInfo::kStatusInvoke) { 423 mFunctors.add(f); 424 } 425 } 426 resume(); 427 } 428 429 return result; 430 } 431 432 status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) { 433 if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone; 434 435 interrupt(); 436 detachFunctor(functor); 437 438 mCaches.enableScissor(); 439 if (mDirtyClip) { 440 setScissorFromClip(); 441 } 442 443 Rect clip(*mSnapshot->clipRect); 444 clip.snapToPixelBoundaries(); 445 446 // Since we don't know what the functor will draw, let's dirty 447 // tne entire clip region 448 if (hasLayer()) { 449 dirtyLayerUnchecked(clip, getRegion()); 450 } 451 452 DrawGlInfo info; 453 info.clipLeft = clip.left; 454 info.clipTop = clip.top; 455 info.clipRight = clip.right; 456 info.clipBottom = clip.bottom; 457 info.isLayer = hasLayer(); 458 info.width = getSnapshot()->viewport.getWidth(); 459 info.height = getSnapshot()->height; 460 getSnapshot()->transform->copyTo(&info.transform[0]); 461 462 status_t result = (*functor)(DrawGlInfo::kModeDraw, &info) | DrawGlInfo::kStatusDrew; 463 464 if (result != DrawGlInfo::kStatusDone) { 465 Rect localDirty(info.dirtyLeft, info.dirtyTop, info.dirtyRight, info.dirtyBottom); 466 dirty.unionWith(localDirty); 467 468 if (result & DrawGlInfo::kStatusInvoke) { 469 mFunctors.add(functor); 470 } 471 } 472 473 resume(); 474 return result; 475 } 476 477 /////////////////////////////////////////////////////////////////////////////// 478 // Debug 479 /////////////////////////////////////////////////////////////////////////////// 480 481 void OpenGLRenderer::eventMark(const char* name) const { 482 mCaches.eventMark(0, name); 483 } 484 485 void OpenGLRenderer::startMark(const char* name) const { 486 mCaches.startMark(0, name); 487 } 488 489 void OpenGLRenderer::endMark() const { 490 mCaches.endMark(); 491 } 492 493 void OpenGLRenderer::debugOverdraw(bool enable, bool clear) { 494 if (mCaches.debugOverdraw && getTargetFbo() == 0) { 495 if (clear) { 496 mCaches.disableScissor(); 497 mCaches.stencil.clear(); 498 } 499 if (enable) { 500 mCaches.stencil.enableDebugWrite(); 501 } else { 502 mCaches.stencil.disable(); 503 } 504 } 505 } 506 507 void OpenGLRenderer::renderOverdraw() { 508 if (mCaches.debugOverdraw && getTargetFbo() == 0) { 509 const Rect* clip = &mTilingClip; 510 511 mCaches.enableScissor(); 512 mCaches.setScissor(clip->left, mFirstSnapshot->height - clip->bottom, 513 clip->right - clip->left, clip->bottom - clip->top); 514 515 mCaches.stencil.enableDebugTest(2); 516 drawColor(0x2f0000ff, SkXfermode::kSrcOver_Mode); 517 mCaches.stencil.enableDebugTest(3); 518 drawColor(0x2f00ff00, SkXfermode::kSrcOver_Mode); 519 mCaches.stencil.enableDebugTest(4); 520 drawColor(0x3fff0000, SkXfermode::kSrcOver_Mode); 521 mCaches.stencil.enableDebugTest(4, true); 522 drawColor(0x7fff0000, SkXfermode::kSrcOver_Mode); 523 mCaches.stencil.disable(); 524 } 525 } 526 527 /////////////////////////////////////////////////////////////////////////////// 528 // Layers 529 /////////////////////////////////////////////////////////////////////////////// 530 531 bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) { 532 if (layer->deferredUpdateScheduled && layer->renderer && 533 layer->displayList && layer->displayList->isRenderable()) { 534 Rect& dirty = layer->dirtyRect; 535 536 if (inFrame) { 537 endTiling(); 538 debugOverdraw(false, false); 539 } 540 541 if (CC_UNLIKELY(inFrame || mCaches.drawDeferDisabled)) { 542 layer->render(); 543 } else { 544 layer->defer(); 545 } 546 547 if (inFrame) { 548 resumeAfterLayer(); 549 startTiling(mSnapshot); 550 } 551 552 layer->debugDrawUpdate = mCaches.debugLayersUpdates; 553 layer->hasDrawnSinceUpdate = false; 554 555 return true; 556 } 557 558 return false; 559 } 560 561 void OpenGLRenderer::updateLayers() { 562 // If draw deferring is enabled this method will simply defer 563 // the display list of each individual layer. The layers remain 564 // in the layer updates list which will be cleared by flushLayers(). 565 int count = mLayerUpdates.size(); 566 if (count > 0) { 567 if (CC_UNLIKELY(mCaches.drawDeferDisabled)) { 568 startMark("Layer Updates"); 569 } else { 570 startMark("Defer Layer Updates"); 571 } 572 573 // Note: it is very important to update the layers in order 574 for (int i = 0; i < count; i++) { 575 Layer* layer = mLayerUpdates.itemAt(i); 576 updateLayer(layer, false); 577 if (CC_UNLIKELY(mCaches.drawDeferDisabled)) { 578 mCaches.resourceCache.decrementRefcount(layer); 579 } 580 } 581 582 if (CC_UNLIKELY(mCaches.drawDeferDisabled)) { 583 mLayerUpdates.clear(); 584 glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo()); 585 } 586 endMark(); 587 } 588 } 589 590 void OpenGLRenderer::flushLayers() { 591 int count = mLayerUpdates.size(); 592 if (count > 0) { 593 startMark("Apply Layer Updates"); 594 char layerName[12]; 595 596 // Note: it is very important to update the layers in order 597 for (int i = 0; i < count; i++) { 598 sprintf(layerName, "Layer #%d", i); 599 startMark(layerName); 600 601 Layer* layer = mLayerUpdates.itemAt(i); 602 layer->flush(); 603 mCaches.resourceCache.decrementRefcount(layer); 604 605 endMark(); 606 } 607 608 mLayerUpdates.clear(); 609 glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo()); 610 611 endMark(); 612 } 613 } 614 615 void OpenGLRenderer::pushLayerUpdate(Layer* layer) { 616 if (layer) { 617 // Make sure we don't introduce duplicates. 618 // SortedVector would do this automatically but we need to respect 619 // the insertion order. The linear search is not an issue since 620 // this list is usually very short (typically one item, at most a few) 621 for (int i = mLayerUpdates.size() - 1; i >= 0; i--) { 622 if (mLayerUpdates.itemAt(i) == layer) { 623 return; 624 } 625 } 626 mLayerUpdates.push_back(layer); 627 mCaches.resourceCache.incrementRefcount(layer); 628 } 629 } 630 631 void OpenGLRenderer::clearLayerUpdates() { 632 size_t count = mLayerUpdates.size(); 633 if (count > 0) { 634 mCaches.resourceCache.lock(); 635 for (size_t i = 0; i < count; i++) { 636 mCaches.resourceCache.decrementRefcountLocked(mLayerUpdates.itemAt(i)); 637 } 638 mCaches.resourceCache.unlock(); 639 mLayerUpdates.clear(); 640 } 641 } 642 643 /////////////////////////////////////////////////////////////////////////////// 644 // State management 645 /////////////////////////////////////////////////////////////////////////////// 646 647 int OpenGLRenderer::getSaveCount() const { 648 return mSaveCount; 649 } 650 651 int OpenGLRenderer::save(int flags) { 652 return saveSnapshot(flags); 653 } 654 655 void OpenGLRenderer::restore() { 656 if (mSaveCount > 1) { 657 restoreSnapshot(); 658 } 659 } 660 661 void OpenGLRenderer::restoreToCount(int saveCount) { 662 if (saveCount < 1) saveCount = 1; 663 664 while (mSaveCount > saveCount) { 665 restoreSnapshot(); 666 } 667 } 668 669 int OpenGLRenderer::saveSnapshot(int flags) { 670 mSnapshot = new Snapshot(mSnapshot, flags); 671 return mSaveCount++; 672 } 673 674 bool OpenGLRenderer::restoreSnapshot() { 675 bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet; 676 bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer; 677 bool restoreOrtho = mSnapshot->flags & Snapshot::kFlagDirtyOrtho; 678 679 sp<Snapshot> current = mSnapshot; 680 sp<Snapshot> previous = mSnapshot->previous; 681 682 if (restoreOrtho) { 683 Rect& r = previous->viewport; 684 glViewport(r.left, r.top, r.right, r.bottom); 685 mOrthoMatrix.load(current->orthoMatrix); 686 } 687 688 mSaveCount--; 689 mSnapshot = previous; 690 691 if (restoreClip) { 692 dirtyClip(); 693 } 694 695 if (restoreLayer) { 696 endMark(); // Savelayer 697 startMark("ComposeLayer"); 698 composeLayer(current, previous); 699 endMark(); 700 } 701 702 return restoreClip; 703 } 704 705 /////////////////////////////////////////////////////////////////////////////// 706 // Layers 707 /////////////////////////////////////////////////////////////////////////////// 708 709 int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom, 710 int alpha, SkXfermode::Mode mode, int flags) { 711 const GLuint previousFbo = mSnapshot->fbo; 712 const int count = saveSnapshot(flags); 713 714 if (!mSnapshot->isIgnored()) { 715 createLayer(left, top, right, bottom, alpha, mode, flags, previousFbo); 716 } 717 718 return count; 719 } 720 721 void OpenGLRenderer::calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool fboLayer) { 722 const Rect untransformedBounds(bounds); 723 724 currentTransform().mapRect(bounds); 725 726 // Layers only make sense if they are in the framebuffer's bounds 727 if (bounds.intersect(*mSnapshot->clipRect)) { 728 // We cannot work with sub-pixels in this case 729 bounds.snapToPixelBoundaries(); 730 731 // When the layer is not an FBO, we may use glCopyTexImage so we 732 // need to make sure the layer does not extend outside the bounds 733 // of the framebuffer 734 if (!bounds.intersect(mSnapshot->previous->viewport)) { 735 bounds.setEmpty(); 736 } else if (fboLayer) { 737 clip.set(bounds); 738 mat4 inverse; 739 inverse.loadInverse(currentTransform()); 740 inverse.mapRect(clip); 741 clip.snapToPixelBoundaries(); 742 if (clip.intersect(untransformedBounds)) { 743 clip.translate(-untransformedBounds.left, -untransformedBounds.top); 744 bounds.set(untransformedBounds); 745 } else { 746 clip.setEmpty(); 747 } 748 } 749 } else { 750 bounds.setEmpty(); 751 } 752 } 753 754 void OpenGLRenderer::updateSnapshotIgnoreForLayer(const Rect& bounds, const Rect& clip, 755 bool fboLayer, int alpha) { 756 if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize || 757 bounds.getHeight() > mCaches.maxTextureSize || 758 (fboLayer && clip.isEmpty())) { 759 mSnapshot->empty = fboLayer; 760 } else { 761 mSnapshot->invisible = mSnapshot->invisible || (alpha <= ALPHA_THRESHOLD && fboLayer); 762 } 763 } 764 765 int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float bottom, 766 int alpha, SkXfermode::Mode mode, int flags) { 767 const GLuint previousFbo = mSnapshot->fbo; 768 const int count = saveSnapshot(flags); 769 770 if (!mSnapshot->isIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) { 771 // initialize the snapshot as though it almost represents an FBO layer so deferred draw 772 // operations will be able to store and restore the current clip and transform info, and 773 // quick rejection will be correct (for display lists) 774 775 Rect bounds(left, top, right, bottom); 776 Rect clip; 777 calculateLayerBoundsAndClip(bounds, clip, true); 778 updateSnapshotIgnoreForLayer(bounds, clip, true, alpha); 779 780 if (!mSnapshot->isIgnored()) { 781 mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f); 782 mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom); 783 } 784 } 785 786 return count; 787 } 788 789 790 /** 791 * Layers are viewed by Skia are slightly different than layers in image editing 792 * programs (for instance.) When a layer is created, previously created layers 793 * and the frame buffer still receive every drawing command. For instance, if a 794 * layer is created and a shape intersecting the bounds of the layers and the 795 * framebuffer is draw, the shape will be drawn on both (unless the layer was 796 * created with the SkCanvas::kClipToLayer_SaveFlag flag.) 797 * 798 * A way to implement layers is to create an FBO for each layer, backed by an RGBA 799 * texture. Unfortunately, this is inefficient as it requires every primitive to 800 * be drawn n + 1 times, where n is the number of active layers. In practice this 801 * means, for every primitive: 802 * - Switch active frame buffer 803 * - Change viewport, clip and projection matrix 804 * - Issue the drawing 805 * 806 * Switching rendering target n + 1 times per drawn primitive is extremely costly. 807 * To avoid this, layers are implemented in a different way here, at least in the 808 * general case. FBOs are used, as an optimization, when the "clip to layer" flag 809 * is set. When this flag is set we can redirect all drawing operations into a 810 * single FBO. 811 * 812 * This implementation relies on the frame buffer being at least RGBA 8888. When 813 * a layer is created, only a texture is created, not an FBO. The content of the 814 * frame buffer contained within the layer's bounds is copied into this texture 815 * using glCopyTexImage2D(). The layer's region is then cleared(1) in the frame 816 * buffer and drawing continues as normal. This technique therefore treats the 817 * frame buffer as a scratch buffer for the layers. 818 * 819 * To compose the layers back onto the frame buffer, each layer texture 820 * (containing the original frame buffer data) is drawn as a simple quad over 821 * the frame buffer. The trick is that the quad is set as the composition 822 * destination in the blending equation, and the frame buffer becomes the source 823 * of the composition. 824 * 825 * Drawing layers with an alpha value requires an extra step before composition. 826 * An empty quad is drawn over the layer's region in the frame buffer. This quad 827 * is drawn with the rgba color (0,0,0,alpha). The alpha value offered by the 828 * quad is used to multiply the colors in the frame buffer. This is achieved by 829 * changing the GL blend functions for the GL_FUNC_ADD blend equation to 830 * GL_ZERO, GL_SRC_ALPHA. 831 * 832 * Because glCopyTexImage2D() can be slow, an alternative implementation might 833 * be use to draw a single clipped layer. The implementation described above 834 * is correct in every case. 835 * 836 * (1) The frame buffer is actually not cleared right away. To allow the GPU 837 * to potentially optimize series of calls to glCopyTexImage2D, the frame 838 * buffer is left untouched until the first drawing operation. Only when 839 * something actually gets drawn are the layers regions cleared. 840 */ 841 bool OpenGLRenderer::createLayer(float left, float top, float right, float bottom, 842 int alpha, SkXfermode::Mode mode, int flags, GLuint previousFbo) { 843 LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top); 844 LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize()); 845 846 const bool fboLayer = flags & SkCanvas::kClipToLayer_SaveFlag; 847 848 // Window coordinates of the layer 849 Rect clip; 850 Rect bounds(left, top, right, bottom); 851 calculateLayerBoundsAndClip(bounds, clip, fboLayer); 852 updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, alpha); 853 854 // Bail out if we won't draw in this snapshot 855 if (mSnapshot->isIgnored()) { 856 return false; 857 } 858 859 mCaches.activeTexture(0); 860 Layer* layer = mCaches.layerCache.get(bounds.getWidth(), bounds.getHeight()); 861 if (!layer) { 862 return false; 863 } 864 865 layer->setAlpha(alpha, mode); 866 layer->layer.set(bounds); 867 layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()), 868 bounds.getWidth() / float(layer->getWidth()), 0.0f); 869 layer->setColorFilter(mDrawModifiers.mColorFilter); 870 layer->setBlend(true); 871 layer->setDirty(false); 872 873 // Save the layer in the snapshot 874 mSnapshot->flags |= Snapshot::kFlagIsLayer; 875 mSnapshot->layer = layer; 876 877 startMark("SaveLayer"); 878 if (fboLayer) { 879 return createFboLayer(layer, bounds, clip, previousFbo); 880 } else { 881 // Copy the framebuffer into the layer 882 layer->bindTexture(); 883 if (!bounds.isEmpty()) { 884 if (layer->isEmpty()) { 885 // Workaround for some GL drivers. When reading pixels lying outside 886 // of the window we should get undefined values for those pixels. 887 // Unfortunately some drivers will turn the entire target texture black 888 // when reading outside of the window. 889 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->getWidth(), layer->getHeight(), 890 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); 891 layer->setEmpty(false); 892 } 893 894 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left, 895 mSnapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight()); 896 897 // Enqueue the buffer coordinates to clear the corresponding region later 898 mLayers.push(new Rect(bounds)); 899 } 900 } 901 902 return true; 903 } 904 905 bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip, GLuint previousFbo) { 906 layer->clipRect.set(clip); 907 layer->setFbo(mCaches.fboCache.get()); 908 909 mSnapshot->region = &mSnapshot->layer->region; 910 mSnapshot->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer | 911 Snapshot::kFlagDirtyOrtho; 912 mSnapshot->fbo = layer->getFbo(); 913 mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f); 914 mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom); 915 mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight()); 916 mSnapshot->height = bounds.getHeight(); 917 mSnapshot->orthoMatrix.load(mOrthoMatrix); 918 919 endTiling(); 920 debugOverdraw(false, false); 921 // Bind texture to FBO 922 glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo()); 923 layer->bindTexture(); 924 925 // Initialize the texture if needed 926 if (layer->isEmpty()) { 927 layer->allocateTexture(); 928 layer->setEmpty(false); 929 } 930 931 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 932 layer->getTexture(), 0); 933 934 startTiling(mSnapshot, true); 935 936 // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering 937 mCaches.enableScissor(); 938 mCaches.setScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f, 939 clip.getWidth() + 2.0f, clip.getHeight() + 2.0f); 940 glClear(GL_COLOR_BUFFER_BIT); 941 942 dirtyClip(); 943 944 // Change the ortho projection 945 glViewport(0, 0, bounds.getWidth(), bounds.getHeight()); 946 mOrthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f); 947 948 return true; 949 } 950 951 /** 952 * Read the documentation of createLayer() before doing anything in this method. 953 */ 954 void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { 955 if (!current->layer) { 956 ALOGE("Attempting to compose a layer that does not exist"); 957 return; 958 } 959 960 Layer* layer = current->layer; 961 const Rect& rect = layer->layer; 962 const bool fboLayer = current->flags & Snapshot::kFlagIsFboLayer; 963 964 if (fboLayer) { 965 endTiling(); 966 967 // Detach the texture from the FBO 968 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); 969 970 layer->removeFbo(false); 971 972 // Unbind current FBO and restore previous one 973 glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo); 974 debugOverdraw(true, false); 975 976 startTiling(previous); 977 } 978 979 if (!fboLayer && layer->getAlpha() < 255) { 980 drawColorRect(rect.left, rect.top, rect.right, rect.bottom, 981 layer->getAlpha() << 24, SkXfermode::kDstIn_Mode, true); 982 // Required below, composeLayerRect() will divide by 255 983 layer->setAlpha(255); 984 } 985 986 mCaches.unbindMeshBuffer(); 987 988 mCaches.activeTexture(0); 989 990 // When the layer is stored in an FBO, we can save a bit of fillrate by 991 // drawing only the dirty region 992 if (fboLayer) { 993 dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *previous->transform); 994 if (layer->getColorFilter()) { 995 setupColorFilter(layer->getColorFilter()); 996 } 997 composeLayerRegion(layer, rect); 998 if (layer->getColorFilter()) { 999 resetColorFilter(); 1000 } 1001 } else if (!rect.isEmpty()) { 1002 dirtyLayer(rect.left, rect.top, rect.right, rect.bottom); 1003 composeLayerRect(layer, rect, true); 1004 } 1005 1006 dirtyClip(); 1007 1008 // Failing to add the layer to the cache should happen only if the layer is too large 1009 if (!mCaches.layerCache.put(layer)) { 1010 LAYER_LOGD("Deleting layer"); 1011 Caches::getInstance().resourceCache.decrementRefcount(layer); 1012 } 1013 } 1014 1015 void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) { 1016 float alpha = layer->getAlpha() / 255.0f * mSnapshot->alpha; 1017 1018 setupDraw(); 1019 if (layer->getRenderTarget() == GL_TEXTURE_2D) { 1020 setupDrawWithTexture(); 1021 } else { 1022 setupDrawWithExternalTexture(); 1023 } 1024 setupDrawTextureTransform(); 1025 setupDrawColor(alpha, alpha, alpha, alpha); 1026 setupDrawColorFilter(); 1027 setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode()); 1028 setupDrawProgram(); 1029 setupDrawPureColorUniforms(); 1030 setupDrawColorFilterUniforms(); 1031 if (layer->getRenderTarget() == GL_TEXTURE_2D) { 1032 setupDrawTexture(layer->getTexture()); 1033 } else { 1034 setupDrawExternalTexture(layer->getTexture()); 1035 } 1036 if (currentTransform().isPureTranslate() && 1037 layer->getWidth() == (uint32_t) rect.getWidth() && 1038 layer->getHeight() == (uint32_t) rect.getHeight()) { 1039 const float x = (int) floorf(rect.left + currentTransform().getTranslateX() + 0.5f); 1040 const float y = (int) floorf(rect.top + currentTransform().getTranslateY() + 0.5f); 1041 1042 layer->setFilter(GL_NEAREST); 1043 setupDrawModelView(x, y, x + rect.getWidth(), y + rect.getHeight(), true); 1044 } else { 1045 layer->setFilter(GL_LINEAR); 1046 setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom); 1047 } 1048 setupDrawTextureTransformUniforms(layer->getTexTransform()); 1049 setupDrawMesh(&mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]); 1050 1051 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); 1052 1053 finishDrawTexture(); 1054 } 1055 1056 void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) { 1057 if (!layer->isTextureLayer()) { 1058 const Rect& texCoords = layer->texCoords; 1059 resetDrawTextureTexCoords(texCoords.left, texCoords.top, 1060 texCoords.right, texCoords.bottom); 1061 1062 float x = rect.left; 1063 float y = rect.top; 1064 bool simpleTransform = currentTransform().isPureTranslate() && 1065 layer->getWidth() == (uint32_t) rect.getWidth() && 1066 layer->getHeight() == (uint32_t) rect.getHeight(); 1067 1068 if (simpleTransform) { 1069 // When we're swapping, the layer is already in screen coordinates 1070 if (!swap) { 1071 x = (int) floorf(rect.left + currentTransform().getTranslateX() + 0.5f); 1072 y = (int) floorf(rect.top + currentTransform().getTranslateY() + 0.5f); 1073 } 1074 1075 layer->setFilter(GL_NEAREST, true); 1076 } else { 1077 layer->setFilter(GL_LINEAR, true); 1078 } 1079 1080 float alpha = getLayerAlpha(layer); 1081 bool blend = layer->isBlend() || alpha < 1.0f; 1082 drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(), 1083 layer->getTexture(), alpha, layer->getMode(), blend, 1084 &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], 1085 GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform); 1086 1087 resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); 1088 } else { 1089 resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f); 1090 drawTextureLayer(layer, rect); 1091 resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); 1092 } 1093 } 1094 1095 /** 1096 * Issues the command X, and if we're composing a save layer to the fbo or drawing a newly updated 1097 * hardware layer with overdraw debug on, draws again to the stencil only, so that these draw 1098 * operations are correctly counted twice for overdraw. NOTE: assumes composeLayerRegion only used 1099 * by saveLayer's restore 1100 */ 1101 #define DRAW_DOUBLE_STENCIL_IF(COND, DRAW_COMMAND) { \ 1102 DRAW_COMMAND; \ 1103 if (CC_UNLIKELY(mCaches.debugOverdraw && getTargetFbo() == 0 && COND)) { \ 1104 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); \ 1105 DRAW_COMMAND; \ 1106 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); \ 1107 } \ 1108 } 1109 1110 #define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND) 1111 1112 void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { 1113 if (layer->region.isRect()) { 1114 layer->setRegionAsRect(); 1115 1116 DRAW_DOUBLE_STENCIL(composeLayerRect(layer, layer->regionRect)); 1117 1118 layer->region.clear(); 1119 return; 1120 } 1121 1122 // TODO: See LayerRenderer.cpp::generateMesh() for important 1123 // information about this implementation 1124 if (CC_LIKELY(!layer->region.isEmpty())) { 1125 size_t count; 1126 const android::Rect* rects; 1127 Region safeRegion; 1128 if (CC_LIKELY(hasRectToRectTransform())) { 1129 rects = layer->region.getArray(&count); 1130 } else { 1131 safeRegion = Region::createTJunctionFreeRegion(layer->region); 1132 rects = safeRegion.getArray(&count); 1133 } 1134 1135 const float alpha = getLayerAlpha(layer); 1136 const float texX = 1.0f / float(layer->getWidth()); 1137 const float texY = 1.0f / float(layer->getHeight()); 1138 const float height = rect.getHeight(); 1139 1140 setupDraw(); 1141 1142 // We must get (and therefore bind) the region mesh buffer 1143 // after we setup drawing in case we need to mess with the 1144 // stencil buffer in setupDraw() 1145 TextureVertex* mesh = mCaches.getRegionMesh(); 1146 GLsizei numQuads = 0; 1147 1148 setupDrawWithTexture(); 1149 setupDrawColor(alpha, alpha, alpha, alpha); 1150 setupDrawColorFilter(); 1151 setupDrawBlending(layer->isBlend() || alpha < 1.0f, layer->getMode(), false); 1152 setupDrawProgram(); 1153 setupDrawDirtyRegionsDisabled(); 1154 setupDrawPureColorUniforms(); 1155 setupDrawColorFilterUniforms(); 1156 setupDrawTexture(layer->getTexture()); 1157 if (currentTransform().isPureTranslate()) { 1158 const float x = (int) floorf(rect.left + currentTransform().getTranslateX() + 0.5f); 1159 const float y = (int) floorf(rect.top + currentTransform().getTranslateY() + 0.5f); 1160 1161 layer->setFilter(GL_NEAREST); 1162 setupDrawModelViewTranslate(x, y, x + rect.getWidth(), y + rect.getHeight(), true); 1163 } else { 1164 layer->setFilter(GL_LINEAR); 1165 setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom); 1166 } 1167 setupDrawMeshIndices(&mesh[0].position[0], &mesh[0].texture[0]); 1168 1169 for (size_t i = 0; i < count; i++) { 1170 const android::Rect* r = &rects[i]; 1171 1172 const float u1 = r->left * texX; 1173 const float v1 = (height - r->top) * texY; 1174 const float u2 = r->right * texX; 1175 const float v2 = (height - r->bottom) * texY; 1176 1177 // TODO: Reject quads outside of the clip 1178 TextureVertex::set(mesh++, r->left, r->top, u1, v1); 1179 TextureVertex::set(mesh++, r->right, r->top, u2, v1); 1180 TextureVertex::set(mesh++, r->left, r->bottom, u1, v2); 1181 TextureVertex::set(mesh++, r->right, r->bottom, u2, v2); 1182 1183 numQuads++; 1184 1185 if (numQuads >= REGION_MESH_QUAD_COUNT) { 1186 DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6, 1187 GL_UNSIGNED_SHORT, NULL)); 1188 numQuads = 0; 1189 mesh = mCaches.getRegionMesh(); 1190 } 1191 } 1192 1193 if (numQuads > 0) { 1194 DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6, 1195 GL_UNSIGNED_SHORT, NULL)); 1196 } 1197 1198 finishDrawTexture(); 1199 1200 #if DEBUG_LAYERS_AS_REGIONS 1201 drawRegionRects(layer->region); 1202 #endif 1203 1204 layer->region.clear(); 1205 } 1206 } 1207 1208 void OpenGLRenderer::drawRegionRects(const Region& region) { 1209 #if DEBUG_LAYERS_AS_REGIONS 1210 size_t count; 1211 const android::Rect* rects = region.getArray(&count); 1212 1213 uint32_t colors[] = { 1214 0x7fff0000, 0x7f00ff00, 1215 0x7f0000ff, 0x7fff00ff, 1216 }; 1217 1218 int offset = 0; 1219 int32_t top = rects[0].top; 1220 1221 for (size_t i = 0; i < count; i++) { 1222 if (top != rects[i].top) { 1223 offset ^= 0x2; 1224 top = rects[i].top; 1225 } 1226 1227 Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom); 1228 drawColorRect(r.left, r.top, r.right, r.bottom, colors[offset + (i & 0x1)], 1229 SkXfermode::kSrcOver_Mode); 1230 } 1231 #endif 1232 } 1233 1234 void OpenGLRenderer::drawRegionRects(const SkRegion& region, int color, 1235 SkXfermode::Mode mode, bool dirty) { 1236 int count = 0; 1237 Vector<float> rects; 1238 1239 SkRegion::Iterator it(region); 1240 while (!it.done()) { 1241 const SkIRect& r = it.rect(); 1242 rects.push(r.fLeft); 1243 rects.push(r.fTop); 1244 rects.push(r.fRight); 1245 rects.push(r.fBottom); 1246 count += 4; 1247 it.next(); 1248 } 1249 1250 drawColorRects(rects.array(), count, color, mode, true, dirty, false); 1251 } 1252 1253 void OpenGLRenderer::dirtyLayer(const float left, const float top, 1254 const float right, const float bottom, const mat4 transform) { 1255 if (hasLayer()) { 1256 Rect bounds(left, top, right, bottom); 1257 transform.mapRect(bounds); 1258 dirtyLayerUnchecked(bounds, getRegion()); 1259 } 1260 } 1261 1262 void OpenGLRenderer::dirtyLayer(const float left, const float top, 1263 const float right, const float bottom) { 1264 if (hasLayer()) { 1265 Rect bounds(left, top, right, bottom); 1266 dirtyLayerUnchecked(bounds, getRegion()); 1267 } 1268 } 1269 1270 void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) { 1271 if (bounds.intersect(*mSnapshot->clipRect)) { 1272 bounds.snapToPixelBoundaries(); 1273 android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom); 1274 if (!dirty.isEmpty()) { 1275 region->orSelf(dirty); 1276 } 1277 } 1278 } 1279 1280 void OpenGLRenderer::clearLayerRegions() { 1281 const size_t count = mLayers.size(); 1282 if (count == 0) return; 1283 1284 if (!mSnapshot->isIgnored()) { 1285 // Doing several glScissor/glClear here can negatively impact 1286 // GPUs with a tiler architecture, instead we draw quads with 1287 // the Clear blending mode 1288 1289 // The list contains bounds that have already been clipped 1290 // against their initial clip rect, and the current clip 1291 // is likely different so we need to disable clipping here 1292 bool scissorChanged = mCaches.disableScissor(); 1293 1294 Vertex mesh[count * 6]; 1295 Vertex* vertex = mesh; 1296 1297 for (uint32_t i = 0; i < count; i++) { 1298 Rect* bounds = mLayers.itemAt(i); 1299 1300 Vertex::set(vertex++, bounds->left, bounds->bottom); 1301 Vertex::set(vertex++, bounds->left, bounds->top); 1302 Vertex::set(vertex++, bounds->right, bounds->top); 1303 Vertex::set(vertex++, bounds->left, bounds->bottom); 1304 Vertex::set(vertex++, bounds->right, bounds->top); 1305 Vertex::set(vertex++, bounds->right, bounds->bottom); 1306 1307 delete bounds; 1308 } 1309 // We must clear the list of dirty rects before we 1310 // call setupDraw() to prevent stencil setup to do 1311 // the same thing again 1312 mLayers.clear(); 1313 1314 setupDraw(false); 1315 setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f); 1316 setupDrawBlending(true, SkXfermode::kClear_Mode); 1317 setupDrawProgram(); 1318 setupDrawPureColorUniforms(); 1319 setupDrawModelViewTranslate(0.0f, 0.0f, 0.0f, 0.0f, true); 1320 setupDrawVertices(&mesh[0].position[0]); 1321 1322 glDrawArrays(GL_TRIANGLES, 0, count * 6); 1323 1324 if (scissorChanged) mCaches.enableScissor(); 1325 } else { 1326 for (uint32_t i = 0; i < count; i++) { 1327 delete mLayers.itemAt(i); 1328 } 1329 mLayers.clear(); 1330 } 1331 } 1332 1333 /////////////////////////////////////////////////////////////////////////////// 1334 // State Deferral 1335 /////////////////////////////////////////////////////////////////////////////// 1336 1337 bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) { 1338 const Rect& currentClip = *(mSnapshot->clipRect); 1339 const mat4& currentMatrix = *(mSnapshot->transform); 1340 1341 if (stateDeferFlags & kStateDeferFlag_Draw) { 1342 // state has bounds initialized in local coordinates 1343 if (!state.mBounds.isEmpty()) { 1344 currentMatrix.mapRect(state.mBounds); 1345 if (!state.mBounds.intersect(currentClip)) { 1346 // quick rejected 1347 return true; 1348 } 1349 } else { 1350 state.mBounds.set(currentClip); 1351 } 1352 } 1353 1354 state.mClipValid = (stateDeferFlags & kStateDeferFlag_Clip); 1355 if (state.mClipValid) { 1356 state.mClip.set(currentClip); 1357 } 1358 1359 // Transform, drawModifiers, and alpha always deferred, since they are used by state operations 1360 // (Note: saveLayer/restore use colorFilter and alpha, so we just save restore everything) 1361 state.mMatrix.load(currentMatrix); 1362 state.mDrawModifiers = mDrawModifiers; 1363 state.mAlpha = mSnapshot->alpha; 1364 return false; 1365 } 1366 1367 void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) { 1368 currentTransform().load(state.mMatrix); 1369 mDrawModifiers = state.mDrawModifiers; 1370 mSnapshot->alpha = state.mAlpha; 1371 1372 if (state.mClipValid && !skipClipRestore) { 1373 mSnapshot->setClip(state.mClip.left, state.mClip.top, state.mClip.right, state.mClip.bottom); 1374 dirtyClip(); 1375 } 1376 } 1377 1378 void OpenGLRenderer::setFullScreenClip() { 1379 mSnapshot->setClip(0, 0, mWidth, mHeight); 1380 dirtyClip(); 1381 } 1382 1383 /////////////////////////////////////////////////////////////////////////////// 1384 // Transforms 1385 /////////////////////////////////////////////////////////////////////////////// 1386 1387 void OpenGLRenderer::translate(float dx, float dy) { 1388 currentTransform().translate(dx, dy, 0.0f); 1389 } 1390 1391 void OpenGLRenderer::rotate(float degrees) { 1392 currentTransform().rotate(degrees, 0.0f, 0.0f, 1.0f); 1393 } 1394 1395 void OpenGLRenderer::scale(float sx, float sy) { 1396 currentTransform().scale(sx, sy, 1.0f); 1397 } 1398 1399 void OpenGLRenderer::skew(float sx, float sy) { 1400 currentTransform().skew(sx, sy); 1401 } 1402 1403 void OpenGLRenderer::setMatrix(SkMatrix* matrix) { 1404 if (matrix) { 1405 currentTransform().load(*matrix); 1406 } else { 1407 currentTransform().loadIdentity(); 1408 } 1409 } 1410 1411 bool OpenGLRenderer::hasRectToRectTransform() { 1412 return CC_LIKELY(currentTransform().rectToRect()); 1413 } 1414 1415 void OpenGLRenderer::getMatrix(SkMatrix* matrix) { 1416 currentTransform().copyTo(*matrix); 1417 } 1418 1419 void OpenGLRenderer::concatMatrix(SkMatrix* matrix) { 1420 SkMatrix transform; 1421 currentTransform().copyTo(transform); 1422 transform.preConcat(*matrix); 1423 currentTransform().load(transform); 1424 } 1425 1426 /////////////////////////////////////////////////////////////////////////////// 1427 // Clipping 1428 /////////////////////////////////////////////////////////////////////////////// 1429 1430 void OpenGLRenderer::setScissorFromClip() { 1431 Rect clip(*mSnapshot->clipRect); 1432 clip.snapToPixelBoundaries(); 1433 1434 if (mCaches.setScissor(clip.left, mSnapshot->height - clip.bottom, 1435 clip.getWidth(), clip.getHeight())) { 1436 mDirtyClip = false; 1437 } 1438 } 1439 1440 void OpenGLRenderer::ensureStencilBuffer() { 1441 // Thanks to the mismatch between EGL and OpenGL ES FBO we 1442 // cannot attach a stencil buffer to fbo0 dynamically. Let's 1443 // just hope we have one when hasLayer() returns false. 1444 if (hasLayer()) { 1445 attachStencilBufferToLayer(mSnapshot->layer); 1446 } 1447 } 1448 1449 void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) { 1450 // The layer's FBO is already bound when we reach this stage 1451 if (!layer->getStencilRenderBuffer()) { 1452 // GL_QCOM_tiled_rendering doesn't like it if a renderbuffer 1453 // is attached after we initiated tiling. We must turn it off, 1454 // attach the new render buffer then turn tiling back on 1455 endTiling(); 1456 1457 RenderBuffer* buffer = mCaches.renderBufferCache.get( 1458 Stencil::getSmallestStencilFormat(), layer->getWidth(), layer->getHeight()); 1459 layer->setStencilRenderBuffer(buffer); 1460 1461 startTiling(layer->clipRect, layer->layer.getHeight()); 1462 } 1463 } 1464 1465 void OpenGLRenderer::setStencilFromClip() { 1466 if (!mCaches.debugOverdraw) { 1467 if (!mSnapshot->clipRegion->isEmpty()) { 1468 // NOTE: The order here is important, we must set dirtyClip to false 1469 // before any draw call to avoid calling back into this method 1470 mDirtyClip = false; 1471 1472 ensureStencilBuffer(); 1473 1474 mCaches.stencil.enableWrite(); 1475 1476 // Clear the stencil but first make sure we restrict drawing 1477 // to the region's bounds 1478 bool resetScissor = mCaches.enableScissor(); 1479 if (resetScissor) { 1480 // The scissor was not set so we now need to update it 1481 setScissorFromClip(); 1482 } 1483 mCaches.stencil.clear(); 1484 if (resetScissor) mCaches.disableScissor(); 1485 1486 // NOTE: We could use the region contour path to generate a smaller mesh 1487 // Since we are using the stencil we could use the red book path 1488 // drawing technique. It might increase bandwidth usage though. 1489 1490 // The last parameter is important: we are not drawing in the color buffer 1491 // so we don't want to dirty the current layer, if any 1492 drawRegionRects(*mSnapshot->clipRegion, 0xff000000, SkXfermode::kSrc_Mode, false); 1493 1494 mCaches.stencil.enableTest(); 1495 1496 // Draw the region used to generate the stencil if the appropriate debug 1497 // mode is enabled 1498 if (mCaches.debugStencilClip == Caches::kStencilShowRegion) { 1499 drawRegionRects(*mSnapshot->clipRegion, 0x7f0000ff, SkXfermode::kSrcOver_Mode); 1500 } 1501 } else { 1502 mCaches.stencil.disable(); 1503 } 1504 } 1505 } 1506 1507 const Rect& OpenGLRenderer::getClipBounds() { 1508 return mSnapshot->getLocalClip(); 1509 } 1510 1511 bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom) { 1512 if (mSnapshot->isIgnored()) { 1513 return true; 1514 } 1515 1516 Rect r(left, top, right, bottom); 1517 currentTransform().mapRect(r); 1518 r.snapToPixelBoundaries(); 1519 1520 Rect clipRect(*mSnapshot->clipRect); 1521 clipRect.snapToPixelBoundaries(); 1522 1523 return !clipRect.intersects(r); 1524 } 1525 1526 bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom, 1527 Rect& transformed, Rect& clip) { 1528 if (mSnapshot->isIgnored()) { 1529 return true; 1530 } 1531 1532 transformed.set(left, top, right, bottom); 1533 currentTransform().mapRect(transformed); 1534 transformed.snapToPixelBoundaries(); 1535 1536 clip.set(*mSnapshot->clipRect); 1537 clip.snapToPixelBoundaries(); 1538 1539 return !clip.intersects(transformed); 1540 } 1541 1542 bool OpenGLRenderer::quickRejectPreStroke(float left, float top, float right, float bottom, 1543 SkPaint* paint) { 1544 if (paint->getStyle() != SkPaint::kFill_Style) { 1545 float outset = paint->getStrokeWidth() * 0.5f; 1546 return quickReject(left - outset, top - outset, right + outset, bottom + outset); 1547 } else { 1548 return quickReject(left, top, right, bottom); 1549 } 1550 } 1551 1552 bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) { 1553 if (mSnapshot->isIgnored() || bottom <= top || right <= left) { 1554 return true; 1555 } 1556 1557 Rect r(left, top, right, bottom); 1558 currentTransform().mapRect(r); 1559 r.snapToPixelBoundaries(); 1560 1561 Rect clipRect(*mSnapshot->clipRect); 1562 clipRect.snapToPixelBoundaries(); 1563 1564 bool rejected = !clipRect.intersects(r); 1565 if (!isDeferred() && !rejected) { 1566 mCaches.setScissorEnabled(mScissorOptimizationDisabled || !clipRect.contains(r)); 1567 } 1568 1569 return rejected; 1570 } 1571 1572 void OpenGLRenderer::debugClip() { 1573 #if DEBUG_CLIP_REGIONS 1574 if (!isDeferred() && !mSnapshot->clipRegion->isEmpty()) { 1575 drawRegionRects(*mSnapshot->clipRegion, 0x7f00ff00, SkXfermode::kSrcOver_Mode); 1576 } 1577 #endif 1578 } 1579 1580 bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) { 1581 if (CC_LIKELY(currentTransform().rectToRect())) { 1582 bool clipped = mSnapshot->clip(left, top, right, bottom, op); 1583 if (clipped) { 1584 dirtyClip(); 1585 } 1586 return !mSnapshot->clipRect->isEmpty(); 1587 } 1588 1589 SkPath path; 1590 path.addRect(left, top, right, bottom); 1591 1592 return clipPath(&path, op); 1593 } 1594 1595 bool OpenGLRenderer::clipPath(SkPath* path, SkRegion::Op op) { 1596 SkMatrix transform; 1597 currentTransform().copyTo(transform); 1598 1599 SkPath transformed; 1600 path->transform(transform, &transformed); 1601 1602 SkRegion clip; 1603 if (!mSnapshot->clipRegion->isEmpty()) { 1604 clip.setRegion(*mSnapshot->clipRegion); 1605 } else { 1606 Rect* bounds = mSnapshot->clipRect; 1607 clip.setRect(bounds->left, bounds->top, bounds->right, bounds->bottom); 1608 } 1609 1610 SkRegion region; 1611 region.setPath(transformed, clip); 1612 1613 bool clipped = mSnapshot->clipRegionTransformed(region, op); 1614 if (clipped) { 1615 dirtyClip(); 1616 } 1617 return !mSnapshot->clipRect->isEmpty(); 1618 } 1619 1620 bool OpenGLRenderer::clipRegion(SkRegion* region, SkRegion::Op op) { 1621 bool clipped = mSnapshot->clipRegionTransformed(*region, op); 1622 if (clipped) { 1623 dirtyClip(); 1624 } 1625 return !mSnapshot->clipRect->isEmpty(); 1626 } 1627 1628 Rect* OpenGLRenderer::getClipRect() { 1629 return mSnapshot->clipRect; 1630 } 1631 1632 /////////////////////////////////////////////////////////////////////////////// 1633 // Drawing commands 1634 /////////////////////////////////////////////////////////////////////////////// 1635 1636 void OpenGLRenderer::setupDraw(bool clear) { 1637 // TODO: It would be best if we could do this before quickReject() 1638 // changes the scissor test state 1639 if (clear) clearLayerRegions(); 1640 // Make sure setScissor & setStencil happen at the beginning of 1641 // this method 1642 if (mDirtyClip) { 1643 if (mCaches.scissorEnabled) { 1644 setScissorFromClip(); 1645 } 1646 setStencilFromClip(); 1647 } 1648 1649 mDescription.reset(); 1650 1651 mSetShaderColor = false; 1652 mColorSet = false; 1653 mColorA = mColorR = mColorG = mColorB = 0.0f; 1654 mTextureUnit = 0; 1655 mTrackDirtyRegions = true; 1656 1657 // Enable debug highlight when what we're about to draw is tested against 1658 // the stencil buffer and if stencil highlight debugging is on 1659 mDescription.hasDebugHighlight = !mCaches.debugOverdraw && 1660 mCaches.debugStencilClip == Caches::kStencilShowHighlight && 1661 mCaches.stencil.isTestEnabled(); 1662 } 1663 1664 void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) { 1665 mDescription.hasTexture = true; 1666 mDescription.hasAlpha8Texture = isAlpha8; 1667 } 1668 1669 void OpenGLRenderer::setupDrawWithTextureAndColor(bool isAlpha8) { 1670 mDescription.hasTexture = true; 1671 mDescription.hasColors = true; 1672 mDescription.hasAlpha8Texture = isAlpha8; 1673 } 1674 1675 void OpenGLRenderer::setupDrawWithExternalTexture() { 1676 mDescription.hasExternalTexture = true; 1677 } 1678 1679 void OpenGLRenderer::setupDrawNoTexture() { 1680 mCaches.disableTexCoordsVertexArray(); 1681 } 1682 1683 void OpenGLRenderer::setupDrawAA() { 1684 mDescription.isAA = true; 1685 } 1686 1687 void OpenGLRenderer::setupDrawPoint(float pointSize) { 1688 mDescription.isPoint = true; 1689 mDescription.pointSize = pointSize; 1690 } 1691 1692 void OpenGLRenderer::setupDrawColor(int color, int alpha) { 1693 mColorA = alpha / 255.0f; 1694 mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f; 1695 mColorG = mColorA * ((color >> 8) & 0xFF) / 255.0f; 1696 mColorB = mColorA * ((color ) & 0xFF) / 255.0f; 1697 mColorSet = true; 1698 mSetShaderColor = mDescription.setColor(mColorR, mColorG, mColorB, mColorA); 1699 } 1700 1701 void OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) { 1702 mColorA = alpha / 255.0f; 1703 mColorR = mColorA * ((color >> 16) & 0xFF) / 255.0f; 1704 mColorG = mColorA * ((color >> 8) & 0xFF) / 255.0f; 1705 mColorB = mColorA * ((color ) & 0xFF) / 255.0f; 1706 mColorSet = true; 1707 mSetShaderColor = mDescription.setAlpha8Color(mColorR, mColorG, mColorB, mColorA); 1708 } 1709 1710 void OpenGLRenderer::setupDrawTextGamma(const SkPaint* paint) { 1711 mCaches.fontRenderer->describe(mDescription, paint); 1712 } 1713 1714 void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) { 1715 mColorA = a; 1716 mColorR = r; 1717 mColorG = g; 1718 mColorB = b; 1719 mColorSet = true; 1720 mSetShaderColor = mDescription.setColor(r, g, b, a); 1721 } 1722 1723 void OpenGLRenderer::setupDrawShader() { 1724 if (mDrawModifiers.mShader) { 1725 mDrawModifiers.mShader->describe(mDescription, mExtensions); 1726 } 1727 } 1728 1729 void OpenGLRenderer::setupDrawColorFilter() { 1730 if (mDrawModifiers.mColorFilter) { 1731 mDrawModifiers.mColorFilter->describe(mDescription, mExtensions); 1732 } 1733 } 1734 1735 void OpenGLRenderer::accountForClear(SkXfermode::Mode mode) { 1736 if (mColorSet && mode == SkXfermode::kClear_Mode) { 1737 mColorA = 1.0f; 1738 mColorR = mColorG = mColorB = 0.0f; 1739 mSetShaderColor = mDescription.modulate = true; 1740 } 1741 } 1742 1743 void OpenGLRenderer::setupDrawBlending(SkXfermode::Mode mode, bool swapSrcDst) { 1744 // When the blending mode is kClear_Mode, we need to use a modulate color 1745 // argb=1,0,0,0 1746 accountForClear(mode); 1747 bool blend = (mColorSet && mColorA < 1.0f) || 1748 (mDrawModifiers.mShader && mDrawModifiers.mShader->blend()); 1749 chooseBlending(blend, mode, mDescription, swapSrcDst); 1750 } 1751 1752 void OpenGLRenderer::setupDrawBlending(bool blend, SkXfermode::Mode mode, bool swapSrcDst) { 1753 // When the blending mode is kClear_Mode, we need to use a modulate color 1754 // argb=1,0,0,0 1755 accountForClear(mode); 1756 blend |= (mColorSet && mColorA < 1.0f) || 1757 (mDrawModifiers.mShader && mDrawModifiers.mShader->blend()) || 1758 (mDrawModifiers.mColorFilter && mDrawModifiers.mColorFilter->blend()); 1759 chooseBlending(blend, mode, mDescription, swapSrcDst); 1760 } 1761 1762 void OpenGLRenderer::setupDrawProgram() { 1763 useProgram(mCaches.programCache.get(mDescription)); 1764 } 1765 1766 void OpenGLRenderer::setupDrawDirtyRegionsDisabled() { 1767 mTrackDirtyRegions = false; 1768 } 1769 1770 void OpenGLRenderer::setupDrawModelViewTranslate(float left, float top, float right, float bottom, 1771 bool ignoreTransform) { 1772 mModelView.loadTranslate(left, top, 0.0f); 1773 if (!ignoreTransform) { 1774 mCaches.currentProgram->set(mOrthoMatrix, mModelView, currentTransform()); 1775 if (mTrackDirtyRegions) dirtyLayer(left, top, right, bottom, currentTransform()); 1776 } else { 1777 mCaches.currentProgram->set(mOrthoMatrix, mModelView, mat4::identity()); 1778 if (mTrackDirtyRegions) dirtyLayer(left, top, right, bottom); 1779 } 1780 } 1781 1782 void OpenGLRenderer::setupDrawModelViewIdentity(bool offset) { 1783 mCaches.currentProgram->set(mOrthoMatrix, mat4::identity(), currentTransform(), offset); 1784 } 1785 1786 void OpenGLRenderer::setupDrawModelView(float left, float top, float right, float bottom, 1787 bool ignoreTransform, bool ignoreModelView) { 1788 if (!ignoreModelView) { 1789 mModelView.loadTranslate(left, top, 0.0f); 1790 mModelView.scale(right - left, bottom - top, 1.0f); 1791 } else { 1792 mModelView.loadIdentity(); 1793 } 1794 bool dirty = right - left > 0.0f && bottom - top > 0.0f; 1795 if (!ignoreTransform) { 1796 mCaches.currentProgram->set(mOrthoMatrix, mModelView, currentTransform()); 1797 if (mTrackDirtyRegions && dirty) { 1798 dirtyLayer(left, top, right, bottom, currentTransform()); 1799 } 1800 } else { 1801 mCaches.currentProgram->set(mOrthoMatrix, mModelView, mat4::identity()); 1802 if (mTrackDirtyRegions && dirty) dirtyLayer(left, top, right, bottom); 1803 } 1804 } 1805 1806 void OpenGLRenderer::setupDrawPointUniforms() { 1807 int slot = mCaches.currentProgram->getUniform("pointSize"); 1808 glUniform1f(slot, mDescription.pointSize); 1809 } 1810 1811 void OpenGLRenderer::setupDrawColorUniforms() { 1812 if ((mColorSet && !mDrawModifiers.mShader) || (mDrawModifiers.mShader && mSetShaderColor)) { 1813 mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA); 1814 } 1815 } 1816 1817 void OpenGLRenderer::setupDrawPureColorUniforms() { 1818 if (mSetShaderColor) { 1819 mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA); 1820 } 1821 } 1822 1823 void OpenGLRenderer::setupDrawShaderUniforms(bool ignoreTransform) { 1824 if (mDrawModifiers.mShader) { 1825 if (ignoreTransform) { 1826 mModelView.loadInverse(currentTransform()); 1827 } 1828 mDrawModifiers.mShader->setupProgram(mCaches.currentProgram, 1829 mModelView, *mSnapshot, &mTextureUnit); 1830 } 1831 } 1832 1833 void OpenGLRenderer::setupDrawShaderIdentityUniforms() { 1834 if (mDrawModifiers.mShader) { 1835 mDrawModifiers.mShader->setupProgram(mCaches.currentProgram, 1836 mat4::identity(), *mSnapshot, &mTextureUnit); 1837 } 1838 } 1839 1840 void OpenGLRenderer::setupDrawColorFilterUniforms() { 1841 if (mDrawModifiers.mColorFilter) { 1842 mDrawModifiers.mColorFilter->setupProgram(mCaches.currentProgram); 1843 } 1844 } 1845 1846 void OpenGLRenderer::setupDrawTextGammaUniforms() { 1847 mCaches.fontRenderer->setupProgram(mDescription, mCaches.currentProgram); 1848 } 1849 1850 void OpenGLRenderer::setupDrawSimpleMesh() { 1851 bool force = mCaches.bindMeshBuffer(); 1852 mCaches.bindPositionVertexPointer(force, 0); 1853 mCaches.unbindIndicesBuffer(); 1854 } 1855 1856 void OpenGLRenderer::setupDrawTexture(GLuint texture) { 1857 if (texture) bindTexture(texture); 1858 mTextureUnit++; 1859 mCaches.enableTexCoordsVertexArray(); 1860 } 1861 1862 void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) { 1863 bindExternalTexture(texture); 1864 mTextureUnit++; 1865 mCaches.enableTexCoordsVertexArray(); 1866 } 1867 1868 void OpenGLRenderer::setupDrawTextureTransform() { 1869 mDescription.hasTextureTransform = true; 1870 } 1871 1872 void OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) { 1873 glUniformMatrix4fv(mCaches.currentProgram->getUniform("mainTextureTransform"), 1, 1874 GL_FALSE, &transform.data[0]); 1875 } 1876 1877 void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLuint vbo) { 1878 bool force = false; 1879 if (!vertices) { 1880 force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo); 1881 } else { 1882 force = mCaches.unbindMeshBuffer(); 1883 } 1884 1885 mCaches.bindPositionVertexPointer(force, vertices); 1886 if (mCaches.currentProgram->texCoords >= 0) { 1887 mCaches.bindTexCoordsVertexPointer(force, texCoords); 1888 } 1889 1890 mCaches.unbindIndicesBuffer(); 1891 } 1892 1893 void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLvoid* colors) { 1894 bool force = mCaches.unbindMeshBuffer(); 1895 GLsizei stride = sizeof(ColorTextureVertex); 1896 1897 mCaches.bindPositionVertexPointer(force, vertices, stride); 1898 if (mCaches.currentProgram->texCoords >= 0) { 1899 mCaches.bindTexCoordsVertexPointer(force, texCoords, stride); 1900 } 1901 int slot = mCaches.currentProgram->getAttrib("colors"); 1902 if (slot >= 0) { 1903 glEnableVertexAttribArray(slot); 1904 glVertexAttribPointer(slot, 4, GL_FLOAT, GL_FALSE, stride, colors); 1905 } 1906 1907 mCaches.unbindIndicesBuffer(); 1908 } 1909 1910 void OpenGLRenderer::setupDrawMeshIndices(GLvoid* vertices, GLvoid* texCoords) { 1911 bool force = mCaches.unbindMeshBuffer(); 1912 mCaches.bindPositionVertexPointer(force, vertices); 1913 if (mCaches.currentProgram->texCoords >= 0) { 1914 mCaches.bindTexCoordsVertexPointer(force, texCoords); 1915 } 1916 } 1917 1918 void OpenGLRenderer::setupDrawVertices(GLvoid* vertices) { 1919 bool force = mCaches.unbindMeshBuffer(); 1920 mCaches.bindPositionVertexPointer(force, vertices, gVertexStride); 1921 mCaches.unbindIndicesBuffer(); 1922 } 1923 1924 void OpenGLRenderer::finishDrawTexture() { 1925 } 1926 1927 /////////////////////////////////////////////////////////////////////////////// 1928 // Drawing 1929 /////////////////////////////////////////////////////////////////////////////// 1930 1931 status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty, 1932 int32_t replayFlags) { 1933 status_t status; 1934 // All the usual checks and setup operations (quickReject, setupDraw, etc.) 1935 // will be performed by the display list itself 1936 if (displayList && displayList->isRenderable()) { 1937 if (CC_UNLIKELY(mCaches.drawDeferDisabled)) { 1938 status = startFrame(); 1939 ReplayStateStruct replayStruct(*this, dirty, replayFlags); 1940 displayList->replay(replayStruct, 0); 1941 return status | replayStruct.mDrawGlStatus; 1942 } 1943 1944 DeferredDisplayList deferredList; 1945 DeferStateStruct deferStruct(deferredList, *this, replayFlags); 1946 displayList->defer(deferStruct, 0); 1947 1948 flushLayers(); 1949 status = startFrame(); 1950 1951 return status | deferredList.flush(*this, dirty); 1952 } 1953 1954 return DrawGlInfo::kStatusDone; 1955 } 1956 1957 void OpenGLRenderer::outputDisplayList(DisplayList* displayList) { 1958 if (displayList) { 1959 displayList->output(1); 1960 } 1961 } 1962 1963 void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint) { 1964 int alpha; 1965 SkXfermode::Mode mode; 1966 getAlphaAndMode(paint, &alpha, &mode); 1967 1968 int color = paint != NULL ? paint->getColor() : 0; 1969 1970 float x = left; 1971 float y = top; 1972 1973 texture->setWrap(GL_CLAMP_TO_EDGE, true); 1974 1975 bool ignoreTransform = false; 1976 if (currentTransform().isPureTranslate()) { 1977 x = (int) floorf(left + currentTransform().getTranslateX() + 0.5f); 1978 y = (int) floorf(top + currentTransform().getTranslateY() + 0.5f); 1979 ignoreTransform = true; 1980 1981 texture->setFilter(GL_NEAREST, true); 1982 } else { 1983 texture->setFilter(FILTER(paint), true); 1984 } 1985 1986 drawAlpha8TextureMesh(x, y, x + texture->width, y + texture->height, texture->id, 1987 paint != NULL, color, alpha, mode, (GLvoid*) NULL, 1988 (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform); 1989 } 1990 1991 status_t OpenGLRenderer::drawBitmaps(SkBitmap* bitmap, int bitmapCount, TextureVertex* vertices, 1992 const Rect& bounds, SkPaint* paint) { 1993 1994 // merged draw operations don't need scissor, but clip should still be valid 1995 mCaches.setScissorEnabled(mScissorOptimizationDisabled); 1996 1997 mCaches.activeTexture(0); 1998 Texture* texture = mCaches.textureCache.get(bitmap); 1999 if (!texture) return DrawGlInfo::kStatusDone; 2000 const AutoTexture autoCleanup(texture); 2001 2002 int alpha; 2003 SkXfermode::Mode mode; 2004 getAlphaAndMode(paint, &alpha, &mode); 2005 2006 texture->setWrap(GL_CLAMP_TO_EDGE, true); 2007 texture->setFilter(GL_NEAREST, true); // merged ops are always pure-translation for now 2008 2009 const float x = (int) floorf(bounds.left + 0.5f); 2010 const float y = (int) floorf(bounds.top + 0.5f); 2011 if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) { 2012 int color = paint != NULL ? paint->getColor() : 0; 2013 drawAlpha8TextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(), 2014 texture->id, paint != NULL, color, alpha, mode, 2015 &vertices[0].position[0], &vertices[0].texture[0], 2016 GL_TRIANGLES, bitmapCount * 6, true, true); 2017 } else { 2018 drawTextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(), 2019 texture->id, alpha / 255.0f, mode, texture->blend, 2020 &vertices[0].position[0], &vertices[0].texture[0], 2021 GL_TRIANGLES, bitmapCount * 6, false, true, 0, true); 2022 } 2023 2024 return DrawGlInfo::kStatusDrew; 2025 } 2026 2027 status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) { 2028 const float right = left + bitmap->width(); 2029 const float bottom = top + bitmap->height(); 2030 2031 if (quickReject(left, top, right, bottom)) { 2032 return DrawGlInfo::kStatusDone; 2033 } 2034 2035 mCaches.activeTexture(0); 2036 Texture* texture = mCaches.textureCache.get(bitmap); 2037 if (!texture) return DrawGlInfo::kStatusDone; 2038 const AutoTexture autoCleanup(texture); 2039 2040 if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) { 2041 drawAlphaBitmap(texture, left, top, paint); 2042 } else { 2043 drawTextureRect(left, top, right, bottom, texture, paint); 2044 } 2045 2046 return DrawGlInfo::kStatusDrew; 2047 } 2048 2049 status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint) { 2050 Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height()); 2051 const mat4 transform(*matrix); 2052 transform.mapRect(r); 2053 2054 if (quickReject(r.left, r.top, r.right, r.bottom)) { 2055 return DrawGlInfo::kStatusDone; 2056 } 2057 2058 mCaches.activeTexture(0); 2059 Texture* texture = mCaches.textureCache.get(bitmap); 2060 if (!texture) return DrawGlInfo::kStatusDone; 2061 const AutoTexture autoCleanup(texture); 2062 2063 // This could be done in a cheaper way, all we need is pass the matrix 2064 // to the vertex shader. The save/restore is a bit overkill. 2065 save(SkCanvas::kMatrix_SaveFlag); 2066 concatMatrix(matrix); 2067 if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) { 2068 drawAlphaBitmap(texture, 0.0f, 0.0f, paint); 2069 } else { 2070 drawTextureRect(0.0f, 0.0f, bitmap->width(), bitmap->height(), texture, paint); 2071 } 2072 restore(); 2073 2074 return DrawGlInfo::kStatusDrew; 2075 } 2076 2077 status_t OpenGLRenderer::drawBitmapData(SkBitmap* bitmap, float left, float top, SkPaint* paint) { 2078 const float right = left + bitmap->width(); 2079 const float bottom = top + bitmap->height(); 2080 2081 if (quickReject(left, top, right, bottom)) { 2082 return DrawGlInfo::kStatusDone; 2083 } 2084 2085 mCaches.activeTexture(0); 2086 Texture* texture = mCaches.textureCache.getTransient(bitmap); 2087 const AutoTexture autoCleanup(texture); 2088 2089 if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) { 2090 drawAlphaBitmap(texture, left, top, paint); 2091 } else { 2092 drawTextureRect(left, top, right, bottom, texture, paint); 2093 } 2094 2095 return DrawGlInfo::kStatusDrew; 2096 } 2097 2098 status_t OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight, 2099 float* vertices, int* colors, SkPaint* paint) { 2100 if (!vertices || mSnapshot->isIgnored()) { 2101 return DrawGlInfo::kStatusDone; 2102 } 2103 2104 float left = FLT_MAX; 2105 float top = FLT_MAX; 2106 float right = FLT_MIN; 2107 float bottom = FLT_MIN; 2108 2109 const uint32_t count = meshWidth * meshHeight * 6; 2110 2111 ColorTextureVertex mesh[count]; 2112 ColorTextureVertex* vertex = mesh; 2113 2114 bool cleanupColors = false; 2115 if (!colors) { 2116 uint32_t colorsCount = (meshWidth + 1) * (meshHeight + 1); 2117 colors = new int[colorsCount]; 2118 memset(colors, 0xff, colorsCount * sizeof(int)); 2119 cleanupColors = true; 2120 } 2121 2122 for (int32_t y = 0; y < meshHeight; y++) { 2123 for (int32_t x = 0; x < meshWidth; x++) { 2124 uint32_t i = (y * (meshWidth + 1) + x) * 2; 2125 2126 float u1 = float(x) / meshWidth; 2127 float u2 = float(x + 1) / meshWidth; 2128 float v1 = float(y) / meshHeight; 2129 float v2 = float(y + 1) / meshHeight; 2130 2131 int ax = i + (meshWidth + 1) * 2; 2132 int ay = ax + 1; 2133 int bx = i; 2134 int by = bx + 1; 2135 int cx = i + 2; 2136 int cy = cx + 1; 2137 int dx = i + (meshWidth + 1) * 2 + 2; 2138 int dy = dx + 1; 2139 2140 ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]); 2141 ColorTextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2, colors[ax / 2]); 2142 ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]); 2143 2144 ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]); 2145 ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]); 2146 ColorTextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1, colors[cx / 2]); 2147 2148 left = fminf(left, fminf(vertices[ax], fminf(vertices[bx], vertices[cx]))); 2149 top = fminf(top, fminf(vertices[ay], fminf(vertices[by], vertices[cy]))); 2150 right = fmaxf(right, fmaxf(vertices[ax], fmaxf(vertices[bx], vertices[cx]))); 2151 bottom = fmaxf(bottom, fmaxf(vertices[ay], fmaxf(vertices[by], vertices[cy]))); 2152 } 2153 } 2154 2155 if (quickReject(left, top, right, bottom)) { 2156 if (cleanupColors) delete[] colors; 2157 return DrawGlInfo::kStatusDone; 2158 } 2159 2160 mCaches.activeTexture(0); 2161 Texture* texture = mCaches.textureCache.get(bitmap); 2162 if (!texture) { 2163 if (cleanupColors) delete[] colors; 2164 return DrawGlInfo::kStatusDone; 2165 } 2166 const AutoTexture autoCleanup(texture); 2167 2168 texture->setWrap(GL_CLAMP_TO_EDGE, true); 2169 texture->setFilter(FILTER(paint), true); 2170 2171 int alpha; 2172 SkXfermode::Mode mode; 2173 getAlphaAndMode(paint, &alpha, &mode); 2174 2175 float a = alpha / 255.0f; 2176 2177 if (hasLayer()) { 2178 dirtyLayer(left, top, right, bottom, currentTransform()); 2179 } 2180 2181 setupDraw(); 2182 setupDrawWithTextureAndColor(); 2183 setupDrawColor(a, a, a, a); 2184 setupDrawColorFilter(); 2185 setupDrawBlending(true, mode, false); 2186 setupDrawProgram(); 2187 setupDrawDirtyRegionsDisabled(); 2188 setupDrawModelView(0.0f, 0.0f, 1.0f, 1.0f, false); 2189 setupDrawTexture(texture->id); 2190 setupDrawPureColorUniforms(); 2191 setupDrawColorFilterUniforms(); 2192 setupDrawMesh(&mesh[0].position[0], &mesh[0].texture[0], &mesh[0].color[0]); 2193 2194 glDrawArrays(GL_TRIANGLES, 0, count); 2195 2196 finishDrawTexture(); 2197 2198 int slot = mCaches.currentProgram->getAttrib("colors"); 2199 if (slot >= 0) { 2200 glDisableVertexAttribArray(slot); 2201 } 2202 2203 if (cleanupColors) delete[] colors; 2204 2205 return DrawGlInfo::kStatusDrew; 2206 } 2207 2208 status_t OpenGLRenderer::drawBitmap(SkBitmap* bitmap, 2209 float srcLeft, float srcTop, float srcRight, float srcBottom, 2210 float dstLeft, float dstTop, float dstRight, float dstBottom, 2211 SkPaint* paint) { 2212 if (quickReject(dstLeft, dstTop, dstRight, dstBottom)) { 2213 return DrawGlInfo::kStatusDone; 2214 } 2215 2216 mCaches.activeTexture(0); 2217 Texture* texture = mCaches.textureCache.get(bitmap); 2218 if (!texture) return DrawGlInfo::kStatusDone; 2219 const AutoTexture autoCleanup(texture); 2220 2221 const float width = texture->width; 2222 const float height = texture->height; 2223 2224 const float u1 = fmax(0.0f, srcLeft / width); 2225 const float v1 = fmax(0.0f, srcTop / height); 2226 const float u2 = fmin(1.0f, srcRight / width); 2227 const float v2 = fmin(1.0f, srcBottom / height); 2228 2229 mCaches.unbindMeshBuffer(); 2230 resetDrawTextureTexCoords(u1, v1, u2, v2); 2231 2232 int alpha; 2233 SkXfermode::Mode mode; 2234 getAlphaAndMode(paint, &alpha, &mode); 2235 2236 texture->setWrap(GL_CLAMP_TO_EDGE, true); 2237 2238 float scaleX = (dstRight - dstLeft) / (srcRight - srcLeft); 2239 float scaleY = (dstBottom - dstTop) / (srcBottom - srcTop); 2240 2241 bool scaled = scaleX != 1.0f || scaleY != 1.0f; 2242 // Apply a scale transform on the canvas only when a shader is in use 2243 // Skia handles the ratio between the dst and src rects as a scale factor 2244 // when a shader is set 2245 bool useScaleTransform = mDrawModifiers.mShader && scaled; 2246 bool ignoreTransform = false; 2247 2248 if (CC_LIKELY(currentTransform().isPureTranslate() && !useScaleTransform)) { 2249 float x = (int) floorf(dstLeft + currentTransform().getTranslateX() + 0.5f); 2250 float y = (int) floorf(dstTop + currentTransform().getTranslateY() + 0.5f); 2251 2252 dstRight = x + (dstRight - dstLeft); 2253 dstBottom = y + (dstBottom - dstTop); 2254 2255 dstLeft = x; 2256 dstTop = y; 2257 2258 texture->setFilter(scaled ? FILTER(paint) : GL_NEAREST, true); 2259 ignoreTransform = true; 2260 } else { 2261 texture->setFilter(FILTER(paint), true); 2262 } 2263 2264 if (CC_UNLIKELY(useScaleTransform)) { 2265 save(SkCanvas::kMatrix_SaveFlag); 2266 translate(dstLeft, dstTop); 2267 scale(scaleX, scaleY); 2268 2269 dstLeft = 0.0f; 2270 dstTop = 0.0f; 2271 2272 dstRight = srcRight - srcLeft; 2273 dstBottom = srcBottom - srcTop; 2274 } 2275 2276 if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) { 2277 int color = paint ? paint->getColor() : 0; 2278 drawAlpha8TextureMesh(dstLeft, dstTop, dstRight, dstBottom, 2279 texture->id, paint != NULL, color, alpha, mode, 2280 &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], 2281 GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform); 2282 } else { 2283 drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom, 2284 texture->id, alpha / 255.0f, mode, texture->blend, 2285 &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], 2286 GL_TRIANGLE_STRIP, gMeshCount, false, ignoreTransform); 2287 } 2288 2289 if (CC_UNLIKELY(useScaleTransform)) { 2290 restore(); 2291 } 2292 2293 resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); 2294 2295 return DrawGlInfo::kStatusDrew; 2296 } 2297 2298 status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, 2299 const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, 2300 float left, float top, float right, float bottom, SkPaint* paint) { 2301 int alpha; 2302 SkXfermode::Mode mode; 2303 getAlphaAndMode(paint, &alpha, &mode); 2304 2305 return drawPatch(bitmap, xDivs, yDivs, colors, width, height, numColors, 2306 left, top, right, bottom, alpha, mode); 2307 } 2308 2309 status_t OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, 2310 const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, 2311 float left, float top, float right, float bottom, int alpha, SkXfermode::Mode mode) { 2312 if (quickReject(left, top, right, bottom)) { 2313 return DrawGlInfo::kStatusDone; 2314 } 2315 2316 alpha *= mSnapshot->alpha; 2317 2318 const Patch* mesh = mCaches.patchCache.get(bitmap->width(), bitmap->height(), 2319 right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors); 2320 2321 if (CC_LIKELY(mesh && mesh->verticesCount > 0)) { 2322 mCaches.activeTexture(0); 2323 Texture* texture = mCaches.textureCache.get(bitmap); 2324 if (!texture) return DrawGlInfo::kStatusDone; 2325 const AutoTexture autoCleanup(texture); 2326 texture->setWrap(GL_CLAMP_TO_EDGE, true); 2327 texture->setFilter(GL_LINEAR, true); 2328 2329 const bool pureTranslate = currentTransform().isPureTranslate(); 2330 // Mark the current layer dirty where we are going to draw the patch 2331 if (hasLayer() && mesh->hasEmptyQuads) { 2332 const float offsetX = left + currentTransform().getTranslateX(); 2333 const float offsetY = top + currentTransform().getTranslateY(); 2334 const size_t count = mesh->quads.size(); 2335 for (size_t i = 0; i < count; i++) { 2336 const Rect& bounds = mesh->quads.itemAt(i); 2337 if (CC_LIKELY(pureTranslate)) { 2338 const float x = (int) floorf(bounds.left + offsetX + 0.5f); 2339 const float y = (int) floorf(bounds.top + offsetY + 0.5f); 2340 dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight()); 2341 } else { 2342 dirtyLayer(left + bounds.left, top + bounds.top, 2343 left + bounds.right, top + bounds.bottom, currentTransform()); 2344 } 2345 } 2346 } 2347 2348 if (CC_LIKELY(pureTranslate)) { 2349 const float x = (int) floorf(left + currentTransform().getTranslateX() + 0.5f); 2350 const float y = (int) floorf(top + currentTransform().getTranslateY() + 0.5f); 2351 2352 drawTextureMesh(x, y, x + right - left, y + bottom - top, texture->id, alpha / 255.0f, 2353 mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset, 2354 GL_TRIANGLES, mesh->verticesCount, false, true, mesh->meshBuffer, 2355 true, !mesh->hasEmptyQuads); 2356 } else { 2357 drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, 2358 mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset, 2359 GL_TRIANGLES, mesh->verticesCount, false, false, mesh->meshBuffer, 2360 true, !mesh->hasEmptyQuads); 2361 } 2362 } 2363 2364 return DrawGlInfo::kStatusDrew; 2365 } 2366 2367 status_t OpenGLRenderer::drawVertexBuffer(const VertexBuffer& vertexBuffer, SkPaint* paint, 2368 bool useOffset) { 2369 if (!vertexBuffer.getSize()) { 2370 // no vertices to draw 2371 return DrawGlInfo::kStatusDone; 2372 } 2373 2374 int color = paint->getColor(); 2375 SkXfermode::Mode mode = getXfermode(paint->getXfermode()); 2376 bool isAA = paint->isAntiAlias(); 2377 2378 setupDraw(); 2379 setupDrawNoTexture(); 2380 if (isAA) setupDrawAA(); 2381 setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha); 2382 setupDrawColorFilter(); 2383 setupDrawShader(); 2384 setupDrawBlending(isAA, mode); 2385 setupDrawProgram(); 2386 setupDrawModelViewIdentity(useOffset); 2387 setupDrawColorUniforms(); 2388 setupDrawColorFilterUniforms(); 2389 setupDrawShaderIdentityUniforms(); 2390 2391 void* vertices = vertexBuffer.getBuffer(); 2392 bool force = mCaches.unbindMeshBuffer(); 2393 mCaches.bindPositionVertexPointer(true, vertices, isAA ? gAlphaVertexStride : gVertexStride); 2394 mCaches.resetTexCoordsVertexPointer(); 2395 mCaches.unbindIndicesBuffer(); 2396 2397 int alphaSlot = -1; 2398 if (isAA) { 2399 void* alphaCoords = ((GLbyte*) vertices) + gVertexAlphaOffset; 2400 alphaSlot = mCaches.currentProgram->getAttrib("vtxAlpha"); 2401 2402 // TODO: avoid enable/disable in back to back uses of the alpha attribute 2403 glEnableVertexAttribArray(alphaSlot); 2404 glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords); 2405 } 2406 2407 glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getSize()); 2408 2409 if (isAA) { 2410 glDisableVertexAttribArray(alphaSlot); 2411 } 2412 2413 return DrawGlInfo::kStatusDrew; 2414 } 2415 2416 /** 2417 * Renders a convex path via tessellation. For AA paths, this function uses a similar approach to 2418 * that of AA lines in the drawLines() function. We expand the convex path by a half pixel in 2419 * screen space in all directions. However, instead of using a fragment shader to compute the 2420 * translucency of the color from its position, we simply use a varying parameter to define how far 2421 * a given pixel is from the edge. For non-AA paths, the expansion and alpha varying are not used. 2422 * 2423 * Doesn't yet support joins, caps, or path effects. 2424 */ 2425 status_t OpenGLRenderer::drawConvexPath(const SkPath& path, SkPaint* paint) { 2426 VertexBuffer vertexBuffer; 2427 // TODO: try clipping large paths to viewport 2428 PathTessellator::tessellatePath(path, paint, mSnapshot->transform, vertexBuffer); 2429 2430 if (hasLayer()) { 2431 SkRect bounds = path.getBounds(); 2432 PathTessellator::expandBoundsForStroke(bounds, paint, false); 2433 dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, currentTransform()); 2434 } 2435 2436 return drawVertexBuffer(vertexBuffer, paint); 2437 } 2438 2439 /** 2440 * We create tristrips for the lines much like shape stroke tessellation, using a per-vertex alpha 2441 * and additional geometry for defining an alpha slope perimeter. 2442 * 2443 * Using GL_LINES can be difficult because the rasterization rules for those lines produces some 2444 * unexpected results, and may vary between hardware devices. Previously we used a varying-base 2445 * in-shader alpha region, but found it to be taxing on some GPUs. 2446 * 2447 * TODO: try using a fixed input buffer for non-capped lines as in text rendering. this may reduce 2448 * memory transfer by removing need for degenerate vertices. 2449 */ 2450 status_t OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { 2451 if (mSnapshot->isIgnored() || count < 4) return DrawGlInfo::kStatusDone; 2452 2453 count &= ~0x3; // round down to nearest four 2454 2455 VertexBuffer buffer; 2456 SkRect bounds; 2457 PathTessellator::tessellateLines(points, count, paint, mSnapshot->transform, bounds, buffer); 2458 2459 if (quickReject(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom)) { 2460 return DrawGlInfo::kStatusDone; 2461 } 2462 2463 dirtyLayer(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, currentTransform()); 2464 2465 bool useOffset = !paint->isAntiAlias(); 2466 return drawVertexBuffer(buffer, paint, useOffset); 2467 } 2468 2469 status_t OpenGLRenderer::drawPoints(float* points, int count, SkPaint* paint) { 2470 if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone; 2471 2472 // TODO: The paint's cap style defines whether the points are square or circular 2473 // TODO: Handle AA for round points 2474 2475 // A stroke width of 0 has a special meaning in Skia: 2476 // it draws an unscaled 1px point 2477 float strokeWidth = paint->getStrokeWidth(); 2478 const bool isHairLine = paint->getStrokeWidth() == 0.0f; 2479 if (isHairLine) { 2480 // Now that we know it's hairline, we can set the effective width, to be used later 2481 strokeWidth = 1.0f; 2482 } 2483 const float halfWidth = strokeWidth / 2; 2484 2485 int alpha; 2486 SkXfermode::Mode mode; 2487 getAlphaAndMode(paint, &alpha, &mode); 2488 2489 int verticesCount = count >> 1; 2490 int generatedVerticesCount = 0; 2491 2492 TextureVertex pointsData[verticesCount]; 2493 TextureVertex* vertex = &pointsData[0]; 2494 2495 // TODO: We should optimize this method to not generate vertices for points 2496 // that lie outside of the clip. 2497 mCaches.enableScissor(); 2498 2499 setupDraw(); 2500 setupDrawNoTexture(); 2501 setupDrawPoint(strokeWidth); 2502 setupDrawColor(paint->getColor(), alpha); 2503 setupDrawColorFilter(); 2504 setupDrawShader(); 2505 setupDrawBlending(mode); 2506 setupDrawProgram(); 2507 setupDrawModelViewIdentity(true); 2508 setupDrawColorUniforms(); 2509 setupDrawColorFilterUniforms(); 2510 setupDrawPointUniforms(); 2511 setupDrawShaderIdentityUniforms(); 2512 setupDrawMesh(vertex); 2513 2514 for (int i = 0; i < count; i += 2) { 2515 TextureVertex::set(vertex++, points[i], points[i + 1], 0.0f, 0.0f); 2516 generatedVerticesCount++; 2517 2518 float left = points[i] - halfWidth; 2519 float right = points[i] + halfWidth; 2520 float top = points[i + 1] - halfWidth; 2521 float bottom = points [i + 1] + halfWidth; 2522 2523 dirtyLayer(left, top, right, bottom, currentTransform()); 2524 } 2525 2526 glDrawArrays(GL_POINTS, 0, generatedVerticesCount); 2527 2528 return DrawGlInfo::kStatusDrew; 2529 } 2530 2531 status_t OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { 2532 // No need to check against the clip, we fill the clip region 2533 if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone; 2534 2535 Rect& clip(*mSnapshot->clipRect); 2536 clip.snapToPixelBoundaries(); 2537 2538 drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true); 2539 2540 return DrawGlInfo::kStatusDrew; 2541 } 2542 2543 status_t OpenGLRenderer::drawShape(float left, float top, const PathTexture* texture, 2544 SkPaint* paint) { 2545 if (!texture) return DrawGlInfo::kStatusDone; 2546 const AutoTexture autoCleanup(texture); 2547 2548 const float x = left + texture->left - texture->offset; 2549 const float y = top + texture->top - texture->offset; 2550 2551 drawPathTexture(texture, x, y, paint); 2552 2553 return DrawGlInfo::kStatusDrew; 2554 } 2555 2556 status_t OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom, 2557 float rx, float ry, SkPaint* p) { 2558 if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p) || 2559 (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) { 2560 return DrawGlInfo::kStatusDone; 2561 } 2562 2563 if (p->getPathEffect() != 0) { 2564 mCaches.activeTexture(0); 2565 const PathTexture* texture = mCaches.pathCache.getRoundRect( 2566 right - left, bottom - top, rx, ry, p); 2567 return drawShape(left, top, texture, p); 2568 } 2569 2570 SkPath path; 2571 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); 2572 if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { 2573 float outset = p->getStrokeWidth() / 2; 2574 rect.outset(outset, outset); 2575 rx += outset; 2576 ry += outset; 2577 } 2578 path.addRoundRect(rect, rx, ry); 2579 return drawConvexPath(path, p); 2580 } 2581 2582 status_t OpenGLRenderer::drawCircle(float x, float y, float radius, SkPaint* p) { 2583 if (mSnapshot->isIgnored() || quickRejectPreStroke(x - radius, y - radius, 2584 x + radius, y + radius, p) || 2585 (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) { 2586 return DrawGlInfo::kStatusDone; 2587 } 2588 if (p->getPathEffect() != 0) { 2589 mCaches.activeTexture(0); 2590 const PathTexture* texture = mCaches.pathCache.getCircle(radius, p); 2591 return drawShape(x - radius, y - radius, texture, p); 2592 } 2593 2594 SkPath path; 2595 if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { 2596 path.addCircle(x, y, radius + p->getStrokeWidth() / 2); 2597 } else { 2598 path.addCircle(x, y, radius); 2599 } 2600 return drawConvexPath(path, p); 2601 } 2602 2603 status_t OpenGLRenderer::drawOval(float left, float top, float right, float bottom, 2604 SkPaint* p) { 2605 if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p) || 2606 (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) { 2607 return DrawGlInfo::kStatusDone; 2608 } 2609 2610 if (p->getPathEffect() != 0) { 2611 mCaches.activeTexture(0); 2612 const PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p); 2613 return drawShape(left, top, texture, p); 2614 } 2615 2616 SkPath path; 2617 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); 2618 if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { 2619 rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2); 2620 } 2621 path.addOval(rect); 2622 return drawConvexPath(path, p); 2623 } 2624 2625 status_t OpenGLRenderer::drawArc(float left, float top, float right, float bottom, 2626 float startAngle, float sweepAngle, bool useCenter, SkPaint* p) { 2627 if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p) || 2628 (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) { 2629 return DrawGlInfo::kStatusDone; 2630 } 2631 2632 if (fabs(sweepAngle) >= 360.0f) { 2633 return drawOval(left, top, right, bottom, p); 2634 } 2635 2636 // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180) 2637 if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != 0 || useCenter) { 2638 mCaches.activeTexture(0); 2639 const PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top, 2640 startAngle, sweepAngle, useCenter, p); 2641 return drawShape(left, top, texture, p); 2642 } 2643 2644 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); 2645 if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { 2646 rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2); 2647 } 2648 2649 SkPath path; 2650 if (useCenter) { 2651 path.moveTo(rect.centerX(), rect.centerY()); 2652 } 2653 path.arcTo(rect, startAngle, sweepAngle, !useCenter); 2654 if (useCenter) { 2655 path.close(); 2656 } 2657 return drawConvexPath(path, p); 2658 } 2659 2660 // See SkPaintDefaults.h 2661 #define SkPaintDefaults_MiterLimit SkIntToScalar(4) 2662 2663 status_t OpenGLRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* p) { 2664 if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p) || 2665 (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) { 2666 return DrawGlInfo::kStatusDone; 2667 } 2668 2669 if (p->getStyle() != SkPaint::kFill_Style) { 2670 // only fill style is supported by drawConvexPath, since others have to handle joins 2671 if (p->getPathEffect() != 0 || p->getStrokeJoin() != SkPaint::kMiter_Join || 2672 p->getStrokeMiter() != SkPaintDefaults_MiterLimit) { 2673 mCaches.activeTexture(0); 2674 const PathTexture* texture = 2675 mCaches.pathCache.getRect(right - left, bottom - top, p); 2676 return drawShape(left, top, texture, p); 2677 } 2678 2679 SkPath path; 2680 SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); 2681 if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { 2682 rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2); 2683 } 2684 path.addRect(rect); 2685 return drawConvexPath(path, p); 2686 } 2687 2688 if (p->isAntiAlias() && !currentTransform().isSimple()) { 2689 SkPath path; 2690 path.addRect(left, top, right, bottom); 2691 return drawConvexPath(path, p); 2692 } else { 2693 drawColorRect(left, top, right, bottom, p->getColor(), getXfermode(p->getXfermode())); 2694 return DrawGlInfo::kStatusDrew; 2695 } 2696 } 2697 2698 void OpenGLRenderer::drawTextShadow(SkPaint* paint, const char* text, int bytesCount, int count, 2699 const float* positions, FontRenderer& fontRenderer, int alpha, SkXfermode::Mode mode, 2700 float x, float y) { 2701 mCaches.activeTexture(0); 2702 2703 // NOTE: The drop shadow will not perform gamma correction 2704 // if shader-based correction is enabled 2705 mCaches.dropShadowCache.setFontRenderer(fontRenderer); 2706 const ShadowTexture* shadow = mCaches.dropShadowCache.get( 2707 paint, text, bytesCount, count, mDrawModifiers.mShadowRadius, positions); 2708 // If the drop shadow exceeds the max texture size or couldn't be 2709 // allocated, skip drawing 2710 if (!shadow) return; 2711 const AutoTexture autoCleanup(shadow); 2712 2713 const float sx = x - shadow->left + mDrawModifiers.mShadowDx; 2714 const float sy = y - shadow->top + mDrawModifiers.mShadowDy; 2715 2716 const int shadowAlpha = ((mDrawModifiers.mShadowColor >> 24) & 0xFF) * mSnapshot->alpha; 2717 int shadowColor = mDrawModifiers.mShadowColor; 2718 if (mDrawModifiers.mShader) { 2719 shadowColor = 0xffffffff; 2720 } 2721 2722 setupDraw(); 2723 setupDrawWithTexture(true); 2724 setupDrawAlpha8Color(shadowColor, shadowAlpha < 255 ? shadowAlpha : alpha); 2725 setupDrawColorFilter(); 2726 setupDrawShader(); 2727 setupDrawBlending(true, mode); 2728 setupDrawProgram(); 2729 setupDrawModelView(sx, sy, sx + shadow->width, sy + shadow->height); 2730 setupDrawTexture(shadow->id); 2731 setupDrawPureColorUniforms(); 2732 setupDrawColorFilterUniforms(); 2733 setupDrawShaderUniforms(); 2734 setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset); 2735 2736 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); 2737 } 2738 2739 bool OpenGLRenderer::canSkipText(const SkPaint* paint) const { 2740 float alpha = (mDrawModifiers.mHasShadow ? 1.0f : paint->getAlpha()) * mSnapshot->alpha; 2741 return alpha == 0.0f && getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode; 2742 } 2743 2744 class TextSetupFunctor: public Functor { 2745 public: 2746 TextSetupFunctor(OpenGLRenderer& renderer, float x, float y, bool pureTranslate, 2747 int alpha, SkXfermode::Mode mode, SkPaint* paint): Functor(), 2748 renderer(renderer), x(x), y(y), pureTranslate(pureTranslate), 2749 alpha(alpha), mode(mode), paint(paint) { 2750 } 2751 ~TextSetupFunctor() { } 2752 2753 status_t operator ()(int what, void* data) { 2754 renderer.setupDraw(); 2755 renderer.setupDrawTextGamma(paint); 2756 renderer.setupDrawDirtyRegionsDisabled(); 2757 renderer.setupDrawWithTexture(true); 2758 renderer.setupDrawAlpha8Color(paint->getColor(), alpha); 2759 renderer.setupDrawColorFilter(); 2760 renderer.setupDrawShader(); 2761 renderer.setupDrawBlending(true, mode); 2762 renderer.setupDrawProgram(); 2763 renderer.setupDrawModelView(x, y, x, y, pureTranslate, true); 2764 // Calling setupDrawTexture with the name 0 will enable the 2765 // uv attributes and increase the texture unit count 2766 // texture binding will be performed by the font renderer as 2767 // needed 2768 renderer.setupDrawTexture(0); 2769 renderer.setupDrawPureColorUniforms(); 2770 renderer.setupDrawColorFilterUniforms(); 2771 renderer.setupDrawShaderUniforms(pureTranslate); 2772 renderer.setupDrawTextGammaUniforms(); 2773 2774 return NO_ERROR; 2775 } 2776 2777 OpenGLRenderer& renderer; 2778 float x; 2779 float y; 2780 bool pureTranslate; 2781 int alpha; 2782 SkXfermode::Mode mode; 2783 SkPaint* paint; 2784 }; 2785 2786 status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count, 2787 const float* positions, SkPaint* paint) { 2788 if (text == NULL || count == 0 || mSnapshot->isIgnored() || canSkipText(paint)) { 2789 return DrawGlInfo::kStatusDone; 2790 } 2791 2792 // NOTE: Skia does not support perspective transform on drawPosText yet 2793 if (!currentTransform().isSimple()) { 2794 return DrawGlInfo::kStatusDone; 2795 } 2796 2797 float x = 0.0f; 2798 float y = 0.0f; 2799 const bool pureTranslate = currentTransform().isPureTranslate(); 2800 if (pureTranslate) { 2801 x = (int) floorf(x + currentTransform().getTranslateX() + 0.5f); 2802 y = (int) floorf(y + currentTransform().getTranslateY() + 0.5f); 2803 } 2804 2805 FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint); 2806 fontRenderer.setFont(paint, mat4::identity()); 2807 2808 int alpha; 2809 SkXfermode::Mode mode; 2810 getAlphaAndMode(paint, &alpha, &mode); 2811 2812 if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) { 2813 drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer, 2814 alpha, mode, 0.0f, 0.0f); 2815 } 2816 2817 // Pick the appropriate texture filtering 2818 bool linearFilter = currentTransform().changesBounds(); 2819 if (pureTranslate && !linearFilter) { 2820 linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f; 2821 } 2822 fontRenderer.setTextureFiltering(linearFilter); 2823 2824 const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip(); 2825 Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); 2826 2827 const bool hasActiveLayer = hasLayer(); 2828 2829 TextSetupFunctor functor(*this, x, y, pureTranslate, alpha, mode, paint); 2830 if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y, 2831 positions, hasActiveLayer ? &bounds : NULL, &functor)) { 2832 if (hasActiveLayer) { 2833 if (!pureTranslate) { 2834 currentTransform().mapRect(bounds); 2835 } 2836 dirtyLayerUnchecked(bounds, getRegion()); 2837 } 2838 } 2839 2840 return DrawGlInfo::kStatusDrew; 2841 } 2842 2843 mat4 OpenGLRenderer::findBestFontTransform(const mat4& transform) const { 2844 mat4 fontTransform; 2845 if (CC_LIKELY(transform.isPureTranslate())) { 2846 fontTransform = mat4::identity(); 2847 } else { 2848 if (CC_UNLIKELY(transform.isPerspective())) { 2849 fontTransform = mat4::identity(); 2850 } else { 2851 float sx, sy; 2852 currentTransform().decomposeScale(sx, sy); 2853 fontTransform.loadScale(sx, sy, 1.0f); 2854 } 2855 } 2856 return fontTransform; 2857 } 2858 2859 status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, 2860 float x, float y, const float* positions, SkPaint* paint, float length, 2861 DrawOpMode drawOpMode) { 2862 2863 if (drawOpMode == kDrawOpMode_Immediate && 2864 (text == NULL || count == 0 || mSnapshot->isIgnored() || canSkipText(paint))) { 2865 return DrawGlInfo::kStatusDone; 2866 } 2867 2868 if (length < 0.0f) length = paint->measureText(text, bytesCount); 2869 switch (paint->getTextAlign()) { 2870 case SkPaint::kCenter_Align: 2871 x -= length / 2.0f; 2872 break; 2873 case SkPaint::kRight_Align: 2874 x -= length; 2875 break; 2876 default: 2877 break; 2878 } 2879 2880 SkPaint::FontMetrics metrics; 2881 paint->getFontMetrics(&metrics, 0.0f); 2882 if (drawOpMode == kDrawOpMode_Immediate) { 2883 if (quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom)) { 2884 return DrawGlInfo::kStatusDone; 2885 } 2886 } else { 2887 // merged draw operations don't need scissor, but clip should still be valid 2888 mCaches.setScissorEnabled(mScissorOptimizationDisabled); 2889 } 2890 2891 const float oldX = x; 2892 const float oldY = y; 2893 2894 const mat4& transform = currentTransform(); 2895 const bool pureTranslate = transform.isPureTranslate(); 2896 2897 if (CC_LIKELY(pureTranslate)) { 2898 x = (int) floorf(x + transform.getTranslateX() + 0.5f); 2899 y = (int) floorf(y + transform.getTranslateY() + 0.5f); 2900 } 2901 2902 int alpha; 2903 SkXfermode::Mode mode; 2904 getAlphaAndMode(paint, &alpha, &mode); 2905 2906 FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint); 2907 2908 if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) { 2909 fontRenderer.setFont(paint, mat4::identity()); 2910 drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer, 2911 alpha, mode, oldX, oldY); 2912 } 2913 2914 const bool hasActiveLayer = hasLayer(); 2915 2916 // We only pass a partial transform to the font renderer. That partial 2917 // matrix defines how glyphs are rasterized. Typically we want glyphs 2918 // to be rasterized at their final size on screen, which means the partial 2919 // matrix needs to take the scale factor into account. 2920 // When a partial matrix is used to transform glyphs during rasterization, 2921 // the mesh is generated with the inverse transform (in the case of scale, 2922 // the mesh is generated at 1.0 / scale for instance.) This allows us to 2923 // apply the full transform matrix at draw time in the vertex shader. 2924 // Applying the full matrix in the shader is the easiest way to handle 2925 // rotation and perspective and allows us to always generated quads in the 2926 // font renderer which greatly simplifies the code, clipping in particular. 2927 mat4 fontTransform = findBestFontTransform(transform); 2928 fontRenderer.setFont(paint, fontTransform); 2929 2930 // Pick the appropriate texture filtering 2931 bool linearFilter = !pureTranslate || fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f; 2932 fontRenderer.setTextureFiltering(linearFilter); 2933 2934 // TODO: Implement better clipping for scaled/rotated text 2935 const Rect* clip = !pureTranslate ? NULL : mSnapshot->clipRect; 2936 Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); 2937 2938 bool status; 2939 TextSetupFunctor functor(*this, x, y, pureTranslate, alpha, mode, paint); 2940 2941 // don't call issuedrawcommand, do it at end of batch 2942 bool forceFinish = (drawOpMode != kDrawOpMode_Defer); 2943 if (CC_UNLIKELY(paint->getTextAlign() != SkPaint::kLeft_Align)) { 2944 SkPaint paintCopy(*paint); 2945 paintCopy.setTextAlign(SkPaint::kLeft_Align); 2946 status = fontRenderer.renderPosText(&paintCopy, clip, text, 0, bytesCount, count, x, y, 2947 positions, hasActiveLayer ? &bounds : NULL, &functor, forceFinish); 2948 } else { 2949 status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y, 2950 positions, hasActiveLayer ? &bounds : NULL, &functor, forceFinish); 2951 } 2952 2953 if ((status || drawOpMode != kDrawOpMode_Immediate) && hasActiveLayer) { 2954 if (!pureTranslate) { 2955 transform.mapRect(bounds); 2956 } 2957 dirtyLayerUnchecked(bounds, getRegion()); 2958 } 2959 2960 drawTextDecorations(text, bytesCount, length, oldX, oldY, paint); 2961 2962 return DrawGlInfo::kStatusDrew; 2963 } 2964 2965 status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count, SkPath* path, 2966 float hOffset, float vOffset, SkPaint* paint) { 2967 if (text == NULL || count == 0 || mSnapshot->isIgnored() || canSkipText(paint)) { 2968 return DrawGlInfo::kStatusDone; 2969 } 2970 2971 FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint); 2972 fontRenderer.setFont(paint, mat4::identity()); 2973 fontRenderer.setTextureFiltering(true); 2974 2975 int alpha; 2976 SkXfermode::Mode mode; 2977 getAlphaAndMode(paint, &alpha, &mode); 2978 2979 setupDraw(); 2980 setupDrawTextGamma(paint); 2981 setupDrawDirtyRegionsDisabled(); 2982 setupDrawWithTexture(true); 2983 setupDrawAlpha8Color(paint->getColor(), alpha); 2984 setupDrawColorFilter(); 2985 setupDrawShader(); 2986 setupDrawBlending(true, mode); 2987 setupDrawProgram(); 2988 setupDrawModelView(0.0f, 0.0f, 0.0f, 0.0f, false, true); 2989 // Calling setupDrawTexture with the name 0 will enable the 2990 // uv attributes and increase the texture unit count 2991 // texture binding will be performed by the font renderer as 2992 // needed 2993 setupDrawTexture(0); 2994 setupDrawPureColorUniforms(); 2995 setupDrawColorFilterUniforms(); 2996 setupDrawShaderUniforms(false); 2997 setupDrawTextGammaUniforms(); 2998 2999 const Rect* clip = &mSnapshot->getLocalClip(); 3000 Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); 3001 3002 const bool hasActiveLayer = hasLayer(); 3003 3004 if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path, 3005 hOffset, vOffset, hasActiveLayer ? &bounds : NULL)) { 3006 if (hasActiveLayer) { 3007 currentTransform().mapRect(bounds); 3008 dirtyLayerUnchecked(bounds, getRegion()); 3009 } 3010 } 3011 3012 return DrawGlInfo::kStatusDrew; 3013 } 3014 3015 status_t OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) { 3016 if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone; 3017 3018 mCaches.activeTexture(0); 3019 3020 const PathTexture* texture = mCaches.pathCache.get(path, paint); 3021 if (!texture) return DrawGlInfo::kStatusDone; 3022 const AutoTexture autoCleanup(texture); 3023 3024 const float x = texture->left - texture->offset; 3025 const float y = texture->top - texture->offset; 3026 3027 drawPathTexture(texture, x, y, paint); 3028 3029 return DrawGlInfo::kStatusDrew; 3030 } 3031 3032 status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) { 3033 if (!layer) { 3034 return DrawGlInfo::kStatusDone; 3035 } 3036 3037 mat4* transform = NULL; 3038 if (layer->isTextureLayer()) { 3039 transform = &layer->getTransform(); 3040 if (!transform->isIdentity()) { 3041 save(0); 3042 currentTransform().multiply(*transform); 3043 } 3044 } 3045 3046 Rect transformed; 3047 Rect clip; 3048 const bool rejected = quickRejectNoScissor(x, y, 3049 x + layer->layer.getWidth(), y + layer->layer.getHeight(), transformed, clip); 3050 3051 if (rejected) { 3052 if (transform && !transform->isIdentity()) { 3053 restore(); 3054 } 3055 return DrawGlInfo::kStatusDone; 3056 } 3057 3058 updateLayer(layer, true); 3059 3060 mCaches.setScissorEnabled(mScissorOptimizationDisabled || !clip.contains(transformed)); 3061 mCaches.activeTexture(0); 3062 3063 if (CC_LIKELY(!layer->region.isEmpty())) { 3064 SkiaColorFilter* oldFilter = mDrawModifiers.mColorFilter; 3065 mDrawModifiers.mColorFilter = layer->getColorFilter(); 3066 3067 if (layer->region.isRect()) { 3068 DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, 3069 composeLayerRect(layer, layer->regionRect)); 3070 } else if (layer->mesh) { 3071 const float a = getLayerAlpha(layer); 3072 setupDraw(); 3073 setupDrawWithTexture(); 3074 setupDrawColor(a, a, a, a); 3075 setupDrawColorFilter(); 3076 setupDrawBlending(layer->isBlend() || a < 1.0f, layer->getMode(), false); 3077 setupDrawProgram(); 3078 setupDrawPureColorUniforms(); 3079 setupDrawColorFilterUniforms(); 3080 setupDrawTexture(layer->getTexture()); 3081 if (CC_LIKELY(currentTransform().isPureTranslate())) { 3082 int tx = (int) floorf(x + currentTransform().getTranslateX() + 0.5f); 3083 int ty = (int) floorf(y + currentTransform().getTranslateY() + 0.5f); 3084 3085 layer->setFilter(GL_NEAREST); 3086 setupDrawModelViewTranslate(tx, ty, 3087 tx + layer->layer.getWidth(), ty + layer->layer.getHeight(), true); 3088 } else { 3089 layer->setFilter(GL_LINEAR); 3090 setupDrawModelViewTranslate(x, y, 3091 x + layer->layer.getWidth(), y + layer->layer.getHeight()); 3092 } 3093 setupDrawMesh(&layer->mesh[0].position[0], &layer->mesh[0].texture[0]); 3094 3095 DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, 3096 glDrawElements(GL_TRIANGLES, layer->meshElementCount, 3097 GL_UNSIGNED_SHORT, layer->meshIndices)); 3098 3099 finishDrawTexture(); 3100 3101 #if DEBUG_LAYERS_AS_REGIONS 3102 drawRegionRects(layer->region); 3103 #endif 3104 } 3105 3106 mDrawModifiers.mColorFilter = oldFilter; 3107 3108 if (layer->debugDrawUpdate) { 3109 layer->debugDrawUpdate = false; 3110 drawColorRect(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(), 3111 0x7f00ff00, SkXfermode::kSrcOver_Mode); 3112 } 3113 } 3114 layer->hasDrawnSinceUpdate = true; 3115 3116 if (transform && !transform->isIdentity()) { 3117 restore(); 3118 } 3119 3120 return DrawGlInfo::kStatusDrew; 3121 } 3122 3123 /////////////////////////////////////////////////////////////////////////////// 3124 // Shaders 3125 /////////////////////////////////////////////////////////////////////////////// 3126 3127 void OpenGLRenderer::resetShader() { 3128 mDrawModifiers.mShader = NULL; 3129 } 3130 3131 void OpenGLRenderer::setupShader(SkiaShader* shader) { 3132 mDrawModifiers.mShader = shader; 3133 if (mDrawModifiers.mShader) { 3134 mDrawModifiers.mShader->set(&mCaches.textureCache, &mCaches.gradientCache); 3135 } 3136 } 3137 3138 /////////////////////////////////////////////////////////////////////////////// 3139 // Color filters 3140 /////////////////////////////////////////////////////////////////////////////// 3141 3142 void OpenGLRenderer::resetColorFilter() { 3143 mDrawModifiers.mColorFilter = NULL; 3144 } 3145 3146 void OpenGLRenderer::setupColorFilter(SkiaColorFilter* filter) { 3147 mDrawModifiers.mColorFilter = filter; 3148 } 3149 3150 /////////////////////////////////////////////////////////////////////////////// 3151 // Drop shadow 3152 /////////////////////////////////////////////////////////////////////////////// 3153 3154 void OpenGLRenderer::resetShadow() { 3155 mDrawModifiers.mHasShadow = false; 3156 } 3157 3158 void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) { 3159 mDrawModifiers.mHasShadow = true; 3160 mDrawModifiers.mShadowRadius = radius; 3161 mDrawModifiers.mShadowDx = dx; 3162 mDrawModifiers.mShadowDy = dy; 3163 mDrawModifiers.mShadowColor = color; 3164 } 3165 3166 /////////////////////////////////////////////////////////////////////////////// 3167 // Draw filters 3168 /////////////////////////////////////////////////////////////////////////////// 3169 3170 void OpenGLRenderer::resetPaintFilter() { 3171 // when clearing the PaintFilter, the masks should also be cleared for simple DrawModifier 3172 // comparison, see MergingDrawBatch::canMergeWith 3173 mDrawModifiers.mHasDrawFilter = false; 3174 mDrawModifiers.mPaintFilterClearBits = 0; 3175 mDrawModifiers.mPaintFilterSetBits = 0; 3176 } 3177 3178 void OpenGLRenderer::setupPaintFilter(int clearBits, int setBits) { 3179 mDrawModifiers.mHasDrawFilter = true; 3180 mDrawModifiers.mPaintFilterClearBits = clearBits & SkPaint::kAllFlags; 3181 mDrawModifiers.mPaintFilterSetBits = setBits & SkPaint::kAllFlags; 3182 } 3183 3184 SkPaint* OpenGLRenderer::filterPaint(SkPaint* paint) { 3185 if (CC_LIKELY(!mDrawModifiers.mHasDrawFilter || !paint)) { 3186 return paint; 3187 } 3188 3189 uint32_t flags = paint->getFlags(); 3190 3191 mFilteredPaint = *paint; 3192 mFilteredPaint.setFlags((flags & ~mDrawModifiers.mPaintFilterClearBits) | 3193 mDrawModifiers.mPaintFilterSetBits); 3194 3195 return &mFilteredPaint; 3196 } 3197 3198 /////////////////////////////////////////////////////////////////////////////// 3199 // Drawing implementation 3200 /////////////////////////////////////////////////////////////////////////////// 3201 3202 void OpenGLRenderer::drawPathTexture(const PathTexture* texture, 3203 float x, float y, SkPaint* paint) { 3204 if (quickReject(x, y, x + texture->width, y + texture->height)) { 3205 return; 3206 } 3207 3208 int alpha; 3209 SkXfermode::Mode mode; 3210 getAlphaAndMode(paint, &alpha, &mode); 3211 3212 setupDraw(); 3213 setupDrawWithTexture(true); 3214 setupDrawAlpha8Color(paint->getColor(), alpha); 3215 setupDrawColorFilter(); 3216 setupDrawShader(); 3217 setupDrawBlending(true, mode); 3218 setupDrawProgram(); 3219 setupDrawModelView(x, y, x + texture->width, y + texture->height); 3220 setupDrawTexture(texture->id); 3221 setupDrawPureColorUniforms(); 3222 setupDrawColorFilterUniforms(); 3223 setupDrawShaderUniforms(); 3224 setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset); 3225 3226 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); 3227 3228 finishDrawTexture(); 3229 } 3230 3231 // Same values used by Skia 3232 #define kStdStrikeThru_Offset (-6.0f / 21.0f) 3233 #define kStdUnderline_Offset (1.0f / 9.0f) 3234 #define kStdUnderline_Thickness (1.0f / 18.0f) 3235 3236 void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float length, 3237 float x, float y, SkPaint* paint) { 3238 // Handle underline and strike-through 3239 uint32_t flags = paint->getFlags(); 3240 if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) { 3241 SkPaint paintCopy(*paint); 3242 float underlineWidth = length; 3243 // If length is > 0.0f, we already measured the text for the text alignment 3244 if (length <= 0.0f) { 3245 underlineWidth = paintCopy.measureText(text, bytesCount); 3246 } 3247 3248 if (CC_LIKELY(underlineWidth > 0.0f)) { 3249 const float textSize = paintCopy.getTextSize(); 3250 const float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f); 3251 3252 const float left = x; 3253 float top = 0.0f; 3254 3255 int linesCount = 0; 3256 if (flags & SkPaint::kUnderlineText_Flag) linesCount++; 3257 if (flags & SkPaint::kStrikeThruText_Flag) linesCount++; 3258 3259 const int pointsCount = 4 * linesCount; 3260 float points[pointsCount]; 3261 int currentPoint = 0; 3262 3263 if (flags & SkPaint::kUnderlineText_Flag) { 3264 top = y + textSize * kStdUnderline_Offset; 3265 points[currentPoint++] = left; 3266 points[currentPoint++] = top; 3267 points[currentPoint++] = left + underlineWidth; 3268 points[currentPoint++] = top; 3269 } 3270 3271 if (flags & SkPaint::kStrikeThruText_Flag) { 3272 top = y + textSize * kStdStrikeThru_Offset; 3273 points[currentPoint++] = left; 3274 points[currentPoint++] = top; 3275 points[currentPoint++] = left + underlineWidth; 3276 points[currentPoint++] = top; 3277 } 3278 3279 paintCopy.setStrokeWidth(strokeWidth); 3280 3281 drawLines(&points[0], pointsCount, &paintCopy); 3282 } 3283 } 3284 } 3285 3286 status_t OpenGLRenderer::drawRects(const float* rects, int count, SkPaint* paint) { 3287 if (mSnapshot->isIgnored()) { 3288 return DrawGlInfo::kStatusDone; 3289 } 3290 3291 int color = paint->getColor(); 3292 // If a shader is set, preserve only the alpha 3293 if (mDrawModifiers.mShader) { 3294 color |= 0x00ffffff; 3295 } 3296 SkXfermode::Mode mode = getXfermode(paint->getXfermode()); 3297 3298 return drawColorRects(rects, count, color, mode); 3299 } 3300 3301 status_t OpenGLRenderer::drawColorRects(const float* rects, int count, int color, 3302 SkXfermode::Mode mode, bool ignoreTransform, bool dirty, bool clip) { 3303 if (count == 0) { 3304 return DrawGlInfo::kStatusDone; 3305 } 3306 3307 float left = FLT_MAX; 3308 float top = FLT_MAX; 3309 float right = FLT_MIN; 3310 float bottom = FLT_MIN; 3311 3312 int vertexCount = 0; 3313 Vertex mesh[count * 6]; 3314 Vertex* vertex = mesh; 3315 3316 for (int index = 0; index < count; index += 4) { 3317 float l = rects[index + 0]; 3318 float t = rects[index + 1]; 3319 float r = rects[index + 2]; 3320 float b = rects[index + 3]; 3321 3322 Vertex::set(vertex++, l, b); 3323 Vertex::set(vertex++, l, t); 3324 Vertex::set(vertex++, r, t); 3325 Vertex::set(vertex++, l, b); 3326 Vertex::set(vertex++, r, t); 3327 Vertex::set(vertex++, r, b); 3328 3329 vertexCount += 6; 3330 3331 left = fminf(left, l); 3332 top = fminf(top, t); 3333 right = fmaxf(right, r); 3334 bottom = fmaxf(bottom, b); 3335 } 3336 3337 if (clip && quickReject(left, top, right, bottom)) { 3338 return DrawGlInfo::kStatusDone; 3339 } 3340 3341 setupDraw(); 3342 setupDrawNoTexture(); 3343 setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha); 3344 setupDrawShader(); 3345 setupDrawColorFilter(); 3346 setupDrawBlending(mode); 3347 setupDrawProgram(); 3348 setupDrawDirtyRegionsDisabled(); 3349 setupDrawModelView(0.0f, 0.0f, 1.0f, 1.0f, ignoreTransform, true); 3350 setupDrawColorUniforms(); 3351 setupDrawShaderUniforms(); 3352 setupDrawColorFilterUniforms(); 3353 setupDrawVertices((GLvoid*) &mesh[0].position[0]); 3354 3355 if (dirty && hasLayer()) { 3356 dirtyLayer(left, top, right, bottom, currentTransform()); 3357 } 3358 3359 glDrawArrays(GL_TRIANGLES, 0, vertexCount); 3360 3361 return DrawGlInfo::kStatusDrew; 3362 } 3363 3364 void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, 3365 int color, SkXfermode::Mode mode, bool ignoreTransform) { 3366 // If a shader is set, preserve only the alpha 3367 if (mDrawModifiers.mShader) { 3368 color |= 0x00ffffff; 3369 } 3370 3371 setupDraw(); 3372 setupDrawNoTexture(); 3373 setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha); 3374 setupDrawShader(); 3375 setupDrawColorFilter(); 3376 setupDrawBlending(mode); 3377 setupDrawProgram(); 3378 setupDrawModelView(left, top, right, bottom, ignoreTransform); 3379 setupDrawColorUniforms(); 3380 setupDrawShaderUniforms(ignoreTransform); 3381 setupDrawColorFilterUniforms(); 3382 setupDrawSimpleMesh(); 3383 3384 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); 3385 } 3386 3387 void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, 3388 Texture* texture, SkPaint* paint) { 3389 int alpha; 3390 SkXfermode::Mode mode; 3391 getAlphaAndMode(paint, &alpha, &mode); 3392 3393 texture->setWrap(GL_CLAMP_TO_EDGE, true); 3394 3395 if (CC_LIKELY(currentTransform().isPureTranslate())) { 3396 const float x = (int) floorf(left + currentTransform().getTranslateX() + 0.5f); 3397 const float y = (int) floorf(top + currentTransform().getTranslateY() + 0.5f); 3398 3399 texture->setFilter(GL_NEAREST, true); 3400 drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id, 3401 alpha / 255.0f, mode, texture->blend, (GLvoid*) NULL, 3402 (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount, false, true); 3403 } else { 3404 texture->setFilter(FILTER(paint), true); 3405 drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode, 3406 texture->blend, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset, 3407 GL_TRIANGLE_STRIP, gMeshCount); 3408 } 3409 } 3410 3411 void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, 3412 GLuint texture, float alpha, SkXfermode::Mode mode, bool blend) { 3413 drawTextureMesh(left, top, right, bottom, texture, alpha, mode, blend, 3414 (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount); 3415 } 3416 3417 void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom, 3418 GLuint texture, float alpha, SkXfermode::Mode mode, bool blend, 3419 GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount, 3420 bool swapSrcDst, bool ignoreTransform, GLuint vbo, bool ignoreScale, bool dirty) { 3421 3422 setupDraw(); 3423 setupDrawWithTexture(); 3424 setupDrawColor(alpha, alpha, alpha, alpha); 3425 setupDrawColorFilter(); 3426 setupDrawBlending(blend, mode, swapSrcDst); 3427 setupDrawProgram(); 3428 if (!dirty) setupDrawDirtyRegionsDisabled(); 3429 if (!ignoreScale) { 3430 setupDrawModelView(left, top, right, bottom, ignoreTransform); 3431 } else { 3432 setupDrawModelViewTranslate(left, top, right, bottom, ignoreTransform); 3433 } 3434 setupDrawTexture(texture); 3435 setupDrawPureColorUniforms(); 3436 setupDrawColorFilterUniforms(); 3437 setupDrawMesh(vertices, texCoords, vbo); 3438 3439 glDrawArrays(drawMode, 0, elementsCount); 3440 3441 finishDrawTexture(); 3442 } 3443 3444 void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom, 3445 GLuint texture, bool hasColor, int color, int alpha, SkXfermode::Mode mode, 3446 GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount, 3447 bool ignoreTransform, bool ignoreScale, bool dirty) { 3448 3449 setupDraw(); 3450 setupDrawWithTexture(true); 3451 if (hasColor) { 3452 setupDrawAlpha8Color(color, alpha); 3453 } 3454 setupDrawColorFilter(); 3455 setupDrawShader(); 3456 setupDrawBlending(true, mode); 3457 setupDrawProgram(); 3458 if (!dirty) setupDrawDirtyRegionsDisabled(); 3459 if (!ignoreScale) { 3460 setupDrawModelView(left, top, right, bottom, ignoreTransform); 3461 } else { 3462 setupDrawModelViewTranslate(left, top, right, bottom, ignoreTransform); 3463 } 3464 setupDrawTexture(texture); 3465 setupDrawPureColorUniforms(); 3466 setupDrawColorFilterUniforms(); 3467 setupDrawShaderUniforms(); 3468 setupDrawMesh(vertices, texCoords); 3469 3470 glDrawArrays(drawMode, 0, elementsCount); 3471 3472 finishDrawTexture(); 3473 } 3474 3475 void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, 3476 ProgramDescription& description, bool swapSrcDst) { 3477 blend = blend || mode != SkXfermode::kSrcOver_Mode; 3478 3479 if (blend) { 3480 // These blend modes are not supported by OpenGL directly and have 3481 // to be implemented using shaders. Since the shader will perform 3482 // the blending, turn blending off here 3483 // If the blend mode cannot be implemented using shaders, fall 3484 // back to the default SrcOver blend mode instead 3485 if (CC_UNLIKELY(mode > SkXfermode::kScreen_Mode)) { 3486 if (CC_UNLIKELY(mExtensions.hasFramebufferFetch())) { 3487 description.framebufferMode = mode; 3488 description.swapSrcDst = swapSrcDst; 3489 3490 if (mCaches.blend) { 3491 glDisable(GL_BLEND); 3492 mCaches.blend = false; 3493 } 3494 3495 return; 3496 } else { 3497 mode = SkXfermode::kSrcOver_Mode; 3498 } 3499 } 3500 3501 if (!mCaches.blend) { 3502 glEnable(GL_BLEND); 3503 } 3504 3505 GLenum sourceMode = swapSrcDst ? gBlendsSwap[mode].src : gBlends[mode].src; 3506 GLenum destMode = swapSrcDst ? gBlendsSwap[mode].dst : gBlends[mode].dst; 3507 3508 if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) { 3509 glBlendFunc(sourceMode, destMode); 3510 mCaches.lastSrcMode = sourceMode; 3511 mCaches.lastDstMode = destMode; 3512 } 3513 } else if (mCaches.blend) { 3514 glDisable(GL_BLEND); 3515 } 3516 mCaches.blend = blend; 3517 } 3518 3519 bool OpenGLRenderer::useProgram(Program* program) { 3520 if (!program->isInUse()) { 3521 if (mCaches.currentProgram != NULL) mCaches.currentProgram->remove(); 3522 program->use(); 3523 mCaches.currentProgram = program; 3524 return false; 3525 } 3526 return true; 3527 } 3528 3529 void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) { 3530 TextureVertex* v = &mMeshVertices[0]; 3531 TextureVertex::setUV(v++, u1, v1); 3532 TextureVertex::setUV(v++, u2, v1); 3533 TextureVertex::setUV(v++, u1, v2); 3534 TextureVertex::setUV(v++, u2, v2); 3535 } 3536 3537 void OpenGLRenderer::getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) const { 3538 getAlphaAndModeDirect(paint, alpha, mode); 3539 if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) { 3540 // if drawing a layer, ignore the paint's alpha 3541 *alpha = mDrawModifiers.mOverrideLayerAlpha * 255; 3542 } 3543 *alpha *= mSnapshot->alpha; 3544 } 3545 3546 float OpenGLRenderer::getLayerAlpha(Layer* layer) const { 3547 float alpha; 3548 if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) { 3549 alpha = mDrawModifiers.mOverrideLayerAlpha; 3550 } else { 3551 alpha = layer->getAlpha() / 255.0f; 3552 } 3553 return alpha * mSnapshot->alpha; 3554 } 3555 3556 }; // namespace uirenderer 3557 }; // namespace android 3558