DisplayListOp.h revision 139088228faa7f3c446af7387e017933998a5570
1/* 2 * Copyright (C) 2013 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#ifndef ANDROID_HWUI_DISPLAY_OPERATION_H 18#define ANDROID_HWUI_DISPLAY_OPERATION_H 19 20#ifndef LOG_TAG 21 #define LOG_TAG "OpenGLRenderer" 22#endif 23 24#include <SkPath.h> 25#include <SkPathOps.h> 26#include <SkXfermode.h> 27 28#include <private/hwui/DrawGlInfo.h> 29 30#include "OpenGLRenderer.h" 31#include "AssetAtlas.h" 32#include "DeferredDisplayList.h" 33#include "DisplayListRenderer.h" 34#include "UvMapper.h" 35#include "utils/LinearAllocator.h" 36 37#define CRASH() do { \ 38 *(int *)(uintptr_t) 0xbbadbeef = 0; \ 39 ((void(*)())0)(); /* More reliable, but doesn't say BBADBEEF */ \ 40} while(false) 41 42// Use OP_LOG for logging with arglist, OP_LOGS if just printing char* 43#define OP_LOGS(s) OP_LOG("%s", (s)) 44#define OP_LOG(s, ...) ALOGD( "%*s" s, level * 2, "", __VA_ARGS__ ) 45 46namespace android { 47namespace uirenderer { 48 49/** 50 * Structure for storing canvas operations when they are recorded into a DisplayList, so that they 51 * may be replayed to an OpenGLRenderer. 52 * 53 * To avoid individual memory allocations, DisplayListOps may only be allocated into a 54 * LinearAllocator's managed memory buffers. Each pointer held by a DisplayListOp is either a 55 * pointer into memory also allocated in the LinearAllocator (mostly for text and float buffers) or 56 * references a externally refcounted object (Sk... and Skia... objects). ~DisplayListOp() is 57 * never called as LinearAllocators are simply discarded, so no memory management should be done in 58 * this class. 59 */ 60class DisplayListOp { 61public: 62 // These objects should always be allocated with a LinearAllocator, and never destroyed/deleted. 63 // standard new() intentionally not implemented, and delete/deconstructor should never be used. 64 virtual ~DisplayListOp() { CRASH(); } 65 static void operator delete(void* ptr) { CRASH(); } 66 /** static void* operator new(size_t size); PURPOSELY OMITTED **/ 67 static void* operator new(size_t size, LinearAllocator& allocator) { 68 return allocator.alloc(size); 69 } 70 71 enum OpLogFlag { 72 kOpLogFlag_Recurse = 0x1, 73 kOpLogFlag_JSON = 0x2 // TODO: add? 74 }; 75 76 virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, 77 bool useQuickReject) = 0; 78 79 virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level, 80 bool useQuickReject) = 0; 81 82 virtual void output(int level, uint32_t logFlags = 0) const = 0; 83 84 // NOTE: it would be nice to declare constants and overriding the implementation in each op to 85 // point at the constants, but that seems to require a .cpp file 86 virtual const char* name() = 0; 87}; 88 89class StateOp : public DisplayListOp { 90public: 91 StateOp() {}; 92 93 virtual ~StateOp() {} 94 95 virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, 96 bool useQuickReject) { 97 // default behavior only affects immediate, deferrable state, issue directly to renderer 98 applyState(deferStruct.mRenderer, saveCount); 99 } 100 101 /** 102 * State operations are applied directly to the renderer, but can cause the deferred drawing op 103 * list to flush 104 */ 105 virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level, 106 bool useQuickReject) { 107 applyState(replayStruct.mRenderer, saveCount); 108 } 109 110 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const = 0; 111}; 112 113class DrawOp : public DisplayListOp { 114friend class MergingDrawBatch; 115public: 116 DrawOp(const SkPaint* paint) 117 : mPaint(paint), mQuickRejected(false) {} 118 119 virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, 120 bool useQuickReject) { 121 if (mQuickRejected && CC_LIKELY(useQuickReject)) { 122 return; 123 } 124 125 deferStruct.mDeferredList.addDrawOp(deferStruct.mRenderer, this); 126 } 127 128 virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level, 129 bool useQuickReject) { 130 if (mQuickRejected && CC_LIKELY(useQuickReject)) { 131 return; 132 } 133 134 replayStruct.mDrawGlStatus |= applyDraw(replayStruct.mRenderer, replayStruct.mDirty); 135 } 136 137 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) = 0; 138 139 /** 140 * Draw multiple instances of an operation, must be overidden for operations that merge 141 * 142 * Currently guarantees certain similarities between ops (see MergingDrawBatch::canMergeWith), 143 * and pure translation transformations. Other guarantees of similarity should be enforced by 144 * reducing which operations are tagged as mergeable. 145 */ 146 virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty, 147 const Vector<OpStatePair>& ops, const Rect& bounds) { 148 status_t status = DrawGlInfo::kStatusDone; 149 for (unsigned int i = 0; i < ops.size(); i++) { 150 renderer.restoreDisplayState(*(ops[i].state), true); 151 status |= ops[i].op->applyDraw(renderer, dirty); 152 } 153 return status; 154 } 155 156 /** 157 * When this method is invoked the state field is initialized to have the 158 * final rendering state. We can thus use it to process data as it will be 159 * used at draw time. 160 * 161 * Additionally, this method allows subclasses to provide defer-time preferences for batching 162 * and merging. 163 * 164 * if a subclass can set deferInfo.mergeable to true, it should implement multiDraw() 165 */ 166 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, 167 const DeferredDisplayState& state) {} 168 169 /** 170 * Query the conservative, local bounds (unmapped) bounds of the op. 171 * 172 * returns true if bounds exist 173 */ 174 virtual bool getLocalBounds(const DrawModifiers& drawModifiers, Rect& localBounds) { 175 return false; 176 } 177 178 // TODO: better refine localbounds usage 179 void setQuickRejected(bool quickRejected) { mQuickRejected = quickRejected; } 180 bool getQuickRejected() { return mQuickRejected; } 181 182 inline int getPaintAlpha() const { 183 return OpenGLRenderer::getAlphaDirect(mPaint); 184 } 185 186 virtual bool hasTextShadow() const { 187 return false; 188 } 189 190 inline float strokeWidthOutset() { 191 // since anything AA stroke with less than 1.0 pixel width is drawn with an alpha-reduced 192 // 1.0 stroke, treat 1.0 as minimum. 193 194 // TODO: it would be nice if this could take scale into account, but scale isn't stable 195 // since higher levels of the view hierarchy can change scale out from underneath it. 196 return fmaxf(mPaint->getStrokeWidth(), 1) * 0.5f; 197 } 198 199protected: 200 const SkPaint* getPaint(OpenGLRenderer& renderer) { 201 return renderer.filterPaint(mPaint); 202 } 203 204 // Helper method for determining op opaqueness. Assumes op fills its bounds in local 205 // coordinates, and that paint's alpha is used 206 inline bool isOpaqueOverBounds(const DeferredDisplayState& state) { 207 // ensure that local bounds cover mapped bounds 208 if (!state.mMatrix.isSimple()) return false; 209 210 // check state/paint for transparency 211 if (mPaint) { 212 if (mPaint->getShader() && !mPaint->getShader()->isOpaque()) { 213 return false; 214 } 215 if (mPaint->getAlpha() != 0xFF) { 216 return false; 217 } 218 } 219 220 if (state.mAlpha != 1.0f) return false; 221 222 SkXfermode::Mode mode = OpenGLRenderer::getXfermodeDirect(mPaint); 223 return (mode == SkXfermode::kSrcOver_Mode || 224 mode == SkXfermode::kSrc_Mode); 225 226 } 227 228 const SkPaint* mPaint; // should be accessed via getPaint() when applying 229 bool mQuickRejected; 230}; 231 232class DrawBoundedOp : public DrawOp { 233public: 234 DrawBoundedOp(float left, float top, float right, float bottom, const SkPaint* paint) 235 : DrawOp(paint), mLocalBounds(left, top, right, bottom) {} 236 237 DrawBoundedOp(const Rect& localBounds, const SkPaint* paint) 238 : DrawOp(paint), mLocalBounds(localBounds) {} 239 240 // Calculates bounds as smallest rect encompassing all points 241 // NOTE: requires at least 1 vertex, and doesn't account for stroke size (should be handled in 242 // subclass' constructor) 243 DrawBoundedOp(const float* points, int count, const SkPaint* paint) 244 : DrawOp(paint), mLocalBounds(points[0], points[1], points[0], points[1]) { 245 for (int i = 2; i < count; i += 2) { 246 mLocalBounds.left = fminf(mLocalBounds.left, points[i]); 247 mLocalBounds.right = fmaxf(mLocalBounds.right, points[i]); 248 mLocalBounds.top = fminf(mLocalBounds.top, points[i + 1]); 249 mLocalBounds.bottom = fmaxf(mLocalBounds.bottom, points[i + 1]); 250 } 251 } 252 253 // default empty constructor for bounds, to be overridden in child constructor body 254 DrawBoundedOp(const SkPaint* paint): DrawOp(paint) { } 255 256 bool getLocalBounds(const DrawModifiers& drawModifiers, Rect& localBounds) { 257 localBounds.set(mLocalBounds); 258 OpenGLRenderer::TextShadow textShadow; 259 if (OpenGLRenderer::getTextShadow(mPaint, &textShadow)) { 260 Rect shadow(mLocalBounds); 261 shadow.translate(textShadow.dx, textShadow.dx); 262 shadow.outset(textShadow.radius); 263 localBounds.unionWith(shadow); 264 } 265 return true; 266 } 267 268protected: 269 Rect mLocalBounds; // displayed area in LOCAL coord. doesn't incorporate stroke, so check paint 270}; 271 272/////////////////////////////////////////////////////////////////////////////// 273// STATE OPERATIONS - these may affect the state of the canvas/renderer, but do 274// not directly draw or alter output 275/////////////////////////////////////////////////////////////////////////////// 276 277class SaveOp : public StateOp { 278public: 279 SaveOp(int flags) 280 : mFlags(flags) {} 281 282 virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, 283 bool useQuickReject) { 284 int newSaveCount = deferStruct.mRenderer.save(mFlags); 285 deferStruct.mDeferredList.addSave(deferStruct.mRenderer, this, newSaveCount); 286 } 287 288 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { 289 renderer.save(mFlags); 290 } 291 292 virtual void output(int level, uint32_t logFlags) const { 293 OP_LOG("Save flags %x", mFlags); 294 } 295 296 virtual const char* name() { return "Save"; } 297 298 int getFlags() const { return mFlags; } 299private: 300 int mFlags; 301}; 302 303class RestoreToCountOp : public StateOp { 304public: 305 RestoreToCountOp(int count) 306 : mCount(count) {} 307 308 virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, 309 bool useQuickReject) { 310 deferStruct.mDeferredList.addRestoreToCount(deferStruct.mRenderer, 311 this, saveCount + mCount); 312 deferStruct.mRenderer.restoreToCount(saveCount + mCount); 313 } 314 315 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { 316 renderer.restoreToCount(saveCount + mCount); 317 } 318 319 virtual void output(int level, uint32_t logFlags) const { 320 OP_LOG("Restore to count %d", mCount); 321 } 322 323 virtual const char* name() { return "RestoreToCount"; } 324 325private: 326 int mCount; 327}; 328 329class SaveLayerOp : public StateOp { 330public: 331 SaveLayerOp(float left, float top, float right, float bottom, int alpha, int flags) 332 : mArea(left, top, right, bottom) 333 , mPaint(&mCachedPaint) 334 , mFlags(flags) 335 , mConvexMask(NULL) { 336 mCachedPaint.setAlpha(alpha); 337 } 338 339 SaveLayerOp(float left, float top, float right, float bottom, const SkPaint* paint, int flags) 340 : mArea(left, top, right, bottom) 341 , mPaint(paint) 342 , mFlags(flags) 343 , mConvexMask(NULL) 344 {} 345 346 virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, 347 bool useQuickReject) { 348 // NOTE: don't bother with actual saveLayer, instead issuing it at flush time 349 int newSaveCount = deferStruct.mRenderer.getSaveCount(); 350 deferStruct.mDeferredList.addSaveLayer(deferStruct.mRenderer, this, newSaveCount); 351 352 // NOTE: don't issue full saveLayer, since that has side effects/is costly. instead just 353 // setup the snapshot for deferral, and re-issue the op at flush time 354 deferStruct.mRenderer.saveLayerDeferred(mArea.left, mArea.top, mArea.right, mArea.bottom, 355 mPaint, mFlags); 356 } 357 358 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { 359 renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom, 360 mPaint, mFlags, mConvexMask); 361 } 362 363 virtual void output(int level, uint32_t logFlags) const { 364 OP_LOG("SaveLayer%s of area " RECT_STRING, 365 (isSaveLayerAlpha() ? "Alpha" : ""),RECT_ARGS(mArea)); 366 } 367 368 virtual const char* name() { return isSaveLayerAlpha() ? "SaveLayerAlpha" : "SaveLayer"; } 369 370 int getFlags() { return mFlags; } 371 372 // Called to make SaveLayerOp clip to the provided mask when drawing back/restored 373 void setMask(const SkPath* convexMask) { 374 mConvexMask = convexMask; 375 } 376 377private: 378 bool isSaveLayerAlpha() const { 379 SkXfermode::Mode mode = OpenGLRenderer::getXfermodeDirect(mPaint); 380 int alpha = OpenGLRenderer::getAlphaDirect(mPaint); 381 return alpha < 255 && mode == SkXfermode::kSrcOver_Mode; 382 } 383 384 Rect mArea; 385 const SkPaint* mPaint; 386 SkPaint mCachedPaint; 387 int mFlags; 388 389 // Convex path, points at data in RenderNode, valid for the duration of the frame only 390 // Only used for masking the SaveLayer which wraps projected RenderNodes 391 const SkPath* mConvexMask; 392}; 393 394class TranslateOp : public StateOp { 395public: 396 TranslateOp(float dx, float dy) 397 : mDx(dx), mDy(dy) {} 398 399 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { 400 renderer.translate(mDx, mDy); 401 } 402 403 virtual void output(int level, uint32_t logFlags) const { 404 OP_LOG("Translate by %f %f", mDx, mDy); 405 } 406 407 virtual const char* name() { return "Translate"; } 408 409private: 410 float mDx; 411 float mDy; 412}; 413 414class RotateOp : public StateOp { 415public: 416 RotateOp(float degrees) 417 : mDegrees(degrees) {} 418 419 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { 420 renderer.rotate(mDegrees); 421 } 422 423 virtual void output(int level, uint32_t logFlags) const { 424 OP_LOG("Rotate by %f degrees", mDegrees); 425 } 426 427 virtual const char* name() { return "Rotate"; } 428 429private: 430 float mDegrees; 431}; 432 433class ScaleOp : public StateOp { 434public: 435 ScaleOp(float sx, float sy) 436 : mSx(sx), mSy(sy) {} 437 438 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { 439 renderer.scale(mSx, mSy); 440 } 441 442 virtual void output(int level, uint32_t logFlags) const { 443 OP_LOG("Scale by %f %f", mSx, mSy); 444 } 445 446 virtual const char* name() { return "Scale"; } 447 448private: 449 float mSx; 450 float mSy; 451}; 452 453class SkewOp : public StateOp { 454public: 455 SkewOp(float sx, float sy) 456 : mSx(sx), mSy(sy) {} 457 458 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { 459 renderer.skew(mSx, mSy); 460 } 461 462 virtual void output(int level, uint32_t logFlags) const { 463 OP_LOG("Skew by %f %f", mSx, mSy); 464 } 465 466 virtual const char* name() { return "Skew"; } 467 468private: 469 float mSx; 470 float mSy; 471}; 472 473class SetMatrixOp : public StateOp { 474public: 475 SetMatrixOp(const SkMatrix& matrix) 476 : mMatrix(matrix) {} 477 478 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { 479 renderer.setMatrix(mMatrix); 480 } 481 482 virtual void output(int level, uint32_t logFlags) const { 483 if (mMatrix.isIdentity()) { 484 OP_LOGS("SetMatrix (reset)"); 485 } else { 486 OP_LOG("SetMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(&mMatrix)); 487 } 488 } 489 490 virtual const char* name() { return "SetMatrix"; } 491 492private: 493 const SkMatrix mMatrix; 494}; 495 496class ConcatMatrixOp : public StateOp { 497public: 498 ConcatMatrixOp(const SkMatrix& matrix) 499 : mMatrix(matrix) {} 500 501 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { 502 renderer.concatMatrix(mMatrix); 503 } 504 505 virtual void output(int level, uint32_t logFlags) const { 506 OP_LOG("ConcatMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(&mMatrix)); 507 } 508 509 virtual const char* name() { return "ConcatMatrix"; } 510 511private: 512 const SkMatrix mMatrix; 513}; 514 515class ClipOp : public StateOp { 516public: 517 ClipOp(SkRegion::Op op) : mOp(op) {} 518 519 virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, 520 bool useQuickReject) { 521 // NOTE: must defer op BEFORE applying state, since it may read clip 522 deferStruct.mDeferredList.addClip(deferStruct.mRenderer, this); 523 524 // TODO: Can we avoid applying complex clips at defer time? 525 applyState(deferStruct.mRenderer, saveCount); 526 } 527 528 bool canCauseComplexClip() { 529 return ((mOp != SkRegion::kIntersect_Op) && (mOp != SkRegion::kReplace_Op)) || !isRect(); 530 } 531 532protected: 533 virtual bool isRect() { return false; } 534 535 SkRegion::Op mOp; 536}; 537 538class ClipRectOp : public ClipOp { 539public: 540 ClipRectOp(float left, float top, float right, float bottom, SkRegion::Op op) 541 : ClipOp(op), mArea(left, top, right, bottom) {} 542 543 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { 544 renderer.clipRect(mArea.left, mArea.top, mArea.right, mArea.bottom, mOp); 545 } 546 547 virtual void output(int level, uint32_t logFlags) const { 548 OP_LOG("ClipRect " RECT_STRING, RECT_ARGS(mArea)); 549 } 550 551 virtual const char* name() { return "ClipRect"; } 552 553protected: 554 virtual bool isRect() { return true; } 555 556private: 557 Rect mArea; 558}; 559 560class ClipPathOp : public ClipOp { 561public: 562 ClipPathOp(const SkPath* path, SkRegion::Op op) 563 : ClipOp(op), mPath(path) {} 564 565 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { 566 renderer.clipPath(mPath, mOp); 567 } 568 569 virtual void output(int level, uint32_t logFlags) const { 570 SkRect bounds = mPath->getBounds(); 571 OP_LOG("ClipPath bounds " RECT_STRING, 572 bounds.left(), bounds.top(), bounds.right(), bounds.bottom()); 573 } 574 575 virtual const char* name() { return "ClipPath"; } 576 577private: 578 const SkPath* mPath; 579}; 580 581class ClipRegionOp : public ClipOp { 582public: 583 ClipRegionOp(const SkRegion* region, SkRegion::Op op) 584 : ClipOp(op), mRegion(region) {} 585 586 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { 587 renderer.clipRegion(mRegion, mOp); 588 } 589 590 virtual void output(int level, uint32_t logFlags) const { 591 SkIRect bounds = mRegion->getBounds(); 592 OP_LOG("ClipRegion bounds %d %d %d %d", 593 bounds.left(), bounds.top(), bounds.right(), bounds.bottom()); 594 } 595 596 virtual const char* name() { return "ClipRegion"; } 597 598private: 599 const SkRegion* mRegion; 600}; 601 602class ResetPaintFilterOp : public StateOp { 603public: 604 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { 605 renderer.resetPaintFilter(); 606 } 607 608 virtual void output(int level, uint32_t logFlags) const { 609 OP_LOGS("ResetPaintFilter"); 610 } 611 612 virtual const char* name() { return "ResetPaintFilter"; } 613}; 614 615class SetupPaintFilterOp : public StateOp { 616public: 617 SetupPaintFilterOp(int clearBits, int setBits) 618 : mClearBits(clearBits), mSetBits(setBits) {} 619 620 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const { 621 renderer.setupPaintFilter(mClearBits, mSetBits); 622 } 623 624 virtual void output(int level, uint32_t logFlags) const { 625 OP_LOG("SetupPaintFilter, clear %#x, set %#x", mClearBits, mSetBits); 626 } 627 628 virtual const char* name() { return "SetupPaintFilter"; } 629 630private: 631 int mClearBits; 632 int mSetBits; 633}; 634 635/////////////////////////////////////////////////////////////////////////////// 636// DRAW OPERATIONS - these are operations that can draw to the canvas's device 637/////////////////////////////////////////////////////////////////////////////// 638 639class DrawBitmapOp : public DrawBoundedOp { 640public: 641 DrawBitmapOp(const SkBitmap* bitmap, float left, float top, const SkPaint* paint) 642 : DrawBoundedOp(left, top, left + bitmap->width(), top + bitmap->height(), paint), 643 mBitmap(bitmap), mAtlas(Caches::getInstance().assetAtlas) { 644 mEntry = mAtlas.getEntry(bitmap); 645 if (mEntry) { 646 mEntryGenerationId = mAtlas.getGenerationId(); 647 mUvMapper = mEntry->uvMapper; 648 } 649 } 650 651 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 652 return renderer.drawBitmap(mBitmap, mLocalBounds.left, mLocalBounds.top, 653 getPaint(renderer)); 654 } 655 656 AssetAtlas::Entry* getAtlasEntry() { 657 // The atlas entry is stale, let's get a new one 658 if (mEntry && mEntryGenerationId != mAtlas.getGenerationId()) { 659 mEntryGenerationId = mAtlas.getGenerationId(); 660 mEntry = mAtlas.getEntry(mBitmap); 661 mUvMapper = mEntry->uvMapper; 662 } 663 return mEntry; 664 } 665 666#define SET_TEXTURE(ptr, posRect, offsetRect, texCoordsRect, xDim, yDim) \ 667 TextureVertex::set(ptr++, posRect.xDim - offsetRect.left, posRect.yDim - offsetRect.top, \ 668 texCoordsRect.xDim, texCoordsRect.yDim) 669 670 /** 671 * This multi-draw operation builds a mesh on the stack by generating a quad 672 * for each bitmap in the batch. This method is also responsible for dirtying 673 * the current layer, if any. 674 */ 675 virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty, 676 const Vector<OpStatePair>& ops, const Rect& bounds) { 677 const DeferredDisplayState& firstState = *(ops[0].state); 678 renderer.restoreDisplayState(firstState, true); // restore all but the clip 679 680 TextureVertex vertices[6 * ops.size()]; 681 TextureVertex* vertex = &vertices[0]; 682 683 const bool hasLayer = renderer.hasLayer(); 684 bool pureTranslate = true; 685 686 // TODO: manually handle rect clip for bitmaps by adjusting texCoords per op, 687 // and allowing them to be merged in getBatchId() 688 for (unsigned int i = 0; i < ops.size(); i++) { 689 const DeferredDisplayState& state = *(ops[i].state); 690 const Rect& opBounds = state.mBounds; 691 // When we reach multiDraw(), the matrix can be either 692 // pureTranslate or simple (translate and/or scale). 693 // If the matrix is not pureTranslate, then we have a scale 694 pureTranslate &= state.mMatrix.isPureTranslate(); 695 696 Rect texCoords(0, 0, 1, 1); 697 ((DrawBitmapOp*) ops[i].op)->mUvMapper.map(texCoords); 698 699 SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, top); 700 SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top); 701 SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, bottom); 702 703 SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, bottom); 704 SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top); 705 SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, bottom); 706 707 if (hasLayer) { 708 renderer.dirtyLayer(opBounds.left, opBounds.top, opBounds.right, opBounds.bottom); 709 } 710 } 711 712 return renderer.drawBitmaps(mBitmap, mEntry, ops.size(), &vertices[0], 713 pureTranslate, bounds, mPaint); 714 } 715 716 virtual void output(int level, uint32_t logFlags) const { 717 OP_LOG("Draw bitmap %p at %f %f", mBitmap, mLocalBounds.left, mLocalBounds.top); 718 } 719 720 virtual const char* name() { return "DrawBitmap"; } 721 722 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, 723 const DeferredDisplayState& state) { 724 deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap; 725 deferInfo.mergeId = getAtlasEntry() ? 726 (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap; 727 728 // Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation 729 // Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in 730 // MergingDrawBatch::canMergeWith() 731 // TODO: support clipped bitmaps by handling them in SET_TEXTURE 732 deferInfo.mergeable = state.mMatrix.isSimple() && state.mMatrix.positiveScale() && 733 !state.mClipSideFlags && 734 OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode && 735 (mBitmap->config() != SkBitmap::kA8_Config); 736 } 737 738 const SkBitmap* bitmap() { return mBitmap; } 739protected: 740 const SkBitmap* mBitmap; 741 const AssetAtlas& mAtlas; 742 uint32_t mEntryGenerationId; 743 AssetAtlas::Entry* mEntry; 744 UvMapper mUvMapper; 745}; 746 747class DrawBitmapMatrixOp : public DrawBoundedOp { 748public: 749 DrawBitmapMatrixOp(const SkBitmap* bitmap, const SkMatrix& matrix, const SkPaint* paint) 750 : DrawBoundedOp(paint), mBitmap(bitmap), mMatrix(matrix) { 751 mLocalBounds.set(0, 0, bitmap->width(), bitmap->height()); 752 const mat4 transform(matrix); 753 transform.mapRect(mLocalBounds); 754 } 755 756 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 757 return renderer.drawBitmap(mBitmap, mMatrix, getPaint(renderer)); 758 } 759 760 virtual void output(int level, uint32_t logFlags) const { 761 OP_LOG("Draw bitmap %p matrix " SK_MATRIX_STRING, mBitmap, SK_MATRIX_ARGS(&mMatrix)); 762 } 763 764 virtual const char* name() { return "DrawBitmapMatrix"; } 765 766 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, 767 const DeferredDisplayState& state) { 768 deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap; 769 } 770 771private: 772 const SkBitmap* mBitmap; 773 const SkMatrix mMatrix; 774}; 775 776class DrawBitmapRectOp : public DrawBoundedOp { 777public: 778 DrawBitmapRectOp(const SkBitmap* bitmap, 779 float srcLeft, float srcTop, float srcRight, float srcBottom, 780 float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) 781 : DrawBoundedOp(dstLeft, dstTop, dstRight, dstBottom, paint), 782 mBitmap(bitmap), mSrc(srcLeft, srcTop, srcRight, srcBottom) {} 783 784 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 785 return renderer.drawBitmap(mBitmap, mSrc.left, mSrc.top, mSrc.right, mSrc.bottom, 786 mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom, 787 getPaint(renderer)); 788 } 789 790 virtual void output(int level, uint32_t logFlags) const { 791 OP_LOG("Draw bitmap %p src="RECT_STRING", dst="RECT_STRING, 792 mBitmap, RECT_ARGS(mSrc), RECT_ARGS(mLocalBounds)); 793 } 794 795 virtual const char* name() { return "DrawBitmapRect"; } 796 797 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, 798 const DeferredDisplayState& state) { 799 deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap; 800 } 801 802private: 803 const SkBitmap* mBitmap; 804 Rect mSrc; 805}; 806 807class DrawBitmapDataOp : public DrawBitmapOp { 808public: 809 DrawBitmapDataOp(const SkBitmap* bitmap, float left, float top, const SkPaint* paint) 810 : DrawBitmapOp(bitmap, left, top, paint) {} 811 812 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 813 return renderer.drawBitmapData(mBitmap, mLocalBounds.left, 814 mLocalBounds.top, getPaint(renderer)); 815 } 816 817 virtual void output(int level, uint32_t logFlags) const { 818 OP_LOG("Draw bitmap %p", mBitmap); 819 } 820 821 virtual const char* name() { return "DrawBitmapData"; } 822 823 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, 824 const DeferredDisplayState& state) { 825 deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap; 826 } 827}; 828 829class DrawBitmapMeshOp : public DrawBoundedOp { 830public: 831 DrawBitmapMeshOp(const SkBitmap* bitmap, int meshWidth, int meshHeight, 832 const float* vertices, const int* colors, const SkPaint* paint) 833 : DrawBoundedOp(vertices, 2 * (meshWidth + 1) * (meshHeight + 1), paint), 834 mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight), 835 mVertices(vertices), mColors(colors) {} 836 837 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 838 return renderer.drawBitmapMesh(mBitmap, mMeshWidth, mMeshHeight, 839 mVertices, mColors, getPaint(renderer)); 840 } 841 842 virtual void output(int level, uint32_t logFlags) const { 843 OP_LOG("Draw bitmap %p mesh %d x %d", mBitmap, mMeshWidth, mMeshHeight); 844 } 845 846 virtual const char* name() { return "DrawBitmapMesh"; } 847 848 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, 849 const DeferredDisplayState& state) { 850 deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap; 851 } 852 853private: 854 const SkBitmap* mBitmap; 855 int mMeshWidth; 856 int mMeshHeight; 857 const float* mVertices; 858 const int* mColors; 859}; 860 861class DrawPatchOp : public DrawBoundedOp { 862public: 863 DrawPatchOp(const SkBitmap* bitmap, const Res_png_9patch* patch, 864 float left, float top, float right, float bottom, const SkPaint* paint) 865 : DrawBoundedOp(left, top, right, bottom, paint), 866 mBitmap(bitmap), mPatch(patch), mGenerationId(0), mMesh(NULL), 867 mAtlas(Caches::getInstance().assetAtlas) { 868 mEntry = mAtlas.getEntry(bitmap); 869 if (mEntry) { 870 mEntryGenerationId = mAtlas.getGenerationId(); 871 } 872 }; 873 874 AssetAtlas::Entry* getAtlasEntry() { 875 // The atlas entry is stale, let's get a new one 876 if (mEntry && mEntryGenerationId != mAtlas.getGenerationId()) { 877 mEntryGenerationId = mAtlas.getGenerationId(); 878 mEntry = mAtlas.getEntry(mBitmap); 879 } 880 return mEntry; 881 } 882 883 const Patch* getMesh(OpenGLRenderer& renderer) { 884 if (!mMesh || renderer.getCaches().patchCache.getGenerationId() != mGenerationId) { 885 PatchCache& cache = renderer.getCaches().patchCache; 886 mMesh = cache.get(getAtlasEntry(), mBitmap->width(), mBitmap->height(), 887 mLocalBounds.getWidth(), mLocalBounds.getHeight(), mPatch); 888 mGenerationId = cache.getGenerationId(); 889 } 890 return mMesh; 891 } 892 893 /** 894 * This multi-draw operation builds an indexed mesh on the stack by copying 895 * and transforming the vertices of each 9-patch in the batch. This method 896 * is also responsible for dirtying the current layer, if any. 897 */ 898 virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty, 899 const Vector<OpStatePair>& ops, const Rect& bounds) { 900 const DeferredDisplayState& firstState = *(ops[0].state); 901 renderer.restoreDisplayState(firstState, true); // restore all but the clip 902 903 // Batches will usually contain a small number of items so it's 904 // worth performing a first iteration to count the exact number 905 // of vertices we need in the new mesh 906 uint32_t totalVertices = 0; 907 for (unsigned int i = 0; i < ops.size(); i++) { 908 totalVertices += ((DrawPatchOp*) ops[i].op)->getMesh(renderer)->verticesCount; 909 } 910 911 const bool hasLayer = renderer.hasLayer(); 912 913 uint32_t indexCount = 0; 914 915 TextureVertex vertices[totalVertices]; 916 TextureVertex* vertex = &vertices[0]; 917 918 // Create a mesh that contains the transformed vertices for all the 919 // 9-patch objects that are part of the batch. Note that onDefer() 920 // enforces ops drawn by this function to have a pure translate or 921 // identity matrix 922 for (unsigned int i = 0; i < ops.size(); i++) { 923 DrawPatchOp* patchOp = (DrawPatchOp*) ops[i].op; 924 const DeferredDisplayState* state = ops[i].state; 925 const Patch* opMesh = patchOp->getMesh(renderer); 926 uint32_t vertexCount = opMesh->verticesCount; 927 if (vertexCount == 0) continue; 928 929 // We use the bounds to know where to translate our vertices 930 // Using patchOp->state.mBounds wouldn't work because these 931 // bounds are clipped 932 const float tx = (int) floorf(state->mMatrix.getTranslateX() + 933 patchOp->mLocalBounds.left + 0.5f); 934 const float ty = (int) floorf(state->mMatrix.getTranslateY() + 935 patchOp->mLocalBounds.top + 0.5f); 936 937 // Copy & transform all the vertices for the current operation 938 TextureVertex* opVertices = opMesh->vertices; 939 for (uint32_t j = 0; j < vertexCount; j++, opVertices++) { 940 TextureVertex::set(vertex++, 941 opVertices->x + tx, opVertices->y + ty, 942 opVertices->u, opVertices->v); 943 } 944 945 // Dirty the current layer if possible. When the 9-patch does not 946 // contain empty quads we can take a shortcut and simply set the 947 // dirty rect to the object's bounds. 948 if (hasLayer) { 949 if (!opMesh->hasEmptyQuads) { 950 renderer.dirtyLayer(tx, ty, 951 tx + patchOp->mLocalBounds.getWidth(), 952 ty + patchOp->mLocalBounds.getHeight()); 953 } else { 954 const size_t count = opMesh->quads.size(); 955 for (size_t i = 0; i < count; i++) { 956 const Rect& quadBounds = opMesh->quads[i]; 957 const float x = tx + quadBounds.left; 958 const float y = ty + quadBounds.top; 959 renderer.dirtyLayer(x, y, 960 x + quadBounds.getWidth(), y + quadBounds.getHeight()); 961 } 962 } 963 } 964 965 indexCount += opMesh->indexCount; 966 } 967 968 return renderer.drawPatches(mBitmap, getAtlasEntry(), 969 &vertices[0], indexCount, getPaint(renderer)); 970 } 971 972 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 973 // We're not calling the public variant of drawPatch() here 974 // This method won't perform the quickReject() since we've already done it at this point 975 return renderer.drawPatch(mBitmap, getMesh(renderer), getAtlasEntry(), 976 mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom, 977 getPaint(renderer)); 978 } 979 980 virtual void output(int level, uint32_t logFlags) const { 981 OP_LOG("Draw patch "RECT_STRING, RECT_ARGS(mLocalBounds)); 982 } 983 984 virtual const char* name() { return "DrawPatch"; } 985 986 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, 987 const DeferredDisplayState& state) { 988 deferInfo.batchId = DeferredDisplayList::kOpBatch_Patch; 989 deferInfo.mergeId = getAtlasEntry() ? (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap; 990 deferInfo.mergeable = state.mMatrix.isPureTranslate() && 991 OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode; 992 deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) && mBitmap->isOpaque(); 993 } 994 995private: 996 const SkBitmap* mBitmap; 997 const Res_png_9patch* mPatch; 998 999 uint32_t mGenerationId; 1000 const Patch* mMesh; 1001 1002 const AssetAtlas& mAtlas; 1003 uint32_t mEntryGenerationId; 1004 AssetAtlas::Entry* mEntry; 1005}; 1006 1007class DrawColorOp : public DrawOp { 1008public: 1009 DrawColorOp(int color, SkXfermode::Mode mode) 1010 : DrawOp(NULL), mColor(color), mMode(mode) {}; 1011 1012 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 1013 return renderer.drawColor(mColor, mMode); 1014 } 1015 1016 virtual void output(int level, uint32_t logFlags) const { 1017 OP_LOG("Draw color %#x, mode %d", mColor, mMode); 1018 } 1019 1020 virtual const char* name() { return "DrawColor"; } 1021 1022private: 1023 int mColor; 1024 SkXfermode::Mode mMode; 1025}; 1026 1027class DrawStrokableOp : public DrawBoundedOp { 1028public: 1029 DrawStrokableOp(float left, float top, float right, float bottom, const SkPaint* paint) 1030 : DrawBoundedOp(left, top, right, bottom, paint) {}; 1031 1032 bool getLocalBounds(const DrawModifiers& drawModifiers, Rect& localBounds) { 1033 localBounds.set(mLocalBounds); 1034 if (mPaint && mPaint->getStyle() != SkPaint::kFill_Style) { 1035 localBounds.outset(strokeWidthOutset()); 1036 } 1037 return true; 1038 } 1039 1040 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, 1041 const DeferredDisplayState& state) { 1042 if (mPaint->getPathEffect()) { 1043 deferInfo.batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture; 1044 } else { 1045 deferInfo.batchId = mPaint->isAntiAlias() ? 1046 DeferredDisplayList::kOpBatch_AlphaVertices : 1047 DeferredDisplayList::kOpBatch_Vertices; 1048 } 1049 } 1050}; 1051 1052class DrawRectOp : public DrawStrokableOp { 1053public: 1054 DrawRectOp(float left, float top, float right, float bottom, const SkPaint* paint) 1055 : DrawStrokableOp(left, top, right, bottom, paint) {} 1056 1057 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 1058 return renderer.drawRect(mLocalBounds.left, mLocalBounds.top, 1059 mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer)); 1060 } 1061 1062 virtual void output(int level, uint32_t logFlags) const { 1063 OP_LOG("Draw Rect "RECT_STRING, RECT_ARGS(mLocalBounds)); 1064 } 1065 1066 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, 1067 const DeferredDisplayState& state) { 1068 DrawStrokableOp::onDefer(renderer, deferInfo, state); 1069 deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) && 1070 mPaint->getStyle() == SkPaint::kFill_Style; 1071 } 1072 1073 virtual const char* name() { return "DrawRect"; } 1074}; 1075 1076class DrawRectsOp : public DrawBoundedOp { 1077public: 1078 DrawRectsOp(const float* rects, int count, const SkPaint* paint) 1079 : DrawBoundedOp(rects, count, paint), 1080 mRects(rects), mCount(count) {} 1081 1082 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 1083 return renderer.drawRects(mRects, mCount, getPaint(renderer)); 1084 } 1085 1086 virtual void output(int level, uint32_t logFlags) const { 1087 OP_LOG("Draw Rects count %d", mCount); 1088 } 1089 1090 virtual const char* name() { return "DrawRects"; } 1091 1092 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, 1093 const DeferredDisplayState& state) { 1094 deferInfo.batchId = DeferredDisplayList::kOpBatch_Vertices; 1095 } 1096 1097private: 1098 const float* mRects; 1099 int mCount; 1100}; 1101 1102class DrawRoundRectOp : public DrawStrokableOp { 1103public: 1104 DrawRoundRectOp(float left, float top, float right, float bottom, 1105 float rx, float ry, const SkPaint* paint) 1106 : DrawStrokableOp(left, top, right, bottom, paint), mRx(rx), mRy(ry) {} 1107 1108 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 1109 return renderer.drawRoundRect(mLocalBounds.left, mLocalBounds.top, 1110 mLocalBounds.right, mLocalBounds.bottom, mRx, mRy, getPaint(renderer)); 1111 } 1112 1113 virtual void output(int level, uint32_t logFlags) const { 1114 OP_LOG("Draw RoundRect "RECT_STRING", rx %f, ry %f", RECT_ARGS(mLocalBounds), mRx, mRy); 1115 } 1116 1117 virtual const char* name() { return "DrawRoundRect"; } 1118 1119private: 1120 float mRx; 1121 float mRy; 1122}; 1123 1124class DrawCircleOp : public DrawStrokableOp { 1125public: 1126 DrawCircleOp(float x, float y, float radius, const SkPaint* paint) 1127 : DrawStrokableOp(x - radius, y - radius, x + radius, y + radius, paint), 1128 mX(x), mY(y), mRadius(radius) {} 1129 1130 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 1131 return renderer.drawCircle(mX, mY, mRadius, getPaint(renderer)); 1132 } 1133 1134 virtual void output(int level, uint32_t logFlags) const { 1135 OP_LOG("Draw Circle x %f, y %f, r %f", mX, mY, mRadius); 1136 } 1137 1138 virtual const char* name() { return "DrawCircle"; } 1139 1140private: 1141 float mX; 1142 float mY; 1143 float mRadius; 1144}; 1145 1146class DrawCirclePropsOp : public DrawOp { 1147public: 1148 DrawCirclePropsOp(float* x, float* y, float* radius, const SkPaint* paint) 1149 : DrawOp(paint), mX(x), mY(y), mRadius(radius) {} 1150 1151 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 1152 return renderer.drawCircle(*mX, *mY, *mRadius, getPaint(renderer)); 1153 } 1154 1155 virtual void output(int level, uint32_t logFlags) const { 1156 OP_LOG("Draw Circle Props x %p, y %p, r %p", mX, mY, mRadius); 1157 } 1158 1159 virtual const char* name() { return "DrawCircleProps"; } 1160 1161private: 1162 float* mX; 1163 float* mY; 1164 float* mRadius; 1165}; 1166 1167class DrawOvalOp : public DrawStrokableOp { 1168public: 1169 DrawOvalOp(float left, float top, float right, float bottom, const SkPaint* paint) 1170 : DrawStrokableOp(left, top, right, bottom, paint) {} 1171 1172 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 1173 return renderer.drawOval(mLocalBounds.left, mLocalBounds.top, 1174 mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer)); 1175 } 1176 1177 virtual void output(int level, uint32_t logFlags) const { 1178 OP_LOG("Draw Oval "RECT_STRING, RECT_ARGS(mLocalBounds)); 1179 } 1180 1181 virtual const char* name() { return "DrawOval"; } 1182}; 1183 1184class DrawArcOp : public DrawStrokableOp { 1185public: 1186 DrawArcOp(float left, float top, float right, float bottom, 1187 float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint) 1188 : DrawStrokableOp(left, top, right, bottom, paint), 1189 mStartAngle(startAngle), mSweepAngle(sweepAngle), mUseCenter(useCenter) {} 1190 1191 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 1192 return renderer.drawArc(mLocalBounds.left, mLocalBounds.top, 1193 mLocalBounds.right, mLocalBounds.bottom, 1194 mStartAngle, mSweepAngle, mUseCenter, getPaint(renderer)); 1195 } 1196 1197 virtual void output(int level, uint32_t logFlags) const { 1198 OP_LOG("Draw Arc "RECT_STRING", start %f, sweep %f, useCenter %d", 1199 RECT_ARGS(mLocalBounds), mStartAngle, mSweepAngle, mUseCenter); 1200 } 1201 1202 virtual const char* name() { return "DrawArc"; } 1203 1204private: 1205 float mStartAngle; 1206 float mSweepAngle; 1207 bool mUseCenter; 1208}; 1209 1210class DrawPathOp : public DrawBoundedOp { 1211public: 1212 DrawPathOp(const SkPath* path, const SkPaint* paint) 1213 : DrawBoundedOp(paint), mPath(path) { 1214 float left, top, offset; 1215 uint32_t width, height; 1216 PathCache::computePathBounds(path, paint, left, top, offset, width, height); 1217 left -= offset; 1218 top -= offset; 1219 mLocalBounds.set(left, top, left + width, top + height); 1220 } 1221 1222 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 1223 return renderer.drawPath(mPath, getPaint(renderer)); 1224 } 1225 1226 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, 1227 const DeferredDisplayState& state) { 1228 const SkPaint* paint = getPaint(renderer); 1229 renderer.getCaches().pathCache.precache(mPath, paint); 1230 1231 deferInfo.batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture; 1232 } 1233 1234 virtual void output(int level, uint32_t logFlags) const { 1235 OP_LOG("Draw Path %p in "RECT_STRING, mPath, RECT_ARGS(mLocalBounds)); 1236 } 1237 1238 virtual const char* name() { return "DrawPath"; } 1239 1240private: 1241 const SkPath* mPath; 1242}; 1243 1244class DrawLinesOp : public DrawBoundedOp { 1245public: 1246 DrawLinesOp(const float* points, int count, const SkPaint* paint) 1247 : DrawBoundedOp(points, count, paint), 1248 mPoints(points), mCount(count) { 1249 mLocalBounds.outset(strokeWidthOutset()); 1250 } 1251 1252 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 1253 return renderer.drawLines(mPoints, mCount, getPaint(renderer)); 1254 } 1255 1256 virtual void output(int level, uint32_t logFlags) const { 1257 OP_LOG("Draw Lines count %d", mCount); 1258 } 1259 1260 virtual const char* name() { return "DrawLines"; } 1261 1262 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, 1263 const DeferredDisplayState& state) { 1264 deferInfo.batchId = mPaint->isAntiAlias() ? 1265 DeferredDisplayList::kOpBatch_AlphaVertices : 1266 DeferredDisplayList::kOpBatch_Vertices; 1267 } 1268 1269protected: 1270 const float* mPoints; 1271 int mCount; 1272}; 1273 1274class DrawPointsOp : public DrawLinesOp { 1275public: 1276 DrawPointsOp(const float* points, int count, const SkPaint* paint) 1277 : DrawLinesOp(points, count, paint) {} 1278 1279 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 1280 return renderer.drawPoints(mPoints, mCount, getPaint(renderer)); 1281 } 1282 1283 virtual void output(int level, uint32_t logFlags) const { 1284 OP_LOG("Draw Points count %d", mCount); 1285 } 1286 1287 virtual const char* name() { return "DrawPoints"; } 1288}; 1289 1290class DrawSomeTextOp : public DrawOp { 1291public: 1292 DrawSomeTextOp(const char* text, int bytesCount, int count, const SkPaint* paint) 1293 : DrawOp(paint), mText(text), mBytesCount(bytesCount), mCount(count) {}; 1294 1295 virtual void output(int level, uint32_t logFlags) const { 1296 OP_LOG("Draw some text, %d bytes", mBytesCount); 1297 } 1298 1299 virtual bool hasTextShadow() const { 1300 return OpenGLRenderer::hasTextShadow(mPaint); 1301 } 1302 1303 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, 1304 const DeferredDisplayState& state) { 1305 const SkPaint* paint = getPaint(renderer); 1306 FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint); 1307 fontRenderer.precache(paint, mText, mCount, mat4::identity()); 1308 1309 deferInfo.batchId = mPaint->getColor() == 0xff000000 ? 1310 DeferredDisplayList::kOpBatch_Text : 1311 DeferredDisplayList::kOpBatch_ColorText; 1312 } 1313 1314protected: 1315 const char* mText; 1316 int mBytesCount; 1317 int mCount; 1318}; 1319 1320class DrawTextOnPathOp : public DrawSomeTextOp { 1321public: 1322 DrawTextOnPathOp(const char* text, int bytesCount, int count, 1323 const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) 1324 : DrawSomeTextOp(text, bytesCount, count, paint), 1325 mPath(path), mHOffset(hOffset), mVOffset(vOffset) { 1326 /* TODO: inherit from DrawBounded and init mLocalBounds */ 1327 } 1328 1329 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 1330 return renderer.drawTextOnPath(mText, mBytesCount, mCount, mPath, 1331 mHOffset, mVOffset, getPaint(renderer)); 1332 } 1333 1334 virtual const char* name() { return "DrawTextOnPath"; } 1335 1336private: 1337 const SkPath* mPath; 1338 float mHOffset; 1339 float mVOffset; 1340}; 1341 1342class DrawPosTextOp : public DrawSomeTextOp { 1343public: 1344 DrawPosTextOp(const char* text, int bytesCount, int count, 1345 const float* positions, const SkPaint* paint) 1346 : DrawSomeTextOp(text, bytesCount, count, paint), mPositions(positions) { 1347 /* TODO: inherit from DrawBounded and init mLocalBounds */ 1348 } 1349 1350 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 1351 return renderer.drawPosText(mText, mBytesCount, mCount, mPositions, getPaint(renderer)); 1352 } 1353 1354 virtual const char* name() { return "DrawPosText"; } 1355 1356private: 1357 const float* mPositions; 1358}; 1359 1360class DrawTextOp : public DrawBoundedOp { 1361public: 1362 DrawTextOp(const char* text, int bytesCount, int count, float x, float y, 1363 const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds) 1364 : DrawBoundedOp(bounds, paint), mText(text), mBytesCount(bytesCount), mCount(count), 1365 mX(x), mY(y), mPositions(positions), mTotalAdvance(totalAdvance) { 1366 memset(&mPrecacheTransform.data[0], 0xff, 16 * sizeof(float)); 1367 } 1368 1369 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, 1370 const DeferredDisplayState& state) { 1371 const SkPaint* paint = getPaint(renderer); 1372 FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint); 1373 const mat4& transform = renderer.findBestFontTransform(state.mMatrix); 1374 if (mPrecacheTransform != transform) { 1375 fontRenderer.precache(paint, mText, mCount, transform); 1376 mPrecacheTransform = transform; 1377 } 1378 deferInfo.batchId = mPaint->getColor() == 0xff000000 ? 1379 DeferredDisplayList::kOpBatch_Text : 1380 DeferredDisplayList::kOpBatch_ColorText; 1381 1382 deferInfo.mergeId = reinterpret_cast<mergeid_t>(mPaint->getColor()); 1383 1384 // don't merge decorated text - the decorations won't draw in order 1385 bool noDecorations = !(mPaint->getFlags() & (SkPaint::kUnderlineText_Flag | 1386 SkPaint::kStrikeThruText_Flag)); 1387 deferInfo.mergeable = state.mMatrix.isPureTranslate() && noDecorations && 1388 OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode; 1389 } 1390 1391 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 1392 Rect bounds; 1393 getLocalBounds(renderer.getDrawModifiers(), bounds); 1394 return renderer.drawText(mText, mBytesCount, mCount, mX, mY, 1395 mPositions, getPaint(renderer), mTotalAdvance, bounds); 1396 } 1397 1398 virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty, 1399 const Vector<OpStatePair>& ops, const Rect& bounds) { 1400 status_t status = DrawGlInfo::kStatusDone; 1401 for (unsigned int i = 0; i < ops.size(); i++) { 1402 const DeferredDisplayState& state = *(ops[i].state); 1403 DrawOpMode drawOpMode = (i == ops.size() - 1) ? kDrawOpMode_Flush : kDrawOpMode_Defer; 1404 renderer.restoreDisplayState(state, true); // restore all but the clip 1405 1406 DrawTextOp& op = *((DrawTextOp*)ops[i].op); 1407 // quickReject() will not occure in drawText() so we can use mLocalBounds 1408 // directly, we do not need to account for shadow by calling getLocalBounds() 1409 status |= renderer.drawText(op.mText, op.mBytesCount, op.mCount, op.mX, op.mY, 1410 op.mPositions, op.getPaint(renderer), op.mTotalAdvance, op.mLocalBounds, 1411 drawOpMode); 1412 } 1413 return status; 1414 } 1415 1416 virtual void output(int level, uint32_t logFlags) const { 1417 OP_LOG("Draw Text of count %d, bytes %d", mCount, mBytesCount); 1418 } 1419 1420 virtual const char* name() { return "DrawText"; } 1421 1422private: 1423 const char* mText; 1424 int mBytesCount; 1425 int mCount; 1426 float mX; 1427 float mY; 1428 const float* mPositions; 1429 float mTotalAdvance; 1430 mat4 mPrecacheTransform; 1431}; 1432 1433/////////////////////////////////////////////////////////////////////////////// 1434// SPECIAL DRAW OPERATIONS 1435/////////////////////////////////////////////////////////////////////////////// 1436 1437class DrawFunctorOp : public DrawOp { 1438public: 1439 DrawFunctorOp(Functor* functor) 1440 : DrawOp(NULL), mFunctor(functor) {} 1441 1442 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 1443 renderer.startMark("GL functor"); 1444 status_t ret = renderer.callDrawGLFunction(mFunctor, dirty); 1445 renderer.endMark(); 1446 return ret; 1447 } 1448 1449 virtual void output(int level, uint32_t logFlags) const { 1450 OP_LOG("Draw Functor %p", mFunctor); 1451 } 1452 1453 virtual const char* name() { return "DrawFunctor"; } 1454 1455private: 1456 Functor* mFunctor; 1457}; 1458 1459class DrawDisplayListOp : public DrawBoundedOp { 1460 friend class RenderNode; // grant DisplayList access to info of child 1461public: 1462 DrawDisplayListOp(RenderNode* displayList, int flags, const mat4& transformFromParent) 1463 : DrawBoundedOp(0, 0, displayList->getWidth(), displayList->getHeight(), 0), 1464 mDisplayList(displayList), mFlags(flags), mTransformFromParent(transformFromParent) {} 1465 1466 virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, 1467 bool useQuickReject) { 1468 if (mDisplayList && mDisplayList->isRenderable() && !mSkipInOrderDraw) { 1469 mDisplayList->deferNodeInParent(deferStruct, level + 1); 1470 } 1471 } 1472 virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level, 1473 bool useQuickReject) { 1474 if (mDisplayList && mDisplayList->isRenderable() && !mSkipInOrderDraw) { 1475 mDisplayList->replayNodeInParent(replayStruct, level + 1); 1476 } 1477 } 1478 1479 // NOT USED since replay() is overridden 1480 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 1481 return DrawGlInfo::kStatusDone; 1482 } 1483 1484 virtual void output(int level, uint32_t logFlags) const { 1485 OP_LOG("Draw Display List %p, flags %#x", mDisplayList, mFlags); 1486 if (mDisplayList && (logFlags & kOpLogFlag_Recurse)) { 1487 mDisplayList->output(level + 1); 1488 } 1489 } 1490 1491 virtual const char* name() { return "DrawDisplayList"; } 1492 1493 RenderNode* renderNode() { return mDisplayList; } 1494 1495private: 1496 RenderNode* mDisplayList; 1497 const int mFlags; 1498 1499 /////////////////////////// 1500 // Properties below are used by DisplayList::computeOrderingImpl() and iterate() 1501 /////////////////////////// 1502 /** 1503 * Records transform vs parent, used for computing total transform without rerunning DL contents 1504 */ 1505 const mat4 mTransformFromParent; 1506 1507 /** 1508 * Holds the transformation between the projection surface ViewGroup and this DisplayList 1509 * drawing instance. Represents any translations / transformations done within the drawing of 1510 * the compositing ancestor ViewGroup's draw, before the draw of the View represented by this 1511 * DisplayList draw instance. 1512 * 1513 * Note: doesn't include any transformation recorded within the DisplayList and its properties. 1514 */ 1515 mat4 mTransformFromCompositingAncestor; 1516 bool mSkipInOrderDraw; 1517}; 1518 1519/** 1520 * Not a canvas operation, used only by 3d / z ordering logic in RenderNode::iterate() 1521 */ 1522class DrawShadowOp : public DrawOp { 1523public: 1524 DrawShadowOp(const mat4& transformXY, const mat4& transformZ, 1525 float casterAlpha, bool casterUnclipped, 1526 const SkPath* casterOutline, const SkPath* revealClip) 1527 : DrawOp(NULL), mTransformXY(transformXY), mTransformZ(transformZ), 1528 mCasterAlpha(casterAlpha), mCasterUnclipped(casterUnclipped) { 1529 mOutline = *casterOutline; 1530 if (revealClip) { 1531 // intersect the outline with the convex reveal clip 1532 Op(mOutline, *revealClip, kIntersect_PathOp, &mOutline); 1533 } 1534 } 1535 1536 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 1537 return renderer.drawShadow(mTransformXY, mTransformZ, 1538 mCasterAlpha, mCasterUnclipped, &mOutline); 1539 } 1540 1541 virtual void output(int level, uint32_t logFlags) const { 1542 OP_LOGS("DrawShadow"); 1543 } 1544 1545 virtual const char* name() { return "DrawShadow"; } 1546 1547private: 1548 const mat4 mTransformXY; 1549 const mat4 mTransformZ; 1550 const float mCasterAlpha; 1551 const bool mCasterUnclipped; 1552 SkPath mOutline; 1553}; 1554 1555class DrawLayerOp : public DrawOp { 1556public: 1557 DrawLayerOp(Layer* layer, float x, float y) 1558 : DrawOp(NULL), mLayer(layer), mX(x), mY(y) {} 1559 1560 virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { 1561 return renderer.drawLayer(mLayer, mX, mY); 1562 } 1563 1564 virtual void output(int level, uint32_t logFlags) const { 1565 OP_LOG("Draw Layer %p at %f %f", mLayer, mX, mY); 1566 } 1567 1568 virtual const char* name() { return "DrawLayer"; } 1569 1570private: 1571 Layer* mLayer; 1572 float mX; 1573 float mY; 1574}; 1575 1576}; // namespace uirenderer 1577}; // namespace android 1578 1579#endif // ANDROID_HWUI_DISPLAY_OPERATION_H 1580