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