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