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