2 * Copyright (C) 2013 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #ifndef ANDROID_HWUI_DISPLAY_OPERATION_H
18 #define ANDROID_HWUI_DISPLAY_OPERATION_H
20 #include "OpenGLRenderer.h"
21 #include "AssetAtlas.h"
22 #include "DeferredDisplayList.h"
23 #include "DisplayListCanvas.h"
24 #include "GammaFontRenderer.h"
26 #include "RenderNode.h"
27 #include "renderstate/RenderState.h"
29 #include "utils/LinearAllocator.h"
30 #include "utils/PaintUtils.h"
31 #include "VectorDrawable.h"
37 #include <SkPathOps.h>
38 #include <SkXfermode.h>
40 #include <private/hwui/DrawGlInfo.h>
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__ )
47 namespace uirenderer {
50 * Structure for storing canvas operations when they are recorded into a DisplayList, so that they
51 * may be replayed to an OpenGLRenderer.
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
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() { LOG_ALWAYS_FATAL("Destructor not supported"); }
65 static void operator delete(void* ptr) { LOG_ALWAYS_FATAL("delete not supported"); }
66 static void* operator new(size_t size) = delete; /** PURPOSELY OMITTED **/
67 static void* operator new(size_t size, LinearAllocator& allocator) {
68 // FIXME: Quick hack to keep old pipeline working, delete this when
69 // we no longer need to support HWUI_NEWOPS := false
70 return allocator.alloc<char>(size);
74 kOpLogFlag_Recurse = 0x1,
75 kOpLogFlag_JSON = 0x2 // TODO: add?
78 virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
79 bool useQuickReject) = 0;
81 virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
82 bool useQuickReject) = 0;
84 virtual void output(int level, uint32_t logFlags = 0) const = 0;
86 // NOTE: it would be nice to declare constants and overriding the implementation in each op to
87 // point at the constants, but that seems to require a .cpp file
88 virtual const char* name() = 0;
91 class StateOp : public DisplayListOp {
93 virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
94 bool useQuickReject) override {
95 // default behavior only affects immediate, deferrable state, issue directly to renderer
96 applyState(deferStruct.mRenderer, saveCount);
100 * State operations are applied directly to the renderer, but can cause the deferred drawing op
103 virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
104 bool useQuickReject) override {
105 applyState(replayStruct.mRenderer, saveCount);
108 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const = 0;
111 class DrawOp : public DisplayListOp {
112 friend class MergingDrawBatch;
114 DrawOp(const SkPaint* paint)
115 : mPaint(paint), mQuickRejected(false) {}
117 virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
118 bool useQuickReject) override {
119 if (mQuickRejected && CC_LIKELY(useQuickReject)) {
123 deferStruct.mDeferredList.addDrawOp(deferStruct.mRenderer, this);
126 virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
127 bool useQuickReject) override {
128 if (mQuickRejected && CC_LIKELY(useQuickReject)) {
132 applyDraw(replayStruct.mRenderer, replayStruct.mDirty);
135 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) = 0;
138 * Draw multiple instances of an operation, must be overidden for operations that merge
140 * Currently guarantees certain similarities between ops (see MergingDrawBatch::canMergeWith),
141 * and pure translation transformations. Other guarantees of similarity should be enforced by
142 * reducing which operations are tagged as mergeable.
144 virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty,
145 const std::vector<OpStatePair>& ops, const Rect& bounds) {
146 for (unsigned int i = 0; i < ops.size(); i++) {
147 renderer.restoreDisplayState(*(ops[i].state), true);
148 ops[i].op->applyDraw(renderer, dirty);
153 * When this method is invoked the state field is initialized to have the
154 * final rendering state. We can thus use it to process data as it will be
157 * Additionally, this method allows subclasses to provide defer-time preferences for batching
160 * if a subclass can set deferInfo.mergeable to true, it should implement multiDraw()
162 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
163 const DeferredDisplayState& state) {}
166 * Query the conservative, local bounds (unmapped) bounds of the op.
168 * returns true if bounds exist
170 virtual bool getLocalBounds(Rect& localBounds) {
174 // TODO: better refine localbounds usage
175 void setQuickRejected(bool quickRejected) { mQuickRejected = quickRejected; }
176 bool getQuickRejected() { return mQuickRejected; }
178 virtual bool hasTextShadow() const {
182 inline float strokeWidthOutset() {
183 // since anything AA stroke with less than 1.0 pixel width is drawn with an alpha-reduced
184 // 1.0 stroke, treat 1.0 as minimum.
186 // TODO: it would be nice if this could take scale into account, but scale isn't stable
187 // since higher levels of the view hierarchy can change scale out from underneath it.
188 return std::max(mPaint->getStrokeWidth(), 1.0f) * 0.5f;
192 // Helper method for determining op opaqueness. Assumes op fills its bounds in local
193 // coordinates, and that paint's alpha is used
194 inline bool isOpaqueOverBounds(const DeferredDisplayState& state) {
195 // ensure that local bounds cover mapped bounds
196 if (!state.mMatrix.isSimple()) return false;
198 if (state.mRoundRectClipState) return false;
200 // check state/paint for transparency
202 if (mPaint->getAlpha() != 0xFF) {
205 if (mPaint->getShader() && !mPaint->getShader()->isOpaque()) {
208 if (PaintUtils::isBlendedColorFilter(mPaint->getColorFilter())) {
213 if (state.mAlpha != 1.0f) return false;
215 SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(mPaint);
216 return (mode == SkXfermode::kSrcOver_Mode ||
217 mode == SkXfermode::kSrc_Mode);
221 const SkPaint* mPaint;
225 class DrawBoundedOp : public DrawOp {
227 DrawBoundedOp(float left, float top, float right, float bottom, const SkPaint* paint)
228 : DrawOp(paint), mLocalBounds(left, top, right, bottom) {}
230 DrawBoundedOp(const Rect& localBounds, const SkPaint* paint)
231 : DrawOp(paint), mLocalBounds(localBounds) {}
233 // Calculates bounds as smallest rect encompassing all points
234 // NOTE: requires at least 1 vertex, and doesn't account for stroke size (should be handled in
235 // subclass' constructor)
236 DrawBoundedOp(const float* points, int count, const SkPaint* paint)
237 : DrawOp(paint), mLocalBounds(points[0], points[1], points[0], points[1]) {
238 for (int i = 2; i < count; i += 2) {
239 mLocalBounds.left = std::min(mLocalBounds.left, points[i]);
240 mLocalBounds.right = std::max(mLocalBounds.right, points[i]);
241 mLocalBounds.top = std::min(mLocalBounds.top, points[i + 1]);
242 mLocalBounds.bottom = std::max(mLocalBounds.bottom, points[i + 1]);
246 // default empty constructor for bounds, to be overridden in child constructor body
247 DrawBoundedOp(const SkPaint* paint): DrawOp(paint) { }
249 virtual bool getLocalBounds(Rect& localBounds) override {
250 localBounds.set(mLocalBounds);
251 PaintUtils::TextShadow textShadow;
252 if (PaintUtils::getTextShadow(mPaint, &textShadow)) {
253 Rect shadow(mLocalBounds);
254 shadow.translate(textShadow.dx, textShadow.dx);
255 shadow.outset(textShadow.radius);
256 localBounds.unionWith(shadow);
262 Rect mLocalBounds; // displayed area in LOCAL coord. doesn't incorporate stroke, so check paint
265 ///////////////////////////////////////////////////////////////////////////////
266 // STATE OPERATIONS - these may affect the state of the canvas/renderer, but do
267 // not directly draw or alter output
268 ///////////////////////////////////////////////////////////////////////////////
270 class SaveOp : public StateOp {
275 virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
276 bool useQuickReject) override {
277 int newSaveCount = deferStruct.mRenderer.save(mFlags);
278 deferStruct.mDeferredList.addSave(deferStruct.mRenderer, this, newSaveCount);
281 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
282 renderer.save(mFlags);
285 virtual void output(int level, uint32_t logFlags) const override {
286 OP_LOG("Save flags %x", mFlags);
289 virtual const char* name() override { return "Save"; }
291 int getFlags() const { return mFlags; }
296 class RestoreToCountOp : public StateOp {
298 RestoreToCountOp(int count)
301 virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
302 bool useQuickReject) override {
303 deferStruct.mDeferredList.addRestoreToCount(deferStruct.mRenderer,
304 this, saveCount + mCount);
305 deferStruct.mRenderer.restoreToCount(saveCount + mCount);
308 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
309 renderer.restoreToCount(saveCount + mCount);
312 virtual void output(int level, uint32_t logFlags) const override {
313 OP_LOG("Restore to count %d", mCount);
316 virtual const char* name() override { return "RestoreToCount"; }
322 class SaveLayerOp : public StateOp {
324 SaveLayerOp(float left, float top, float right, float bottom, int alpha, int flags)
325 : mArea(left, top, right, bottom)
326 , mPaint(&mCachedPaint)
328 , mConvexMask(nullptr) {
329 mCachedPaint.setAlpha(alpha);
332 SaveLayerOp(float left, float top, float right, float bottom, const SkPaint* paint, int flags)
333 : mArea(left, top, right, bottom)
336 , mConvexMask(nullptr)
339 virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
340 bool useQuickReject) override {
341 // NOTE: don't bother with actual saveLayer, instead issuing it at flush time
342 int newSaveCount = deferStruct.mRenderer.getSaveCount();
343 deferStruct.mDeferredList.addSaveLayer(deferStruct.mRenderer, this, newSaveCount);
345 // NOTE: don't issue full saveLayer, since that has side effects/is costly. instead just
346 // setup the snapshot for deferral, and re-issue the op at flush time
347 deferStruct.mRenderer.saveLayerDeferred(mArea.left, mArea.top, mArea.right, mArea.bottom,
351 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
352 renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom,
353 mPaint, mFlags, mConvexMask);
356 virtual void output(int level, uint32_t logFlags) const override {
357 OP_LOG("SaveLayer%s of area " RECT_STRING,
358 (isSaveLayerAlpha() ? "Alpha" : ""),RECT_ARGS(mArea));
361 virtual const char* name() override {
362 return isSaveLayerAlpha() ? "SaveLayerAlpha" : "SaveLayer";
365 int getFlags() { return mFlags; }
367 // Called to make SaveLayerOp clip to the provided mask when drawing back/restored
368 void setMask(const SkPath* convexMask) {
369 mConvexMask = convexMask;
373 bool isSaveLayerAlpha() const {
374 SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(mPaint);
375 int alpha = PaintUtils::getAlphaDirect(mPaint);
376 return alpha < 255 && mode == SkXfermode::kSrcOver_Mode;
380 const SkPaint* mPaint;
381 SkPaint mCachedPaint;
384 // Convex path, points at data in RenderNode, valid for the duration of the frame only
385 // Only used for masking the SaveLayer which wraps projected RenderNodes
386 const SkPath* mConvexMask;
389 class TranslateOp : public StateOp {
391 TranslateOp(float dx, float dy)
392 : mDx(dx), mDy(dy) {}
394 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
395 renderer.translate(mDx, mDy);
398 virtual void output(int level, uint32_t logFlags) const override {
399 OP_LOG("Translate by %f %f", mDx, mDy);
402 virtual const char* name() override { return "Translate"; }
409 class RotateOp : public StateOp {
411 RotateOp(float degrees)
412 : mDegrees(degrees) {}
414 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
415 renderer.rotate(mDegrees);
418 virtual void output(int level, uint32_t logFlags) const override {
419 OP_LOG("Rotate by %f degrees", mDegrees);
422 virtual const char* name() override { return "Rotate"; }
428 class ScaleOp : public StateOp {
430 ScaleOp(float sx, float sy)
431 : mSx(sx), mSy(sy) {}
433 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
434 renderer.scale(mSx, mSy);
437 virtual void output(int level, uint32_t logFlags) const override {
438 OP_LOG("Scale by %f %f", mSx, mSy);
441 virtual const char* name() override { return "Scale"; }
448 class SkewOp : public StateOp {
450 SkewOp(float sx, float sy)
451 : mSx(sx), mSy(sy) {}
453 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
454 renderer.skew(mSx, mSy);
457 virtual void output(int level, uint32_t logFlags) const override {
458 OP_LOG("Skew by %f %f", mSx, mSy);
461 virtual const char* name() override { return "Skew"; }
468 class SetMatrixOp : public StateOp {
470 SetMatrixOp(const SkMatrix& matrix)
473 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
474 // Setting a matrix on a Canvas isn't equivalent to setting a total matrix on the scene.
475 // Set a canvas-relative matrix on the renderer instead.
476 renderer.setLocalMatrix(mMatrix);
479 virtual void output(int level, uint32_t logFlags) const override {
480 if (mMatrix.isIdentity()) {
481 OP_LOGS("SetMatrix (reset)");
483 OP_LOG("SetMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(&mMatrix));
487 virtual const char* name() override { return "SetMatrix"; }
490 const SkMatrix mMatrix;
493 class ConcatMatrixOp : public StateOp {
495 ConcatMatrixOp(const SkMatrix& matrix)
498 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
499 renderer.concatMatrix(mMatrix);
502 virtual void output(int level, uint32_t logFlags) const override {
503 OP_LOG("ConcatMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(&mMatrix));
506 virtual const char* name() override { return "ConcatMatrix"; }
509 const SkMatrix mMatrix;
512 class ClipOp : public StateOp {
514 ClipOp(SkRegion::Op op) : mOp(op) {}
516 virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
517 bool useQuickReject) override {
518 // NOTE: must defer op BEFORE applying state, since it may read clip
519 deferStruct.mDeferredList.addClip(deferStruct.mRenderer, this);
521 // TODO: Can we avoid applying complex clips at defer time?
522 applyState(deferStruct.mRenderer, saveCount);
525 bool canCauseComplexClip() {
526 return ((mOp != SkRegion::kIntersect_Op) && (mOp != SkRegion::kReplace_Op)) || !isRect();
530 virtual bool isRect() { return false; }
535 class ClipRectOp : public ClipOp {
537 ClipRectOp(float left, float top, float right, float bottom, SkRegion::Op op)
538 : ClipOp(op), mArea(left, top, right, bottom) {}
540 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
541 renderer.clipRect(mArea.left, mArea.top, mArea.right, mArea.bottom, mOp);
544 virtual void output(int level, uint32_t logFlags) const override {
545 OP_LOG("ClipRect " RECT_STRING, RECT_ARGS(mArea));
548 virtual const char* name() override { return "ClipRect"; }
551 virtual bool isRect() override { return true; }
557 class ClipPathOp : public ClipOp {
559 ClipPathOp(const SkPath* path, SkRegion::Op op)
560 : ClipOp(op), mPath(path) {}
562 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
563 renderer.clipPath(mPath, mOp);
566 virtual void output(int level, uint32_t logFlags) const override {
567 SkRect bounds = mPath->getBounds();
568 OP_LOG("ClipPath bounds " RECT_STRING,
569 bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
572 virtual const char* name() override { return "ClipPath"; }
578 class ClipRegionOp : public ClipOp {
580 ClipRegionOp(const SkRegion* region, SkRegion::Op op)
581 : ClipOp(op), mRegion(region) {}
583 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
584 renderer.clipRegion(mRegion, mOp);
587 virtual void output(int level, uint32_t logFlags) const override {
588 SkIRect bounds = mRegion->getBounds();
589 OP_LOG("ClipRegion bounds %d %d %d %d",
590 bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
593 virtual const char* name() override { return "ClipRegion"; }
596 const SkRegion* mRegion;
599 ///////////////////////////////////////////////////////////////////////////////
600 // DRAW OPERATIONS - these are operations that can draw to the canvas's device
601 ///////////////////////////////////////////////////////////////////////////////
603 class DrawBitmapOp : public DrawBoundedOp {
605 DrawBitmapOp(const SkBitmap* bitmap, const SkPaint* paint)
606 : DrawBoundedOp(0, 0, bitmap->width(), bitmap->height(), paint)
608 , mEntryValid(false), mEntry(nullptr) {
611 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
612 renderer.drawBitmap(mBitmap, mPaint);
615 AssetAtlas::Entry* getAtlasEntry(OpenGLRenderer& renderer) {
618 mEntry = renderer.renderState().assetAtlas().getEntry(mBitmap->pixelRef());
623 #define SET_TEXTURE(ptr, posRect, offsetRect, texCoordsRect, xDim, yDim) \
624 TextureVertex::set(ptr++, posRect.xDim - offsetRect.left, posRect.yDim - offsetRect.top, \
625 texCoordsRect.xDim, texCoordsRect.yDim)
628 * This multi-draw operation builds a mesh on the stack by generating a quad
629 * for each bitmap in the batch. This method is also responsible for dirtying
630 * the current layer, if any.
632 virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty,
633 const std::vector<OpStatePair>& ops, const Rect& bounds) override {
634 const DeferredDisplayState& firstState = *(ops[0].state);
635 renderer.restoreDisplayState(firstState, true); // restore all but the clip
637 TextureVertex vertices[6 * ops.size()];
638 TextureVertex* vertex = &vertices[0];
640 const bool hasLayer = renderer.hasLayer();
641 bool pureTranslate = true;
643 // TODO: manually handle rect clip for bitmaps by adjusting texCoords per op,
644 // and allowing them to be merged in getBatchId()
645 for (unsigned int i = 0; i < ops.size(); i++) {
646 const DeferredDisplayState& state = *(ops[i].state);
647 const Rect& opBounds = state.mBounds;
648 // When we reach multiDraw(), the matrix can be either
649 // pureTranslate or simple (translate and/or scale).
650 // If the matrix is not pureTranslate, then we have a scale
651 pureTranslate &= state.mMatrix.isPureTranslate();
653 Rect texCoords(0, 0, 1, 1);
654 ((DrawBitmapOp*) ops[i].op)->uvMap(renderer, texCoords);
656 SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, top);
657 SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top);
658 SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, bottom);
660 SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, bottom);
661 SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top);
662 SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, bottom);
665 renderer.dirtyLayer(opBounds.left, opBounds.top, opBounds.right, opBounds.bottom);
669 renderer.drawBitmaps(mBitmap, mEntry, ops.size(), &vertices[0],
670 pureTranslate, bounds, mPaint);
673 virtual void output(int level, uint32_t logFlags) const override {
674 OP_LOG("Draw bitmap %p of size %dx%d%s",
675 mBitmap, mBitmap->width(), mBitmap->height(),
676 mEntry ? " using AssetAtlas" : "");
679 virtual const char* name() override { return "DrawBitmap"; }
681 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
682 const DeferredDisplayState& state) override {
683 deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
684 deferInfo.mergeId = getAtlasEntry(renderer) ?
685 (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
687 // Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation
688 // Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in
689 // MergingDrawBatch::canMergeWith()
690 // TODO: support clipped bitmaps by handling them in SET_TEXTURE
691 deferInfo.mergeable = state.mMatrix.isSimple() && state.mMatrix.positiveScale() &&
692 !state.mClipSideFlags &&
693 PaintUtils::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode &&
694 (mBitmap->colorType() != kAlpha_8_SkColorType);
697 void uvMap(OpenGLRenderer& renderer, Rect& texCoords) {
698 if (getAtlasEntry(renderer)) {
699 mEntry->uvMapper.map(texCoords);
703 const SkBitmap* bitmap() { return mBitmap; }
705 const SkBitmap* mBitmap;
707 AssetAtlas::Entry* mEntry;
710 class DrawBitmapRectOp : public DrawBoundedOp {
712 DrawBitmapRectOp(const SkBitmap* bitmap,
713 float srcLeft, float srcTop, float srcRight, float srcBottom,
714 float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint)
715 : DrawBoundedOp(dstLeft, dstTop, dstRight, dstBottom, paint),
716 mBitmap(bitmap), mSrc(srcLeft, srcTop, srcRight, srcBottom) {}
718 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
719 renderer.drawBitmap(mBitmap, mSrc, mLocalBounds, mPaint);
722 virtual void output(int level, uint32_t logFlags) const override {
723 OP_LOG("Draw bitmap %p src=" RECT_STRING ", dst=" RECT_STRING,
724 mBitmap, RECT_ARGS(mSrc), RECT_ARGS(mLocalBounds));
727 virtual const char* name() override { return "DrawBitmapRect"; }
729 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
730 const DeferredDisplayState& state) override {
731 deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
735 const SkBitmap* mBitmap;
739 class DrawBitmapMeshOp : public DrawBoundedOp {
741 DrawBitmapMeshOp(const SkBitmap* bitmap, int meshWidth, int meshHeight,
742 const float* vertices, const int* colors, const SkPaint* paint)
743 : DrawBoundedOp(vertices, 2 * (meshWidth + 1) * (meshHeight + 1), paint),
744 mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight),
745 mVertices(vertices), mColors(colors) {}
747 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
748 renderer.drawBitmapMesh(mBitmap, mMeshWidth, mMeshHeight,
749 mVertices, mColors, mPaint);
752 virtual void output(int level, uint32_t logFlags) const override {
753 OP_LOG("Draw bitmap %p mesh %d x %d", mBitmap, mMeshWidth, mMeshHeight);
756 virtual const char* name() override { return "DrawBitmapMesh"; }
758 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
759 const DeferredDisplayState& state) override {
760 deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
764 const SkBitmap* mBitmap;
767 const float* mVertices;
771 class DrawPatchOp : public DrawBoundedOp {
773 DrawPatchOp(const SkBitmap* bitmap, const Res_png_9patch* patch,
774 float left, float top, float right, float bottom, const SkPaint* paint)
775 : DrawBoundedOp(left, top, right, bottom, paint),
776 mBitmap(bitmap), mPatch(patch), mGenerationId(0), mMesh(nullptr),
777 mEntryValid(false), mEntry(nullptr) {
780 AssetAtlas::Entry* getAtlasEntry(OpenGLRenderer& renderer) {
783 mEntry = renderer.renderState().assetAtlas().getEntry(mBitmap->pixelRef());
788 const Patch* getMesh(OpenGLRenderer& renderer) {
789 if (!mMesh || renderer.getCaches().patchCache.getGenerationId() != mGenerationId) {
790 PatchCache& cache = renderer.getCaches().patchCache;
791 mMesh = cache.get(getAtlasEntry(renderer), mBitmap->width(), mBitmap->height(),
792 mLocalBounds.getWidth(), mLocalBounds.getHeight(), mPatch);
793 mGenerationId = cache.getGenerationId();
799 * This multi-draw operation builds an indexed mesh on the stack by copying
800 * and transforming the vertices of each 9-patch in the batch. This method
801 * is also responsible for dirtying the current layer, if any.
803 virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty,
804 const std::vector<OpStatePair>& ops, const Rect& bounds) override {
805 const DeferredDisplayState& firstState = *(ops[0].state);
806 renderer.restoreDisplayState(firstState, true); // restore all but the clip
808 // Batches will usually contain a small number of items so it's
809 // worth performing a first iteration to count the exact number
810 // of vertices we need in the new mesh
811 uint32_t totalVertices = 0;
812 for (unsigned int i = 0; i < ops.size(); i++) {
813 totalVertices += ((DrawPatchOp*) ops[i].op)->getMesh(renderer)->verticesCount;
816 const bool hasLayer = renderer.hasLayer();
818 uint32_t indexCount = 0;
820 TextureVertex vertices[totalVertices];
821 TextureVertex* vertex = &vertices[0];
823 // Create a mesh that contains the transformed vertices for all the
824 // 9-patch objects that are part of the batch. Note that onDefer()
825 // enforces ops drawn by this function to have a pure translate or
827 for (unsigned int i = 0; i < ops.size(); i++) {
828 DrawPatchOp* patchOp = (DrawPatchOp*) ops[i].op;
829 const DeferredDisplayState* state = ops[i].state;
830 const Patch* opMesh = patchOp->getMesh(renderer);
831 uint32_t vertexCount = opMesh->verticesCount;
832 if (vertexCount == 0) continue;
834 // We use the bounds to know where to translate our vertices
835 // Using patchOp->state.mBounds wouldn't work because these
836 // bounds are clipped
837 const float tx = (int) floorf(state->mMatrix.getTranslateX() +
838 patchOp->mLocalBounds.left + 0.5f);
839 const float ty = (int) floorf(state->mMatrix.getTranslateY() +
840 patchOp->mLocalBounds.top + 0.5f);
842 // Copy & transform all the vertices for the current operation
843 TextureVertex* opVertices = opMesh->vertices.get();
844 for (uint32_t j = 0; j < vertexCount; j++, opVertices++) {
845 TextureVertex::set(vertex++,
846 opVertices->x + tx, opVertices->y + ty,
847 opVertices->u, opVertices->v);
850 // Dirty the current layer if possible. When the 9-patch does not
851 // contain empty quads we can take a shortcut and simply set the
852 // dirty rect to the object's bounds.
854 if (!opMesh->hasEmptyQuads) {
855 renderer.dirtyLayer(tx, ty,
856 tx + patchOp->mLocalBounds.getWidth(),
857 ty + patchOp->mLocalBounds.getHeight());
859 const size_t count = opMesh->quads.size();
860 for (size_t i = 0; i < count; i++) {
861 const Rect& quadBounds = opMesh->quads[i];
862 const float x = tx + quadBounds.left;
863 const float y = ty + quadBounds.top;
864 renderer.dirtyLayer(x, y,
865 x + quadBounds.getWidth(), y + quadBounds.getHeight());
870 indexCount += opMesh->indexCount;
873 renderer.drawPatches(mBitmap, getAtlasEntry(renderer),
874 &vertices[0], indexCount, mPaint);
877 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
878 // We're not calling the public variant of drawPatch() here
879 // This method won't perform the quickReject() since we've already done it at this point
880 renderer.drawPatch(mBitmap, getMesh(renderer), getAtlasEntry(renderer),
881 mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
885 virtual void output(int level, uint32_t logFlags) const override {
886 OP_LOG("Draw patch " RECT_STRING "%s", RECT_ARGS(mLocalBounds),
887 mEntry ? " with AssetAtlas" : "");
890 virtual const char* name() override { return "DrawPatch"; }
892 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
893 const DeferredDisplayState& state) override {
894 deferInfo.batchId = DeferredDisplayList::kOpBatch_Patch;
895 deferInfo.mergeId = getAtlasEntry(renderer) ? (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
896 deferInfo.mergeable = state.mMatrix.isPureTranslate() &&
897 PaintUtils::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode;
898 deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) && mBitmap->isOpaque();
902 const SkBitmap* mBitmap;
903 const Res_png_9patch* mPatch;
905 uint32_t mGenerationId;
909 AssetAtlas::Entry* mEntry;
912 class DrawColorOp : public DrawOp {
914 DrawColorOp(int color, SkXfermode::Mode mode)
915 : DrawOp(nullptr), mColor(color), mMode(mode) {};
917 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
918 renderer.drawColor(mColor, mMode);
921 virtual void output(int level, uint32_t logFlags) const override {
922 OP_LOG("Draw color %#x, mode %d", mColor, mMode);
925 virtual const char* name() override { return "DrawColor"; }
929 SkXfermode::Mode mMode;
932 class DrawStrokableOp : public DrawBoundedOp {
934 DrawStrokableOp(float left, float top, float right, float bottom, const SkPaint* paint)
935 : DrawBoundedOp(left, top, right, bottom, paint) {};
936 DrawStrokableOp(const Rect& localBounds, const SkPaint* paint)
937 : DrawBoundedOp(localBounds, paint) {};
939 virtual bool getLocalBounds(Rect& localBounds) override {
940 localBounds.set(mLocalBounds);
941 if (mPaint && mPaint->getStyle() != SkPaint::kFill_Style) {
942 localBounds.outset(strokeWidthOutset());
947 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
948 const DeferredDisplayState& state) override {
949 if (mPaint->getPathEffect()) {
950 deferInfo.batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
952 deferInfo.batchId = mPaint->isAntiAlias() ?
953 DeferredDisplayList::kOpBatch_AlphaVertices :
954 DeferredDisplayList::kOpBatch_Vertices;
959 class DrawRectOp : public DrawStrokableOp {
961 DrawRectOp(float left, float top, float right, float bottom, const SkPaint* paint)
962 : DrawStrokableOp(left, top, right, bottom, paint) {}
964 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
965 renderer.drawRect(mLocalBounds.left, mLocalBounds.top,
966 mLocalBounds.right, mLocalBounds.bottom, mPaint);
969 virtual void output(int level, uint32_t logFlags) const override {
970 OP_LOG("Draw Rect " RECT_STRING, RECT_ARGS(mLocalBounds));
973 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
974 const DeferredDisplayState& state) override {
975 DrawStrokableOp::onDefer(renderer, deferInfo, state);
976 deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) &&
977 mPaint->getStyle() == SkPaint::kFill_Style;
980 virtual const char* name() override { return "DrawRect"; }
983 class DrawRectsOp : public DrawBoundedOp {
985 DrawRectsOp(const float* rects, int count, const SkPaint* paint)
986 : DrawBoundedOp(rects, count, paint),
987 mRects(rects), mCount(count) {}
989 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
990 renderer.drawRects(mRects, mCount, mPaint);
993 virtual void output(int level, uint32_t logFlags) const override {
994 OP_LOG("Draw Rects count %d", mCount);
997 virtual const char* name() override { return "DrawRects"; }
999 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1000 const DeferredDisplayState& state) override {
1001 deferInfo.batchId = DeferredDisplayList::kOpBatch_Vertices;
1005 const float* mRects;
1009 class DrawRoundRectOp : public DrawStrokableOp {
1011 DrawRoundRectOp(float left, float top, float right, float bottom,
1012 float rx, float ry, const SkPaint* paint)
1013 : DrawStrokableOp(left, top, right, bottom, paint), mRx(rx), mRy(ry) {}
1015 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
1016 renderer.drawRoundRect(mLocalBounds.left, mLocalBounds.top,
1017 mLocalBounds.right, mLocalBounds.bottom, mRx, mRy, mPaint);
1020 virtual void output(int level, uint32_t logFlags) const override {
1021 OP_LOG("Draw RoundRect " RECT_STRING ", rx %f, ry %f", RECT_ARGS(mLocalBounds), mRx, mRy);
1024 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1025 const DeferredDisplayState& state) override {
1026 DrawStrokableOp::onDefer(renderer, deferInfo, state);
1027 if (!mPaint->getPathEffect()) {
1028 renderer.getCaches().tessellationCache.precacheRoundRect(state.mMatrix, *mPaint,
1029 mLocalBounds.getWidth(), mLocalBounds.getHeight(), mRx, mRy);
1033 virtual const char* name() override { return "DrawRoundRect"; }
1040 class DrawRoundRectPropsOp : public DrawOp {
1042 DrawRoundRectPropsOp(float* left, float* top, float* right, float* bottom,
1043 float *rx, float *ry, const SkPaint* paint)
1044 : DrawOp(paint), mLeft(left), mTop(top), mRight(right), mBottom(bottom),
1047 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
1048 renderer.drawRoundRect(*mLeft, *mTop, *mRight, *mBottom,
1049 *mRx, *mRy, mPaint);
1052 virtual void output(int level, uint32_t logFlags) const override {
1053 OP_LOG("Draw RoundRect Props " RECT_STRING ", rx %f, ry %f",
1054 *mLeft, *mTop, *mRight, *mBottom, *mRx, *mRy);
1057 virtual const char* name() override { return "DrawRoundRectProps"; }
1068 class DrawCircleOp : public DrawStrokableOp {
1070 DrawCircleOp(float x, float y, float radius, const SkPaint* paint)
1071 : DrawStrokableOp(x - radius, y - radius, x + radius, y + radius, paint),
1072 mX(x), mY(y), mRadius(radius) {}
1074 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
1075 renderer.drawCircle(mX, mY, mRadius, mPaint);
1078 virtual void output(int level, uint32_t logFlags) const override {
1079 OP_LOG("Draw Circle x %f, y %f, r %f", mX, mY, mRadius);
1082 virtual const char* name() override { return "DrawCircle"; }
1090 class DrawCirclePropsOp : public DrawOp {
1092 DrawCirclePropsOp(float* x, float* y, float* radius, const SkPaint* paint)
1093 : DrawOp(paint), mX(x), mY(y), mRadius(radius) {}
1095 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
1096 renderer.drawCircle(*mX, *mY, *mRadius, mPaint);
1099 virtual void output(int level, uint32_t logFlags) const override {
1100 OP_LOG("Draw Circle Props x %p, y %p, r %p", mX, mY, mRadius);
1103 virtual const char* name() override { return "DrawCircleProps"; }
1111 class DrawVectorDrawableOp : public DrawOp {
1113 DrawVectorDrawableOp(VectorDrawableRoot* tree, const SkRect& bounds)
1114 : DrawOp(nullptr), mTree(tree), mDst(bounds) {}
1116 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
1117 const SkBitmap& bitmap = mTree->getBitmapUpdateIfDirty();
1118 SkPaint* paint = mTree->getPaint();
1119 renderer.drawBitmap(&bitmap, Rect(0, 0, bitmap.width(), bitmap.height()),
1123 virtual void output(int level, uint32_t logFlags) const override {
1124 OP_LOG("Draw Vector Drawable %p", mTree);
1127 virtual const char* name() override { return "DrawVectorDrawable"; }
1130 VectorDrawableRoot* mTree;
1135 class DrawOvalOp : public DrawStrokableOp {
1137 DrawOvalOp(float left, float top, float right, float bottom, const SkPaint* paint)
1138 : DrawStrokableOp(left, top, right, bottom, paint) {}
1140 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
1141 renderer.drawOval(mLocalBounds.left, mLocalBounds.top,
1142 mLocalBounds.right, mLocalBounds.bottom, mPaint);
1145 virtual void output(int level, uint32_t logFlags) const override {
1146 OP_LOG("Draw Oval " RECT_STRING, RECT_ARGS(mLocalBounds));
1149 virtual const char* name() override { return "DrawOval"; }
1152 class DrawArcOp : public DrawStrokableOp {
1154 DrawArcOp(float left, float top, float right, float bottom,
1155 float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint)
1156 : DrawStrokableOp(left, top, right, bottom, paint),
1157 mStartAngle(startAngle), mSweepAngle(sweepAngle), mUseCenter(useCenter) {}
1159 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
1160 renderer.drawArc(mLocalBounds.left, mLocalBounds.top,
1161 mLocalBounds.right, mLocalBounds.bottom,
1162 mStartAngle, mSweepAngle, mUseCenter, mPaint);
1165 virtual void output(int level, uint32_t logFlags) const override {
1166 OP_LOG("Draw Arc " RECT_STRING ", start %f, sweep %f, useCenter %d",
1167 RECT_ARGS(mLocalBounds), mStartAngle, mSweepAngle, mUseCenter);
1170 virtual const char* name() override { return "DrawArc"; }
1178 class DrawPathOp : public DrawBoundedOp {
1180 DrawPathOp(const SkPath* path, const SkPaint* paint)
1181 : DrawBoundedOp(paint), mPath(path) {
1182 float left, top, offset;
1183 uint32_t width, height;
1184 PathCache::computePathBounds(path, paint, left, top, offset, width, height);
1187 mLocalBounds.set(left, top, left + width, top + height);
1190 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
1191 renderer.drawPath(mPath, mPaint);
1194 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1195 const DeferredDisplayState& state) override {
1196 renderer.getCaches().pathCache.precache(mPath, mPaint);
1198 deferInfo.batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
1201 virtual void output(int level, uint32_t logFlags) const override {
1202 OP_LOG("Draw Path %p in " RECT_STRING, mPath, RECT_ARGS(mLocalBounds));
1205 virtual const char* name() override { return "DrawPath"; }
1208 const SkPath* mPath;
1211 class DrawLinesOp : public DrawBoundedOp {
1213 DrawLinesOp(const float* points, int count, const SkPaint* paint)
1214 : DrawBoundedOp(points, count, paint),
1215 mPoints(points), mCount(count) {
1216 mLocalBounds.outset(strokeWidthOutset());
1219 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
1220 renderer.drawLines(mPoints, mCount, mPaint);
1223 virtual void output(int level, uint32_t logFlags) const override {
1224 OP_LOG("Draw Lines count %d", mCount);
1227 virtual const char* name() override { return "DrawLines"; }
1229 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1230 const DeferredDisplayState& state) override {
1231 deferInfo.batchId = mPaint->isAntiAlias() ?
1232 DeferredDisplayList::kOpBatch_AlphaVertices :
1233 DeferredDisplayList::kOpBatch_Vertices;
1237 const float* mPoints;
1241 class DrawPointsOp : public DrawLinesOp {
1243 DrawPointsOp(const float* points, int count, const SkPaint* paint)
1244 : DrawLinesOp(points, count, paint) {}
1246 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
1247 renderer.drawPoints(mPoints, mCount, mPaint);
1250 virtual void output(int level, uint32_t logFlags) const override {
1251 OP_LOG("Draw Points count %d", mCount);
1254 virtual const char* name() override { return "DrawPoints"; }
1257 class DrawSomeTextOp : public DrawOp {
1259 DrawSomeTextOp(const glyph_t* text, int bytesCount, int count, const SkPaint* paint)
1260 : DrawOp(paint), mText(text), mBytesCount(bytesCount), mCount(count) {};
1262 virtual void output(int level, uint32_t logFlags) const override {
1263 OP_LOG("Draw some text, %d bytes", mBytesCount);
1266 virtual bool hasTextShadow() const override {
1267 return PaintUtils::hasTextShadow(mPaint);
1270 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1271 const DeferredDisplayState& state) override {
1272 FontRenderer& fontRenderer = renderer.getCaches().fontRenderer.getFontRenderer();
1273 fontRenderer.precache(mPaint, mText, mCount, SkMatrix::I());
1275 deferInfo.batchId = mPaint->getColor() == SK_ColorBLACK ?
1276 DeferredDisplayList::kOpBatch_Text :
1277 DeferredDisplayList::kOpBatch_ColorText;
1281 const glyph_t* mText;
1286 class DrawTextOnPathOp : public DrawSomeTextOp {
1288 DrawTextOnPathOp(const glyph_t* text, int bytesCount, int count,
1289 const SkPath* path, float hOffset, float vOffset, const SkPaint* paint)
1290 : DrawSomeTextOp(text, bytesCount, count, paint),
1291 mPath(path), mHOffset(hOffset), mVOffset(vOffset) {
1292 /* TODO: inherit from DrawBounded and init mLocalBounds */
1295 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
1296 renderer.drawTextOnPath(mText, mBytesCount, mCount, mPath,
1297 mHOffset, mVOffset, mPaint);
1300 virtual const char* name() override { return "DrawTextOnPath"; }
1303 const SkPath* mPath;
1308 class DrawTextOp : public DrawStrokableOp {
1310 DrawTextOp(const glyph_t* text, int bytesCount, int count, float x, float y,
1311 const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds)
1312 : DrawStrokableOp(bounds, paint), mText(text), mBytesCount(bytesCount), mCount(count),
1313 mX(x), mY(y), mPositions(positions), mTotalAdvance(totalAdvance) {
1314 mPrecacheTransform = SkMatrix::InvalidMatrix();
1317 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1318 const DeferredDisplayState& state) override {
1319 FontRenderer& fontRenderer = renderer.getCaches().fontRenderer.getFontRenderer();
1321 renderer.findBestFontTransform(state.mMatrix, &transform);
1322 if (mPrecacheTransform != transform) {
1323 fontRenderer.precache(mPaint, mText, mCount, transform);
1324 mPrecacheTransform = transform;
1326 deferInfo.batchId = mPaint->getColor() == SK_ColorBLACK ?
1327 DeferredDisplayList::kOpBatch_Text :
1328 DeferredDisplayList::kOpBatch_ColorText;
1330 deferInfo.mergeId = reinterpret_cast<mergeid_t>(mPaint->getColor());
1332 // don't merge decorated text - the decorations won't draw in order
1333 bool hasDecorations = mPaint->getFlags()
1334 & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag);
1336 deferInfo.mergeable = state.mMatrix.isPureTranslate()
1338 && PaintUtils::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode;
1341 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
1343 getLocalBounds(bounds);
1344 renderer.drawText(mText, mBytesCount, mCount, mX, mY,
1345 mPositions, mPaint, mTotalAdvance, bounds);
1348 virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty,
1349 const std::vector<OpStatePair>& ops, const Rect& bounds) override {
1350 for (unsigned int i = 0; i < ops.size(); i++) {
1351 const DeferredDisplayState& state = *(ops[i].state);
1352 DrawOpMode drawOpMode = (i == ops.size() - 1) ? DrawOpMode::kFlush : DrawOpMode::kDefer;
1353 renderer.restoreDisplayState(state, true); // restore all but the clip
1355 DrawTextOp& op = *((DrawTextOp*)ops[i].op);
1356 // quickReject() will not occure in drawText() so we can use mLocalBounds
1357 // directly, we do not need to account for shadow by calling getLocalBounds()
1358 renderer.drawText(op.mText, op.mBytesCount, op.mCount, op.mX, op.mY,
1359 op.mPositions, op.mPaint, op.mTotalAdvance, op.mLocalBounds,
1364 virtual void output(int level, uint32_t logFlags) const override {
1365 OP_LOG("Draw Text of count %d, bytes %d", mCount, mBytesCount);
1368 virtual const char* name() override { return "DrawText"; }
1371 const glyph_t* mText;
1376 const float* mPositions;
1377 float mTotalAdvance;
1378 SkMatrix mPrecacheTransform;
1381 ///////////////////////////////////////////////////////////////////////////////
1382 // SPECIAL DRAW OPERATIONS
1383 ///////////////////////////////////////////////////////////////////////////////
1385 class DrawFunctorOp : public DrawOp {
1387 DrawFunctorOp(Functor* functor)
1388 : DrawOp(nullptr), mFunctor(functor) {}
1390 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
1391 renderer.startMark("GL functor");
1392 renderer.callDrawGLFunction(mFunctor, dirty);
1396 virtual void output(int level, uint32_t logFlags) const override {
1397 OP_LOG("Draw Functor %p", mFunctor);
1400 virtual const char* name() override { return "DrawFunctor"; }
1406 class DrawRenderNodeOp : public DrawBoundedOp {
1407 friend class RenderNode; // grant RenderNode access to info of child
1408 friend class DisplayList; // grant DisplayList access to info of child
1409 friend class DisplayListCanvas;
1410 friend class TestUtils;
1412 DrawRenderNodeOp(RenderNode* renderNode, const mat4& transformFromParent, bool clipIsSimple)
1413 : DrawBoundedOp(0, 0,
1414 renderNode->stagingProperties().getWidth(),
1415 renderNode->stagingProperties().getHeight(),
1417 , renderNode(renderNode)
1418 , mRecordedWithPotentialStencilClip(!clipIsSimple || !transformFromParent.isSimple())
1419 , localMatrix(transformFromParent)
1420 , skipInOrderDraw(false) {}
1422 virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
1423 bool useQuickReject) override {
1424 if (renderNode->isRenderable() && !skipInOrderDraw) {
1425 renderNode->defer(deferStruct, level + 1);
1429 virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
1430 bool useQuickReject) override {
1431 if (renderNode->isRenderable() && !skipInOrderDraw) {
1432 renderNode->replay(replayStruct, level + 1);
1436 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
1437 LOG_ALWAYS_FATAL("should not be called, because replay() is overridden");
1440 virtual void output(int level, uint32_t logFlags) const override {
1441 OP_LOG("Draw RenderNode %p %s", renderNode, renderNode->getName());
1442 if (renderNode && (logFlags & kOpLogFlag_Recurse)) {
1443 renderNode->output(level + 1);
1447 virtual const char* name() override { return "DrawRenderNode"; }
1450 RenderNode* renderNode;
1453 * This RenderNode was drawn into a DisplayList with the canvas in a state that will likely
1454 * require rendering with stencil clipping. Either:
1456 * 1) A path clip or rotated rect clip was in effect on the canvas at record time
1457 * 2) The RenderNode was recorded with a non-simple canvas transform (e.g. rotation)
1459 * Note: even if this is false, non-rect clipping may still be applied applied either due to
1460 * property-driven rotation (either in this RenderNode, or any ancestor), or record time
1461 * clipping in an ancestor. These are handled in RenderNode::prepareTreeImpl since they are
1462 * dynamic (relative to a static DisplayList of a parent), and don't affect this flag.
1464 bool mRecordedWithPotentialStencilClip;
1466 ///////////////////////////
1467 // Properties below are used by RenderNode::computeOrderingImpl() and issueOperations()
1468 ///////////////////////////
1470 * Records transform vs parent, used for computing total transform without rerunning DL contents
1472 const mat4 localMatrix;
1475 * Holds the transformation between the projection surface ViewGroup and this RenderNode
1476 * drawing instance. Represents any translations / transformations done within the drawing of
1477 * the compositing ancestor ViewGroup's draw, before the draw of the View represented by this
1478 * DisplayList draw instance.
1480 * Note: doesn't include transformation within the RenderNode, or its properties.
1482 mat4 transformFromCompositingAncestor;
1483 bool skipInOrderDraw;
1487 * Not a canvas operation, used only by 3d / z ordering logic in RenderNode::iterate()
1489 class DrawShadowOp : public DrawOp {
1491 DrawShadowOp(const mat4& transformXY, const mat4& transformZ,
1492 float casterAlpha, const SkPath* casterOutline)
1494 , mTransformXY(transformXY)
1495 , mTransformZ(transformZ)
1496 , mCasterAlpha(casterAlpha)
1497 , mCasterOutline(casterOutline) {
1500 virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1501 const DeferredDisplayState& state) override {
1502 renderer.getCaches().tessellationCache.precacheShadows(&state.mMatrix,
1503 renderer.getLocalClipBounds(), isCasterOpaque(), mCasterOutline,
1504 &mTransformXY, &mTransformZ, renderer.getLightCenter(), renderer.getLightRadius());
1507 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
1508 TessellationCache::vertexBuffer_pair_t buffers;
1509 Matrix4 drawTransform(*(renderer.currentTransform()));
1510 renderer.getCaches().tessellationCache.getShadowBuffers(&drawTransform,
1511 renderer.getLocalClipBounds(), isCasterOpaque(), mCasterOutline,
1512 &mTransformXY, &mTransformZ, renderer.getLightCenter(), renderer.getLightRadius(),
1515 renderer.drawShadow(mCasterAlpha, buffers.first, buffers.second);
1518 virtual void output(int level, uint32_t logFlags) const override {
1519 OP_LOGS("DrawShadow");
1522 virtual const char* name() override { return "DrawShadow"; }
1525 bool isCasterOpaque() { return mCasterAlpha >= 1.0f; }
1527 const mat4 mTransformXY;
1528 const mat4 mTransformZ;
1529 const float mCasterAlpha;
1530 const SkPath* mCasterOutline;
1533 class DrawLayerOp : public DrawOp {
1535 DrawLayerOp(Layer* layer)
1536 : DrawOp(nullptr), mLayer(layer) {}
1538 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
1539 renderer.drawLayer(mLayer);
1542 virtual void output(int level, uint32_t logFlags) const override {
1543 OP_LOG("Draw Layer %p", mLayer);
1546 virtual const char* name() override { return "DrawLayer"; }
1552 }; // namespace uirenderer
1553 }; // namespace android
1555 #endif // ANDROID_HWUI_DISPLAY_OPERATION_H