diff options
author | 2016-07-06 16:10:09 -0700 | |
---|---|---|
committer | 2016-07-07 15:53:50 -0700 | |
commit | 5e00c7ce063116c11315639f0035aca8ad73e8cc (patch) | |
tree | 6ca43728a401d92762fb5fd65cfd39afe9438571 /libs | |
parent | 32d9ae186733115802eafe241c2029a63794efc2 (diff) |
Delete old rendering pipeline
fixes: 30002246
Change-Id: I45df0e924708526cee045b14c291bd23aa1a92db
Diffstat (limited to 'libs')
56 files changed, 145 insertions, 9097 deletions
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index d90f88fb7a1d..95b28d3e8c26 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -2,8 +2,6 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -HWUI_NEW_OPS := true - # Enables fine-grained GLES error checking # If set to true, every GLES call is wrapped & error checked # Has moderate overhead @@ -45,19 +43,21 @@ hwui_src_files := \ Animator.cpp \ AnimatorManager.cpp \ AssetAtlas.cpp \ + BakedOpDispatcher.cpp \ + BakedOpRenderer.cpp \ + BakedOpState.cpp \ Caches.cpp \ CanvasState.cpp \ ClipArea.cpp \ DamageAccumulator.cpp \ - DeferredDisplayList.cpp \ DeferredLayerUpdater.cpp \ DeviceInfo.cpp \ DisplayList.cpp \ - DisplayListCanvas.cpp \ Dither.cpp \ Extensions.cpp \ FboCache.cpp \ FontRenderer.cpp \ + FrameBuilder.cpp \ FrameInfo.cpp \ FrameInfoVisualizer.cpp \ GammaFontRenderer.cpp \ @@ -68,23 +68,24 @@ hwui_src_files := \ Interpolator.cpp \ JankTracker.cpp \ Layer.cpp \ - LayerCache.cpp \ + LayerBuilder.cpp \ LayerRenderer.cpp \ LayerUpdateQueue.cpp \ Matrix.cpp \ - OpenGLRenderer.cpp \ + OpDumper.cpp \ Patch.cpp \ PatchCache.cpp \ PathCache.cpp \ - PathTessellator.cpp \ PathParser.cpp \ + PathTessellator.cpp \ PixelBuffer.cpp \ Program.cpp \ ProgramCache.cpp \ Properties.cpp \ - PropertyValuesHolder.cpp \ PropertyValuesAnimatorSet.cpp \ + PropertyValuesHolder.cpp \ Readback.cpp \ + RecordingCanvas.cpp \ RenderBufferCache.cpp \ RenderNode.cpp \ RenderProperties.cpp \ @@ -130,20 +131,6 @@ hwui_cflags += -Wno-free-nonheap-object # clang's warning is broken, see: https://llvm.org/bugs/show_bug.cgi?id=21629 hwui_cflags += -Wno-missing-braces -ifeq (true, $(HWUI_NEW_OPS)) - hwui_src_files += \ - BakedOpDispatcher.cpp \ - BakedOpRenderer.cpp \ - BakedOpState.cpp \ - FrameBuilder.cpp \ - LayerBuilder.cpp \ - OpDumper.cpp \ - RecordingCanvas.cpp - - hwui_cflags += -DHWUI_NEW_OPS - -endif - ifndef HWUI_COMPILE_SYMBOLS hwui_cflags += -fvisibility=hidden endif @@ -255,40 +242,36 @@ LOCAL_C_INCLUDES := $(hwui_c_includes) LOCAL_SRC_FILES += \ $(hwui_test_common_src_files) \ tests/unit/main.cpp \ + tests/unit/BakedOpDispatcherTests.cpp \ + tests/unit/BakedOpRendererTests.cpp \ + tests/unit/BakedOpStateTests.cpp \ tests/unit/CanvasStateTests.cpp \ tests/unit/ClipAreaTests.cpp \ tests/unit/DamageAccumulatorTests.cpp \ tests/unit/DeviceInfoTests.cpp \ tests/unit/FatVectorTests.cpp \ tests/unit/FontRendererTests.cpp \ + tests/unit/FrameBuilderTests.cpp \ tests/unit/GlopBuilderTests.cpp \ tests/unit/GpuMemoryTrackerTests.cpp \ tests/unit/GradientCacheTests.cpp \ tests/unit/LayerUpdateQueueTests.cpp \ + tests/unit/LeakCheckTests.cpp \ tests/unit/LinearAllocatorTests.cpp \ tests/unit/MatrixTests.cpp \ tests/unit/MeshStateTests.cpp \ tests/unit/OffscreenBufferPoolTests.cpp \ + tests/unit/OpDumperTests.cpp \ + tests/unit/RecordingCanvasTests.cpp \ tests/unit/RenderNodeTests.cpp \ tests/unit/RenderPropertiesTests.cpp \ tests/unit/SkiaBehaviorTests.cpp \ + tests/unit/SkiaCanvasTests.cpp \ tests/unit/SnapshotTests.cpp \ tests/unit/StringUtilsTests.cpp \ tests/unit/TestUtilsTests.cpp \ tests/unit/TextDropShadowCacheTests.cpp \ - tests/unit/VectorDrawableTests.cpp - -ifeq (true, $(HWUI_NEW_OPS)) - LOCAL_SRC_FILES += \ - tests/unit/BakedOpDispatcherTests.cpp \ - tests/unit/BakedOpRendererTests.cpp \ - tests/unit/BakedOpStateTests.cpp \ - tests/unit/FrameBuilderTests.cpp \ - tests/unit/LeakCheckTests.cpp \ - tests/unit/OpDumperTests.cpp \ - tests/unit/RecordingCanvasTests.cpp \ - tests/unit/SkiaCanvasTests.cpp -endif + tests/unit/VectorDrawableTests.cpp \ include $(LOCAL_PATH)/hwui_static_deps.mk include $(BUILD_NATIVE_TEST) @@ -344,15 +327,12 @@ LOCAL_SRC_FILES += \ tests/microbench/main.cpp \ tests/microbench/DisplayListCanvasBench.cpp \ tests/microbench/FontBench.cpp \ + tests/microbench/FrameBuilderBench.cpp \ tests/microbench/LinearAllocatorBench.cpp \ tests/microbench/PathParserBench.cpp \ tests/microbench/ShadowBench.cpp \ tests/microbench/TaskManagerBench.cpp -ifeq (true, $(HWUI_NEW_OPS)) - LOCAL_SRC_FILES += \ - tests/microbench/FrameBuilderBench.cpp -endif include $(LOCAL_PATH)/hwui_static_deps.mk include $(BUILD_NATIVE_BENCHMARK) diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index f2d344fca0cd..ef81a522c050 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -163,17 +163,15 @@ void Caches::dumpMemoryUsage(String8 &log) { log.appendFormat("Current memory usage / total memory usage (bytes):\n"); log.appendFormat(" TextureCache %8d / %8d\n", textureCache.getSize(), textureCache.getMaxSize()); - log.appendFormat(" LayerCache %8d / %8d (numLayers = %zu)\n", - layerCache.getSize(), layerCache.getMaxSize(), layerCache.getCount()); if (mRenderState) { int memused = 0; for (std::set<Layer*>::iterator it = mRenderState->mActiveLayers.begin(); it != mRenderState->mActiveLayers.end(); it++) { const Layer* layer = *it; - log.appendFormat(" Layer size %dx%d; isTextureLayer()=%d; texid=%u fbo=%u; refs=%d\n", + log.appendFormat(" Layer size %dx%d; texid=%u refs=%d\n", layer->getWidth(), layer->getHeight(), - layer->isTextureLayer(), layer->getTextureId(), - layer->getFbo(), layer->getStrongCount()); + layer->getTextureId(), + layer->getStrongCount()); memused += layer->getWidth() * layer->getHeight() * 4; } log.appendFormat(" Layers total %8d (numLayers = %zu)\n", @@ -248,7 +246,6 @@ void Caches::flush(FlushMode mode) { tessellationCache.clear(); // fall through case FlushMode::Layers: - layerCache.clear(); renderBufferCache.clear(); break; } diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index eac9359beab3..fe9411d8bb3f 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_CACHES_H -#define ANDROID_HWUI_CACHES_H +#pragma once #include "AssetAtlas.h" #include "Dither.h" @@ -23,7 +22,6 @@ #include "FboCache.h" #include "GammaFontRenderer.h" #include "GradientCache.h" -#include "LayerCache.h" #include "PatchCache.h" #include "ProgramCache.h" #include "PathCache.h" @@ -146,7 +144,6 @@ private: Extensions mExtensions; public: TextureCache textureCache; - LayerCache layerCache; RenderBufferCache renderBufferCache; GradientCache gradientCache; PatchCache patchCache; @@ -205,5 +202,3 @@ private: }; // namespace uirenderer }; // namespace android - -#endif // ANDROID_HWUI_CACHES_H diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp index e2149d1e4a69..7e2c28c5eb41 100644 --- a/libs/hwui/CanvasState.cpp +++ b/libs/hwui/CanvasState.cpp @@ -23,8 +23,7 @@ namespace uirenderer { CanvasState::CanvasState(CanvasStateClient& renderer) - : mDirtyClip(false) - , mWidth(-1) + : mWidth(-1) , mHeight(-1) , mSaveCount(1) , mCanvas(renderer) @@ -205,19 +204,16 @@ void CanvasState::concatMatrix(const Matrix4& matrix) { bool CanvasState::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) { mSnapshot->clip(Rect(left, top, right, bottom), op); - mDirtyClip = true; return !mSnapshot->clipIsEmpty(); } bool CanvasState::clipPath(const SkPath* path, SkRegion::Op op) { mSnapshot->clipPath(*path, op); - mDirtyClip = true; return !mSnapshot->clipIsEmpty(); } bool CanvasState::clipRegion(const SkRegion* region, SkRegion::Op op) { mSnapshot->clipRegionTransformed(*region, op); - mDirtyClip = true; return !mSnapshot->clipIsEmpty(); } @@ -236,15 +232,6 @@ void CanvasState::setClippingOutline(LinearAllocator& allocator, const Outline* } } -void CanvasState::setClippingRoundRect(LinearAllocator& allocator, - const Rect& rect, float radius, bool highPriority) { - mSnapshot->setClippingRoundRect(allocator, rect, radius, highPriority); -} - -void CanvasState::setProjectionPathMask(LinearAllocator& allocator, const SkPath* path) { - mSnapshot->setProjectionPathMask(allocator, path); -} - /////////////////////////////////////////////////////////////////////////////// // Quick Rejection /////////////////////////////////////////////////////////////////////////////// @@ -263,7 +250,7 @@ bool CanvasState::calculateQuickRejectForScissor(float left, float top, float right, float bottom, bool* clipRequired, bool* roundRectClipRequired, bool snapOut) const { - if (mSnapshot->isIgnored() || bottom <= top || right <= left) { + if (bottom <= top || right <= left) { return true; } @@ -291,7 +278,7 @@ bool CanvasState::calculateQuickRejectForScissor(float left, float top, bool CanvasState::quickRejectConservative(float left, float top, float right, float bottom) const { - if (mSnapshot->isIgnored() || bottom <= top || right <= left) { + if (bottom <= top || right <= left) { return true; } diff --git a/libs/hwui/CanvasState.h b/libs/hwui/CanvasState.h index b9e87ae5595d..ba260d1ab88e 100644 --- a/libs/hwui/CanvasState.h +++ b/libs/hwui/CanvasState.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_CANVAS_STATE_H -#define ANDROID_HWUI_CANVAS_STATE_H +#pragma once #include "Snapshot.h" @@ -62,11 +61,11 @@ public: * Renderer interface. Drawing and recording classes that include a CanvasState will have * different use cases: * - * Drawing code maintaining canvas state (i.e. OpenGLRenderer) can query attributes (such as + * Drawing code maintaining canvas state (e.g. FrameBuilder) can query attributes (such as * transform) or hook into changes (e.g. save/restore) with minimal surface area for manipulating * the stack itself. * - * Recording code maintaining canvas state (i.e. DisplayListCanvas) can both record and pass + * Recording code maintaining canvas state (e.g. RecordingCanvas) can both record and pass * through state operations to CanvasState, so that not only will querying operations work * (getClip/Matrix), but so that quickRejection can also be used. */ @@ -134,8 +133,12 @@ public: */ void setClippingOutline(LinearAllocator& allocator, const Outline* outline); void setClippingRoundRect(LinearAllocator& allocator, - const Rect& rect, float radius, bool highPriority = true); - void setProjectionPathMask(LinearAllocator& allocator, const SkPath* path); + const Rect& rect, float radius, bool highPriority = true) { + mSnapshot->setClippingRoundRect(allocator, rect, radius, highPriority); + } + void setProjectionPathMask(const SkPath* path) { + mSnapshot->setProjectionPathMask(path); + } /** * Returns true if drawing in the rectangle (left, top, right, bottom) @@ -145,19 +148,12 @@ public: bool calculateQuickRejectForScissor(float left, float top, float right, float bottom, bool* clipRequired, bool* roundRectClipRequired, bool snapOut) const; - void setDirtyClip(bool opaque) { mDirtyClip = opaque; } - bool getDirtyClip() const { return mDirtyClip; } - void scaleAlpha(float alpha) { mSnapshot->alpha *= alpha; } - void setEmpty(bool value) { mSnapshot->empty = value; } - void setInvisible(bool value) { mSnapshot->invisible = value; } inline const mat4* currentTransform() const { return currentSnapshot()->transform; } inline const Rect& currentRenderTargetClip() const { return currentSnapshot()->getRenderTargetClip(); } - inline Region* currentRegion() const { return currentSnapshot()->region; } inline int currentFlags() const { return currentSnapshot()->flags; } const Vector3& currentLightCenter() const { return currentSnapshot()->getRelativeLightCenter(); } - inline bool currentlyIgnored() const { return currentSnapshot()->isIgnored(); } int getViewportWidth() const { return currentSnapshot()->getViewportWidth(); } int getViewportHeight() const { return currentSnapshot()->getViewportHeight(); } int getWidth() const { return mWidth; } @@ -173,10 +169,6 @@ private: void freeSnapshot(Snapshot* snapshot); void freeAllSnapshots(); - /// indicates that the clip has been changed since the last time it was consumed - // TODO: delete when switching to HWUI_NEW_OPS - bool mDirtyClip; - /// Dimensions of the drawing surface int mWidth, mHeight; @@ -201,5 +193,3 @@ private: }; // namespace uirenderer }; // namespace android - -#endif // ANDROID_HWUI_CANVAS_STATE_H diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp deleted file mode 100644 index 689179dd8fb4..000000000000 --- a/libs/hwui/DeferredDisplayList.cpp +++ /dev/null @@ -1,686 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <utils/Trace.h> -#include <ui/Rect.h> -#include <ui/Region.h> - -#include "Caches.h" -#include "Debug.h" -#include "DeferredDisplayList.h" -#include "DisplayListOp.h" -#include "OpenGLRenderer.h" -#include "Properties.h" -#include "utils/MathUtils.h" - -#if DEBUG_DEFER - #define DEFER_LOGD(...) ALOGD(__VA_ARGS__) -#else - #define DEFER_LOGD(...) -#endif - -namespace android { -namespace uirenderer { - -// Depth of the save stack at the beginning of batch playback at flush time -#define FLUSH_SAVE_STACK_DEPTH 2 - -#define DEBUG_COLOR_BARRIER 0x1f000000 -#define DEBUG_COLOR_MERGEDBATCH 0x5f7f7fff -#define DEBUG_COLOR_MERGEDBATCH_SOLO 0x5f7fff7f - -static bool avoidOverdraw() { - // Don't avoid overdraw when visualizing it, since that makes it harder to - // debug where it's coming from, and when the problem occurs. - return !Properties::debugOverdraw; -}; - -///////////////////////////////////////////////////////////////////////////////// -// Operation Batches -///////////////////////////////////////////////////////////////////////////////// - -class Batch { -public: - virtual void replay(OpenGLRenderer& renderer, Rect& dirty, int index) = 0; - virtual ~Batch() {} - virtual bool purelyDrawBatch() { return false; } - virtual bool coversBounds(const Rect& bounds) { return false; } -}; - -class DrawBatch : public Batch { -public: - explicit DrawBatch(const DeferInfo& deferInfo) : mAllOpsOpaque(true), - mBatchId(deferInfo.batchId), mMergeId(deferInfo.mergeId) { - mOps.clear(); - } - - virtual ~DrawBatch() { mOps.clear(); } - - virtual void add(DrawOp* op, const DeferredDisplayState* state, bool opaqueOverBounds) { - // NOTE: ignore empty bounds special case, since we don't merge across those ops - mBounds.unionWith(state->mBounds); - mAllOpsOpaque &= opaqueOverBounds; - mOps.push_back(OpStatePair(op, state)); - } - - bool intersects(const Rect& rect) { - if (!rect.intersects(mBounds)) return false; - - for (unsigned int i = 0; i < mOps.size(); i++) { - if (rect.intersects(mOps[i].state->mBounds)) { -#if DEBUG_DEFER - DEFER_LOGD("op intersects with op %p with bounds %f %f %f %f:", mOps[i].op, - mOps[i].state->mBounds.left, mOps[i].state->mBounds.top, - mOps[i].state->mBounds.right, mOps[i].state->mBounds.bottom); - mOps[i].op->output(2); -#endif - return true; - } - } - return false; - } - - virtual void replay(OpenGLRenderer& renderer, Rect& dirty, int index) override { - DEFER_LOGD("%d replaying DrawBatch %p, with %d ops (batch id %x, merge id %p)", - index, this, mOps.size(), getBatchId(), getMergeId()); - - for (unsigned int i = 0; i < mOps.size(); i++) { - DrawOp* op = mOps[i].op; - const DeferredDisplayState* state = mOps[i].state; - renderer.restoreDisplayState(*state); - -#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS - renderer.eventMark(op->name()); -#endif - op->applyDraw(renderer, dirty); - -#if DEBUG_MERGE_BEHAVIOR - const Rect& bounds = state->mBounds; - int batchColor = 0x1f000000; - if (getBatchId() & 0x1) batchColor |= 0x0000ff; - if (getBatchId() & 0x2) batchColor |= 0x00ff00; - if (getBatchId() & 0x4) batchColor |= 0xff0000; - renderer.drawScreenSpaceColorRect(bounds.left, bounds.top, bounds.right, bounds.bottom, - batchColor); -#endif - } - } - - virtual bool purelyDrawBatch() override { return true; } - - virtual bool coversBounds(const Rect& bounds) override { - if (CC_LIKELY(!mAllOpsOpaque || !mBounds.contains(bounds) || count() == 1)) return false; - - Region uncovered(android::Rect(bounds.left, bounds.top, bounds.right, bounds.bottom)); - for (unsigned int i = 0; i < mOps.size(); i++) { - const Rect &r = mOps[i].state->mBounds; - uncovered.subtractSelf(android::Rect(r.left, r.top, r.right, r.bottom)); - } - return uncovered.isEmpty(); - } - - inline int getBatchId() const { return mBatchId; } - inline mergeid_t getMergeId() const { return mMergeId; } - inline int count() const { return mOps.size(); } - -protected: - std::vector<OpStatePair> mOps; - Rect mBounds; // union of bounds of contained ops -private: - bool mAllOpsOpaque; - int mBatchId; - mergeid_t mMergeId; -}; - -class MergingDrawBatch : public DrawBatch { -public: - MergingDrawBatch(DeferInfo& deferInfo, int width, int height) : - DrawBatch(deferInfo), mClipRect(width, height), - mClipSideFlags(kClipSide_None) {} - - /* - * Helper for determining if a new op can merge with a MergingDrawBatch based on their bounds - * and clip side flags. Positive bounds delta means new bounds fit in old. - */ - static inline bool checkSide(const int currentFlags, const int newFlags, const int side, - float boundsDelta) { - bool currentClipExists = currentFlags & side; - bool newClipExists = newFlags & side; - - // if current is clipped, we must be able to fit new bounds in current - if (boundsDelta > 0 && currentClipExists) return false; - - // if new is clipped, we must be able to fit current bounds in new - if (boundsDelta < 0 && newClipExists) return false; - - return true; - } - - /* - * Checks if a (mergeable) op can be merged into this batch - * - * If true, the op's multiDraw must be guaranteed to handle both ops simultaneously, so it is - * important to consider all paint attributes used in the draw calls in deciding both a) if an - * op tries to merge at all, and b) if the op can merge with another set of ops - * - * False positives can lead to information from the paints of subsequent merged operations being - * dropped, so we make simplifying qualifications on the ops that can merge, per op type. - */ - bool canMergeWith(const DrawOp* op, const DeferredDisplayState* state) { - bool isTextBatch = getBatchId() == DeferredDisplayList::kOpBatch_Text || - getBatchId() == DeferredDisplayList::kOpBatch_ColorText; - - // Overlapping other operations is only allowed for text without shadow. For other ops, - // multiDraw isn't guaranteed to overdraw correctly - if (!isTextBatch || op->hasTextShadow()) { - if (intersects(state->mBounds)) return false; - } - const DeferredDisplayState* lhs = state; - const DeferredDisplayState* rhs = mOps[0].state; - - if (!MathUtils::areEqual(lhs->mAlpha, rhs->mAlpha)) return false; - - // Identical round rect clip state means both ops will clip in the same way, or not at all. - // As the state objects are const, we can compare their pointers to determine mergeability - if (lhs->mRoundRectClipState != rhs->mRoundRectClipState) return false; - if (lhs->mProjectionPathMask != rhs->mProjectionPathMask) return false; - - /* Clipping compatibility check - * - * Exploits the fact that if a op or batch is clipped on a side, its bounds will equal its - * clip for that side. - */ - const int currentFlags = mClipSideFlags; - const int newFlags = state->mClipSideFlags; - if (currentFlags != kClipSide_None || newFlags != kClipSide_None) { - const Rect& opBounds = state->mBounds; - float boundsDelta = mBounds.left - opBounds.left; - if (!checkSide(currentFlags, newFlags, kClipSide_Left, boundsDelta)) return false; - boundsDelta = mBounds.top - opBounds.top; - if (!checkSide(currentFlags, newFlags, kClipSide_Top, boundsDelta)) return false; - - // right and bottom delta calculation reversed to account for direction - boundsDelta = opBounds.right - mBounds.right; - if (!checkSide(currentFlags, newFlags, kClipSide_Right, boundsDelta)) return false; - boundsDelta = opBounds.bottom - mBounds.bottom; - if (!checkSide(currentFlags, newFlags, kClipSide_Bottom, boundsDelta)) return false; - } - - // if paints are equal, then modifiers + paint attribs don't need to be compared - if (op->mPaint == mOps[0].op->mPaint) return true; - - if (PaintUtils::getAlphaDirect(op->mPaint) - != PaintUtils::getAlphaDirect(mOps[0].op->mPaint)) { - return false; - } - - if (op->mPaint && mOps[0].op->mPaint && - op->mPaint->getColorFilter() != mOps[0].op->mPaint->getColorFilter()) { - return false; - } - - if (op->mPaint && mOps[0].op->mPaint && - op->mPaint->getShader() != mOps[0].op->mPaint->getShader()) { - return false; - } - - return true; - } - - virtual void add(DrawOp* op, const DeferredDisplayState* state, - bool opaqueOverBounds) override { - DrawBatch::add(op, state, opaqueOverBounds); - - const int newClipSideFlags = state->mClipSideFlags; - mClipSideFlags |= newClipSideFlags; - if (newClipSideFlags & kClipSide_Left) mClipRect.left = state->mClip.left; - if (newClipSideFlags & kClipSide_Top) mClipRect.top = state->mClip.top; - if (newClipSideFlags & kClipSide_Right) mClipRect.right = state->mClip.right; - if (newClipSideFlags & kClipSide_Bottom) mClipRect.bottom = state->mClip.bottom; - } - - virtual void replay(OpenGLRenderer& renderer, Rect& dirty, int index) override { - DEFER_LOGD("%d replaying MergingDrawBatch %p, with %d ops," - " clip flags %x (batch id %x, merge id %p)", - index, this, mOps.size(), mClipSideFlags, getBatchId(), getMergeId()); - if (mOps.size() == 1) { - DrawBatch::replay(renderer, dirty, -1); - return; - } - - // clipping in the merged case is done ahead of time since all ops share the clip (if any) - renderer.setupMergedMultiDraw(mClipSideFlags ? &mClipRect : nullptr); - - DrawOp* op = mOps[0].op; -#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS - renderer.eventMark("multiDraw"); - renderer.eventMark(op->name()); -#endif - op->multiDraw(renderer, dirty, mOps, mBounds); - -#if DEBUG_MERGE_BEHAVIOR - renderer.drawScreenSpaceColorRect(mBounds.left, mBounds.top, mBounds.right, mBounds.bottom, - DEBUG_COLOR_MERGEDBATCH); -#endif - } - -private: - /* - * Contains the effective clip rect shared by all merged ops. Initialized to the layer viewport, - * it will shrink if an op must be clipped on a certain side. The clipped sides are reflected in - * mClipSideFlags. - */ - Rect mClipRect; - int mClipSideFlags; -}; - -class StateOpBatch : public Batch { -public: - // creates a single operation batch - StateOpBatch(const StateOp* op, const DeferredDisplayState* state) : mOp(op), mState(state) {} - - virtual void replay(OpenGLRenderer& renderer, Rect& dirty, int index) override { - DEFER_LOGD("replaying state op batch %p", this); - renderer.restoreDisplayState(*mState); - - // use invalid save count because it won't be used at flush time - RestoreToCountOp is the - // only one to use it, and we don't use that class at flush time, instead calling - // renderer.restoreToCount directly - int saveCount = -1; - mOp->applyState(renderer, saveCount); - } - -private: - const StateOp* mOp; - const DeferredDisplayState* mState; -}; - -class RestoreToCountBatch : public Batch { -public: - RestoreToCountBatch(const StateOp* op, const DeferredDisplayState* state, int restoreCount) : - mState(state), mRestoreCount(restoreCount) {} - - virtual void replay(OpenGLRenderer& renderer, Rect& dirty, int index) override { - DEFER_LOGD("batch %p restoring to count %d", this, mRestoreCount); - - renderer.restoreDisplayState(*mState); - renderer.restoreToCount(mRestoreCount); - } - -private: - // we use the state storage for the RestoreToCountOp, but don't replay the op itself - const DeferredDisplayState* mState; - - /* - * The count used here represents the flush() time saveCount. This is as opposed to the - * DisplayList record time, or defer() time values (which are RestoreToCountOp's mCount, and - * (saveCount + mCount) respectively). Since the count is different from the original - * RestoreToCountOp, we don't store a pointer to the op, as elsewhere. - */ - const int mRestoreCount; -}; - -#if DEBUG_MERGE_BEHAVIOR -class BarrierDebugBatch : public Batch { - virtual void replay(OpenGLRenderer& renderer, Rect& dirty, int index) { - renderer.drawScreenSpaceColorRect(0, 0, 10000, 10000, DEBUG_COLOR_BARRIER); - } -}; -#endif - -///////////////////////////////////////////////////////////////////////////////// -// DeferredDisplayList -///////////////////////////////////////////////////////////////////////////////// - -void DeferredDisplayList::resetBatchingState() { - for (int i = 0; i < kOpBatch_Count; i++) { - mBatchLookup[i] = nullptr; - mMergingBatches[i].clear(); - } -#if DEBUG_MERGE_BEHAVIOR - if (mBatches.size() != 0) { - mBatches.add(new BarrierDebugBatch()); - } -#endif - mEarliestBatchIndex = mBatches.size(); -} - -void DeferredDisplayList::clear() { - resetBatchingState(); - mComplexClipStackStart = -1; - - for (unsigned int i = 0; i < mBatches.size(); i++) { - delete mBatches[i]; - } - mBatches.clear(); - mSaveStack.clear(); - mEarliestBatchIndex = 0; - mEarliestUnclearedIndex = 0; -} - -///////////////////////////////////////////////////////////////////////////////// -// Operation adding -///////////////////////////////////////////////////////////////////////////////// - -int DeferredDisplayList::getStateOpDeferFlags() const { - // For both clipOp and save(Layer)Op, we don't want to save drawing info, and only want to save - // the clip if we aren't recording a complex clip (and can thus trust it to be a rect) - return recordingComplexClip() ? 0 : kStateDeferFlag_Clip; -} - -int DeferredDisplayList::getDrawOpDeferFlags() const { - return kStateDeferFlag_Draw | getStateOpDeferFlags(); -} - -/** - * When an clipping operation occurs that could cause a complex clip, record the operation and all - * subsequent clipOps, save/restores (if the clip flag is set). During a flush, instead of loading - * the clip from deferred state, we play back all of the relevant state operations that generated - * the complex clip. - * - * Note that we don't need to record the associated restore operation, since operations at defer - * time record whether they should store the renderer's current clip - */ -void DeferredDisplayList::addClip(OpenGLRenderer& renderer, ClipOp* op) { - if (recordingComplexClip() || op->canCauseComplexClip() || !renderer.hasRectToRectTransform()) { - DEFER_LOGD("%p Received complex clip operation %p", this, op); - - // NOTE: defer clip op before setting mComplexClipStackStart so previous clip is recorded - storeStateOpBarrier(renderer, op); - - if (!recordingComplexClip()) { - mComplexClipStackStart = renderer.getSaveCount() - 1; - DEFER_LOGD(" Starting complex clip region, start is %d", mComplexClipStackStart); - } - } -} - -/** - * For now, we record save layer operations as barriers in the batch list, preventing drawing - * operations from reordering around the saveLayer and it's associated restore() - * - * In the future, we should send saveLayer commands (if they can be played out of order) and their - * contained drawing operations to a seperate list of batches, so that they may draw at the - * beginning of the frame. This would avoid targetting and removing an FBO in the middle of a frame. - * - * saveLayer operations should be pulled to the beginning of the frame if the canvas doesn't have a - * complex clip, and if the flags (SaveFlags::Clip & SaveFlags::ClipToLayer) are set. - */ -void DeferredDisplayList::addSaveLayer(OpenGLRenderer& renderer, - SaveLayerOp* op, int newSaveCount) { - DEFER_LOGD("%p adding saveLayerOp %p, flags %x, new count %d", - this, op, op->getFlags(), newSaveCount); - - storeStateOpBarrier(renderer, op); - mSaveStack.push_back(newSaveCount); -} - -/** - * Takes save op and it's return value - the new save count - and stores it into the stream as a - * barrier if it's needed to properly modify a complex clip - */ -void DeferredDisplayList::addSave(OpenGLRenderer& renderer, SaveOp* op, int newSaveCount) { - int saveFlags = op->getFlags(); - DEFER_LOGD("%p adding saveOp %p, flags %x, new count %d", this, op, saveFlags, newSaveCount); - - if (recordingComplexClip() && (saveFlags & SaveFlags::Clip)) { - // store and replay the save operation, as it may be needed to correctly playback the clip - DEFER_LOGD(" adding save barrier with new save count %d", newSaveCount); - storeStateOpBarrier(renderer, op); - mSaveStack.push_back(newSaveCount); - } -} - -/** - * saveLayer() commands must be associated with a restoreToCount batch that will clean up and draw - * the layer in the deferred list - * - * other save() commands which occur as children of a snapshot with complex clip will be deferred, - * and must be restored - * - * Either will act as a barrier to draw operation reordering, as we want to play back layer - * save/restore and complex canvas modifications (including save/restore) in order. - */ -void DeferredDisplayList::addRestoreToCount(OpenGLRenderer& renderer, StateOp* op, - int newSaveCount) { - DEFER_LOGD("%p addRestoreToCount %d", this, newSaveCount); - - if (recordingComplexClip() && newSaveCount <= mComplexClipStackStart) { - mComplexClipStackStart = -1; - resetBatchingState(); - } - - if (mSaveStack.empty() || newSaveCount > mSaveStack.back()) { - return; - } - - while (!mSaveStack.empty() && mSaveStack.back() >= newSaveCount) mSaveStack.pop_back(); - - storeRestoreToCountBarrier(renderer, op, mSaveStack.size() + FLUSH_SAVE_STACK_DEPTH); -} - -void DeferredDisplayList::addDrawOp(OpenGLRenderer& renderer, DrawOp* op) { - /* 1: op calculates local bounds */ - DeferredDisplayState* const state = createState(); - if (op->getLocalBounds(state->mBounds)) { - if (state->mBounds.isEmpty()) { - // valid empty bounds, don't bother deferring - tryRecycleState(state); - return; - } - } else { - state->mBounds.setEmpty(); - } - - /* 2: renderer calculates global bounds + stores state */ - if (renderer.storeDisplayState(*state, getDrawOpDeferFlags())) { - tryRecycleState(state); - return; // quick rejected - } - - /* 3: ask op for defer info, given renderer state */ - DeferInfo deferInfo; - op->onDefer(renderer, deferInfo, *state); - - // complex clip has a complex set of expectations on the renderer state - for now, avoid taking - // the merge path in those cases - deferInfo.mergeable &= !recordingComplexClip(); - deferInfo.opaqueOverBounds &= !recordingComplexClip() - && mSaveStack.empty() - && !state->mRoundRectClipState; - - if (CC_LIKELY(avoidOverdraw()) && mBatches.size() && - state->mClipSideFlags != kClipSide_ConservativeFull && - deferInfo.opaqueOverBounds && state->mBounds.contains(mBounds)) { - // avoid overdraw by resetting drawing state + discarding drawing ops - discardDrawingBatches(mBatches.size() - 1); - resetBatchingState(); - } - - if (CC_UNLIKELY(Properties::drawReorderDisabled)) { - // TODO: elegant way to reuse batches? - DrawBatch* b = new DrawBatch(deferInfo); - b->add(op, state, deferInfo.opaqueOverBounds); - mBatches.push_back(b); - return; - } - - // find the latest batch of the new op's type, and try to merge the new op into it - DrawBatch* targetBatch = nullptr; - - // insertion point of a new batch, will hopefully be immediately after similar batch - // (eventually, should be similar shader) - int insertBatchIndex = mBatches.size(); - if (!mBatches.empty()) { - if (state->mBounds.isEmpty()) { - // don't know the bounds for op, so create new batch and start from scratch on next op - DrawBatch* b = new DrawBatch(deferInfo); - b->add(op, state, deferInfo.opaqueOverBounds); - mBatches.push_back(b); - resetBatchingState(); -#if DEBUG_DEFER - DEFER_LOGD("Warning: Encountered op with empty bounds, resetting batches"); - op->output(2); -#endif - return; - } - - if (deferInfo.mergeable) { - // Try to merge with any existing batch with same mergeId. - std::unordered_map<mergeid_t, DrawBatch*>& mergingBatch - = mMergingBatches[deferInfo.batchId]; - auto getResult = mergingBatch.find(deferInfo.mergeId); - if (getResult != mergingBatch.end()) { - targetBatch = getResult->second; - if (!((MergingDrawBatch*) targetBatch)->canMergeWith(op, state)) { - targetBatch = nullptr; - } - } - } else { - // join with similar, non-merging batch - targetBatch = (DrawBatch*)mBatchLookup[deferInfo.batchId]; - } - - if (targetBatch || deferInfo.mergeable) { - // iterate back toward target to see if anything drawn since should overlap the new op - // if no target, merging ops still interate to find similar batch to insert after - for (int i = mBatches.size() - 1; i >= mEarliestBatchIndex; i--) { - DrawBatch* overBatch = (DrawBatch*)mBatches[i]; - - if (overBatch == targetBatch) break; - - // TODO: also consider shader shared between batch types - if (deferInfo.batchId == overBatch->getBatchId()) { - insertBatchIndex = i + 1; - if (!targetBatch) break; // found insert position, quit - } - - if (overBatch->intersects(state->mBounds)) { - // NOTE: it may be possible to optimize for special cases where two operations - // of the same batch/paint could swap order, such as with a non-mergeable - // (clipped) and a mergeable text operation - targetBatch = nullptr; -#if DEBUG_DEFER - DEFER_LOGD("op couldn't join batch %p, was intersected by batch %d", - targetBatch, i); - op->output(2); -#endif - break; - } - } - } - } - - if (!targetBatch) { - if (deferInfo.mergeable) { - targetBatch = new MergingDrawBatch(deferInfo, - renderer.getViewportWidth(), renderer.getViewportHeight()); - mMergingBatches[deferInfo.batchId].insert( - std::make_pair(deferInfo.mergeId, targetBatch)); - } else { - targetBatch = new DrawBatch(deferInfo); - mBatchLookup[deferInfo.batchId] = targetBatch; - } - - DEFER_LOGD("creating %singBatch %p, bid %x, at %d", - deferInfo.mergeable ? "Merg" : "Draw", - targetBatch, deferInfo.batchId, insertBatchIndex); - mBatches.insert(mBatches.begin() + insertBatchIndex, targetBatch); - } - - targetBatch->add(op, state, deferInfo.opaqueOverBounds); -} - -void DeferredDisplayList::storeStateOpBarrier(OpenGLRenderer& renderer, StateOp* op) { - DEFER_LOGD("%p adding state op barrier at pos %d", this, mBatches.size()); - - DeferredDisplayState* state = createState(); - renderer.storeDisplayState(*state, getStateOpDeferFlags()); - mBatches.push_back(new StateOpBatch(op, state)); - resetBatchingState(); -} - -void DeferredDisplayList::storeRestoreToCountBarrier(OpenGLRenderer& renderer, StateOp* op, - int newSaveCount) { - DEFER_LOGD("%p adding restore to count %d barrier, pos %d", - this, newSaveCount, mBatches.size()); - - // store displayState for the restore operation, as it may be associated with a saveLayer that - // doesn't have SaveFlags::Clip set - DeferredDisplayState* state = createState(); - renderer.storeDisplayState(*state, getStateOpDeferFlags()); - mBatches.push_back(new RestoreToCountBatch(op, state, newSaveCount)); - resetBatchingState(); -} - -///////////////////////////////////////////////////////////////////////////////// -// Replay / flush -///////////////////////////////////////////////////////////////////////////////// - -static void replayBatchList(const std::vector<Batch*>& batchList, - OpenGLRenderer& renderer, Rect& dirty) { - - for (unsigned int i = 0; i < batchList.size(); i++) { - if (batchList[i]) { - batchList[i]->replay(renderer, dirty, i); - } - } - DEFER_LOGD("--flushed, drew %d batches", batchList.size()); -} - -void DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty) { - ATRACE_NAME("flush drawing commands"); - Caches::getInstance().fontRenderer.endPrecaching(); - - if (isEmpty()) return; // nothing to flush - renderer.restoreToCount(1); - - DEFER_LOGD("--flushing"); - renderer.eventMark("Flush"); - - // save and restore so that reordering doesn't affect final state - renderer.save(SaveFlags::MatrixClip); - - if (CC_LIKELY(avoidOverdraw())) { - for (unsigned int i = 1; i < mBatches.size(); i++) { - if (mBatches[i] && mBatches[i]->coversBounds(mBounds)) { - discardDrawingBatches(i - 1); - } - } - } - // NOTE: depth of the save stack at this point, before playback, should be reflected in - // FLUSH_SAVE_STACK_DEPTH, so that save/restores match up correctly - replayBatchList(mBatches, renderer, dirty); - - renderer.restoreToCount(1); - - DEFER_LOGD("--flush complete, returning %x", status); - clear(); -} - -void DeferredDisplayList::discardDrawingBatches(const unsigned int maxIndex) { - for (unsigned int i = mEarliestUnclearedIndex; i <= maxIndex; i++) { - // leave deferred state ops alone for simplicity (empty save restore pairs may now exist) - if (mBatches[i] && mBatches[i]->purelyDrawBatch()) { - delete mBatches[i]; - mBatches[i] = nullptr; - } - } - mEarliestUnclearedIndex = maxIndex + 1; -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h deleted file mode 100644 index 98ccf11b1c2a..000000000000 --- a/libs/hwui/DeferredDisplayList.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_HWUI_DEFERRED_DISPLAY_LIST_H -#define ANDROID_HWUI_DEFERRED_DISPLAY_LIST_H - -#include <unordered_map> - -#include <utils/Errors.h> -#include <utils/LinearAllocator.h> - -#include "Matrix.h" -#include "OpenGLRenderer.h" -#include "Rect.h" - -#include <vector> - -class SkBitmap; - -namespace android { -namespace uirenderer { - -class ClipOp; -class DrawOp; -class SaveOp; -class SaveLayerOp; -class StateOp; - -class DeferredDisplayState; - -class Batch; -class DrawBatch; -class MergingDrawBatch; - -typedef const void* mergeid_t; - -class DeferredDisplayState { -public: - // global op bounds, mapped by mMatrix to be in screen space coordinates, clipped - Rect mBounds; - - // the below are set and used by the OpenGLRenderer at record and deferred playback - bool mClipValid; - Rect mClip; - int mClipSideFlags; // specifies which sides of the bounds are clipped, unclipped if cleared - mat4 mMatrix; - float mAlpha; - const RoundRectClipState* mRoundRectClipState; - const ProjectionPathMask* mProjectionPathMask; -}; - -class OpStatePair { -public: - OpStatePair() - : op(nullptr), state(nullptr) {} - OpStatePair(DrawOp* newOp, const DeferredDisplayState* newState) - : op(newOp), state(newState) {} - OpStatePair(const OpStatePair& other) - : op(other.op), state(other.state) {} - DrawOp* op; - const DeferredDisplayState* state; -}; - -class DeferredDisplayList { - friend struct DeferStateStruct; // used to give access to allocator -public: - DeferredDisplayList(const Rect& bounds) - : mBounds(bounds) { - clear(); - } - ~DeferredDisplayList() { clear(); } - - enum OpBatchId { - kOpBatch_None = 0, // Don't batch - kOpBatch_Bitmap, - kOpBatch_Patch, - kOpBatch_AlphaVertices, - kOpBatch_Vertices, - kOpBatch_AlphaMaskTexture, - kOpBatch_Text, - kOpBatch_ColorText, - - kOpBatch_Count, // Add other batch ids before this - }; - - bool isEmpty() { return mBatches.empty(); } - - /** - * Plays back all of the draw ops recorded into batches to the renderer. - * Adjusts the state of the renderer as necessary, and restores it when complete - */ - void flush(OpenGLRenderer& renderer, Rect& dirty); - - void addClip(OpenGLRenderer& renderer, ClipOp* op); - void addSaveLayer(OpenGLRenderer& renderer, SaveLayerOp* op, int newSaveCount); - void addSave(OpenGLRenderer& renderer, SaveOp* op, int newSaveCount); - void addRestoreToCount(OpenGLRenderer& renderer, StateOp* op, int newSaveCount); - - /** - * Add a draw op into the DeferredDisplayList, reordering as needed (for performance) if - * disallowReorder is false, respecting draw order when overlaps occur. - */ - void addDrawOp(OpenGLRenderer& renderer, DrawOp* op); - -private: - DeferredDisplayList(const DeferredDisplayList& other); // disallow copy - - DeferredDisplayState* createState() { - return mAllocator.create_trivial<DeferredDisplayState>(); - } - - void tryRecycleState(DeferredDisplayState* state) { - mAllocator.rewindIfLastAlloc(state); - } - - /** - * Resets the batching back-pointers, creating a barrier in the operation stream so that no ops - * added in the future will be inserted into a batch that already exist. - */ - void resetBatchingState(); - - void clear(); - - void storeStateOpBarrier(OpenGLRenderer& renderer, StateOp* op); - void storeRestoreToCountBarrier(OpenGLRenderer& renderer, StateOp* op, int newSaveCount); - - bool recordingComplexClip() const { return mComplexClipStackStart >= 0; } - - int getStateOpDeferFlags() const; - int getDrawOpDeferFlags() const; - - void discardDrawingBatches(const unsigned int maxIndex); - - // layer space bounds of rendering - Rect mBounds; - - /** - * At defer time, stores the *defer time* savecount of save/saveLayer ops that were deferred, so - * that when an associated restoreToCount is deferred, it can be recorded as a - * RestoreToCountBatch - */ - std::vector<int> mSaveStack; - int mComplexClipStackStart; - - std::vector<Batch*> mBatches; - - // Maps batch ids to the most recent *non-merging* batch of that id - Batch* mBatchLookup[kOpBatch_Count]; - - // Points to the index after the most recent barrier - int mEarliestBatchIndex; - - // Points to the first index that may contain a pure drawing batch - int mEarliestUnclearedIndex; - - /** - * Maps the mergeid_t returned by an op's getMergeId() to the most recently seen - * MergingDrawBatch of that id. These ids are unique per draw type and guaranteed to not - * collide, which avoids the need to resolve mergeid collisions. - */ - std::unordered_map<mergeid_t, DrawBatch*> mMergingBatches[kOpBatch_Count]; - - LinearAllocator mAllocator; -}; - -/** - * Struct containing information that instructs the defer - */ -struct DeferInfo { -public: - DeferInfo() : - batchId(DeferredDisplayList::kOpBatch_None), - mergeId((mergeid_t) -1), - mergeable(false), - opaqueOverBounds(false) { - }; - - int batchId; - mergeid_t mergeId; - bool mergeable; - bool opaqueOverBounds; // opaque over bounds in DeferredDisplayState - can skip ops below -}; - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_DEFERRED_DISPLAY_LIST_H diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index f833a5405a5c..f13cb8d7d1d7 100644 --- a/libs/hwui/DeferredLayerUpdater.cpp +++ b/libs/hwui/DeferredLayerUpdater.cpp @@ -15,11 +15,10 @@ */ #include "DeferredLayerUpdater.h" -#include "OpenGLRenderer.h" - #include "LayerRenderer.h" #include "renderthread/EglManager.h" #include "renderthread/RenderTask.h" +#include "utils/PaintUtils.h" namespace android { namespace uirenderer { @@ -29,8 +28,7 @@ DeferredLayerUpdater::DeferredLayerUpdater(Layer* layer) , mTransform(nullptr) , mNeedsGLContextAttach(false) , mUpdateTexImage(false) - , mLayer(layer) - , mCaches(Caches::getInstance()) { + , mLayer(layer) { mWidth = mLayer->layer.getWidth(); mHeight = mLayer->layer.getHeight(); mBlend = mLayer->isBlend(); @@ -54,7 +52,6 @@ void DeferredLayerUpdater::setPaint(const SkPaint* paint) { } void DeferredLayerUpdater::apply() { - // These properties are applied the same to both layer types mLayer->setColorFilter(mColorFilter); mLayer->setAlpha(mAlpha, mMode); diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h index 44a24c840892..389e17d12080 100644 --- a/libs/hwui/DeferredLayerUpdater.h +++ b/libs/hwui/DeferredLayerUpdater.h @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef DEFERREDLAYERUPDATE_H_ -#define DEFERREDLAYERUPDATE_H_ + +#pragma once #include <cutils/compiler.h> #include <gui/GLConsumer.h> @@ -100,19 +100,15 @@ private: SkColorFilter* mColorFilter; int mAlpha; SkXfermode::Mode mMode; - sp<GLConsumer> mSurfaceTexture; SkMatrix* mTransform; bool mNeedsGLContextAttach; bool mUpdateTexImage; Layer* mLayer; - Caches& mCaches; void doUpdateTexImage(); }; } /* namespace uirenderer */ } /* namespace android */ - -#endif /* DEFERREDLAYERUPDATE_H_ */ diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp index 28be05c52cfc..ca9e2bd4d3ef 100644 --- a/libs/hwui/DisplayList.cpp +++ b/libs/hwui/DisplayList.cpp @@ -21,13 +21,8 @@ #include "Debug.h" #include "DisplayList.h" -#include "RenderNode.h" - -#if HWUI_NEW_OPS #include "RecordedOp.h" -#else -#include "DisplayListOp.h" -#endif +#include "RenderNode.h" namespace android { namespace uirenderer { @@ -45,8 +40,7 @@ DisplayList::DisplayList() , regions(stdAllocator) , referenceHolders(stdAllocator) , functors(stdAllocator) - , vectorDrawables(stdAllocator) - , hasDrawOps(false) { + , vectorDrawables(stdAllocator) { } DisplayList::~DisplayList() { diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h index ccf71c6d360b..a8205c854c14 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_DISPLAY_LIST_H -#define ANDROID_HWUI_DISPLAY_LIST_H +#pragma once #include <SkCamera.h> #include <SkMatrix.h> @@ -34,7 +33,6 @@ #include "Debug.h" #include "CanvasProperty.h" -#include "DeferredDisplayList.h" #include "GlFunctorLifecycleListener.h" #include "Matrix.h" #include "RenderProperties.h" @@ -49,72 +47,20 @@ class SkRegion; namespace android { namespace uirenderer { -class DeferredDisplayList; -class DisplayListOp; -class DisplayListCanvas; -class OpenGLRenderer; class Rect; class Layer; -#if HWUI_NEW_OPS struct RecordedOp; struct RenderNodeOp; typedef RecordedOp BaseOpType; typedef RenderNodeOp NodeOpType; -#else -class DrawRenderNodeOp; - -typedef DisplayListOp BaseOpType; -typedef DrawRenderNodeOp NodeOpType; -#endif namespace VectorDrawable { class Tree; }; typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot; -/** - * Holds data used in the playback a tree of DisplayLists. - */ -struct PlaybackStateStruct { -protected: - PlaybackStateStruct(OpenGLRenderer& renderer, int replayFlags, LinearAllocator* allocator) - : mRenderer(renderer) - , mReplayFlags(replayFlags) - , mAllocator(allocator) {} - -public: - OpenGLRenderer& mRenderer; - const int mReplayFlags; - - // Allocator with the lifetime of a single frame. replay uses an Allocator owned by the struct, - // while defer shares the DeferredDisplayList's Allocator - // TODO: move this allocator to be owned by object with clear frame lifecycle - LinearAllocator * const mAllocator; - - SkPath* allocPathForFrame() { - return mRenderer.allocPathForFrame(); - } -}; - -struct DeferStateStruct : public PlaybackStateStruct { - DeferStateStruct(DeferredDisplayList& deferredList, OpenGLRenderer& renderer, int replayFlags) - : PlaybackStateStruct(renderer, replayFlags, &(deferredList.mAllocator)), - mDeferredList(deferredList) {} - - DeferredDisplayList& mDeferredList; -}; - -struct ReplayStateStruct : public PlaybackStateStruct { - ReplayStateStruct(OpenGLRenderer& renderer, Rect& dirty, int replayFlags) - : PlaybackStateStruct(renderer, replayFlags, &mReplayAllocator), - mDirty(dirty) {} - - Rect& mDirty; - LinearAllocator mReplayAllocator; -}; - struct FunctorContainer { Functor* functor; GlFunctorLifecycleListener* listener; @@ -124,7 +70,6 @@ struct FunctorContainer { * Data structure that holds the list of commands used in display list stream */ class DisplayList { - friend class DisplayListCanvas; friend class RecordingCanvas; public: struct Chunk { @@ -138,9 +83,9 @@ public: // whether children with non-zero Z in the chunk should be reordered bool reorderChildren; -#if HWUI_NEW_OPS + + // clip at the beginning of a reorder section, applied to reordered children const ClipBase* reorderClip; -#endif }; DisplayList(); @@ -169,11 +114,7 @@ public: return allocator.usedSize(); } bool isEmpty() { -#if HWUI_NEW_OPS return ops.empty(); -#else - return !hasDrawOps; -#endif } private: @@ -203,12 +144,8 @@ private: // gets special treatment exclusive for webview. LsaVector<VectorDrawableRoot*> vectorDrawables; - bool hasDrawOps; // only used if !HWUI_NEW_OPS - void cleanupResources(); }; }; // namespace uirenderer }; // namespace android - -#endif // ANDROID_HWUI_OPENGL_RENDERER_H diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp deleted file mode 100644 index bec662959f91..000000000000 --- a/libs/hwui/DisplayListCanvas.cpp +++ /dev/null @@ -1,597 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "DisplayListCanvas.h" - -#include "DeferredDisplayList.h" -#include "DeferredLayerUpdater.h" -#include "DisplayListOp.h" -#include "ResourceCache.h" -#include "RenderNode.h" -#include "VectorDrawable.h" -#include "utils/PaintUtils.h" - -#include <SkCamera.h> -#include <SkCanvas.h> - -#include <private/hwui/DrawGlInfo.h> - -namespace android { -namespace uirenderer { - -DisplayListCanvas::DisplayListCanvas(int width, int height) - : mState(*this) - , mResourceCache(ResourceCache::getInstance()) - , mDisplayList(nullptr) - , mTranslateX(0.0f) - , mTranslateY(0.0f) - , mHasDeferredTranslate(false) - , mDeferredBarrierType(kBarrier_None) - , mHighContrastText(false) - , mRestoreSaveCount(-1) { - resetRecording(width, height); -} - -DisplayListCanvas::~DisplayListCanvas() { - LOG_ALWAYS_FATAL_IF(mDisplayList, - "Destroyed a DisplayListCanvas during a record!"); -} - -void DisplayListCanvas::resetRecording(int width, int height) { - LOG_ALWAYS_FATAL_IF(mDisplayList, - "prepareDirty called a second time during a recording!"); - mDisplayList = new DisplayList(); - - mState.initializeSaveStack(width, height, - 0, 0, width, height, Vector3()); - - mDeferredBarrierType = kBarrier_InOrder; - mState.setDirtyClip(false); - mRestoreSaveCount = -1; -} - - -/////////////////////////////////////////////////////////////////////////////// -// Operations -/////////////////////////////////////////////////////////////////////////////// - -DisplayList* DisplayListCanvas::finishRecording() { - flushRestoreToCount(); - flushTranslate(); - - mPaintMap.clear(); - mRegionMap.clear(); - mPathMap.clear(); - DisplayList* displayList = mDisplayList; - mDisplayList = nullptr; - mSkiaCanvasProxy.reset(nullptr); - return displayList; -} - -void DisplayListCanvas::callDrawGLFunction(Functor* functor, - GlFunctorLifecycleListener* listener) { - addDrawOp(new (alloc()) DrawFunctorOp(functor)); - mDisplayList->functors.push_back({functor, listener}); - mDisplayList->ref(listener); -} - -SkCanvas* DisplayListCanvas::asSkCanvas() { - LOG_ALWAYS_FATAL_IF(!mDisplayList, - "attempting to get an SkCanvas when we are not recording!"); - if (!mSkiaCanvasProxy) { - mSkiaCanvasProxy.reset(new SkiaCanvasProxy(this)); - } - - // SkCanvas instances default to identity transform, but should inherit - // the state of this Canvas; if this code was in the SkiaCanvasProxy - // constructor, we couldn't cache mSkiaCanvasProxy. - SkMatrix parentTransform; - getMatrix(&parentTransform); - mSkiaCanvasProxy.get()->setMatrix(parentTransform); - - return mSkiaCanvasProxy.get(); -} - -int DisplayListCanvas::save(SaveFlags::Flags flags) { - addStateOp(new (alloc()) SaveOp((int) flags)); - return mState.save((int) flags); -} - -void DisplayListCanvas::restore() { - if (mRestoreSaveCount < 0) { - restoreToCount(getSaveCount() - 1); - return; - } - - mRestoreSaveCount--; - flushTranslate(); - mState.restore(); -} - -void DisplayListCanvas::restoreToCount(int saveCount) { - mRestoreSaveCount = saveCount; - flushTranslate(); - mState.restoreToCount(saveCount); -} - -int DisplayListCanvas::saveLayer(float left, float top, float right, float bottom, - const SkPaint* paint, SaveFlags::Flags flags) { - // force matrix/clip isolation for layer - flags |= SaveFlags::MatrixClip; - - paint = refPaint(paint); - addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, paint, (int) flags)); - return mState.save((int) flags); -} - -void DisplayListCanvas::translate(float dx, float dy) { - if (dx == 0.0f && dy == 0.0f) return; - - mHasDeferredTranslate = true; - mTranslateX += dx; - mTranslateY += dy; - flushRestoreToCount(); - mState.translate(dx, dy, 0.0f); -} - -void DisplayListCanvas::rotate(float degrees) { - if (degrees == 0.0f) return; - - addStateOp(new (alloc()) RotateOp(degrees)); - mState.rotate(degrees); -} - -void DisplayListCanvas::scale(float sx, float sy) { - if (sx == 1.0f && sy == 1.0f) return; - - addStateOp(new (alloc()) ScaleOp(sx, sy)); - mState.scale(sx, sy); -} - -void DisplayListCanvas::skew(float sx, float sy) { - addStateOp(new (alloc()) SkewOp(sx, sy)); - mState.skew(sx, sy); -} - -void DisplayListCanvas::setMatrix(const SkMatrix& matrix) { - addStateOp(new (alloc()) SetMatrixOp(matrix)); - mState.setMatrix(matrix); -} - -void DisplayListCanvas::concat(const SkMatrix& matrix) { - addStateOp(new (alloc()) ConcatMatrixOp(matrix)); - mState.concatMatrix(matrix); -} - -bool DisplayListCanvas::getClipBounds(SkRect* outRect) const { - Rect bounds = mState.getLocalClipBounds(); - *outRect = SkRect::MakeLTRB(bounds.left, bounds.top, bounds.right, bounds.bottom); - return !(outRect->isEmpty()); -} - -bool DisplayListCanvas::quickRejectRect(float left, float top, float right, float bottom) const { - return mState.quickRejectConservative(left, top, right, bottom); -} - -bool DisplayListCanvas::quickRejectPath(const SkPath& path) const { - SkRect bounds = path.getBounds(); - return mState.quickRejectConservative(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom); -} - - -bool DisplayListCanvas::clipRect(float left, float top, float right, float bottom, - SkRegion::Op op) { - addStateOp(new (alloc()) ClipRectOp(left, top, right, bottom, op)); - return mState.clipRect(left, top, right, bottom, op); -} - -bool DisplayListCanvas::clipPath(const SkPath* path, SkRegion::Op op) { - path = refPath(path); - addStateOp(new (alloc()) ClipPathOp(path, op)); - return mState.clipPath(path, op); -} - -bool DisplayListCanvas::clipRegion(const SkRegion* region, SkRegion::Op op) { - region = refRegion(region); - addStateOp(new (alloc()) ClipRegionOp(region, op)); - return mState.clipRegion(region, op); -} - -void DisplayListCanvas::drawRenderNode(RenderNode* renderNode) { - LOG_ALWAYS_FATAL_IF(!renderNode, "missing rendernode"); - DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp( - renderNode, - *mState.currentTransform(), - mState.clipIsSimple()); - addRenderNodeOp(op); -} - -void DisplayListCanvas::drawLayer(DeferredLayerUpdater* layerHandle) { - // We ref the DeferredLayerUpdater due to its thread-safe ref-counting - // semantics. - mDisplayList->ref(layerHandle); - addDrawOp(new (alloc()) DrawLayerOp(layerHandle->backingLayer())); -} - -void DisplayListCanvas::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) { - bitmap = refBitmap(*bitmap); - paint = refPaint(paint); - - addDrawOp(new (alloc()) DrawBitmapOp(bitmap, paint)); -} - -void DisplayListCanvas::drawBitmap(const SkBitmap& bitmap, float left, float top, - const SkPaint* paint) { - save(SaveFlags::Matrix); - translate(left, top); - drawBitmap(&bitmap, paint); - restore(); -} - -void DisplayListCanvas::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, - const SkPaint* paint) { - if (matrix.isIdentity()) { - drawBitmap(&bitmap, paint); - } else if (!(matrix.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) - && MathUtils::isPositive(matrix.getScaleX()) - && MathUtils::isPositive(matrix.getScaleY())) { - // SkMatrix::isScaleTranslate() not available in L - SkRect src; - SkRect dst; - bitmap.getBounds(&src); - matrix.mapRect(&dst, src); - drawBitmap(bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom, - dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, paint); - } else { - save(SaveFlags::Matrix); - concat(matrix); - drawBitmap(&bitmap, paint); - restore(); - } -} - -void DisplayListCanvas::drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop, - float srcRight, float srcBottom, float dstLeft, float dstTop, - float dstRight, float dstBottom, const SkPaint* paint) { - if (srcLeft == 0 && srcTop == 0 - && srcRight == bitmap.width() - && srcBottom == bitmap.height() - && (srcBottom - srcTop == dstBottom - dstTop) - && (srcRight - srcLeft == dstRight - dstLeft)) { - // transform simple rect to rect drawing case into position bitmap ops, since they merge - save(SaveFlags::Matrix); - translate(dstLeft, dstTop); - drawBitmap(&bitmap, paint); - restore(); - } else { - paint = refPaint(paint); - - if (paint && paint->getShader()) { - float scaleX = (dstRight - dstLeft) / (srcRight - srcLeft); - float scaleY = (dstBottom - dstTop) / (srcBottom - srcTop); - if (!MathUtils::areEqual(scaleX, 1.0f) || !MathUtils::areEqual(scaleY, 1.0f)) { - // Apply the scale transform on the canvas, so that the shader - // effectively calculates positions relative to src rect space - - save(SaveFlags::Matrix); - translate(dstLeft, dstTop); - scale(scaleX, scaleY); - - dstLeft = 0.0f; - dstTop = 0.0f; - dstRight = srcRight - srcLeft; - dstBottom = srcBottom - srcTop; - - addDrawOp(new (alloc()) DrawBitmapRectOp(refBitmap(bitmap), - srcLeft, srcTop, srcRight, srcBottom, - dstLeft, dstTop, dstRight, dstBottom, paint)); - restore(); - return; - } - } - - addDrawOp(new (alloc()) DrawBitmapRectOp(refBitmap(bitmap), - srcLeft, srcTop, srcRight, srcBottom, - dstLeft, dstTop, dstRight, dstBottom, paint)); - } -} - -void DisplayListCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight, - const float* vertices, const int* colors, const SkPaint* paint) { - int vertexCount = (meshWidth + 1) * (meshHeight + 1); - vertices = refBuffer<float>(vertices, vertexCount * 2); // 2 floats per vertex - paint = refPaint(paint); - colors = refBuffer<int>(colors, vertexCount); // 1 color per vertex - - addDrawOp(new (alloc()) DrawBitmapMeshOp(refBitmap(bitmap), meshWidth, meshHeight, - vertices, colors, paint)); -} - -void DisplayListCanvas::drawNinePatch(const SkBitmap& bitmap, const Res_png_9patch& patch, - float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) { - const SkBitmap* bitmapPtr = refBitmap(bitmap); - const Res_png_9patch* patchPtr = refPatch(&patch); - paint = refPaint(paint); - - addDrawOp(new (alloc()) DrawPatchOp(bitmapPtr, patchPtr, - dstLeft, dstTop, dstRight, dstBottom, paint)); -} - -void DisplayListCanvas::drawColor(int color, SkXfermode::Mode mode) { - addDrawOp(new (alloc()) DrawColorOp(color, mode)); -} - -void DisplayListCanvas::drawPaint(const SkPaint& paint) { - SkRect bounds; - if (getClipBounds(&bounds)) { - drawRect(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, paint); - } -} - - -void DisplayListCanvas::drawRect(float left, float top, float right, float bottom, - const SkPaint& paint) { - addDrawOp(new (alloc()) DrawRectOp(left, top, right, bottom, refPaint(&paint))); -} - -void DisplayListCanvas::drawRoundRect(float left, float top, float right, float bottom, - float rx, float ry, const SkPaint& paint) { - addDrawOp(new (alloc()) DrawRoundRectOp(left, top, right, bottom, rx, ry, refPaint(&paint))); -} - -void DisplayListCanvas::drawRoundRect( - CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top, - CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom, - CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry, - CanvasPropertyPaint* paint) { - mDisplayList->ref(left); - mDisplayList->ref(top); - mDisplayList->ref(right); - mDisplayList->ref(bottom); - mDisplayList->ref(rx); - mDisplayList->ref(ry); - mDisplayList->ref(paint); - refBitmapsInShader(paint->value.getShader()); - addDrawOp(new (alloc()) DrawRoundRectPropsOp(&left->value, &top->value, - &right->value, &bottom->value, &rx->value, &ry->value, &paint->value)); -} - -void DisplayListCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) { - addDrawOp(new (alloc()) DrawCircleOp(x, y, radius, refPaint(&paint))); -} - -void DisplayListCanvas::drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y, - CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) { - mDisplayList->ref(x); - mDisplayList->ref(y); - mDisplayList->ref(radius); - mDisplayList->ref(paint); - refBitmapsInShader(paint->value.getShader()); - addDrawOp(new (alloc()) DrawCirclePropsOp(&x->value, &y->value, - &radius->value, &paint->value)); -} - -void DisplayListCanvas::drawOval(float left, float top, float right, float bottom, - const SkPaint& paint) { - addDrawOp(new (alloc()) DrawOvalOp(left, top, right, bottom, refPaint(&paint))); -} - -void DisplayListCanvas::drawArc(float left, float top, float right, float bottom, - float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) { - if (fabs(sweepAngle) >= 360.0f) { - drawOval(left, top, right, bottom, paint); - } else { - addDrawOp(new (alloc()) DrawArcOp(left, top, right, bottom, - startAngle, sweepAngle, useCenter, refPaint(&paint))); - } -} - -void DisplayListCanvas::drawPath(const SkPath& path, const SkPaint& paint) { - addDrawOp(new (alloc()) DrawPathOp(refPath(&path), refPaint(&paint))); -} - -void DisplayListCanvas::drawLines(const float* points, int count, const SkPaint& paint) { - points = refBuffer<float>(points, count); - - addDrawOp(new (alloc()) DrawLinesOp(points, count, refPaint(&paint))); -} - -void DisplayListCanvas::drawPoints(const float* points, int count, const SkPaint& paint) { - points = refBuffer<float>(points, count); - - addDrawOp(new (alloc()) DrawPointsOp(points, count, refPaint(&paint))); -} - -void DisplayListCanvas::drawVectorDrawable(VectorDrawableRoot* tree) { - mDisplayList->ref(tree); - mDisplayList->vectorDrawables.push_back(tree); - addDrawOp(new (alloc()) DrawVectorDrawableOp(tree, tree->stagingProperties()->getBounds())); -} - -void DisplayListCanvas::drawGlyphsOnPath(const uint16_t* glyphs, int count, - const SkPath& path, float hOffset, float vOffset, const SkPaint& paint) { - if (!glyphs || count <= 0) return; - - int bytesCount = 2 * count; - DrawOp* op = new (alloc()) DrawTextOnPathOp(refBuffer<glyph_t>(glyphs, count), - bytesCount, count, refPath(&path), - hOffset, vOffset, refPaint(&paint)); - addDrawOp(op); -} - -void DisplayListCanvas::drawGlyphs(const uint16_t* glyphs, const float* positions, - int count, const SkPaint& paint, float x, float y, - float boundsLeft, float boundsTop, float boundsRight, float boundsBottom, - float totalAdvance) { - - if (!glyphs || count <= 0 || PaintUtils::paintWillNotDrawText(paint)) return; - - int bytesCount = count * 2; - positions = refBuffer<float>(positions, count * 2); - Rect bounds(boundsLeft, boundsTop, boundsRight, boundsBottom); - - DrawOp* op = new (alloc()) DrawTextOp(refBuffer<glyph_t>(glyphs, count), bytesCount, count, - x, y, positions, refPaint(&paint), totalAdvance, bounds); - addDrawOp(op); - drawTextDecorations(x, y, totalAdvance, paint); -} - -void DisplayListCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) { - if (paint.getStyle() != SkPaint::kFill_Style || - (paint.isAntiAlias() && !mState.currentTransform()->isSimple())) { - SkRegion::Iterator it(region); - while (!it.done()) { - const SkIRect& r = it.rect(); - drawRect(r.fLeft, r.fTop, r.fRight, r.fBottom, paint); - it.next(); - } - } else { - int count = 0; - Vector<float> rects; - SkRegion::Iterator it(region); - while (!it.done()) { - const SkIRect& r = it.rect(); - rects.push(r.fLeft); - rects.push(r.fTop); - rects.push(r.fRight); - rects.push(r.fBottom); - count += 4; - it.next(); - } - drawRects(rects.array(), count, &paint); - } -} - -void DisplayListCanvas::drawRects(const float* rects, int count, const SkPaint* paint) { - if (count <= 0) return; - - rects = refBuffer<float>(rects, count); - paint = refPaint(paint); - addDrawOp(new (alloc()) DrawRectsOp(rects, count, paint)); -} - -void DisplayListCanvas::setDrawFilter(SkDrawFilter* filter) { - mDrawFilter.reset(SkSafeRef(filter)); -} - -void DisplayListCanvas::insertReorderBarrier(bool enableReorder) { - flushRestoreToCount(); - flushTranslate(); - mDeferredBarrierType = enableReorder ? kBarrier_OutOfOrder : kBarrier_InOrder; -} - -void DisplayListCanvas::flushRestoreToCount() { - if (mRestoreSaveCount >= 0) { - addOpAndUpdateChunk(new (alloc()) RestoreToCountOp(mRestoreSaveCount)); - mRestoreSaveCount = -1; - } -} - -void DisplayListCanvas::flushTranslate() { - if (mHasDeferredTranslate) { - if (mTranslateX != 0.0f || mTranslateY != 0.0f) { - addOpAndUpdateChunk(new (alloc()) TranslateOp(mTranslateX, mTranslateY)); - mTranslateX = mTranslateY = 0.0f; - } - mHasDeferredTranslate = false; - } -} - -size_t DisplayListCanvas::addOpAndUpdateChunk(DisplayListOp* op) { - int insertIndex = mDisplayList->ops.size(); -#if HWUI_NEW_OPS - LOG_ALWAYS_FATAL("unsupported"); -#else - mDisplayList->ops.push_back(op); -#endif - if (mDeferredBarrierType != kBarrier_None) { - // op is first in new chunk - mDisplayList->chunks.emplace_back(); - DisplayList::Chunk& newChunk = mDisplayList->chunks.back(); - newChunk.beginOpIndex = insertIndex; - newChunk.endOpIndex = insertIndex + 1; - newChunk.reorderChildren = (mDeferredBarrierType == kBarrier_OutOfOrder); - - int nextChildIndex = mDisplayList->children.size(); - newChunk.beginChildIndex = newChunk.endChildIndex = nextChildIndex; - mDeferredBarrierType = kBarrier_None; - } else { - // standard case - append to existing chunk - mDisplayList->chunks.back().endOpIndex = insertIndex + 1; - } - return insertIndex; -} - -size_t DisplayListCanvas::flushAndAddOp(DisplayListOp* op) { - flushRestoreToCount(); - flushTranslate(); - return addOpAndUpdateChunk(op); -} - -size_t DisplayListCanvas::addStateOp(StateOp* op) { - return flushAndAddOp(op); -} - -size_t DisplayListCanvas::addDrawOp(DrawOp* op) { - Rect localBounds; - if (op->getLocalBounds(localBounds)) { - bool rejected = quickRejectRect(localBounds.left, localBounds.top, - localBounds.right, localBounds.bottom); - op->setQuickRejected(rejected); - } - - mDisplayList->hasDrawOps = true; - return flushAndAddOp(op); -} - -size_t DisplayListCanvas::addRenderNodeOp(DrawRenderNodeOp* op) { - int opIndex = addDrawOp(op); -#if !HWUI_NEW_OPS - int childIndex = mDisplayList->addChild(op); - - // update the chunk's child indices - DisplayList::Chunk& chunk = mDisplayList->chunks.back(); - chunk.endChildIndex = childIndex + 1; - - if (op->renderNode->stagingProperties().isProjectionReceiver()) { - // use staging property, since recording on UI thread - mDisplayList->projectionReceiveIndex = opIndex; - } -#endif - return opIndex; -} - -void DisplayListCanvas::refBitmapsInShader(const SkShader* shader) { - if (!shader) return; - - // If this paint has an SkShader that has an SkBitmap add - // it to the bitmap pile - SkBitmap bitmap; - SkShader::TileMode xy[2]; - if (shader->isABitmap(&bitmap, nullptr, xy)) { - refBitmap(bitmap); - return; - } - SkShader::ComposeRec rec; - if (shader->asACompose(&rec)) { - refBitmapsInShader(rec.fShaderA); - refBitmapsInShader(rec.fShaderB); - return; - } -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/DisplayListCanvas.h b/libs/hwui/DisplayListCanvas.h deleted file mode 100644 index 664f79e283b6..000000000000 --- a/libs/hwui/DisplayListCanvas.h +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_HWUI_DISPLAY_LIST_RENDERER_H -#define ANDROID_HWUI_DISPLAY_LIST_RENDERER_H - -#include "CanvasState.h" -#include "DisplayList.h" -#include "RenderNode.h" -#include "ResourceCache.h" -#include "SkiaCanvasProxy.h" -#include "hwui/Canvas.h" -#include "utils/Macros.h" - -#include <SkDrawFilter.h> -#include <SkMatrix.h> -#include <SkPaint.h> -#include <SkPath.h> -#include <SkRegion.h> -#include <SkTLazy.h> -#include <cutils/compiler.h> - -namespace android { -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// Defines -/////////////////////////////////////////////////////////////////////////////// - -// Debug -#if DEBUG_DISPLAY_LIST - #define DISPLAY_LIST_LOGD(...) ALOGD(__VA_ARGS__) -#else - #define DISPLAY_LIST_LOGD(...) -#endif - -/////////////////////////////////////////////////////////////////////////////// -// Display list -/////////////////////////////////////////////////////////////////////////////// - -class DeferredDisplayList; -class DeferredLayerUpdater; -class DisplayListOp; -class DrawOp; -class DrawRenderNodeOp; -class RenderNode; -class StateOp; - -/** - * Records drawing commands in a display list for later playback into an OpenGLRenderer. - */ -class ANDROID_API DisplayListCanvas: public Canvas, public CanvasStateClient { -public: - DisplayListCanvas(int width, int height); - virtual ~DisplayListCanvas(); - - virtual void resetRecording(int width, int height) override; - virtual WARN_UNUSED_RESULT DisplayList* finishRecording() override; - -// ---------------------------------------------------------------------------- -// HWUI Canvas state operations -// ---------------------------------------------------------------------------- - - virtual void insertReorderBarrier(bool enableReorder) override; - -// ---------------------------------------------------------------------------- -// HWUI Canvas draw operations -// ---------------------------------------------------------------------------- - - // Shapes - virtual void drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top, - CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom, - CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry, - CanvasPropertyPaint* paint) override; - virtual void drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y, - CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) override; - -// ---------------------------------------------------------------------------- -// HWUI Canvas draw operations - special -// ---------------------------------------------------------------------------- - virtual void drawLayer(DeferredLayerUpdater* layerHandle) override; - virtual void drawRenderNode(RenderNode* renderNode) override; - virtual void callDrawGLFunction(Functor* functor, - GlFunctorLifecycleListener* listener) override; - -// ---------------------------------------------------------------------------- -// CanvasStateClient interface -// ---------------------------------------------------------------------------- - virtual void onViewportInitialized() override { } - virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) override { } - virtual GLuint getTargetFbo() const override { return -1; } - -// ---------------------------------------------------------------------------- -// android/graphics/Canvas interface -// ---------------------------------------------------------------------------- - virtual SkCanvas* asSkCanvas() override; - - virtual void setBitmap(const SkBitmap& bitmap) override { - LOG_ALWAYS_FATAL("DisplayListCanvas is not backed by a bitmap."); - } - - virtual bool isOpaque() override { return false; } - virtual int width() override { return mState.getWidth(); } - virtual int height() override { return mState.getHeight(); } - - virtual void setHighContrastText(bool highContrastText) override { - mHighContrastText = highContrastText; - } - virtual bool isHighContrastText() override { return mHighContrastText; } - -// ---------------------------------------------------------------------------- -// android/graphics/Canvas state operations -// ---------------------------------------------------------------------------- - // Save (layer) - virtual int getSaveCount() const override { return mState.getSaveCount(); } - virtual int save(SaveFlags::Flags flags) override; - virtual void restore() override; - virtual void restoreToCount(int saveCount) override; - - virtual int saveLayer(float left, float top, float right, float bottom, const SkPaint* paint, - SaveFlags::Flags flags) override; - virtual int saveLayerAlpha(float left, float top, float right, float bottom, - int alpha, SaveFlags::Flags flags) override { - SkPaint paint; - paint.setAlpha(alpha); - return saveLayer(left, top, right, bottom, &paint, flags); - } - - // Matrix - virtual void getMatrix(SkMatrix* outMatrix) const override { mState.getMatrix(outMatrix); } - virtual void setMatrix(const SkMatrix& matrix) override; - - virtual void concat(const SkMatrix& matrix) override; - virtual void rotate(float degrees) override; - virtual void scale(float sx, float sy) override; - virtual void skew(float sx, float sy) override; - virtual void translate(float dx, float dy) override; - - // Clip - virtual bool getClipBounds(SkRect* outRect) const override; - virtual bool quickRejectRect(float left, float top, float right, float bottom) const override; - virtual bool quickRejectPath(const SkPath& path) const override; - - virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op) override; - virtual bool clipPath(const SkPath* path, SkRegion::Op op) override; - virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) override; - - // Misc - virtual SkDrawFilter* getDrawFilter() override { return mDrawFilter.get(); } - virtual void setDrawFilter(SkDrawFilter* filter) override; - -// ---------------------------------------------------------------------------- -// android/graphics/Canvas draw operations -// ---------------------------------------------------------------------------- - virtual void drawColor(int color, SkXfermode::Mode mode) override; - virtual void drawPaint(const SkPaint& paint) override; - - // Geometry - virtual void drawPoint(float x, float y, const SkPaint& paint) override { - float points[2] = { x, y }; - drawPoints(points, 2, paint); - } - virtual void drawPoints(const float* points, int count, const SkPaint& paint) override; - virtual void drawLine(float startX, float startY, float stopX, float stopY, - const SkPaint& paint) override { - float points[4] = { startX, startY, stopX, stopY }; - drawLines(points, 4, paint); - } - virtual void drawLines(const float* points, int count, const SkPaint& paint) override; - virtual void drawRect(float left, float top, float right, float bottom, const SkPaint& paint) override; - virtual void drawRegion(const SkRegion& region, const SkPaint& paint) override; - virtual void drawRoundRect(float left, float top, float right, float bottom, - float rx, float ry, const SkPaint& paint) override; - virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) override; - virtual void drawOval(float left, float top, float right, float bottom, const SkPaint& paint) override; - virtual void drawArc(float left, float top, float right, float bottom, - float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) override; - virtual void drawPath(const SkPath& path, const SkPaint& paint) override; - virtual void drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount, - const float* verts, const float* tex, const int* colors, - const uint16_t* indices, int indexCount, const SkPaint& paint) override - { /* DisplayListCanvas does not support drawVertices(); ignore */ } - - // Bitmap-based - virtual void drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint) override; - virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, - const SkPaint* paint) override; - virtual void drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop, - float srcRight, float srcBottom, float dstLeft, float dstTop, - float dstRight, float dstBottom, const SkPaint* paint) override; - virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight, - const float* vertices, const int* colors, const SkPaint* paint) override; - virtual void drawNinePatch(const SkBitmap& bitmap, const android::Res_png_9patch& chunk, - float dstLeft, float dstTop, float dstRight, float dstBottom, - const SkPaint* paint) override; - - virtual void drawVectorDrawable(VectorDrawableRoot* tree) override; - - // Text - virtual void drawGlyphs(const uint16_t* glyphs, const float* positions, int count, - const SkPaint& paint, float x, float y, float boundsLeft, float boundsTop, - float boundsRight, float boundsBottom, float totalAdvance) override; - virtual void drawGlyphsOnPath(const uint16_t* glyphs, int count, const SkPath& path, - float hOffset, float vOffset, const SkPaint& paint) override; - virtual bool drawTextAbsolutePos() const override { return false; } - -private: - - CanvasState mState; - std::unique_ptr<SkiaCanvasProxy> mSkiaCanvasProxy; - - enum DeferredBarrierType { - kBarrier_None, - kBarrier_InOrder, - kBarrier_OutOfOrder, - }; - - void drawBitmap(const SkBitmap* bitmap, const SkPaint* paint); - void drawRects(const float* rects, int count, const SkPaint* paint); - - void flushRestoreToCount(); - void flushTranslate(); - void flushReorderBarrier(); - - LinearAllocator& alloc() { return mDisplayList->allocator; } - - // Each method returns final index of op - size_t addOpAndUpdateChunk(DisplayListOp* op); - // flushes any deferred operations, and appends the op - size_t flushAndAddOp(DisplayListOp* op); - - size_t addStateOp(StateOp* op); - size_t addDrawOp(DrawOp* op); - size_t addRenderNodeOp(DrawRenderNodeOp* op); - - void refBitmapsInShader(const SkShader* shader); - - template<class T> - inline const T* refBuffer(const T* srcBuffer, int32_t count) { - if (!srcBuffer) return nullptr; - - T* dstBuffer = (T*) mDisplayList->allocator.alloc<T>(count * sizeof(T)); - memcpy(dstBuffer, srcBuffer, count * sizeof(T)); - return dstBuffer; - } - - inline const SkPath* refPath(const SkPath* path) { - if (!path) return nullptr; - - // The points/verbs within the path are refcounted so this copy operation - // is inexpensive and maintains the generationID of the original path. - const SkPath* cachedPath = new SkPath(*path); - mDisplayList->pathResources.push_back(cachedPath); - return cachedPath; - } - - inline const SkPaint* refPaint(const SkPaint* paint) { - if (!paint) return nullptr; - - // If there is a draw filter apply it here and store the modified paint - // so that we don't need to modify the paint every time we access it. - SkTLazy<SkPaint> filteredPaint; - if (mDrawFilter.get()) { - filteredPaint.set(*paint); - mDrawFilter->filter(filteredPaint.get(), SkDrawFilter::kPaint_Type); - paint = filteredPaint.get(); - } - - // compute the hash key for the paint and check the cache. - const uint32_t key = paint->getHash(); - const SkPaint* cachedPaint = mPaintMap.valueFor(key); - // In the unlikely event that 2 unique paints have the same hash we do a - // object equality check to ensure we don't erroneously dedup them. - if (cachedPaint == nullptr || *cachedPaint != *paint) { - cachedPaint = new SkPaint(*paint); - std::unique_ptr<const SkPaint> copy(cachedPaint); - mDisplayList->paints.push_back(std::move(copy)); - - // replaceValueFor() performs an add if the entry doesn't exist - mPaintMap.replaceValueFor(key, cachedPaint); - refBitmapsInShader(cachedPaint->getShader()); - } - - return cachedPaint; - } - - inline const SkRegion* refRegion(const SkRegion* region) { - if (!region) { - return region; - } - - const SkRegion* cachedRegion = mRegionMap.valueFor(region); - // TODO: Add generation ID to SkRegion - if (cachedRegion == nullptr) { - std::unique_ptr<const SkRegion> copy(new SkRegion(*region)); - cachedRegion = copy.get(); - mDisplayList->regions.push_back(std::move(copy)); - - // replaceValueFor() performs an add if the entry doesn't exist - mRegionMap.replaceValueFor(region, cachedRegion); - } - - return cachedRegion; - } - - inline const SkBitmap* refBitmap(const SkBitmap& bitmap) { - // Note that this assumes the bitmap is immutable. There are cases this won't handle - // correctly, such as creating the bitmap from scratch, drawing with it, changing its - // contents, and drawing again. The only fix would be to always copy it the first time, - // which doesn't seem worth the extra cycles for this unlikely case. - SkBitmap* localBitmap = alloc().create<SkBitmap>(bitmap); - mDisplayList->bitmapResources.push_back(localBitmap); - return localBitmap; - } - - inline const Res_png_9patch* refPatch(const Res_png_9patch* patch) { - mDisplayList->patchResources.push_back(patch); - mResourceCache.incrementRefcount(patch); - return patch; - } - - DefaultKeyedVector<uint32_t, const SkPaint*> mPaintMap; - DefaultKeyedVector<const SkPath*, const SkPath*> mPathMap; - DefaultKeyedVector<const SkRegion*, const SkRegion*> mRegionMap; - - ResourceCache& mResourceCache; - DisplayList* mDisplayList; - - float mTranslateX; - float mTranslateY; - bool mHasDeferredTranslate; - DeferredBarrierType mDeferredBarrierType; - bool mHighContrastText; - - int mRestoreSaveCount; - - SkAutoTUnref<SkDrawFilter> mDrawFilter; - - friend class RenderNode; - -}; // class DisplayListCanvas - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_DISPLAY_LIST_RENDERER_H diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h deleted file mode 100644 index 2a859132e783..000000000000 --- a/libs/hwui/DisplayListOp.h +++ /dev/null @@ -1,1555 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_HWUI_DISPLAY_OPERATION_H -#define ANDROID_HWUI_DISPLAY_OPERATION_H - -#include "OpenGLRenderer.h" -#include "AssetAtlas.h" -#include "DeferredDisplayList.h" -#include "DisplayListCanvas.h" -#include "GammaFontRenderer.h" -#include "Patch.h" -#include "RenderNode.h" -#include "renderstate/RenderState.h" -#include "UvMapper.h" -#include "utils/LinearAllocator.h" -#include "utils/PaintUtils.h" -#include "VectorDrawable.h" - -#include <algorithm> - -#include <SkColor.h> -#include <SkPath.h> -#include <SkPathOps.h> -#include <SkXfermode.h> - -#include <private/hwui/DrawGlInfo.h> - -// Use OP_LOG for logging with arglist, OP_LOGS if just printing char* -#define OP_LOGS(s) OP_LOG("%s", (s)) -#define OP_LOG(s, ...) ALOGD( "%*s" s, level * 2, "", __VA_ARGS__ ) - -namespace android { -namespace uirenderer { - -/** - * Structure for storing canvas operations when they are recorded into a DisplayList, so that they - * may be replayed to an OpenGLRenderer. - * - * To avoid individual memory allocations, DisplayListOps may only be allocated into a - * LinearAllocator's managed memory buffers. Each pointer held by a DisplayListOp is either a - * pointer into memory also allocated in the LinearAllocator (mostly for text and float buffers) or - * references a externally refcounted object (Sk... and Skia... objects). ~DisplayListOp() is - * never called as LinearAllocators are simply discarded, so no memory management should be done in - * this class. - */ -class DisplayListOp { -public: - // These objects should always be allocated with a LinearAllocator, and never destroyed/deleted. - // standard new() intentionally not implemented, and delete/deconstructor should never be used. - virtual ~DisplayListOp() { LOG_ALWAYS_FATAL("Destructor not supported"); } - static void operator delete(void* ptr) { LOG_ALWAYS_FATAL("delete not supported"); } - static void* operator new(size_t size) = delete; /** PURPOSELY OMITTED **/ - static void* operator new(size_t size, LinearAllocator& allocator) { - // FIXME: Quick hack to keep old pipeline working, delete this when - // we no longer need to support HWUI_NEWOPS := false - return allocator.alloc<char>(size); - } - - enum OpLogFlag { - kOpLogFlag_Recurse = 0x1, - kOpLogFlag_JSON = 0x2 // TODO: add? - }; - - virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, - bool useQuickReject) = 0; - - virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level, - bool useQuickReject) = 0; - - virtual void output(int level, uint32_t logFlags = 0) const = 0; - - // NOTE: it would be nice to declare constants and overriding the implementation in each op to - // point at the constants, but that seems to require a .cpp file - virtual const char* name() = 0; -}; - -class StateOp : public DisplayListOp { -public: - virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, - bool useQuickReject) override { - // default behavior only affects immediate, deferrable state, issue directly to renderer - applyState(deferStruct.mRenderer, saveCount); - } - - /** - * State operations are applied directly to the renderer, but can cause the deferred drawing op - * list to flush - */ - virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level, - bool useQuickReject) override { - applyState(replayStruct.mRenderer, saveCount); - } - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const = 0; -}; - -class DrawOp : public DisplayListOp { -friend class MergingDrawBatch; -public: - DrawOp(const SkPaint* paint) - : mPaint(paint), mQuickRejected(false) {} - - virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, - bool useQuickReject) override { - if (mQuickRejected && CC_LIKELY(useQuickReject)) { - return; - } - - deferStruct.mDeferredList.addDrawOp(deferStruct.mRenderer, this); - } - - virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level, - bool useQuickReject) override { - if (mQuickRejected && CC_LIKELY(useQuickReject)) { - return; - } - - applyDraw(replayStruct.mRenderer, replayStruct.mDirty); - } - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) = 0; - - /** - * Draw multiple instances of an operation, must be overidden for operations that merge - * - * Currently guarantees certain similarities between ops (see MergingDrawBatch::canMergeWith), - * and pure translation transformations. Other guarantees of similarity should be enforced by - * reducing which operations are tagged as mergeable. - */ - virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty, - const std::vector<OpStatePair>& ops, const Rect& bounds) { - for (unsigned int i = 0; i < ops.size(); i++) { - renderer.restoreDisplayState(*(ops[i].state), true); - ops[i].op->applyDraw(renderer, dirty); - } - } - - /** - * When this method is invoked the state field is initialized to have the - * final rendering state. We can thus use it to process data as it will be - * used at draw time. - * - * Additionally, this method allows subclasses to provide defer-time preferences for batching - * and merging. - * - * if a subclass can set deferInfo.mergeable to true, it should implement multiDraw() - */ - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) {} - - /** - * Query the conservative, local bounds (unmapped) bounds of the op. - * - * returns true if bounds exist - */ - virtual bool getLocalBounds(Rect& localBounds) { - return false; - } - - // TODO: better refine localbounds usage - void setQuickRejected(bool quickRejected) { mQuickRejected = quickRejected; } - bool getQuickRejected() { return mQuickRejected; } - - virtual bool hasTextShadow() const { - return false; - } - - inline float strokeWidthOutset() { - // since anything AA stroke with less than 1.0 pixel width is drawn with an alpha-reduced - // 1.0 stroke, treat 1.0 as minimum. - - // TODO: it would be nice if this could take scale into account, but scale isn't stable - // since higher levels of the view hierarchy can change scale out from underneath it. - return std::max(mPaint->getStrokeWidth(), 1.0f) * 0.5f; - } - -protected: - // Helper method for determining op opaqueness. Assumes op fills its bounds in local - // coordinates, and that paint's alpha is used - inline bool isOpaqueOverBounds(const DeferredDisplayState& state) { - // ensure that local bounds cover mapped bounds - if (!state.mMatrix.isSimple()) return false; - - if (state.mRoundRectClipState) return false; - - // check state/paint for transparency - if (mPaint) { - if (mPaint->getAlpha() != 0xFF) { - return false; - } - if (mPaint->getShader() && !mPaint->getShader()->isOpaque()) { - return false; - } - if (PaintUtils::isBlendedColorFilter(mPaint->getColorFilter())) { - return false; - } - } - - if (state.mAlpha != 1.0f) return false; - - SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(mPaint); - return (mode == SkXfermode::kSrcOver_Mode || - mode == SkXfermode::kSrc_Mode); - - } - - const SkPaint* mPaint; - bool mQuickRejected; -}; - -class DrawBoundedOp : public DrawOp { -public: - DrawBoundedOp(float left, float top, float right, float bottom, const SkPaint* paint) - : DrawOp(paint), mLocalBounds(left, top, right, bottom) {} - - DrawBoundedOp(const Rect& localBounds, const SkPaint* paint) - : DrawOp(paint), mLocalBounds(localBounds) {} - - // Calculates bounds as smallest rect encompassing all points - // NOTE: requires at least 1 vertex, and doesn't account for stroke size (should be handled in - // subclass' constructor) - DrawBoundedOp(const float* points, int count, const SkPaint* paint) - : DrawOp(paint), mLocalBounds(points[0], points[1], points[0], points[1]) { - for (int i = 2; i < count; i += 2) { - mLocalBounds.left = std::min(mLocalBounds.left, points[i]); - mLocalBounds.right = std::max(mLocalBounds.right, points[i]); - mLocalBounds.top = std::min(mLocalBounds.top, points[i + 1]); - mLocalBounds.bottom = std::max(mLocalBounds.bottom, points[i + 1]); - } - } - - // default empty constructor for bounds, to be overridden in child constructor body - DrawBoundedOp(const SkPaint* paint): DrawOp(paint) { } - - virtual bool getLocalBounds(Rect& localBounds) override { - localBounds.set(mLocalBounds); - PaintUtils::TextShadow textShadow; - if (PaintUtils::getTextShadow(mPaint, &textShadow)) { - Rect shadow(mLocalBounds); - shadow.translate(textShadow.dx, textShadow.dx); - shadow.outset(textShadow.radius); - localBounds.unionWith(shadow); - } - return true; - } - -protected: - Rect mLocalBounds; // displayed area in LOCAL coord. doesn't incorporate stroke, so check paint -}; - -/////////////////////////////////////////////////////////////////////////////// -// STATE OPERATIONS - these may affect the state of the canvas/renderer, but do -// not directly draw or alter output -/////////////////////////////////////////////////////////////////////////////// - -class SaveOp : public StateOp { -public: - SaveOp(int flags) - : mFlags(flags) {} - - virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, - bool useQuickReject) override { - int newSaveCount = deferStruct.mRenderer.save(mFlags); - deferStruct.mDeferredList.addSave(deferStruct.mRenderer, this, newSaveCount); - } - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - renderer.save(mFlags); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Save flags %x", mFlags); - } - - virtual const char* name() override { return "Save"; } - - int getFlags() const { return mFlags; } -private: - int mFlags; -}; - -class RestoreToCountOp : public StateOp { -public: - RestoreToCountOp(int count) - : mCount(count) {} - - virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, - bool useQuickReject) override { - deferStruct.mDeferredList.addRestoreToCount(deferStruct.mRenderer, - this, saveCount + mCount); - deferStruct.mRenderer.restoreToCount(saveCount + mCount); - } - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - renderer.restoreToCount(saveCount + mCount); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Restore to count %d", mCount); - } - - virtual const char* name() override { return "RestoreToCount"; } - -private: - int mCount; -}; - -class SaveLayerOp : public StateOp { -public: - SaveLayerOp(float left, float top, float right, float bottom, int alpha, int flags) - : mArea(left, top, right, bottom) - , mPaint(&mCachedPaint) - , mFlags(flags) - , mConvexMask(nullptr) { - mCachedPaint.setAlpha(alpha); - } - - SaveLayerOp(float left, float top, float right, float bottom, const SkPaint* paint, int flags) - : mArea(left, top, right, bottom) - , mPaint(paint) - , mFlags(flags) - , mConvexMask(nullptr) - {} - - virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, - bool useQuickReject) override { - // NOTE: don't bother with actual saveLayer, instead issuing it at flush time - int newSaveCount = deferStruct.mRenderer.getSaveCount(); - deferStruct.mDeferredList.addSaveLayer(deferStruct.mRenderer, this, newSaveCount); - - // NOTE: don't issue full saveLayer, since that has side effects/is costly. instead just - // setup the snapshot for deferral, and re-issue the op at flush time - deferStruct.mRenderer.saveLayerDeferred(mArea.left, mArea.top, mArea.right, mArea.bottom, - mPaint, mFlags); - } - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom, - mPaint, mFlags, mConvexMask); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("SaveLayer%s of area " RECT_STRING, - (isSaveLayerAlpha() ? "Alpha" : ""),RECT_ARGS(mArea)); - } - - virtual const char* name() override { - return isSaveLayerAlpha() ? "SaveLayerAlpha" : "SaveLayer"; - } - - int getFlags() { return mFlags; } - - // Called to make SaveLayerOp clip to the provided mask when drawing back/restored - void setMask(const SkPath* convexMask) { - mConvexMask = convexMask; - } - -private: - bool isSaveLayerAlpha() const { - SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(mPaint); - int alpha = PaintUtils::getAlphaDirect(mPaint); - return alpha < 255 && mode == SkXfermode::kSrcOver_Mode; - } - - Rect mArea; - const SkPaint* mPaint; - SkPaint mCachedPaint; - int mFlags; - - // Convex path, points at data in RenderNode, valid for the duration of the frame only - // Only used for masking the SaveLayer which wraps projected RenderNodes - const SkPath* mConvexMask; -}; - -class TranslateOp : public StateOp { -public: - TranslateOp(float dx, float dy) - : mDx(dx), mDy(dy) {} - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - renderer.translate(mDx, mDy); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Translate by %f %f", mDx, mDy); - } - - virtual const char* name() override { return "Translate"; } - -private: - float mDx; - float mDy; -}; - -class RotateOp : public StateOp { -public: - RotateOp(float degrees) - : mDegrees(degrees) {} - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - renderer.rotate(mDegrees); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Rotate by %f degrees", mDegrees); - } - - virtual const char* name() override { return "Rotate"; } - -private: - float mDegrees; -}; - -class ScaleOp : public StateOp { -public: - ScaleOp(float sx, float sy) - : mSx(sx), mSy(sy) {} - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - renderer.scale(mSx, mSy); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Scale by %f %f", mSx, mSy); - } - - virtual const char* name() override { return "Scale"; } - -private: - float mSx; - float mSy; -}; - -class SkewOp : public StateOp { -public: - SkewOp(float sx, float sy) - : mSx(sx), mSy(sy) {} - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - renderer.skew(mSx, mSy); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Skew by %f %f", mSx, mSy); - } - - virtual const char* name() override { return "Skew"; } - -private: - float mSx; - float mSy; -}; - -class SetMatrixOp : public StateOp { -public: - SetMatrixOp(const SkMatrix& matrix) - : mMatrix(matrix) {} - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - // Setting a matrix on a Canvas isn't equivalent to setting a total matrix on the scene. - // Set a canvas-relative matrix on the renderer instead. - renderer.setLocalMatrix(mMatrix); - } - - virtual void output(int level, uint32_t logFlags) const override { - if (mMatrix.isIdentity()) { - OP_LOGS("SetMatrix (reset)"); - } else { - OP_LOG("SetMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(&mMatrix)); - } - } - - virtual const char* name() override { return "SetMatrix"; } - -private: - const SkMatrix mMatrix; -}; - -class ConcatMatrixOp : public StateOp { -public: - ConcatMatrixOp(const SkMatrix& matrix) - : mMatrix(matrix) {} - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - renderer.concatMatrix(mMatrix); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("ConcatMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(&mMatrix)); - } - - virtual const char* name() override { return "ConcatMatrix"; } - -private: - const SkMatrix mMatrix; -}; - -class ClipOp : public StateOp { -public: - ClipOp(SkRegion::Op op) : mOp(op) {} - - virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, - bool useQuickReject) override { - // NOTE: must defer op BEFORE applying state, since it may read clip - deferStruct.mDeferredList.addClip(deferStruct.mRenderer, this); - - // TODO: Can we avoid applying complex clips at defer time? - applyState(deferStruct.mRenderer, saveCount); - } - - bool canCauseComplexClip() { - return ((mOp != SkRegion::kIntersect_Op) && (mOp != SkRegion::kReplace_Op)) || !isRect(); - } - -protected: - virtual bool isRect() { return false; } - - SkRegion::Op mOp; -}; - -class ClipRectOp : public ClipOp { -public: - ClipRectOp(float left, float top, float right, float bottom, SkRegion::Op op) - : ClipOp(op), mArea(left, top, right, bottom) {} - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - renderer.clipRect(mArea.left, mArea.top, mArea.right, mArea.bottom, mOp); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("ClipRect " RECT_STRING, RECT_ARGS(mArea)); - } - - virtual const char* name() override { return "ClipRect"; } - -protected: - virtual bool isRect() override { return true; } - -private: - Rect mArea; -}; - -class ClipPathOp : public ClipOp { -public: - ClipPathOp(const SkPath* path, SkRegion::Op op) - : ClipOp(op), mPath(path) {} - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - renderer.clipPath(mPath, mOp); - } - - virtual void output(int level, uint32_t logFlags) const override { - SkRect bounds = mPath->getBounds(); - OP_LOG("ClipPath bounds " RECT_STRING, - bounds.left(), bounds.top(), bounds.right(), bounds.bottom()); - } - - virtual const char* name() override { return "ClipPath"; } - -private: - const SkPath* mPath; -}; - -class ClipRegionOp : public ClipOp { -public: - ClipRegionOp(const SkRegion* region, SkRegion::Op op) - : ClipOp(op), mRegion(region) {} - - virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { - renderer.clipRegion(mRegion, mOp); - } - - virtual void output(int level, uint32_t logFlags) const override { - SkIRect bounds = mRegion->getBounds(); - OP_LOG("ClipRegion bounds %d %d %d %d", - bounds.left(), bounds.top(), bounds.right(), bounds.bottom()); - } - - virtual const char* name() override { return "ClipRegion"; } - -private: - const SkRegion* mRegion; -}; - -/////////////////////////////////////////////////////////////////////////////// -// DRAW OPERATIONS - these are operations that can draw to the canvas's device -/////////////////////////////////////////////////////////////////////////////// - -class DrawBitmapOp : public DrawBoundedOp { -public: - DrawBitmapOp(const SkBitmap* bitmap, const SkPaint* paint) - : DrawBoundedOp(0, 0, bitmap->width(), bitmap->height(), paint) - , mBitmap(bitmap) - , mEntryValid(false), mEntry(nullptr) { - } - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawBitmap(mBitmap, mPaint); - } - - AssetAtlas::Entry* getAtlasEntry(OpenGLRenderer& renderer) { - if (!mEntryValid) { - mEntryValid = true; - mEntry = renderer.renderState().assetAtlas().getEntry(mBitmap->pixelRef()); - } - return mEntry; - } - -#define SET_TEXTURE(ptr, posRect, offsetRect, texCoordsRect, xDim, yDim) \ - TextureVertex::set((ptr)++, (posRect).xDim - (offsetRect).left, (posRect).yDim - (offsetRect).top, \ - (texCoordsRect).xDim, (texCoordsRect).yDim) - - /** - * This multi-draw operation builds a mesh on the stack by generating a quad - * for each bitmap in the batch. This method is also responsible for dirtying - * the current layer, if any. - */ - virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty, - const std::vector<OpStatePair>& ops, const Rect& bounds) override { - const DeferredDisplayState& firstState = *(ops[0].state); - renderer.restoreDisplayState(firstState, true); // restore all but the clip - - TextureVertex vertices[6 * ops.size()]; - TextureVertex* vertex = &vertices[0]; - - const bool hasLayer = renderer.hasLayer(); - bool pureTranslate = true; - - // TODO: manually handle rect clip for bitmaps by adjusting texCoords per op, - // and allowing them to be merged in getBatchId() - for (unsigned int i = 0; i < ops.size(); i++) { - const DeferredDisplayState& state = *(ops[i].state); - const Rect& opBounds = state.mBounds; - // When we reach multiDraw(), the matrix can be either - // pureTranslate or simple (translate and/or scale). - // If the matrix is not pureTranslate, then we have a scale - pureTranslate &= state.mMatrix.isPureTranslate(); - - Rect texCoords(0, 0, 1, 1); - ((DrawBitmapOp*) ops[i].op)->uvMap(renderer, texCoords); - - SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, top); - SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top); - SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, bottom); - - SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, bottom); - SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top); - SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, bottom); - - if (hasLayer) { - renderer.dirtyLayer(opBounds.left, opBounds.top, opBounds.right, opBounds.bottom); - } - } - - renderer.drawBitmaps(mBitmap, mEntry, ops.size(), &vertices[0], - pureTranslate, bounds, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw bitmap %p of size %dx%d%s", - mBitmap, mBitmap->width(), mBitmap->height(), - mEntry ? " using AssetAtlas" : ""); - } - - virtual const char* name() override { return "DrawBitmap"; } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap; - deferInfo.mergeId = getAtlasEntry(renderer) ? - (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap; - - // Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation - // Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in - // MergingDrawBatch::canMergeWith() - // TODO: support clipped bitmaps by handling them in SET_TEXTURE - deferInfo.mergeable = state.mMatrix.isSimple() && state.mMatrix.positiveScale() && - !state.mClipSideFlags && - PaintUtils::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode && - (mBitmap->colorType() != kAlpha_8_SkColorType); - } - - void uvMap(OpenGLRenderer& renderer, Rect& texCoords) { - if (getAtlasEntry(renderer)) { - mEntry->uvMapper.map(texCoords); - } - } - - const SkBitmap* bitmap() { return mBitmap; } -protected: - const SkBitmap* mBitmap; - bool mEntryValid; - AssetAtlas::Entry* mEntry; -}; - -class DrawBitmapRectOp : public DrawBoundedOp { -public: - DrawBitmapRectOp(const SkBitmap* bitmap, - float srcLeft, float srcTop, float srcRight, float srcBottom, - float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) - : DrawBoundedOp(dstLeft, dstTop, dstRight, dstBottom, paint), - mBitmap(bitmap), mSrc(srcLeft, srcTop, srcRight, srcBottom) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawBitmap(mBitmap, mSrc, mLocalBounds, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw bitmap %p src=" RECT_STRING ", dst=" RECT_STRING, - mBitmap, RECT_ARGS(mSrc), RECT_ARGS(mLocalBounds)); - } - - virtual const char* name() override { return "DrawBitmapRect"; } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap; - } - -private: - const SkBitmap* mBitmap; - Rect mSrc; -}; - -class DrawBitmapMeshOp : public DrawBoundedOp { -public: - DrawBitmapMeshOp(const SkBitmap* bitmap, int meshWidth, int meshHeight, - const float* vertices, const int* colors, const SkPaint* paint) - : DrawBoundedOp(vertices, 2 * (meshWidth + 1) * (meshHeight + 1), paint), - mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight), - mVertices(vertices), mColors(colors) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawBitmapMesh(mBitmap, mMeshWidth, mMeshHeight, - mVertices, mColors, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw bitmap %p mesh %d x %d", mBitmap, mMeshWidth, mMeshHeight); - } - - virtual const char* name() override { return "DrawBitmapMesh"; } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap; - } - -private: - const SkBitmap* mBitmap; - int mMeshWidth; - int mMeshHeight; - const float* mVertices; - const int* mColors; -}; - -class DrawPatchOp : public DrawBoundedOp { -public: - DrawPatchOp(const SkBitmap* bitmap, const Res_png_9patch* patch, - float left, float top, float right, float bottom, const SkPaint* paint) - : DrawBoundedOp(left, top, right, bottom, paint), - mBitmap(bitmap), mPatch(patch), mGenerationId(0), mMesh(nullptr), - mEntryValid(false), mEntry(nullptr) { - }; - - AssetAtlas::Entry* getAtlasEntry(OpenGLRenderer& renderer) { - if (!mEntryValid) { - mEntryValid = true; - mEntry = renderer.renderState().assetAtlas().getEntry(mBitmap->pixelRef()); - } - return mEntry; - } - - const Patch* getMesh(OpenGLRenderer& renderer) { - if (!mMesh || renderer.getCaches().patchCache.getGenerationId() != mGenerationId) { - PatchCache& cache = renderer.getCaches().patchCache; - mMesh = cache.get(getAtlasEntry(renderer), mBitmap->width(), mBitmap->height(), - mLocalBounds.getWidth(), mLocalBounds.getHeight(), mPatch); - mGenerationId = cache.getGenerationId(); - } - return mMesh; - } - - /** - * This multi-draw operation builds an indexed mesh on the stack by copying - * and transforming the vertices of each 9-patch in the batch. This method - * is also responsible for dirtying the current layer, if any. - */ - virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty, - const std::vector<OpStatePair>& ops, const Rect& bounds) override { - const DeferredDisplayState& firstState = *(ops[0].state); - renderer.restoreDisplayState(firstState, true); // restore all but the clip - - // Batches will usually contain a small number of items so it's - // worth performing a first iteration to count the exact number - // of vertices we need in the new mesh - uint32_t totalVertices = 0; - for (unsigned int i = 0; i < ops.size(); i++) { - totalVertices += ((DrawPatchOp*) ops[i].op)->getMesh(renderer)->verticesCount; - } - - const bool hasLayer = renderer.hasLayer(); - - uint32_t indexCount = 0; - - TextureVertex vertices[totalVertices]; - TextureVertex* vertex = &vertices[0]; - - // Create a mesh that contains the transformed vertices for all the - // 9-patch objects that are part of the batch. Note that onDefer() - // enforces ops drawn by this function to have a pure translate or - // identity matrix - for (unsigned int i = 0; i < ops.size(); i++) { - DrawPatchOp* patchOp = (DrawPatchOp*) ops[i].op; - const DeferredDisplayState* state = ops[i].state; - const Patch* opMesh = patchOp->getMesh(renderer); - uint32_t vertexCount = opMesh->verticesCount; - if (vertexCount == 0) continue; - - // We use the bounds to know where to translate our vertices - // Using patchOp->state.mBounds wouldn't work because these - // bounds are clipped - const float tx = (int) floorf(state->mMatrix.getTranslateX() + - patchOp->mLocalBounds.left + 0.5f); - const float ty = (int) floorf(state->mMatrix.getTranslateY() + - patchOp->mLocalBounds.top + 0.5f); - - // Copy & transform all the vertices for the current operation - TextureVertex* opVertices = opMesh->vertices.get(); - for (uint32_t j = 0; j < vertexCount; j++, opVertices++) { - TextureVertex::set(vertex++, - opVertices->x + tx, opVertices->y + ty, - opVertices->u, opVertices->v); - } - - // Dirty the current layer if possible. When the 9-patch does not - // contain empty quads we can take a shortcut and simply set the - // dirty rect to the object's bounds. - if (hasLayer) { - if (!opMesh->hasEmptyQuads) { - renderer.dirtyLayer(tx, ty, - tx + patchOp->mLocalBounds.getWidth(), - ty + patchOp->mLocalBounds.getHeight()); - } else { - const size_t count = opMesh->quads.size(); - for (size_t i = 0; i < count; i++) { - const Rect& quadBounds = opMesh->quads[i]; - const float x = tx + quadBounds.left; - const float y = ty + quadBounds.top; - renderer.dirtyLayer(x, y, - x + quadBounds.getWidth(), y + quadBounds.getHeight()); - } - } - } - - indexCount += opMesh->indexCount; - } - - renderer.drawPatches(mBitmap, getAtlasEntry(renderer), - &vertices[0], indexCount, mPaint); - } - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - // We're not calling the public variant of drawPatch() here - // This method won't perform the quickReject() since we've already done it at this point - renderer.drawPatch(mBitmap, getMesh(renderer), getAtlasEntry(renderer), - mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom, - mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw patch " RECT_STRING "%s", RECT_ARGS(mLocalBounds), - mEntry ? " with AssetAtlas" : ""); - } - - virtual const char* name() override { return "DrawPatch"; } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - deferInfo.batchId = DeferredDisplayList::kOpBatch_Patch; - deferInfo.mergeId = getAtlasEntry(renderer) ? (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap; - deferInfo.mergeable = state.mMatrix.isPureTranslate() && - PaintUtils::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode; - deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) && mBitmap->isOpaque(); - } - -private: - const SkBitmap* mBitmap; - const Res_png_9patch* mPatch; - - uint32_t mGenerationId; - const Patch* mMesh; - - bool mEntryValid; - AssetAtlas::Entry* mEntry; -}; - -class DrawColorOp : public DrawOp { -public: - DrawColorOp(int color, SkXfermode::Mode mode) - : DrawOp(nullptr), mColor(color), mMode(mode) {}; - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawColor(mColor, mMode); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw color %#x, mode %d", mColor, mMode); - } - - virtual const char* name() override { return "DrawColor"; } - -private: - int mColor; - SkXfermode::Mode mMode; -}; - -class DrawStrokableOp : public DrawBoundedOp { -public: - DrawStrokableOp(float left, float top, float right, float bottom, const SkPaint* paint) - : DrawBoundedOp(left, top, right, bottom, paint) {}; - DrawStrokableOp(const Rect& localBounds, const SkPaint* paint) - : DrawBoundedOp(localBounds, paint) {}; - - virtual bool getLocalBounds(Rect& localBounds) override { - localBounds.set(mLocalBounds); - if (mPaint && mPaint->getStyle() != SkPaint::kFill_Style) { - localBounds.outset(strokeWidthOutset()); - } - return true; - } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - if (mPaint->getPathEffect()) { - deferInfo.batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture; - } else { - deferInfo.batchId = mPaint->isAntiAlias() ? - DeferredDisplayList::kOpBatch_AlphaVertices : - DeferredDisplayList::kOpBatch_Vertices; - } - } -}; - -class DrawRectOp : public DrawStrokableOp { -public: - DrawRectOp(float left, float top, float right, float bottom, const SkPaint* paint) - : DrawStrokableOp(left, top, right, bottom, paint) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawRect(mLocalBounds.left, mLocalBounds.top, - mLocalBounds.right, mLocalBounds.bottom, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Rect " RECT_STRING, RECT_ARGS(mLocalBounds)); - } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - DrawStrokableOp::onDefer(renderer, deferInfo, state); - deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) && - mPaint->getStyle() == SkPaint::kFill_Style; - } - - virtual const char* name() override { return "DrawRect"; } -}; - -class DrawRectsOp : public DrawBoundedOp { -public: - DrawRectsOp(const float* rects, int count, const SkPaint* paint) - : DrawBoundedOp(rects, count, paint), - mRects(rects), mCount(count) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawRects(mRects, mCount, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Rects count %d", mCount); - } - - virtual const char* name() override { return "DrawRects"; } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - deferInfo.batchId = DeferredDisplayList::kOpBatch_Vertices; - } - -private: - const float* mRects; - int mCount; -}; - -class DrawRoundRectOp : public DrawStrokableOp { -public: - DrawRoundRectOp(float left, float top, float right, float bottom, - float rx, float ry, const SkPaint* paint) - : DrawStrokableOp(left, top, right, bottom, paint), mRx(rx), mRy(ry) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawRoundRect(mLocalBounds.left, mLocalBounds.top, - mLocalBounds.right, mLocalBounds.bottom, mRx, mRy, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw RoundRect " RECT_STRING ", rx %f, ry %f", RECT_ARGS(mLocalBounds), mRx, mRy); - } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - DrawStrokableOp::onDefer(renderer, deferInfo, state); - if (!mPaint->getPathEffect()) { - renderer.getCaches().tessellationCache.precacheRoundRect(state.mMatrix, *mPaint, - mLocalBounds.getWidth(), mLocalBounds.getHeight(), mRx, mRy); - } - } - - virtual const char* name() override { return "DrawRoundRect"; } - -private: - float mRx; - float mRy; -}; - -class DrawRoundRectPropsOp : public DrawOp { -public: - DrawRoundRectPropsOp(float* left, float* top, float* right, float* bottom, - float *rx, float *ry, const SkPaint* paint) - : DrawOp(paint), mLeft(left), mTop(top), mRight(right), mBottom(bottom), - mRx(rx), mRy(ry) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawRoundRect(*mLeft, *mTop, *mRight, *mBottom, - *mRx, *mRy, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw RoundRect Props " RECT_STRING ", rx %f, ry %f", - *mLeft, *mTop, *mRight, *mBottom, *mRx, *mRy); - } - - virtual const char* name() override { return "DrawRoundRectProps"; } - -private: - float* mLeft; - float* mTop; - float* mRight; - float* mBottom; - float* mRx; - float* mRy; -}; - -class DrawCircleOp : public DrawStrokableOp { -public: - DrawCircleOp(float x, float y, float radius, const SkPaint* paint) - : DrawStrokableOp(x - radius, y - radius, x + radius, y + radius, paint), - mX(x), mY(y), mRadius(radius) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawCircle(mX, mY, mRadius, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Circle x %f, y %f, r %f", mX, mY, mRadius); - } - - virtual const char* name() override { return "DrawCircle"; } - -private: - float mX; - float mY; - float mRadius; -}; - -class DrawCirclePropsOp : public DrawOp { -public: - DrawCirclePropsOp(float* x, float* y, float* radius, const SkPaint* paint) - : DrawOp(paint), mX(x), mY(y), mRadius(radius) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawCircle(*mX, *mY, *mRadius, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Circle Props x %p, y %p, r %p", mX, mY, mRadius); - } - - virtual const char* name() override { return "DrawCircleProps"; } - -private: - float* mX; - float* mY; - float* mRadius; -}; - -class DrawVectorDrawableOp : public DrawOp { -public: - DrawVectorDrawableOp(VectorDrawableRoot* tree, const SkRect& bounds) - : DrawOp(nullptr), mTree(tree), mDst(bounds) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - const SkBitmap& bitmap = mTree->getBitmapUpdateIfDirty(); - SkPaint* paint = mTree->getPaint(); - renderer.drawBitmap(&bitmap, Rect(0, 0, bitmap.width(), bitmap.height()), - mDst, paint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Vector Drawable %p", mTree); - } - - virtual const char* name() override { return "DrawVectorDrawable"; } - -private: - VectorDrawableRoot* mTree; - SkRect mDst; - -}; - -class DrawOvalOp : public DrawStrokableOp { -public: - DrawOvalOp(float left, float top, float right, float bottom, const SkPaint* paint) - : DrawStrokableOp(left, top, right, bottom, paint) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawOval(mLocalBounds.left, mLocalBounds.top, - mLocalBounds.right, mLocalBounds.bottom, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Oval " RECT_STRING, RECT_ARGS(mLocalBounds)); - } - - virtual const char* name() override { return "DrawOval"; } -}; - -class DrawArcOp : public DrawStrokableOp { -public: - DrawArcOp(float left, float top, float right, float bottom, - float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint) - : DrawStrokableOp(left, top, right, bottom, paint), - mStartAngle(startAngle), mSweepAngle(sweepAngle), mUseCenter(useCenter) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawArc(mLocalBounds.left, mLocalBounds.top, - mLocalBounds.right, mLocalBounds.bottom, - mStartAngle, mSweepAngle, mUseCenter, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Arc " RECT_STRING ", start %f, sweep %f, useCenter %d", - RECT_ARGS(mLocalBounds), mStartAngle, mSweepAngle, mUseCenter); - } - - virtual const char* name() override { return "DrawArc"; } - -private: - float mStartAngle; - float mSweepAngle; - bool mUseCenter; -}; - -class DrawPathOp : public DrawBoundedOp { -public: - DrawPathOp(const SkPath* path, const SkPaint* paint) - : DrawBoundedOp(paint), mPath(path) { - float left, top, offset; - uint32_t width, height; - PathCache::computePathBounds(path, paint, left, top, offset, width, height); - left -= offset; - top -= offset; - mLocalBounds.set(left, top, left + width, top + height); - } - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawPath(mPath, mPaint); - } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - renderer.getCaches().pathCache.precache(mPath, mPaint); - - deferInfo.batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture; - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Path %p in " RECT_STRING, mPath, RECT_ARGS(mLocalBounds)); - } - - virtual const char* name() override { return "DrawPath"; } - -private: - const SkPath* mPath; -}; - -class DrawLinesOp : public DrawBoundedOp { -public: - DrawLinesOp(const float* points, int count, const SkPaint* paint) - : DrawBoundedOp(points, count, paint), - mPoints(points), mCount(count) { - mLocalBounds.outset(strokeWidthOutset()); - } - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawLines(mPoints, mCount, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Lines count %d", mCount); - } - - virtual const char* name() override { return "DrawLines"; } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - deferInfo.batchId = mPaint->isAntiAlias() ? - DeferredDisplayList::kOpBatch_AlphaVertices : - DeferredDisplayList::kOpBatch_Vertices; - } - -protected: - const float* mPoints; - int mCount; -}; - -class DrawPointsOp : public DrawLinesOp { -public: - DrawPointsOp(const float* points, int count, const SkPaint* paint) - : DrawLinesOp(points, count, paint) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawPoints(mPoints, mCount, mPaint); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Points count %d", mCount); - } - - virtual const char* name() override { return "DrawPoints"; } -}; - -class DrawSomeTextOp : public DrawOp { -public: - DrawSomeTextOp(const glyph_t* text, int bytesCount, int count, const SkPaint* paint) - : DrawOp(paint), mText(text), mBytesCount(bytesCount), mCount(count) {}; - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw some text, %d bytes", mBytesCount); - } - - virtual bool hasTextShadow() const override { - return PaintUtils::hasTextShadow(mPaint); - } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - FontRenderer& fontRenderer = renderer.getCaches().fontRenderer.getFontRenderer(); - fontRenderer.precache(mPaint, mText, mCount, SkMatrix::I()); - - deferInfo.batchId = mPaint->getColor() == SK_ColorBLACK ? - DeferredDisplayList::kOpBatch_Text : - DeferredDisplayList::kOpBatch_ColorText; - } - -protected: - const glyph_t* mText; - int mBytesCount; - int mCount; -}; - -class DrawTextOnPathOp : public DrawSomeTextOp { -public: - DrawTextOnPathOp(const glyph_t* text, int bytesCount, int count, - const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) - : DrawSomeTextOp(text, bytesCount, count, paint), - mPath(path), mHOffset(hOffset), mVOffset(vOffset) { - /* TODO: inherit from DrawBounded and init mLocalBounds */ - } - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawTextOnPath(mText, mBytesCount, mCount, mPath, - mHOffset, mVOffset, mPaint); - } - - virtual const char* name() override { return "DrawTextOnPath"; } - -private: - const SkPath* mPath; - float mHOffset; - float mVOffset; -}; - -class DrawTextOp : public DrawStrokableOp { -public: - DrawTextOp(const glyph_t* text, int bytesCount, int count, float x, float y, - const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds) - : DrawStrokableOp(bounds, paint), mText(text), mBytesCount(bytesCount), mCount(count), - mX(x), mY(y), mPositions(positions), mTotalAdvance(totalAdvance) { - mPrecacheTransform = SkMatrix::InvalidMatrix(); - } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - FontRenderer& fontRenderer = renderer.getCaches().fontRenderer.getFontRenderer(); - SkMatrix transform; - renderer.findBestFontTransform(state.mMatrix, &transform); - if (mPrecacheTransform != transform) { - fontRenderer.precache(mPaint, mText, mCount, transform); - mPrecacheTransform = transform; - } - deferInfo.batchId = mPaint->getColor() == SK_ColorBLACK ? - DeferredDisplayList::kOpBatch_Text : - DeferredDisplayList::kOpBatch_ColorText; - - deferInfo.mergeId = reinterpret_cast<mergeid_t>(mPaint->getColor()); - - // don't merge decorated text - the decorations won't draw in order - bool hasDecorations = mPaint->getFlags() - & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag); - - deferInfo.mergeable = state.mMatrix.isPureTranslate() - && !hasDecorations - && PaintUtils::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode; - } - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - Rect bounds; - getLocalBounds(bounds); - renderer.drawText(mText, mBytesCount, mCount, mX, mY, - mPositions, mPaint, mTotalAdvance, bounds); - } - - virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty, - const std::vector<OpStatePair>& ops, const Rect& bounds) override { - for (unsigned int i = 0; i < ops.size(); i++) { - const DeferredDisplayState& state = *(ops[i].state); - DrawOpMode drawOpMode = (i == ops.size() - 1) ? DrawOpMode::kFlush : DrawOpMode::kDefer; - renderer.restoreDisplayState(state, true); // restore all but the clip - - DrawTextOp& op = *((DrawTextOp*)ops[i].op); - // quickReject() will not occure in drawText() so we can use mLocalBounds - // directly, we do not need to account for shadow by calling getLocalBounds() - renderer.drawText(op.mText, op.mBytesCount, op.mCount, op.mX, op.mY, - op.mPositions, op.mPaint, op.mTotalAdvance, op.mLocalBounds, - drawOpMode); - } - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Text of count %d, bytes %d", mCount, mBytesCount); - } - - virtual const char* name() override { return "DrawText"; } - -private: - const glyph_t* mText; - int mBytesCount; - int mCount; - float mX; - float mY; - const float* mPositions; - float mTotalAdvance; - SkMatrix mPrecacheTransform; -}; - -/////////////////////////////////////////////////////////////////////////////// -// SPECIAL DRAW OPERATIONS -/////////////////////////////////////////////////////////////////////////////// - -class DrawFunctorOp : public DrawOp { -public: - DrawFunctorOp(Functor* functor) - : DrawOp(nullptr), mFunctor(functor) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.startMark("GL functor"); - renderer.callDrawGLFunction(mFunctor, dirty); - renderer.endMark(); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Functor %p", mFunctor); - } - - virtual const char* name() override { return "DrawFunctor"; } - -private: - Functor* mFunctor; -}; - -class DrawRenderNodeOp : public DrawBoundedOp { - friend class RenderNode; // grant RenderNode access to info of child - friend class DisplayList; // grant DisplayList access to info of child - friend class DisplayListCanvas; - friend class TestUtils; -public: - DrawRenderNodeOp(RenderNode* renderNode, const mat4& transformFromParent, bool clipIsSimple) - : DrawBoundedOp(0, 0, - renderNode->stagingProperties().getWidth(), - renderNode->stagingProperties().getHeight(), - nullptr) - , renderNode(renderNode) - , mRecordedWithPotentialStencilClip(!clipIsSimple || !transformFromParent.isSimple()) - , localMatrix(transformFromParent) - , skipInOrderDraw(false) {} - - virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level, - bool useQuickReject) override { - if (renderNode->isRenderable() && !skipInOrderDraw) { - renderNode->defer(deferStruct, level + 1); - } - } - - virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level, - bool useQuickReject) override { - if (renderNode->isRenderable() && !skipInOrderDraw) { - renderNode->replay(replayStruct, level + 1); - } - } - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - LOG_ALWAYS_FATAL("should not be called, because replay() is overridden"); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw RenderNode %p %s", renderNode, renderNode->getName()); - if (renderNode && (logFlags & kOpLogFlag_Recurse)) { - renderNode->output(level + 1); - } - } - - virtual const char* name() override { return "DrawRenderNode"; } - -private: - RenderNode* renderNode; - - /** - * This RenderNode was drawn into a DisplayList with the canvas in a state that will likely - * require rendering with stencil clipping. Either: - * - * 1) A path clip or rotated rect clip was in effect on the canvas at record time - * 2) The RenderNode was recorded with a non-simple canvas transform (e.g. rotation) - * - * Note: even if this is false, non-rect clipping may still be applied applied either due to - * property-driven rotation (either in this RenderNode, or any ancestor), or record time - * clipping in an ancestor. These are handled in RenderNode::prepareTreeImpl since they are - * dynamic (relative to a static DisplayList of a parent), and don't affect this flag. - */ - bool mRecordedWithPotentialStencilClip; - - /////////////////////////// - // Properties below are used by RenderNode::computeOrderingImpl() and issueOperations() - /////////////////////////// - /** - * Records transform vs parent, used for computing total transform without rerunning DL contents - */ - const mat4 localMatrix; - - /** - * Holds the transformation between the projection surface ViewGroup and this RenderNode - * drawing instance. Represents any translations / transformations done within the drawing of - * the compositing ancestor ViewGroup's draw, before the draw of the View represented by this - * DisplayList draw instance. - * - * Note: doesn't include transformation within the RenderNode, or its properties. - */ - mat4 transformFromCompositingAncestor; - bool skipInOrderDraw; -}; - -/** - * Not a canvas operation, used only by 3d / z ordering logic in RenderNode::iterate() - */ -class DrawShadowOp : public DrawOp { -public: - DrawShadowOp(const mat4& transformXY, const mat4& transformZ, - float casterAlpha, const SkPath* casterOutline) - : DrawOp(nullptr) - , mTransformXY(transformXY) - , mTransformZ(transformZ) - , mCasterAlpha(casterAlpha) - , mCasterOutline(casterOutline) { - } - - virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo, - const DeferredDisplayState& state) override { - renderer.getCaches().tessellationCache.precacheShadows(&state.mMatrix, - renderer.getLocalClipBounds(), isCasterOpaque(), mCasterOutline, - &mTransformXY, &mTransformZ, renderer.getLightCenter(), renderer.getLightRadius()); - } - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - TessellationCache::vertexBuffer_pair_t buffers; - Matrix4 drawTransform(*(renderer.currentTransform())); - renderer.getCaches().tessellationCache.getShadowBuffers(&drawTransform, - renderer.getLocalClipBounds(), isCasterOpaque(), mCasterOutline, - &mTransformXY, &mTransformZ, renderer.getLightCenter(), renderer.getLightRadius(), - buffers); - - renderer.drawShadow(mCasterAlpha, buffers.first, buffers.second); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOGS("DrawShadow"); - } - - virtual const char* name() override { return "DrawShadow"; } - -private: - bool isCasterOpaque() { return mCasterAlpha >= 1.0f; } - - const mat4 mTransformXY; - const mat4 mTransformZ; - const float mCasterAlpha; - const SkPath* mCasterOutline; -}; - -class DrawLayerOp : public DrawOp { -public: - DrawLayerOp(Layer* layer) - : DrawOp(nullptr), mLayer(layer) {} - - virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { - renderer.drawLayer(mLayer); - } - - virtual void output(int level, uint32_t logFlags) const override { - OP_LOG("Draw Layer %p", mLayer); - } - - virtual const char* name() override { return "DrawLayer"; } - -private: - Layer* mLayer; -}; - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_DISPLAY_OPERATION_H diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index 276c18d0d3f9..25dc92c8a8dc 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -16,6 +16,9 @@ #include "FontRenderer.h" +#include "BakedOpDispatcher.h" +#include "BakedOpRenderer.h" +#include "BakedOpState.h" #include "Caches.h" #include "Debug.h" #include "Extensions.h" @@ -27,15 +30,6 @@ #include "utils/Blur.h" #include "utils/Timing.h" - -#if HWUI_NEW_OPS -#include "BakedOpDispatcher.h" -#include "BakedOpRenderer.h" -#include "BakedOpState.h" -#else -#include "OpenGLRenderer.h" -#endif - #include <algorithm> #include <cutils/properties.h> #include <SkGlyph.h> @@ -67,7 +61,6 @@ void TextDrawFunctor::draw(CacheTexture& texture, bool linearFiltering) { int transformFlags = pureTranslate ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None; Glop glop; -#if HWUI_NEW_OPS GlopBuilder(renderer->renderState(), renderer->caches(), &glop) .setRoundRectClipState(bakedState->roundRectClipState) .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount()) @@ -77,16 +70,6 @@ void TextDrawFunctor::draw(CacheTexture& texture, bool linearFiltering) { .build(); // Note: don't pass dirty bounds here, so user must manage passing dirty bounds to renderer renderer->renderGlop(nullptr, clip, glop); -#else - GlopBuilder(renderer->mRenderState, renderer->mCaches, &glop) - .setRoundRectClipState(renderer->currentSnapshot()->roundRectClipState) - .setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount()) - .setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, renderer->currentSnapshot()->alpha) - .setTransform(*(renderer->currentSnapshot()), transformFlags) - .setModelViewOffsetRect(0, 0, Rect()) - .build(); - renderer->renderGlop(glop); -#endif } /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h index e10a81b8ccd8..dedc4944299d 100644 --- a/libs/hwui/FontRenderer.h +++ b/libs/hwui/FontRenderer.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_FONT_RENDERER_H -#define ANDROID_HWUI_FONT_RENDERER_H +#pragma once #include "font/FontUtil.h" #include "font/CacheTexture.h" @@ -44,31 +43,21 @@ namespace RSC { namespace android { namespace uirenderer { -#if HWUI_NEW_OPS class BakedOpState; class BakedOpRenderer; struct ClipBase; -#else -class OpenGLRenderer; -#endif class TextDrawFunctor { public: TextDrawFunctor( -#if HWUI_NEW_OPS BakedOpRenderer* renderer, const BakedOpState* bakedState, const ClipBase* clip, -#else - OpenGLRenderer* renderer, -#endif float x, float y, bool pureTranslate, int alpha, SkXfermode::Mode mode, const SkPaint* paint) : renderer(renderer) -#if HWUI_NEW_OPS , bakedState(bakedState) , clip(clip) -#endif , x(x) , y(y) , pureTranslate(pureTranslate) @@ -79,13 +68,9 @@ public: void draw(CacheTexture& texture, bool linearFiltering); -#if HWUI_NEW_OPS BakedOpRenderer* renderer; const BakedOpState* bakedState; const ClipBase* clip; -#else - OpenGLRenderer* renderer; -#endif float x; float y; bool pureTranslate; @@ -218,5 +203,3 @@ private: }; // namespace uirenderer }; // namespace android - -#endif // ANDROID_HWUI_FONT_RENDERER_H diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp index 37d9d0e749e6..be4fdac5f800 100644 --- a/libs/hwui/FrameBuilder.cpp +++ b/libs/hwui/FrameBuilder.cpp @@ -477,7 +477,7 @@ void FrameBuilder::deferProjectedChildren(const RenderNode& renderNode) { projectionReceiverOutline->transform( skCurrentTransform, &transformedMaskPath); - mCanvasState.setProjectionPathMask(mAllocator, &transformedMaskPath); + mCanvasState.setProjectionPathMask(&transformedMaskPath); } for (size_t i = 0; i < renderNode.mProjectedNodes.size(); i++) { diff --git a/libs/hwui/FrameInfoVisualizer.cpp b/libs/hwui/FrameInfoVisualizer.cpp index adadd32a2fc0..570322dfb4eb 100644 --- a/libs/hwui/FrameInfoVisualizer.cpp +++ b/libs/hwui/FrameInfoVisualizer.cpp @@ -15,11 +15,7 @@ */ #include "FrameInfoVisualizer.h" -#if HWUI_NEW_OPS #include "BakedOpRenderer.h" -#else -#include "OpenGLRenderer.h" -#endif #include "utils/Color.h" #include <cutils/compiler.h> diff --git a/libs/hwui/FrameInfoVisualizer.h b/libs/hwui/FrameInfoVisualizer.h index 83adf1985c72..fc958b8b414a 100644 --- a/libs/hwui/FrameInfoVisualizer.h +++ b/libs/hwui/FrameInfoVisualizer.h @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef DRAWPROFILER_H -#define DRAWPROFILER_H + +#pragma once #include "FrameInfo.h" #include "Properties.h" @@ -28,13 +28,8 @@ namespace android { namespace uirenderer { -#if HWUI_NEW_OPS class BakedOpRenderer; typedef BakedOpRenderer ContentRenderer; -#else -class OpenGLRenderer; -typedef OpenGLRenderer ContentRenderer; -#endif // TODO: This is a bit awkward as it needs to match the thing in CanvasContext // A better abstraction here would be nice but iterators are painful @@ -93,5 +88,3 @@ private: } /* namespace uirenderer */ } /* namespace android */ - -#endif /* DRAWPROFILER_H */ diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h index 6433c86908e7..46dd598711b8 100644 --- a/libs/hwui/Glop.h +++ b/libs/hwui/Glop.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_GLOP_H -#define ANDROID_HWUI_GLOP_H +#pragma once #include "FloatColor.h" #include "Matrix.h" @@ -68,7 +67,7 @@ namespace TransformFlags { OffsetByFudgeFactor = 1 << 0, // Canvas transform isn't applied to the mesh at draw time, - //since it's already built in. + // since it's already built in. MeshIgnoresCanvasTransform = 1 << 1, // TODO: remove for HWUI_NEW_OPS }; }; @@ -168,14 +167,6 @@ public: GLenum dst; } blend; -#if !HWUI_NEW_OPS - /** - * Bounds of the drawing command in layer space. Only mapped into layer - * space once GlopBuilder::build() is called. - */ - Rect bounds; // TODO: remove for HWUI_NEW_OPS -#endif - /** * Additional render state to enumerate: * - scissor + (bits for whether each of LTRB needed?) @@ -185,5 +176,3 @@ public: } /* namespace uirenderer */ } /* namespace android */ - -#endif // ANDROID_HWUI_GLOP_H diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp index e502725ddb09..1091736ab9c3 100644 --- a/libs/hwui/GlopBuilder.cpp +++ b/libs/hwui/GlopBuilder.cpp @@ -17,8 +17,10 @@ #include "Caches.h" #include "Glop.h" +#include "Layer.h" #include "Matrix.h" #include "Patch.h" +#include "PathCache.h" #include "renderstate/MeshState.h" #include "renderstate/RenderState.h" #include "SkiaShader.h" @@ -165,20 +167,6 @@ GlopBuilder& GlopBuilder::setMeshTexturedIndexedQuads(TextureVertex* vertexData, return *this; } -GlopBuilder& GlopBuilder::setMeshTexturedMesh(TextureVertex* vertexData, int elementCount) { - TRIGGER_STAGE(kMeshStage); - - mOutGlop->mesh.primitiveMode = GL_TRIANGLES; - mOutGlop->mesh.indices = { 0, nullptr }; - mOutGlop->mesh.vertices = { - 0, - VertexAttribFlags::TextureCoord, - &vertexData[0].x, &vertexData[0].u, nullptr, - kTextureVertexStride }; - mOutGlop->mesh.elementCount = elementCount; - return *this; -} - GlopBuilder& GlopBuilder::setMeshColoredTexturedMesh(ColorTextureVertex* vertexData, int elementCount) { TRIGGER_STAGE(kMeshStage); @@ -514,9 +502,6 @@ GlopBuilder& GlopBuilder::setModelViewMapUnitToRect(const Rect destination) { mOutGlop->transform.modelView.loadTranslate(destination.left, destination.top, 0.0f); mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f); -#if !HWUI_NEW_OPS - mOutGlop->bounds = destination; -#endif return *this; } @@ -540,9 +525,6 @@ GlopBuilder& GlopBuilder::setModelViewMapUnitToRectSnap(const Rect destination) mOutGlop->transform.modelView.loadTranslate(left, top, 0.0f); mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f); -#if !HWUI_NEW_OPS - mOutGlop->bounds = destination; -#endif return *this; } @@ -550,10 +532,6 @@ GlopBuilder& GlopBuilder::setModelViewOffsetRect(float offsetX, float offsetY, c TRIGGER_STAGE(kModelViewStage); mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f); -#if !HWUI_NEW_OPS - mOutGlop->bounds = source; - mOutGlop->bounds.translate(offsetX, offsetY); -#endif return *this; } @@ -573,10 +551,6 @@ GlopBuilder& GlopBuilder::setModelViewOffsetRectSnap(float offsetX, float offset } mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f); -#if !HWUI_NEW_OPS - mOutGlop->bounds = source; - mOutGlop->bounds.translate(offsetX, offsetY); -#endif return *this; } @@ -676,9 +650,6 @@ void GlopBuilder::build() { // Final step: populate program and map bounds into render target space mOutGlop->fill.program = mCaches.programCache.get(mDescription); -#if !HWUI_NEW_OPS - mOutGlop->transform.meshTransform().mapRect(mOutGlop->bounds); -#endif } void GlopBuilder::dump(const Glop& glop) { @@ -718,9 +689,6 @@ void GlopBuilder::dump(const Glop& glop) { ALOGD_IF(glop.roundRectClipState, "Glop RRCS %p", glop.roundRectClipState); ALOGD("Glop blend %d %d", glop.blend.src, glop.blend.dst); -#if !HWUI_NEW_OPS - ALOGD("Glop bounds " RECT_STRING, RECT_ARGS(glop.bounds)); -#endif } } /* namespace uirenderer */ diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h index 1c520c26110e..11524615074e 100644 --- a/libs/hwui/GlopBuilder.h +++ b/libs/hwui/GlopBuilder.h @@ -13,11 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef RENDERSTATE_GLOPBUILDER_H -#define RENDERSTATE_GLOPBUILDER_H + +#pragma once #include "Glop.h" -#include "OpenGLRenderer.h" #include "Program.h" #include "renderstate/Blend.h" #include "utils/Macros.h" @@ -30,9 +29,13 @@ namespace uirenderer { class Caches; class Matrix4; +class Patch; class RenderState; class Texture; +class UvMapper; class VertexBuffer; +struct PathTexture; +struct ShadowTexture; namespace TextureFillFlags { enum { @@ -53,7 +56,6 @@ public: GlopBuilder& setMeshTexturedUvQuad(const UvMapper* uvMapper, const Rect uvs); GlopBuilder& setMeshVertexBuffer(const VertexBuffer& vertexBuffer); GlopBuilder& setMeshIndexedQuads(Vertex* vertexData, int quadCount); - GlopBuilder& setMeshTexturedMesh(TextureVertex* vertexData, int elementCount); // TODO: delete GlopBuilder& setMeshColoredTexturedMesh(ColorTextureVertex* vertexData, int elementCount); // TODO: use indexed quads GlopBuilder& setMeshTexturedIndexedQuads(TextureVertex* vertexData, int elementCount); // TODO: take quadCount GlopBuilder& setMeshPatchQuads(const Patch& patch); @@ -75,9 +77,6 @@ public: // Similarly setFillLayer normally forces its own wrap & filter mode GlopBuilder& setFillExternalTexture(Texture& texture, Matrix4& textureTransform); - GlopBuilder& setTransform(const Snapshot& snapshot, const int transformFlags) { - return setTransform(*snapshot.transform, transformFlags); - } GlopBuilder& setTransform(const Matrix4& canvas, const int transformFlags); GlopBuilder& setModelViewMapUnitToRect(const Rect destination); @@ -133,5 +132,3 @@ private: } /* namespace uirenderer */ } /* namespace android */ - -#endif // RENDERSTATE_GLOPBUILDER_H diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index cdbbbab7730d..8c797d5eebd7 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -17,9 +17,6 @@ #include "Layer.h" #include "Caches.h" -#include "DeferredDisplayList.h" -#include "LayerRenderer.h" -#include "OpenGLRenderer.h" #include "RenderNode.h" #include "renderstate/RenderState.h" #include "utils/TraceUtils.h" @@ -35,13 +32,12 @@ namespace android { namespace uirenderer { -Layer::Layer(Type layerType, RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight) +Layer::Layer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight) : GpuMemoryTracker(GpuObjectType::Layer) , state(State::Uncached) , caches(Caches::getInstance()) , renderState(renderState) - , texture(caches) - , type(layerType) { + , texture(caches) { // TODO: This is a violation of Android's typical ref counting, but it // preserves the old inc/dec ref locations. This should be changed... incStrong(nullptr); @@ -55,8 +51,7 @@ Layer::~Layer() { renderState.unregisterLayer(this); SkSafeUnref(colorFilter); - if (stencil || fbo || texture.mId) { - removeFbo(); + if (texture.mId) { texture.deleteTexture(); } @@ -64,116 +59,9 @@ Layer::~Layer() { } void Layer::onGlContextLost() { - removeFbo(); texture.deleteTexture(); } -uint32_t Layer::computeIdealWidth(uint32_t layerWidth) { - return uint32_t(ceilf(layerWidth / float(LAYER_SIZE)) * LAYER_SIZE); -} - -uint32_t Layer::computeIdealHeight(uint32_t layerHeight) { - return uint32_t(ceilf(layerHeight / float(LAYER_SIZE)) * LAYER_SIZE); -} - -void Layer::requireRenderer() { - if (!renderer) { - renderer.reset(new LayerRenderer(renderState, this)); - renderer->initProperties(); - } -} - -void Layer::updateLightPosFromRenderer(const OpenGLRenderer& rootRenderer) { - if (renderer && rendererLightPosDirty) { - // re-init renderer's light position, based upon last cached location in window - Vector3 lightPos = rootRenderer.getLightCenter(); - cachedInvTransformInWindow.mapPoint3d(lightPos); - renderer->initLight(rootRenderer.getLightRadius(), - rootRenderer.getAmbientShadowAlpha(), - rootRenderer.getSpotShadowAlpha()); - renderer->setLightCenter(lightPos); - rendererLightPosDirty = false; - } -} - -bool Layer::resize(const uint32_t width, const uint32_t height) { - uint32_t desiredWidth = computeIdealWidth(width); - uint32_t desiredHeight = computeIdealWidth(height); - - if (desiredWidth <= getWidth() && desiredHeight <= getHeight()) { - return true; - } - - ATRACE_NAME("resizeLayer"); - - const uint32_t maxTextureSize = caches.maxTextureSize; - if (desiredWidth > maxTextureSize || desiredHeight > maxTextureSize) { - ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)", - desiredWidth, desiredHeight, maxTextureSize, maxTextureSize); - return false; - } - - uint32_t oldWidth = getWidth(); - uint32_t oldHeight = getHeight(); - - setSize(desiredWidth, desiredHeight); - - if (fbo) { - caches.textureState().activateTexture(0); - bindTexture(); - allocateTexture(); - - if (glGetError() != GL_NO_ERROR) { - setSize(oldWidth, oldHeight); - return false; - } - } - - if (stencil) { - stencil->bind(); - stencil->resize(desiredWidth, desiredHeight); - - if (glGetError() != GL_NO_ERROR) { - setSize(oldWidth, oldHeight); - return false; - } - } - - return true; -} - -void Layer::removeFbo(bool flush) { - if (stencil) { - GLuint previousFbo = renderState.getFramebuffer(); - renderState.bindFramebuffer(fbo); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0); - renderState.bindFramebuffer(previousFbo); - - caches.renderBufferCache.put(stencil); - stencil = nullptr; - } - - if (fbo) { - if (flush) LayerRenderer::flushLayer(renderState, this); - renderState.deleteFramebuffer(fbo); - fbo = 0; - } -} - -void Layer::updateDeferred(RenderNode* renderNode, int left, int top, int right, int bottom) { - requireRenderer(); - this->renderNode = renderNode; - const Rect r(left, top, right, bottom); - dirtyRect.unionWith(r); - deferredUpdateScheduled = true; -} - -void Layer::setPaint(const SkPaint* paint) { - alpha = PaintUtils::getAlphaDirect(paint); - mode = PaintUtils::getXfermodeDirect(paint); - setColorFilter((paint) ? paint->getColorFilter() : nullptr); -} - void Layer::setColorFilter(SkColorFilter* filter) { SkRefCnt_SafeAssign(colorFilter, filter); } @@ -184,12 +72,6 @@ void Layer::bindTexture() const { } } -void Layer::bindStencilRenderBuffer() const { - if (stencil) { - stencil->bind(); - } -} - void Layer::generateTexture() { if (!texture.mId) { glGenTextures(1, &texture.mId); @@ -206,86 +88,6 @@ void Layer::clearTexture() { texture.mId = 0; } -void Layer::allocateTexture() { -#if DEBUG_LAYERS - ALOGD(" Allocate layer: %dx%d", getWidth(), getHeight()); -#endif - if (texture.mId) { - texture.updateSize(getWidth(), getHeight(), GL_RGBA); - glTexImage2D(renderTarget, 0, GL_RGBA, getWidth(), getHeight(), 0, - GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - } -} - -void Layer::defer(const OpenGLRenderer& rootRenderer) { - ATRACE_LAYER_WORK("Optimize"); - - updateLightPosFromRenderer(rootRenderer); - const float width = layer.getWidth(); - const float height = layer.getHeight(); - - if (dirtyRect.isEmpty() || (dirtyRect.left <= 0 && dirtyRect.top <= 0 && - dirtyRect.right >= width && dirtyRect.bottom >= height)) { - dirtyRect.set(0, 0, width, height); - } - - deferredList.reset(new DeferredDisplayList(dirtyRect)); - - DeferStateStruct deferredState(*deferredList, *renderer, - RenderNode::kReplayFlag_ClipChildren); - - renderer->setupFrameState(width, height, dirtyRect.left, dirtyRect.top, - dirtyRect.right, dirtyRect.bottom, !isBlend()); - - renderNode->computeOrdering(); - renderNode->defer(deferredState, 0); - - deferredUpdateScheduled = false; -} - -void Layer::cancelDefer() { - renderNode = nullptr; - deferredUpdateScheduled = false; - deferredList.reset(nullptr); -} - -void Layer::flush() { - // renderer is checked as layer may be destroyed/put in layer cache with flush scheduled - if (deferredList && renderer) { - ATRACE_LAYER_WORK("Issue"); - renderer->startMark((renderNode.get() != nullptr) ? renderNode->getName() : "Layer"); - - renderer->prepareDirty(layer.getWidth(), layer.getHeight(), - dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom, !isBlend()); - - deferredList->flush(*renderer, dirtyRect); - - renderer->finish(); - - dirtyRect.setEmpty(); - renderNode = nullptr; - - renderer->endMark(); - } -} - -void Layer::render(const OpenGLRenderer& rootRenderer) { - ATRACE_LAYER_WORK("Direct-Issue"); - - updateLightPosFromRenderer(rootRenderer); - renderer->prepareDirty(layer.getWidth(), layer.getHeight(), - dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom, !isBlend()); - - renderer->drawRenderNode(renderNode.get(), dirtyRect, RenderNode::kReplayFlag_ClipChildren); - - renderer->finish(); - - dirtyRect.setEmpty(); - - deferredUpdateScheduled = false; - renderNode = nullptr; -} - void Layer::postDecStrong() { renderState.postDecStrong(this); } diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index 1e5498bb3d21..8ac11d173a16 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_LAYER_H -#define ANDROID_HWUI_LAYER_H +#pragma once #include <cutils/compiler.h> #include <sys/types.h> @@ -46,22 +45,13 @@ namespace uirenderer { // Forward declarations class Caches; -class RenderNode; class RenderState; -class OpenGLRenderer; -class DeferredDisplayList; -struct DeferStateStruct; /** * A layer has dimensions and is backed by an OpenGL texture or FBO. */ class Layer : public VirtualLightRefBase, GpuMemoryTracker { public: - enum class Type { - Texture, - DisplayList, - }; - // layer lifecycle, controlled from outside enum class State { Uncached = 0, @@ -73,45 +63,9 @@ public: }; State state; // public for logging/debugging purposes - Layer(Type type, RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight); + Layer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight); ~Layer(); - static uint32_t computeIdealWidth(uint32_t layerWidth); - static uint32_t computeIdealHeight(uint32_t layerHeight); - - /** - * Calling this method will remove (either by recycling or - * destroying) the associated FBO, if present, and any render - * buffer (stencil for instance.) - */ - void removeFbo(bool flush = true); - - /** - * Sets this layer's region to a rectangle. Computes the appropriate - * texture coordinates. - */ - void setRegionAsRect() { - const android::Rect& bounds = region.getBounds(); - regionRect.set(bounds.leftTop().x, bounds.leftTop().y, - bounds.rightBottom().x, bounds.rightBottom().y); - - const float texX = 1.0f / float(texture.mWidth); - const float texY = 1.0f / float(texture.mHeight); - const float height = layer.getHeight(); - texCoords.set( - regionRect.left * texX, (height - regionRect.top) * texY, - regionRect.right * texX, (height - regionRect.bottom) * texY); - - regionRect.translate(layer.left, layer.top); - } - - void setWindowTransform(Matrix4& windowTransform) { - cachedInvTransformInWindow.loadInverse(windowTransform); - rendererLightPosDirty = true; - } - - void updateDeferred(RenderNode* renderNode, int left, int top, int right, int bottom); - inline uint32_t getWidth() const { return texture.mWidth; } @@ -120,23 +74,10 @@ public: return texture.mHeight; } - /** - * Resize the layer and its texture if needed. - * - * @param width The new width of the layer - * @param height The new height of the layer - * - * @return True if the layer was resized or nothing happened, false if - * a failure occurred during the resizing operation - */ - bool resize(const uint32_t width, const uint32_t height); - void setSize(uint32_t width, uint32_t height) { texture.updateSize(width, height, texture.format()); } - ANDROID_API void setPaint(const SkPaint* paint); - inline void setBlend(bool blend) { texture.blend = blend; } @@ -170,36 +111,6 @@ public: return mode; } - inline void setEmpty(bool empty) { - this->empty = empty; - } - - inline bool isEmpty() const { - return empty; - } - - inline void setFbo(GLuint fbo) { - this->fbo = fbo; - } - - inline GLuint getFbo() const { - return fbo; - } - - inline void setStencilRenderBuffer(RenderBuffer* renderBuffer) { - if (RenderBuffer::isStencilBuffer(renderBuffer->getFormat())) { - this->stencil = renderBuffer; - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, stencil->getName()); - } else { - ALOGE("The specified render buffer is not a stencil buffer"); - } - } - - inline RenderBuffer* getStencilRenderBuffer() const { - return stencil; - } - inline GLuint getTextureId() const { return texture.id(); } @@ -228,52 +139,21 @@ public: texture.setFilter(filter, bindTexture, force, renderTarget); } - inline bool isCacheable() const { - return cacheable; - } - - inline void setCacheable(bool cacheable) { - this->cacheable = cacheable; - } - - inline bool isDirty() const { - return dirty; - } - - inline void setDirty(bool dirty) { - this->dirty = dirty; - } - - inline bool isTextureLayer() const { - return type == Type::Texture; - } - inline SkColorFilter* getColorFilter() const { return colorFilter; } - ANDROID_API void setColorFilter(SkColorFilter* filter); - - inline void setConvexMask(const SkPath* convexMask) { - this->convexMask = convexMask; - } - - inline const SkPath* getConvexMask() { - return convexMask; - } - - void bindStencilRenderBuffer() const; + void setColorFilter(SkColorFilter* filter); void bindTexture() const; void generateTexture(); - void allocateTexture(); /** * When the caller frees the texture itself, the caller * must call this method to tell this layer that it lost * the texture. */ - ANDROID_API void clearTexture(); + void clearTexture(); inline mat4& getTexTransform() { return texTransform; @@ -283,11 +163,6 @@ public: return transform; } - void defer(const OpenGLRenderer& rootRenderer); - void cancelDefer(); - void flush(); - void render(const OpenGLRenderer& rootRenderer); - /** * Posts a decStrong call to the appropriate thread. * Thread-safe. @@ -314,79 +189,22 @@ public: Rect clipRect; /** - * Dirty region indicating what parts of the layer - * have been drawn. - */ - Region region; - /** - * If the region is a rectangle, coordinates of the - * region are stored here. - */ - Rect regionRect; - - /** * If the layer can be rendered as a mesh, this is non-null. */ TextureVertex* mesh = nullptr; GLsizei meshElementCount = 0; - /** - * Used for deferred updates. - */ - bool deferredUpdateScheduled = false; - std::unique_ptr<OpenGLRenderer> renderer; - sp<RenderNode> renderNode; - Rect dirtyRect; - bool debugDrawUpdate = false; - bool hasDrawnSinceUpdate = false; - bool wasBuildLayered = false; - private: - void requireRenderer(); - void updateLightPosFromRenderer(const OpenGLRenderer& rootRenderer); - Caches& caches; RenderState& renderState; /** - * Name of the FBO used to render the layer. If the name is 0 - * this layer is not backed by an FBO, but a simple texture. - */ - GLuint fbo = 0; - - /** - * The render buffer used as the stencil buffer. - */ - RenderBuffer* stencil = nullptr; - - /** - * Indicates whether this layer has been used already. - */ - bool empty = true; - - /** * The texture backing this layer. */ Texture texture; /** - * If set to true (by default), the layer can be reused. - */ - bool cacheable = true; - - /** - * Denotes whether the layer is a DisplayList, or Texture layer. - */ - const Type type; - - /** - * When set to true, this layer is dirty and should be cleared - * before any rendering occurs. - */ - bool dirty = false; - - /** * Indicates the render target. */ GLenum renderTarget = GL_TEXTURE_2D; @@ -421,28 +239,7 @@ private: */ mat4 transform; - /** - * Cached transform of layer in window, updated only on creation / resize - */ - mat4 cachedInvTransformInWindow; - bool rendererLightPosDirty = true; - - /** - * Used to defer display lists when the layer is updated with a - * display list. - */ - std::unique_ptr<DeferredDisplayList> deferredList; - - /** - * This convex path should be used to mask the layer's draw to the screen. - * - * Data not owned/managed by layer object. - */ - const SkPath* convexMask = nullptr; - }; // struct Layer }; // namespace uirenderer }; // namespace android - -#endif // ANDROID_HWUI_LAYER_H diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp deleted file mode 100644 index f5681ce712d5..000000000000 --- a/libs/hwui/LayerCache.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "LayerCache.h" - -#include "Caches.h" -#include "Properties.h" - -#include <utils/Log.h> - -#include <GLES2/gl2.h> - -namespace android { -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// Constructors/destructor -/////////////////////////////////////////////////////////////////////////////// - -LayerCache::LayerCache() - : mSize(0) - , mMaxSize(Properties::layerPoolSize) {} - -LayerCache::~LayerCache() { - clear(); -} - -/////////////////////////////////////////////////////////////////////////////// -// Size management -/////////////////////////////////////////////////////////////////////////////// - -size_t LayerCache::getCount() { - return mCache.size(); -} - -uint32_t LayerCache::getSize() { - return mSize; -} - -uint32_t LayerCache::getMaxSize() { - return mMaxSize; -} - -void LayerCache::setMaxSize(uint32_t maxSize) { - clear(); - mMaxSize = maxSize; -} - -/////////////////////////////////////////////////////////////////////////////// -// Caching -/////////////////////////////////////////////////////////////////////////////// - -int LayerCache::LayerEntry::compare(const LayerCache::LayerEntry& lhs, - const LayerCache::LayerEntry& rhs) { - int deltaInt = int(lhs.mWidth) - int(rhs.mWidth); - if (deltaInt != 0) return deltaInt; - - return int(lhs.mHeight) - int(rhs.mHeight); -} - -void LayerCache::deleteLayer(Layer* layer) { - if (layer) { - LAYER_LOGD("Destroying layer %dx%d, fbo %d", layer->getWidth(), layer->getHeight(), - layer->getFbo()); - mSize -= layer->getWidth() * layer->getHeight() * 4; - layer->state = Layer::State::DeletedFromCache; - layer->decStrong(nullptr); - } -} - -void LayerCache::clear() { - for (auto entry : mCache) { - deleteLayer(entry.mLayer); - } - mCache.clear(); -} - -Layer* LayerCache::get(RenderState& renderState, const uint32_t width, const uint32_t height) { - Layer* layer = nullptr; - - LayerEntry entry(width, height); - auto iter = mCache.find(entry); - - if (iter != mCache.end()) { - entry = *iter; - mCache.erase(iter); - - layer = entry.mLayer; - layer->state = Layer::State::RemovedFromCache; - mSize -= layer->getWidth() * layer->getHeight() * 4; - - LAYER_LOGD("Reusing layer %dx%d", layer->getWidth(), layer->getHeight()); - } else { - LAYER_LOGD("Creating new layer %dx%d", entry.mWidth, entry.mHeight); - - layer = new Layer(Layer::Type::DisplayList, renderState, entry.mWidth, entry.mHeight); - layer->setBlend(true); - layer->generateTexture(); - layer->bindTexture(); - layer->setFilter(GL_NEAREST); - layer->setWrap(GL_CLAMP_TO_EDGE, false); - -#if DEBUG_LAYERS - dump(); -#endif - } - - return layer; -} - -void LayerCache::dump() { - for (auto entry : mCache) { - ALOGD(" Layer size %dx%d", entry.mWidth, entry.mHeight); - } -} - -bool LayerCache::put(Layer* layer) { - if (!layer->isCacheable()) return false; - - const uint32_t size = layer->getWidth() * layer->getHeight() * 4; - // Don't even try to cache a layer that's bigger than the cache - if (size < mMaxSize) { - // TODO: Use an LRU - while (mSize + size > mMaxSize) { - Layer* victim = mCache.begin()->mLayer; - deleteLayer(victim); - mCache.erase(mCache.begin()); - - LAYER_LOGD(" Deleting layer %.2fx%.2f", victim->layer.getWidth(), - victim->layer.getHeight()); - } - - layer->cancelDefer(); - - LayerEntry entry(layer); - - mCache.insert(entry); - mSize += size; - - layer->state = Layer::State::InCache; - return true; - } - - layer->state = Layer::State::FailedToCache; - return false; -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/LayerCache.h b/libs/hwui/LayerCache.h deleted file mode 100644 index 6fe7b3aae859..000000000000 --- a/libs/hwui/LayerCache.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_HWUI_LAYER_CACHE_H -#define ANDROID_HWUI_LAYER_CACHE_H - -#include "Debug.h" -#include "Layer.h" - -#include <set> - -namespace android { -namespace uirenderer { - -class RenderState; - -/////////////////////////////////////////////////////////////////////////////// -// Defines -/////////////////////////////////////////////////////////////////////////////// - -#if DEBUG_LAYERS - #define LAYER_LOGD(...) ALOGD(__VA_ARGS__) -#else - #define LAYER_LOGD(...) -#endif - -/////////////////////////////////////////////////////////////////////////////// -// Cache -/////////////////////////////////////////////////////////////////////////////// - -class LayerCache { -public: - LayerCache(); - ~LayerCache(); - - /** - * Returns a layer large enough for the specified dimensions. If no suitable - * layer can be found, a new one is created and returned. If creating a new - * layer fails, NULL is returned. - * - * When a layer is obtained from the cache, it is removed and the total - * size of the cache goes down. - * - * @param width The desired width of the layer - * @param height The desired height of the layer - */ - Layer* get(RenderState& renderState, const uint32_t width, const uint32_t height); - - /** - * Adds the layer to the cache. The layer will not be added if there is - * not enough space available. Adding a layer can cause other layers to - * be removed from the cache. - * - * @param layer The layer to add to the cache - * - * @return True if the layer was added, false otherwise. - */ - bool put(Layer* layer); - /** - * Clears the cache. This causes all layers to be deleted. - */ - void clear(); - - /** - * Sets the maximum size of the cache in bytes. - */ - void setMaxSize(uint32_t maxSize); - /** - * Returns the maximum size of the cache in bytes. - */ - uint32_t getMaxSize(); - /** - * Returns the current size of the cache in bytes. - */ - uint32_t getSize(); - - size_t getCount(); - - /** - * Prints out the content of the cache. - */ - void dump(); - -private: - struct LayerEntry { - LayerEntry(): - mLayer(nullptr), mWidth(0), mHeight(0) { - } - - LayerEntry(const uint32_t layerWidth, const uint32_t layerHeight): mLayer(nullptr) { - mWidth = Layer::computeIdealWidth(layerWidth); - mHeight = Layer::computeIdealHeight(layerHeight); - } - - LayerEntry(Layer* layer): - mLayer(layer), mWidth(layer->getWidth()), mHeight(layer->getHeight()) { - } - - static int compare(const LayerEntry& lhs, const LayerEntry& rhs); - - bool operator==(const LayerEntry& other) const { - return compare(*this, other) == 0; - } - - bool operator!=(const LayerEntry& other) const { - return compare(*this, other) != 0; - } - - bool operator<(const LayerEntry& other) const { - return LayerEntry::compare(*this, other) < 0; - } - - Layer* mLayer; - uint32_t mWidth; - uint32_t mHeight; - }; // struct LayerEntry - - void deleteLayer(Layer* layer); - - std::multiset<LayerEntry> mCache; - - uint32_t mSize; - uint32_t mMaxSize; -}; // class LayerCache - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_LAYER_CACHE_H diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp index 405165f07546..8d50dc2ccd94 100644 --- a/libs/hwui/LayerRenderer.cpp +++ b/libs/hwui/LayerRenderer.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ -#include "LayerCache.h" #include "LayerRenderer.h" #include "Matrix.h" #include "Properties.h" @@ -27,257 +26,15 @@ #include <private/hwui/DrawGlInfo.h> - namespace android { namespace uirenderer { -/////////////////////////////////////////////////////////////////////////////// -// Rendering -/////////////////////////////////////////////////////////////////////////////// - -LayerRenderer::LayerRenderer(RenderState& renderState, Layer* layer) - : OpenGLRenderer(renderState) - , mLayer(layer) { -} - -LayerRenderer::~LayerRenderer() { -} - -void LayerRenderer::prepareDirty(int viewportWidth, int viewportHeight, - float left, float top, float right, float bottom, bool opaque) { - LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->getFbo()); - - mRenderState.bindFramebuffer(mLayer->getFbo()); - - const float width = mLayer->layer.getWidth(); - const float height = mLayer->layer.getHeight(); - - Rect dirty(left, top, right, bottom); - if (dirty.isEmpty() || (dirty.left <= 0 && dirty.top <= 0 && - dirty.right >= width && dirty.bottom >= height)) { - mLayer->region.clear(); - dirty.set(0.0f, 0.0f, width, height); - } else { - dirty.doIntersect(0.0f, 0.0f, width, height); - android::Rect r(dirty.left, dirty.top, dirty.right, dirty.bottom); - mLayer->region.subtractSelf(r); - } - mLayer->clipRect.set(dirty); - - OpenGLRenderer::prepareDirty(viewportWidth, viewportHeight, - dirty.left, dirty.top, dirty.right, dirty.bottom, opaque); -} - -void LayerRenderer::clear(float left, float top, float right, float bottom, bool opaque) { - if (mLayer->isDirty()) { - mRenderState.scissor().setEnabled(false); - glClear(GL_COLOR_BUFFER_BIT); - - mRenderState.scissor().reset(); - mLayer->setDirty(false); - } else { - OpenGLRenderer::clear(left, top, right, bottom, opaque); - } -} - -bool LayerRenderer::finish() { - bool retval = OpenGLRenderer::finish(); - - generateMesh(); - - LAYER_RENDERER_LOGD("Finished rendering into layer, fbo = %d", mLayer->getFbo()); - - // No need to unbind our FBO, this will be taken care of by the caller - // who will invoke OpenGLRenderer::resume() - return retval; -} - -GLuint LayerRenderer::getTargetFbo() const { - return mLayer->getFbo(); -} - -bool LayerRenderer::suppressErrorChecks() const { - return true; -} - -/////////////////////////////////////////////////////////////////////////////// -// Layer support -/////////////////////////////////////////////////////////////////////////////// - -bool LayerRenderer::hasLayer() const { - return true; -} - -void LayerRenderer::ensureStencilBuffer() { - attachStencilBufferToLayer(mLayer); -} - -/////////////////////////////////////////////////////////////////////////////// -// Dirty region tracking -/////////////////////////////////////////////////////////////////////////////// - -Region* LayerRenderer::getRegion() const { - if (mState.currentFlags() & Snapshot::kFlagFboTarget) { - return OpenGLRenderer::getRegion(); - } - return &mLayer->region; -} - -// TODO: This implementation uses a very simple approach to fixing T-junctions which keeps the -// results as rectangles, and is thus not necessarily efficient in the geometry -// produced. Eventually, it may be better to develop triangle-based mechanism. -void LayerRenderer::generateMesh() { - if (mLayer->region.isRect() || mLayer->region.isEmpty()) { - if (mLayer->mesh) { - delete[] mLayer->mesh; - mLayer->mesh = nullptr; - mLayer->meshElementCount = 0; - } - - mLayer->setRegionAsRect(); - return; - } - - // avoid T-junctions as they cause artifacts in between the resultant - // geometry when complex transforms occur. - // TODO: generate the safeRegion only if necessary based on drawing transform (see - // OpenGLRenderer::composeLayerRegion()) - Region safeRegion = Region::createTJunctionFreeRegion(mLayer->region); - - size_t count; - const android::Rect* rects = safeRegion.getArray(&count); - - GLsizei elementCount = count * 6; - - if (mLayer->mesh && mLayer->meshElementCount < elementCount) { - delete[] mLayer->mesh; - mLayer->mesh = nullptr; - } - - if (!mLayer->mesh) { - mLayer->mesh = new TextureVertex[count * 4]; - } - mLayer->meshElementCount = elementCount; - - const float texX = 1.0f / float(mLayer->getWidth()); - const float texY = 1.0f / float(mLayer->getHeight()); - const float height = mLayer->layer.getHeight(); - - TextureVertex* mesh = mLayer->mesh; - - for (size_t i = 0; i < count; i++) { - const android::Rect* r = &rects[i]; - - const float u1 = r->left * texX; - const float v1 = (height - r->top) * texY; - const float u2 = r->right * texX; - const float v2 = (height - r->bottom) * texY; - - TextureVertex::set(mesh++, r->left, r->top, u1, v1); - TextureVertex::set(mesh++, r->right, r->top, u2, v1); - TextureVertex::set(mesh++, r->left, r->bottom, u1, v2); - TextureVertex::set(mesh++, r->right, r->bottom, u2, v2); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Layers management -/////////////////////////////////////////////////////////////////////////////// - -Layer* LayerRenderer::createRenderLayer(RenderState& renderState, uint32_t width, uint32_t height) { - ATRACE_FORMAT("Allocate %ux%u HW Layer", width, height); - LAYER_RENDERER_LOGD("Requesting new render layer %dx%d", width, height); - - Caches& caches = Caches::getInstance(); - GLuint fbo = renderState.createFramebuffer(); - if (!fbo) { - ALOGW("Could not obtain an FBO"); - return nullptr; - } - - caches.textureState().activateTexture(0); - Layer* layer = caches.layerCache.get(renderState, width, height); - if (!layer) { - ALOGW("Could not obtain a layer"); - return nullptr; - } - - // We first obtain a layer before comparing against the max texture size - // because layers are not allocated at the exact desired size. They are - // always created slightly larger to improve recycling - const uint32_t maxTextureSize = caches.maxTextureSize; - if (layer->getWidth() > maxTextureSize || layer->getHeight() > maxTextureSize) { - ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)", - width, height, maxTextureSize, maxTextureSize); - - // Creating a new layer always increment its refcount by 1, this allows - // us to destroy the layer object if one was created for us - layer->decStrong(nullptr); - - return nullptr; - } - - layer->setFbo(fbo); - layer->layer.set(0.0f, 0.0f, width, height); - layer->texCoords.set(0.0f, height / float(layer->getHeight()), - width / float(layer->getWidth()), 0.0f); - layer->setAlpha(255, SkXfermode::kSrcOver_Mode); - layer->setColorFilter(nullptr); - layer->setDirty(true); - layer->region.clear(); - - GLuint previousFbo = renderState.getFramebuffer(); - - renderState.bindFramebuffer(layer->getFbo()); - layer->bindTexture(); - - // Initialize the texture if needed - if (layer->isEmpty()) { - layer->setEmpty(false); - layer->allocateTexture(); - - // This should only happen if we run out of memory - if (CC_UNLIKELY(GLUtils::dumpGLErrors())) { - LOG_ALWAYS_FATAL("Could not allocate texture for layer (fbo=%d %dx%d)", - fbo, width, height); - renderState.bindFramebuffer(previousFbo); - layer->decStrong(nullptr); - return nullptr; - } - } - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - layer->getTextureId(), 0); - - renderState.bindFramebuffer(previousFbo); - - return layer; -} - -bool LayerRenderer::resizeLayer(Layer* layer, uint32_t width, uint32_t height) { - if (layer) { - LAYER_RENDERER_LOGD("Resizing layer fbo = %d to %dx%d", layer->getFbo(), width, height); - - if (layer->resize(width, height)) { - layer->layer.set(0.0f, 0.0f, width, height); - layer->texCoords.set(0.0f, height / float(layer->getHeight()), - width / float(layer->getWidth()), 0.0f); - } else { - return false; - } - } - - return true; -} - Layer* LayerRenderer::createTextureLayer(RenderState& renderState) { LAYER_RENDERER_LOGD("Creating new texture layer"); - Layer* layer = new Layer(Layer::Type::Texture, renderState, 0, 0); - layer->setCacheable(false); + Layer* layer = new Layer(renderState, 0, 0); layer->layer.set(0.0f, 0.0f, 0.0f, 0.0f); layer->texCoords.set(0.0f, 1.0f, 1.0f, 0.0f); - layer->region.clear(); layer->setRenderTarget(GL_NONE); // see ::updateTextureLayer() Caches::getInstance().textureState().activateTexture(0); @@ -287,68 +44,19 @@ Layer* LayerRenderer::createTextureLayer(RenderState& renderState) { } void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t height, - bool isOpaque, bool forceFilter, GLenum renderTarget, const float* textureTransform) { - if (layer) { - layer->setBlend(!isOpaque); - layer->setForceFilter(forceFilter); - layer->setSize(width, height); - layer->layer.set(0.0f, 0.0f, width, height); - layer->region.set(width, height); - layer->regionRect.set(0.0f, 0.0f, width, height); - layer->getTexTransform().load(textureTransform); - - if (renderTarget != layer->getRenderTarget()) { - layer->setRenderTarget(renderTarget); - layer->bindTexture(); - layer->setFilter(GL_NEAREST, false, true); - layer->setWrap(GL_CLAMP_TO_EDGE, false, true); - } - } -} - -void LayerRenderer::destroyLayer(Layer* layer) { - if (layer) { - ATRACE_FORMAT("Destroy %ux%u HW Layer", layer->getWidth(), layer->getHeight()); - LAYER_RENDERER_LOGD("Recycling layer, %dx%d fbo = %d", - layer->getWidth(), layer->getHeight(), layer->getFbo()); - - if (!Caches::getInstance().layerCache.put(layer)) { - LAYER_RENDERER_LOGD(" Destroyed!"); - layer->decStrong(nullptr); - } else { - LAYER_RENDERER_LOGD(" Cached!"); -#if DEBUG_LAYER_RENDERER - Caches::getInstance().layerCache.dump(); -#endif - layer->removeFbo(); - layer->region.clear(); - } - } -} - -void LayerRenderer::flushLayer(RenderState& renderState, Layer* layer) { -#ifdef GL_EXT_discard_framebuffer - if (!layer) return; - - GLuint fbo = layer->getFbo(); - if (fbo) { - // If possible, discard any enqueud operations on deferred - // rendering architectures - if (Caches::getInstance().extensions().hasDiscardFramebuffer()) { - GLuint previousFbo = renderState.getFramebuffer(); - if (fbo != previousFbo) { - renderState.bindFramebuffer(fbo); - } - - const GLenum attachments[] = { GL_COLOR_ATTACHMENT0 }; - glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, attachments); + bool isOpaque, bool forceFilter, GLenum renderTarget, const float* textureTransform) { + layer->setBlend(!isOpaque); + layer->setForceFilter(forceFilter); + layer->setSize(width, height); + layer->layer.set(0.0f, 0.0f, width, height); + layer->getTexTransform().load(textureTransform); - if (fbo != previousFbo) { - renderState.bindFramebuffer(previousFbo); - } - } + if (renderTarget != layer->getRenderTarget()) { + layer->setRenderTarget(renderTarget); + layer->bindTexture(); + layer->setFilter(GL_NEAREST, false, true); + layer->setWrap(GL_CLAMP_TO_EDGE, false, true); } -#endif } }; // namespace uirenderer diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h index 1fb6b1460748..7460e3e47fa2 100644 --- a/libs/hwui/LayerRenderer.h +++ b/libs/hwui/LayerRenderer.h @@ -14,12 +14,10 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_LAYER_RENDERER_H -#define ANDROID_HWUI_LAYER_RENDERER_H +#pragma once #include <cutils/compiler.h> -#include "OpenGLRenderer.h" #include "Layer.h" #include <SkBitmap.h> @@ -44,40 +42,12 @@ class RenderState; // Renderer /////////////////////////////////////////////////////////////////////////////// -class LayerRenderer: public OpenGLRenderer { +class LayerRenderer { public: - LayerRenderer(RenderState& renderState, Layer* layer); - virtual ~LayerRenderer(); - - virtual void onViewportInitialized() override { /* do nothing */ } - virtual void prepareDirty(int viewportWidth, int viewportHeight, - float left, float top, float right, float bottom, bool opaque) override; - virtual void clear(float left, float top, float right, float bottom, bool opaque) override; - virtual bool finish() override; - static Layer* createTextureLayer(RenderState& renderState); - static Layer* createRenderLayer(RenderState& renderState, uint32_t width, uint32_t height); - static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height); static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height, bool isOpaque, bool forceFilter, GLenum renderTarget, const float* textureTransform); - static void destroyLayer(Layer* layer); - - static void flushLayer(RenderState& renderState, Layer* layer); - -protected: - virtual void ensureStencilBuffer() override; - virtual bool hasLayer() const override; - virtual Region* getRegion() const override; - virtual GLuint getTargetFbo() const override; - virtual bool suppressErrorChecks() const override; - -private: - void generateMesh(); - - Layer* mLayer; }; // class LayerRenderer }; // namespace uirenderer }; // namespace android - -#endif // ANDROID_HWUI_LAYER_RENDERER_H diff --git a/libs/hwui/OpDumper.cpp b/libs/hwui/OpDumper.cpp index ec9ffdeebb4c..f4b7ee0fe430 100644 --- a/libs/hwui/OpDumper.cpp +++ b/libs/hwui/OpDumper.cpp @@ -16,6 +16,7 @@ #include "OpDumper.h" +#include "ClipArea.h" #include "RecordedOp.h" namespace android { diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp deleted file mode 100644 index 9d821f38fab6..000000000000 --- a/libs/hwui/OpenGLRenderer.cpp +++ /dev/null @@ -1,2451 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <GpuMemoryTracker.h> -#include "OpenGLRenderer.h" - -#include "DeferredDisplayList.h" -#include "GammaFontRenderer.h" -#include "Glop.h" -#include "GlopBuilder.h" -#include "Patch.h" -#include "PathTessellator.h" -#include "Properties.h" -#include "RenderNode.h" -#include "renderstate/MeshState.h" -#include "renderstate/RenderState.h" -#include "ShadowTessellator.h" -#include "SkiaShader.h" -#include "Vector.h" -#include "VertexBuffer.h" -#include "hwui/Canvas.h" -#include "utils/GLUtils.h" -#include "utils/PaintUtils.h" -#include "utils/TraceUtils.h" - -#include <stdlib.h> -#include <stdint.h> -#include <sys/types.h> - -#include <SkColor.h> -#include <SkPaintDefaults.h> -#include <SkPathOps.h> -#include <SkShader.h> -#include <SkTypeface.h> - -#include <utils/Log.h> -#include <utils/StopWatch.h> - -#include <private/hwui/DrawGlInfo.h> - -#include <ui/Rect.h> - -#if DEBUG_DETAILED_EVENTS - #define EVENT_LOGD(...) eventMarkDEBUG(__VA_ARGS__) -#else - #define EVENT_LOGD(...) -#endif - -namespace android { -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// Constructors/destructor -/////////////////////////////////////////////////////////////////////////////// - -OpenGLRenderer::OpenGLRenderer(RenderState& renderState) - : mState(*this) - , mCaches(Caches::getInstance()) - , mRenderState(renderState) - , mFrameStarted(false) - , mScissorOptimizationDisabled(false) - , mDirty(false) - , mLightCenter((Vector3){FLT_MIN, FLT_MIN, FLT_MIN}) - , mLightRadius(FLT_MIN) - , mAmbientShadowAlpha(0) - , mSpotShadowAlpha(0) { -} - -OpenGLRenderer::~OpenGLRenderer() { - // The context has already been destroyed at this point, do not call - // GL APIs. All GL state should be kept in Caches.h -} - -void OpenGLRenderer::initProperties() { - char property[PROPERTY_VALUE_MAX]; - if (property_get(PROPERTY_DISABLE_SCISSOR_OPTIMIZATION, property, "false")) { - mScissorOptimizationDisabled = !strcasecmp(property, "true"); - INIT_LOGD(" Scissor optimization %s", - mScissorOptimizationDisabled ? "disabled" : "enabled"); - } else { - INIT_LOGD(" Scissor optimization enabled"); - } -} - -void OpenGLRenderer::initLight(float lightRadius, uint8_t ambientShadowAlpha, - uint8_t spotShadowAlpha) { - mLightRadius = lightRadius; - mAmbientShadowAlpha = ambientShadowAlpha; - mSpotShadowAlpha = spotShadowAlpha; -} - -void OpenGLRenderer::setLightCenter(const Vector3& lightCenter) { - mLightCenter = lightCenter; -} - -/////////////////////////////////////////////////////////////////////////////// -// Setup -/////////////////////////////////////////////////////////////////////////////// - -void OpenGLRenderer::onViewportInitialized() { - glDisable(GL_DITHER); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); -} - -void OpenGLRenderer::setupFrameState(int viewportWidth, int viewportHeight, - float left, float top, float right, float bottom, bool opaque) { - mCaches.clearGarbage(); - mState.initializeSaveStack(viewportWidth, viewportHeight, - left, top, right, bottom, mLightCenter); - mOpaque = opaque; - mTilingClip.set(left, top, right, bottom); -} - -void OpenGLRenderer::startFrame() { - if (mFrameStarted) return; - mFrameStarted = true; - - mState.setDirtyClip(true); - - discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom); - - mRenderState.setViewport(mState.getWidth(), mState.getHeight()); - - debugOverdraw(true, true); - - clear(mTilingClip.left, mTilingClip.top, - mTilingClip.right, mTilingClip.bottom, mOpaque); -} - -void OpenGLRenderer::prepareDirty(int viewportWidth, int viewportHeight, - float left, float top, float right, float bottom, bool opaque) { - - setupFrameState(viewportWidth, viewportHeight, left, top, right, bottom, opaque); - - // Layer renderers will start the frame immediately - // The framebuffer renderer will first defer the display list - // for each layer and wait until the first drawing command - // to start the frame - if (currentSnapshot()->fbo == 0) { - mRenderState.blend().syncEnabled(); - updateLayers(); - } else { - startFrame(); - } -} - -void OpenGLRenderer::discardFramebuffer(float left, float top, float right, float bottom) { - // If we know that we are going to redraw the entire framebuffer, - // perform a discard to let the driver know we don't need to preserve - // the back buffer for this frame. - if (mCaches.extensions().hasDiscardFramebuffer() && - left <= 0.0f && top <= 0.0f && right >= mState.getWidth() && bottom >= mState.getHeight()) { - const bool isFbo = getTargetFbo() == 0; - const GLenum attachments[] = { - isFbo ? (const GLenum) GL_COLOR_EXT : (const GLenum) GL_COLOR_ATTACHMENT0, - isFbo ? (const GLenum) GL_STENCIL_EXT : (const GLenum) GL_STENCIL_ATTACHMENT }; - glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, attachments); - } -} - -void OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) { - if (!opaque) { - mRenderState.scissor().setEnabled(true); - mRenderState.scissor().set(left, getViewportHeight() - bottom, right - left, bottom - top); - glClear(GL_COLOR_BUFFER_BIT); - mDirty = true; - return; - } - - mRenderState.scissor().reset(); -} - -bool OpenGLRenderer::finish() { - renderOverdraw(); - mTempPaths.clear(); - - // When finish() is invoked on FBO 0 we've reached the end - // of the current frame - if (getTargetFbo() == 0) { - mCaches.pathCache.trim(); - mCaches.tessellationCache.trim(); - } - - if (!suppressErrorChecks()) { - GL_CHECKPOINT(MODERATE); - -#if DEBUG_MEMORY_USAGE - mCaches.dumpMemoryUsage(); - GPUMemoryTracker::dump(); -#else - if (Properties::debugLevel & kDebugMemory) { - mCaches.dumpMemoryUsage(); - } -#endif - } - - mFrameStarted = false; - - return reportAndClearDirty(); -} - -void OpenGLRenderer::resumeAfterLayer() { - mRenderState.setViewport(getViewportWidth(), getViewportHeight()); - mRenderState.bindFramebuffer(currentSnapshot()->fbo); - debugOverdraw(true, false); - - mRenderState.scissor().reset(); - dirtyClip(); -} - -void OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) { - if (mState.currentlyIgnored()) return; - - Rect clip(mState.currentRenderTargetClip()); - clip.snapToPixelBoundaries(); - - // Since we don't know what the functor will draw, let's dirty - // the entire clip region - if (hasLayer()) { - dirtyLayerUnchecked(clip, getRegion()); - } - - DrawGlInfo info; - info.clipLeft = clip.left; - info.clipTop = clip.top; - info.clipRight = clip.right; - info.clipBottom = clip.bottom; - info.isLayer = hasLayer(); - info.width = getViewportWidth(); - info.height = getViewportHeight(); - currentTransform()->copyTo(&info.transform[0]); - - bool prevDirtyClip = mState.getDirtyClip(); - // setup GL state for functor - if (mState.getDirtyClip()) { - setStencilFromClip(); // can issue draws, so must precede enableScissor()/interrupt() - } - if (mRenderState.scissor().setEnabled(true) || prevDirtyClip) { - setScissorFromClip(); - } - - mRenderState.invokeFunctor(functor, DrawGlInfo::kModeDraw, &info); - // Scissor may have been modified, reset dirty clip - dirtyClip(); - - mDirty = true; -} - -/////////////////////////////////////////////////////////////////////////////// -// Debug -/////////////////////////////////////////////////////////////////////////////// - -void OpenGLRenderer::eventMarkDEBUG(const char* fmt, ...) const { -#if DEBUG_DETAILED_EVENTS - const int BUFFER_SIZE = 256; - va_list ap; - char buf[BUFFER_SIZE]; - - va_start(ap, fmt); - vsnprintf(buf, BUFFER_SIZE, fmt, ap); - va_end(ap); - - eventMark(buf); -#endif -} - - -void OpenGLRenderer::eventMark(const char* name) const { - mCaches.eventMark(0, name); -} - -void OpenGLRenderer::startMark(const char* name) const { - mCaches.startMark(0, name); -} - -void OpenGLRenderer::endMark() const { - mCaches.endMark(); -} - -void OpenGLRenderer::debugOverdraw(bool enable, bool clear) { - mRenderState.debugOverdraw(enable, clear); -} - -void OpenGLRenderer::renderOverdraw() { - if (Properties::debugOverdraw && getTargetFbo() == 0) { - const Rect* clip = &mTilingClip; - - mRenderState.scissor().setEnabled(true); - mRenderState.scissor().set(clip->left, - mState.firstSnapshot()->getViewportHeight() - clip->bottom, - clip->right - clip->left, - clip->bottom - clip->top); - - // 1x overdraw - mRenderState.stencil().enableDebugTest(2); - drawColor(mCaches.getOverdrawColor(1), SkXfermode::kSrcOver_Mode); - - // 2x overdraw - mRenderState.stencil().enableDebugTest(3); - drawColor(mCaches.getOverdrawColor(2), SkXfermode::kSrcOver_Mode); - - // 3x overdraw - mRenderState.stencil().enableDebugTest(4); - drawColor(mCaches.getOverdrawColor(3), SkXfermode::kSrcOver_Mode); - - // 4x overdraw and higher - mRenderState.stencil().enableDebugTest(4, true); - drawColor(mCaches.getOverdrawColor(4), SkXfermode::kSrcOver_Mode); - - mRenderState.stencil().disable(); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Layers -/////////////////////////////////////////////////////////////////////////////// - -bool OpenGLRenderer::updateLayer(Layer* layer, bool inFrame) { - if (layer->deferredUpdateScheduled && layer->renderer - && layer->renderNode.get() && layer->renderNode->isRenderable()) { - - if (inFrame) { - debugOverdraw(false, false); - } - - if (CC_UNLIKELY(inFrame || Properties::drawDeferDisabled)) { - layer->render(*this); - } else { - layer->defer(*this); - } - - if (inFrame) { - resumeAfterLayer(); - } - - layer->debugDrawUpdate = Properties::debugLayersUpdates; - layer->hasDrawnSinceUpdate = false; - - return true; - } - - return false; -} - -void OpenGLRenderer::updateLayers() { - // If draw deferring is enabled this method will simply defer - // the display list of each individual layer. The layers remain - // in the layer updates list which will be cleared by flushLayers(). - int count = mLayerUpdates.size(); - if (count > 0) { - if (CC_UNLIKELY(Properties::drawDeferDisabled)) { - startMark("Layer Updates"); - } else { - startMark("Defer Layer Updates"); - } - - // Note: it is very important to update the layers in order - for (int i = 0; i < count; i++) { - Layer* layer = mLayerUpdates[i].get(); - updateLayer(layer, false); - } - - if (CC_UNLIKELY(Properties::drawDeferDisabled)) { - mLayerUpdates.clear(); - mRenderState.bindFramebuffer(getTargetFbo()); - } - endMark(); - } -} - -void OpenGLRenderer::flushLayers() { - int count = mLayerUpdates.size(); - if (count > 0) { - startMark("Apply Layer Updates"); - - // Note: it is very important to update the layers in order - for (int i = 0; i < count; i++) { - mLayerUpdates[i]->flush(); - } - - mLayerUpdates.clear(); - mRenderState.bindFramebuffer(getTargetFbo()); - - endMark(); - } -} - -void OpenGLRenderer::pushLayerUpdate(Layer* layer) { - if (layer) { - // Make sure we don't introduce duplicates. - // SortedVector would do this automatically but we need to respect - // the insertion order. The linear search is not an issue since - // this list is usually very short (typically one item, at most a few) - for (int i = mLayerUpdates.size() - 1; i >= 0; i--) { - if (mLayerUpdates[i] == layer) { - return; - } - } - mLayerUpdates.push_back(layer); - } -} - -void OpenGLRenderer::cancelLayerUpdate(Layer* layer) { - if (layer) { - for (int i = mLayerUpdates.size() - 1; i >= 0; i--) { - if (mLayerUpdates[i] == layer) { - mLayerUpdates.erase(mLayerUpdates.begin() + i); - break; - } - } - } -} - -void OpenGLRenderer::flushLayerUpdates() { - ATRACE_NAME("Update HW Layers"); - mRenderState.blend().syncEnabled(); - updateLayers(); - flushLayers(); - // Wait for all the layer updates to be executed - glFinish(); -} - -void OpenGLRenderer::markLayersAsBuildLayers() { - for (size_t i = 0; i < mLayerUpdates.size(); i++) { - mLayerUpdates[i]->wasBuildLayered = true; - } -} - -/////////////////////////////////////////////////////////////////////////////// -// State management -/////////////////////////////////////////////////////////////////////////////// - -void OpenGLRenderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) { - bool restoreViewport = removed.flags & Snapshot::kFlagIsFboLayer; - bool restoreClip = removed.flags & Snapshot::kFlagClipSet; - bool restoreLayer = removed.flags & Snapshot::kFlagIsLayer; - - if (restoreViewport) { - mRenderState.setViewport(getViewportWidth(), getViewportHeight()); - } - - if (restoreClip) { - dirtyClip(); - } - - if (restoreLayer) { - endMark(); // Savelayer - ATRACE_END(); // SaveLayer - startMark("ComposeLayer"); - composeLayer(removed, restored); - endMark(); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Layers -/////////////////////////////////////////////////////////////////////////////// - -int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom, - const SkPaint* paint, int flags, const SkPath* convexMask) { - // force matrix/clip isolation for layer - flags |= SaveFlags::MatrixClip; - - const int count = mState.saveSnapshot(flags); - - if (!mState.currentlyIgnored()) { - createLayer(left, top, right, bottom, paint, flags, convexMask); - } - - return count; -} - -void OpenGLRenderer::calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool fboLayer) { - const Rect untransformedBounds(bounds); - - currentTransform()->mapRect(bounds); - - // Layers only make sense if they are in the framebuffer's bounds - bounds.doIntersect(mState.currentRenderTargetClip()); - if (!bounds.isEmpty()) { - // We cannot work with sub-pixels in this case - bounds.snapToPixelBoundaries(); - - // When the layer is not an FBO, we may use glCopyTexImage so we - // need to make sure the layer does not extend outside the bounds - // of the framebuffer - const Snapshot& previous = *(currentSnapshot()->previous); - Rect previousViewport(0, 0, previous.getViewportWidth(), previous.getViewportHeight()); - - bounds.doIntersect(previousViewport); - if (!bounds.isEmpty() && fboLayer) { - clip.set(bounds); - mat4 inverse; - inverse.loadInverse(*currentTransform()); - inverse.mapRect(clip); - clip.snapToPixelBoundaries(); - clip.doIntersect(untransformedBounds); - if (!clip.isEmpty()) { - clip.translate(-untransformedBounds.left, -untransformedBounds.top); - bounds.set(untransformedBounds); - } - } - } -} - -void OpenGLRenderer::updateSnapshotIgnoreForLayer(const Rect& bounds, const Rect& clip, - bool fboLayer, int alpha) { - if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize || - bounds.getHeight() > mCaches.maxTextureSize || - (fboLayer && clip.isEmpty())) { - writableSnapshot()->empty = fboLayer; - } else { - writableSnapshot()->invisible = writableSnapshot()->invisible || (alpha <= 0 && fboLayer); - } -} - -int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float bottom, - const SkPaint* paint, int flags) { - const int count = mState.saveSnapshot(flags); - - if (!mState.currentlyIgnored() && (flags & SaveFlags::ClipToLayer)) { - // initialize the snapshot as though it almost represents an FBO layer so deferred draw - // operations will be able to store and restore the current clip and transform info, and - // quick rejection will be correct (for display lists) - - Rect bounds(left, top, right, bottom); - Rect clip; - calculateLayerBoundsAndClip(bounds, clip, true); - updateSnapshotIgnoreForLayer(bounds, clip, true, PaintUtils::getAlphaDirect(paint)); - - if (!mState.currentlyIgnored()) { - writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f); - writableSnapshot()->resetClip(clip.left, clip.top, clip.right, clip.bottom); - writableSnapshot()->initializeViewport(bounds.getWidth(), bounds.getHeight()); - writableSnapshot()->roundRectClipState = nullptr; - } - } - - return count; -} - -/** - * Layers are viewed by Skia are slightly different than layers in image editing - * programs (for instance.) When a layer is created, previously created layers - * and the frame buffer still receive every drawing command. For instance, if a - * layer is created and a shape intersecting the bounds of the layers and the - * framebuffer is draw, the shape will be drawn on both (unless the layer was - * created with the SaveFlags::ClipToLayer flag.) - * - * A way to implement layers is to create an FBO for each layer, backed by an RGBA - * texture. Unfortunately, this is inefficient as it requires every primitive to - * be drawn n + 1 times, where n is the number of active layers. In practice this - * means, for every primitive: - * - Switch active frame buffer - * - Change viewport, clip and projection matrix - * - Issue the drawing - * - * Switching rendering target n + 1 times per drawn primitive is extremely costly. - * To avoid this, layers are implemented in a different way here, at least in the - * general case. FBOs are used, as an optimization, when the "clip to layer" flag - * is set. When this flag is set we can redirect all drawing operations into a - * single FBO. - * - * This implementation relies on the frame buffer being at least RGBA 8888. When - * a layer is created, only a texture is created, not an FBO. The content of the - * frame buffer contained within the layer's bounds is copied into this texture - * using glCopyTexImage2D(). The layer's region is then cleared(1) in the frame - * buffer and drawing continues as normal. This technique therefore treats the - * frame buffer as a scratch buffer for the layers. - * - * To compose the layers back onto the frame buffer, each layer texture - * (containing the original frame buffer data) is drawn as a simple quad over - * the frame buffer. The trick is that the quad is set as the composition - * destination in the blending equation, and the frame buffer becomes the source - * of the composition. - * - * Drawing layers with an alpha value requires an extra step before composition. - * An empty quad is drawn over the layer's region in the frame buffer. This quad - * is drawn with the rgba color (0,0,0,alpha). The alpha value offered by the - * quad is used to multiply the colors in the frame buffer. This is achieved by - * changing the GL blend functions for the GL_FUNC_ADD blend equation to - * GL_ZERO, GL_SRC_ALPHA. - * - * Because glCopyTexImage2D() can be slow, an alternative implementation might - * be use to draw a single clipped layer. The implementation described above - * is correct in every case. - * - * (1) The frame buffer is actually not cleared right away. To allow the GPU - * to potentially optimize series of calls to glCopyTexImage2D, the frame - * buffer is left untouched until the first drawing operation. Only when - * something actually gets drawn are the layers regions cleared. - */ -bool OpenGLRenderer::createLayer(float left, float top, float right, float bottom, - const SkPaint* paint, int flags, const SkPath* convexMask) { - LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top); - LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize()); - - const bool fboLayer = flags & SaveFlags::ClipToLayer; - - // Window coordinates of the layer - Rect clip; - Rect bounds(left, top, right, bottom); - calculateLayerBoundsAndClip(bounds, clip, fboLayer); - updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, PaintUtils::getAlphaDirect(paint)); - - // Bail out if we won't draw in this snapshot - if (mState.currentlyIgnored()) { - return false; - } - - mCaches.textureState().activateTexture(0); - Layer* layer = mCaches.layerCache.get(mRenderState, bounds.getWidth(), bounds.getHeight()); - if (!layer) { - return false; - } - - layer->setPaint(paint); - layer->layer.set(bounds); - layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()), - bounds.getWidth() / float(layer->getWidth()), 0.0f); - - layer->setBlend(true); - layer->setDirty(false); - layer->setConvexMask(convexMask); // note: the mask must be cleared before returning to the cache - - // Save the layer in the snapshot - writableSnapshot()->flags |= Snapshot::kFlagIsLayer; - writableSnapshot()->layer = layer; - - ATRACE_FORMAT_BEGIN("%ssaveLayer %ux%u", - fboLayer ? "" : "unclipped ", - layer->getWidth(), layer->getHeight()); - startMark("SaveLayer"); - if (fboLayer) { - return createFboLayer(layer, bounds, clip); - } else { - // Copy the framebuffer into the layer - layer->bindTexture(); - if (!bounds.isEmpty()) { - if (layer->isEmpty()) { - // Workaround for some GL drivers. When reading pixels lying outside - // of the window we should get undefined values for those pixels. - // Unfortunately some drivers will turn the entire target texture black - // when reading outside of the window. - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->getWidth(), layer->getHeight(), - 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - layer->setEmpty(false); - } - - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, - bounds.left, getViewportHeight() - bounds.bottom, - bounds.getWidth(), bounds.getHeight()); - - // Enqueue the buffer coordinates to clear the corresponding region later - mLayers.push_back(Rect(bounds)); - } - } - - return true; -} - -bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) { - layer->clipRect.set(clip); - layer->setFbo(mRenderState.createFramebuffer()); - - writableSnapshot()->region = &writableSnapshot()->layer->region; - writableSnapshot()->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer; - writableSnapshot()->fbo = layer->getFbo(); - writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f); - writableSnapshot()->resetClip(clip.left, clip.top, clip.right, clip.bottom); - writableSnapshot()->initializeViewport(bounds.getWidth(), bounds.getHeight()); - writableSnapshot()->roundRectClipState = nullptr; - - debugOverdraw(false, false); - // Bind texture to FBO - mRenderState.bindFramebuffer(layer->getFbo()); - layer->bindTexture(); - - // Initialize the texture if needed - if (layer->isEmpty()) { - layer->allocateTexture(); - layer->setEmpty(false); - } - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - layer->getTextureId(), 0); - - // Clear the FBO, expand the clear region by 1 to get nice bilinear filtering - mRenderState.scissor().setEnabled(true); - mRenderState.scissor().set(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f, - clip.getWidth() + 2.0f, clip.getHeight() + 2.0f); - glClear(GL_COLOR_BUFFER_BIT); - - dirtyClip(); - - // Change the ortho projection - mRenderState.setViewport(bounds.getWidth(), bounds.getHeight()); - return true; -} - -/** - * Read the documentation of createLayer() before doing anything in this method. - */ -void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& restored) { - if (!removed.layer) { - ALOGE("Attempting to compose a layer that does not exist"); - return; - } - - Layer* layer = removed.layer; - const Rect& rect = layer->layer; - const bool fboLayer = removed.flags & Snapshot::kFlagIsFboLayer; - - bool clipRequired = false; - mState.calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom, - &clipRequired, nullptr, false); // safely ignore return, should never be rejected - mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired); - - if (fboLayer) { - // Detach the texture from the FBO - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); - - layer->removeFbo(false); - - // Unbind current FBO and restore previous one - mRenderState.bindFramebuffer(restored.fbo); - debugOverdraw(true, false); - } - - if (!fboLayer && layer->getAlpha() < 255) { - SkPaint layerPaint; - layerPaint.setAlpha(layer->getAlpha()); - layerPaint.setXfermodeMode(SkXfermode::kDstIn_Mode); - layerPaint.setColorFilter(layer->getColorFilter()); - - drawColorRect(rect.left, rect.top, rect.right, rect.bottom, &layerPaint, true); - // Required below, composeLayerRect() will divide by 255 - layer->setAlpha(255); - } - - mRenderState.meshState().unbindMeshBuffer(); - - mCaches.textureState().activateTexture(0); - - // When the layer is stored in an FBO, we can save a bit of fillrate by - // drawing only the dirty region - if (fboLayer) { - dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *restored.transform); - composeLayerRegion(layer, rect); - } else if (!rect.isEmpty()) { - dirtyLayer(rect.left, rect.top, rect.right, rect.bottom); - - save(0); - // the layer contains screen buffer content that shouldn't be alpha modulated - // (and any necessary alpha modulation was handled drawing into the layer) - writableSnapshot()->alpha = 1.0f; - composeLayerRectSwapped(layer, rect); - restore(); - } - - dirtyClip(); - - // Failing to add the layer to the cache should happen only if the layer is too large - layer->setConvexMask(nullptr); - if (!mCaches.layerCache.put(layer)) { - LAYER_LOGD("Deleting layer"); - layer->decStrong(nullptr); - } -} - -void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) { - const bool tryToSnap = !layer->getForceFilter() - && layer->getWidth() == (uint32_t) rect.getWidth() - && layer->getHeight() == (uint32_t) rect.getHeight(); - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO - .setFillTextureLayer(*layer, getLayerAlpha(layer)) - .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewMapUnitToRectOptionalSnap(tryToSnap, rect) - .build(); - renderGlop(glop); -} - -void OpenGLRenderer::composeLayerRectSwapped(Layer* layer, const Rect& rect) { - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshTexturedUvQuad(nullptr, layer->texCoords) - .setFillLayer(layer->getTexture(), layer->getColorFilter(), - getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::Swap) - .setTransform(*currentSnapshot(), TransformFlags::MeshIgnoresCanvasTransform) - .setModelViewMapUnitToRect(rect) - .build(); - renderGlop(glop); -} - -void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect) { - if (layer->isTextureLayer()) { - EVENT_LOGD("composeTextureLayerRect"); - drawTextureLayer(layer, rect); - } else { - EVENT_LOGD("composeHardwareLayerRect"); - - const bool tryToSnap = layer->getWidth() == static_cast<uint32_t>(rect.getWidth()) - && layer->getHeight() == static_cast<uint32_t>(rect.getHeight()); - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshTexturedUvQuad(nullptr, layer->texCoords) - .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap) - .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewMapUnitToRectOptionalSnap(tryToSnap, rect) - .build(); - renderGlop(glop); - } -} - -/** - * Issues the command X, and if we're composing a save layer to the fbo or drawing a newly updated - * hardware layer with overdraw debug on, draws again to the stencil only, so that these draw - * operations are correctly counted twice for overdraw. NOTE: assumes composeLayerRegion only used - * by saveLayer's restore - */ -#define DRAW_DOUBLE_STENCIL_IF(COND, DRAW_COMMAND) { \ - DRAW_COMMAND; \ - if (CC_UNLIKELY(Properties::debugOverdraw && getTargetFbo() == 0 && (COND))) { \ - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); \ - DRAW_COMMAND; \ - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); \ - } \ - } - -#define DRAW_DOUBLE_STENCIL(DRAW_COMMAND) DRAW_DOUBLE_STENCIL_IF(true, DRAW_COMMAND) - -// This class is purely for inspection. It inherits from SkShader, but Skia does not know how to -// use it. The OpenGLRenderer will look at it to find its Layer and whether it is opaque. -class LayerShader : public SkShader { -public: - LayerShader(Layer* layer, const SkMatrix* localMatrix) - : INHERITED(localMatrix) - , mLayer(layer) { - } - - virtual bool asACustomShader(void** data) const override { - if (data) { - *data = static_cast<void*>(mLayer); - } - return true; - } - - virtual bool isOpaque() const override { - return !mLayer->isBlend(); - } - -protected: - virtual void shadeSpan(int x, int y, SkPMColor[], int count) { - LOG_ALWAYS_FATAL("LayerShader should never be drawn with raster backend."); - } - - virtual void flatten(SkWriteBuffer&) const override { - LOG_ALWAYS_FATAL("LayerShader should never be flattened."); - } - - virtual Factory getFactory() const override { - LOG_ALWAYS_FATAL("LayerShader should never be created from a stream."); - return nullptr; - } -private: - // Unowned. - Layer* mLayer; - typedef SkShader INHERITED; -}; - -void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) { - if (CC_UNLIKELY(layer->region.isEmpty())) return; // nothing to draw - - if (layer->getConvexMask()) { - save(SaveFlags::MatrixClip); - - // clip to the area of the layer the mask can be larger - clipRect(rect.left, rect.top, rect.right, rect.bottom, SkRegion::kIntersect_Op); - - SkPaint paint; - paint.setAntiAlias(true); - paint.setColor(SkColorSetARGB(int(getLayerAlpha(layer) * 255), 0, 0, 0)); - - // create LayerShader to map SaveLayer content into subsequent draw - SkMatrix shaderMatrix; - shaderMatrix.setTranslate(rect.left, rect.bottom); - shaderMatrix.preScale(1, -1); - LayerShader layerShader(layer, &shaderMatrix); - paint.setShader(&layerShader); - - // Since the drawing primitive is defined in local drawing space, - // we don't need to modify the draw matrix - const SkPath* maskPath = layer->getConvexMask(); - DRAW_DOUBLE_STENCIL(drawConvexPath(*maskPath, &paint)); - - paint.setShader(nullptr); - restore(); - - return; - } - - if (layer->region.isRect()) { - layer->setRegionAsRect(); - - DRAW_DOUBLE_STENCIL(composeLayerRect(layer, layer->regionRect)); - - layer->region.clear(); - return; - } - - EVENT_LOGD("composeLayerRegion"); - // standard Region based draw - size_t count; - const android::Rect* rects; - Region safeRegion; - if (CC_LIKELY(hasRectToRectTransform())) { - rects = layer->region.getArray(&count); - } else { - safeRegion = Region::createTJunctionFreeRegion(layer->region); - rects = safeRegion.getArray(&count); - } - - const float texX = 1.0f / float(layer->getWidth()); - const float texY = 1.0f / float(layer->getHeight()); - const float height = rect.getHeight(); - - TextureVertex quadVertices[count * 4]; - TextureVertex* mesh = &quadVertices[0]; - for (size_t i = 0; i < count; i++) { - const android::Rect* r = &rects[i]; - - const float u1 = r->left * texX; - const float v1 = (height - r->top) * texY; - const float u2 = r->right * texX; - const float v2 = (height - r->bottom) * texY; - - // TODO: Reject quads outside of the clip - TextureVertex::set(mesh++, r->left, r->top, u1, v1); - TextureVertex::set(mesh++, r->right, r->top, u2, v1); - TextureVertex::set(mesh++, r->left, r->bottom, u1, v2); - TextureVertex::set(mesh++, r->right, r->bottom, u2, v2); - } - Rect modelRect = Rect(rect.getWidth(), rect.getHeight()); - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshTexturedIndexedQuads(&quadVertices[0], count * 6) - .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap) - .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewOffsetRectSnap(rect.left, rect.top, modelRect) - .build(); - DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop)); - -#if DEBUG_LAYERS_AS_REGIONS - drawRegionRectsDebug(layer->region); -#endif - - layer->region.clear(); -} - -#if DEBUG_LAYERS_AS_REGIONS -void OpenGLRenderer::drawRegionRectsDebug(const Region& region) { - size_t count; - const android::Rect* rects = region.getArray(&count); - - uint32_t colors[] = { - 0x7fff0000, 0x7f00ff00, - 0x7f0000ff, 0x7fff00ff, - }; - - int offset = 0; - int32_t top = rects[0].top; - - for (size_t i = 0; i < count; i++) { - if (top != rects[i].top) { - offset ^= 0x2; - top = rects[i].top; - } - - SkPaint paint; - paint.setColor(colors[offset + (i & 0x1)]); - Rect r(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom); - drawColorRect(r.left, r.top, r.right, r.bottom, paint); - } -} -#endif - -void OpenGLRenderer::drawRegionRects(const SkRegion& region, const SkPaint& paint, bool dirty) { - Vector<float> rects; - - SkRegion::Iterator it(region); - while (!it.done()) { - const SkIRect& r = it.rect(); - rects.push(r.fLeft); - rects.push(r.fTop); - rects.push(r.fRight); - rects.push(r.fBottom); - it.next(); - } - - drawColorRects(rects.array(), rects.size(), &paint, true, dirty, false); -} - -void OpenGLRenderer::dirtyLayer(const float left, const float top, - const float right, const float bottom, const Matrix4& transform) { - if (hasLayer()) { - Rect bounds(left, top, right, bottom); - transform.mapRect(bounds); - dirtyLayerUnchecked(bounds, getRegion()); - } -} - -void OpenGLRenderer::dirtyLayer(const float left, const float top, - const float right, const float bottom) { - if (hasLayer()) { - Rect bounds(left, top, right, bottom); - dirtyLayerUnchecked(bounds, getRegion()); - } -} - -void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) { - bounds.doIntersect(mState.currentRenderTargetClip()); - if (!bounds.isEmpty()) { - bounds.snapToPixelBoundaries(); - android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom); - if (!dirty.isEmpty()) { - region->orSelf(dirty); - } - } -} - -void OpenGLRenderer::clearLayerRegions() { - const size_t quadCount = mLayers.size(); - if (quadCount == 0) return; - - if (!mState.currentlyIgnored()) { - EVENT_LOGD("clearLayerRegions"); - // Doing several glScissor/glClear here can negatively impact - // GPUs with a tiler architecture, instead we draw quads with - // the Clear blending mode - - // The list contains bounds that have already been clipped - // against their initial clip rect, and the current clip - // is likely different so we need to disable clipping here - bool scissorChanged = mRenderState.scissor().setEnabled(false); - - Vertex mesh[quadCount * 4]; - Vertex* vertex = mesh; - - for (uint32_t i = 0; i < quadCount; i++) { - const Rect& bounds = mLayers[i]; - - Vertex::set(vertex++, bounds.left, bounds.top); - Vertex::set(vertex++, bounds.right, bounds.top); - Vertex::set(vertex++, bounds.left, bounds.bottom); - Vertex::set(vertex++, bounds.right, bounds.bottom); - } - // We must clear the list of dirty rects before we - // call clearLayerRegions() in renderGlop to prevent - // stencil setup from doing the same thing again - mLayers.clear(); - - const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform; - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(nullptr) // clear ignores clip state - .setMeshIndexedQuads(&mesh[0], quadCount) - .setFillClear() - .setTransform(*currentSnapshot(), transformFlags) - .setModelViewOffsetRect(0, 0, Rect(currentSnapshot()->getRenderTargetClip())) - .build(); - renderGlop(glop, GlopRenderType::LayerClear); - - if (scissorChanged) mRenderState.scissor().setEnabled(true); - } else { - mLayers.clear(); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// State Deferral -/////////////////////////////////////////////////////////////////////////////// - -bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) { - const Rect& currentClip = mState.currentRenderTargetClip(); - const mat4* currentMatrix = currentTransform(); - - if (stateDeferFlags & kStateDeferFlag_Draw) { - // state has bounds initialized in local coordinates - if (!state.mBounds.isEmpty()) { - currentMatrix->mapRect(state.mBounds); - Rect clippedBounds(state.mBounds); - // NOTE: if we ever want to use this clipping info to drive whether the scissor - // is used, it should more closely duplicate the quickReject logic (in how it uses - // snapToPixelBoundaries) - - clippedBounds.doIntersect(currentClip); - if (clippedBounds.isEmpty()) { - // quick rejected - return true; - } - - state.mClipSideFlags = kClipSide_None; - if (!currentClip.contains(state.mBounds)) { - int& flags = state.mClipSideFlags; - // op partially clipped, so record which sides are clipped for clip-aware merging - if (currentClip.left > state.mBounds.left) flags |= kClipSide_Left; - if (currentClip.top > state.mBounds.top) flags |= kClipSide_Top; - if (currentClip.right < state.mBounds.right) flags |= kClipSide_Right; - if (currentClip.bottom < state.mBounds.bottom) flags |= kClipSide_Bottom; - } - state.mBounds.set(clippedBounds); - } else { - // Empty bounds implies size unknown. Label op as conservatively clipped to disable - // overdraw avoidance (since we don't know what it overlaps) - state.mClipSideFlags = kClipSide_ConservativeFull; - state.mBounds.set(currentClip); - } - } - - state.mClipValid = (stateDeferFlags & kStateDeferFlag_Clip); - if (state.mClipValid) { - state.mClip.set(currentClip); - } - - // Transform and alpha always deferred, since they are used by state operations - // (Note: saveLayer/restore use colorFilter and alpha, so we just save restore everything) - state.mMatrix = *currentMatrix; - state.mAlpha = currentSnapshot()->alpha; - - // always store/restore, since these are just pointers - state.mRoundRectClipState = currentSnapshot()->roundRectClipState; -#if !HWUI_NEW_OPS - state.mProjectionPathMask = currentSnapshot()->projectionPathMask; -#endif - return false; -} - -void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) { - setGlobalMatrix(state.mMatrix); - writableSnapshot()->alpha = state.mAlpha; - writableSnapshot()->roundRectClipState = state.mRoundRectClipState; -#if !HWUI_NEW_OPS - writableSnapshot()->projectionPathMask = state.mProjectionPathMask; -#endif - - if (state.mClipValid && !skipClipRestore) { - writableSnapshot()->setClip(state.mClip.left, state.mClip.top, - state.mClip.right, state.mClip.bottom); - dirtyClip(); - } -} - -/** - * Merged multidraw (such as in drawText and drawBitmaps rely on the fact that no clipping is done - * in the draw path. Instead, clipping is done ahead of time - either as a single clip rect (when at - * least one op is clipped), or disabled entirely (because no merged op is clipped) - * - * This method should be called when restoreDisplayState() won't be restoring the clip - */ -void OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) { - if (clipRect != nullptr) { - writableSnapshot()->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom); - } else { - writableSnapshot()->setClip(0, 0, mState.getWidth(), mState.getHeight()); - } - dirtyClip(); - bool enableScissor = (clipRect != nullptr) || mScissorOptimizationDisabled; - mRenderState.scissor().setEnabled(enableScissor); -} - -/////////////////////////////////////////////////////////////////////////////// -// Clipping -/////////////////////////////////////////////////////////////////////////////// - -void OpenGLRenderer::setScissorFromClip() { - Rect clip(mState.currentRenderTargetClip()); - clip.snapToPixelBoundaries(); - - if (mRenderState.scissor().set(clip.left, getViewportHeight() - clip.bottom, - clip.getWidth(), clip.getHeight())) { - mState.setDirtyClip(false); - } -} - -void OpenGLRenderer::ensureStencilBuffer() { - // Thanks to the mismatch between EGL and OpenGL ES FBO we - // cannot attach a stencil buffer to fbo0 dynamically. Let's - // just hope we have one when hasLayer() returns false. - if (hasLayer()) { - attachStencilBufferToLayer(currentSnapshot()->layer); - } -} - -void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) { - // The layer's FBO is already bound when we reach this stage - if (!layer->getStencilRenderBuffer()) { - RenderBuffer* buffer = mCaches.renderBufferCache.get( - Stencil::getLayerStencilFormat(), - layer->getWidth(), layer->getHeight()); - layer->setStencilRenderBuffer(buffer); - } -} - -static void handlePoint(std::vector<Vertex>& rectangleVertices, const Matrix4& transform, - float x, float y) { - Vertex v; - v.x = x; - v.y = y; - transform.mapPoint(v.x, v.y); - rectangleVertices.push_back(v); -} - -static void handlePointNoTransform(std::vector<Vertex>& rectangleVertices, float x, float y) { - Vertex v; - v.x = x; - v.y = y; - rectangleVertices.push_back(v); -} - -void OpenGLRenderer::drawRectangleList(const RectangleList& rectangleList) { - int quadCount = rectangleList.getTransformedRectanglesCount(); - std::vector<Vertex> rectangleVertices(quadCount * 4); - Rect scissorBox = rectangleList.calculateBounds(); - scissorBox.snapToPixelBoundaries(); - for (int i = 0; i < quadCount; ++i) { - const TransformedRectangle& tr(rectangleList.getTransformedRectangle(i)); - const Matrix4& transform = tr.getTransform(); - Rect bounds = tr.getBounds(); - if (transform.rectToRect()) { - transform.mapRect(bounds); - bounds.doIntersect(scissorBox); - if (!bounds.isEmpty()) { - handlePointNoTransform(rectangleVertices, bounds.left, bounds.top); - handlePointNoTransform(rectangleVertices, bounds.right, bounds.top); - handlePointNoTransform(rectangleVertices, bounds.left, bounds.bottom); - handlePointNoTransform(rectangleVertices, bounds.right, bounds.bottom); - } - } else { - handlePoint(rectangleVertices, transform, bounds.left, bounds.top); - handlePoint(rectangleVertices, transform, bounds.right, bounds.top); - handlePoint(rectangleVertices, transform, bounds.left, bounds.bottom); - handlePoint(rectangleVertices, transform, bounds.right, bounds.bottom); - } - } - - mRenderState.scissor().set(scissorBox.left, getViewportHeight() - scissorBox.bottom, - scissorBox.getWidth(), scissorBox.getHeight()); - const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform; - Glop glop; - Vertex* vertices = &rectangleVertices[0]; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshIndexedQuads(vertices, rectangleVertices.size() / 4) - .setFillBlack() - .setTransform(*currentSnapshot(), transformFlags) - .setModelViewOffsetRect(0, 0, scissorBox) - .build(); - renderGlop(glop); -} - -void OpenGLRenderer::setStencilFromClip() { - if (!Properties::debugOverdraw) { - if (!currentSnapshot()->clipIsSimple()) { - int incrementThreshold; - EVENT_LOGD("setStencilFromClip - enabling"); - - // NOTE: The order here is important, we must set dirtyClip to false - // before any draw call to avoid calling back into this method - mState.setDirtyClip(false); - - ensureStencilBuffer(); - - const ClipArea& clipArea = currentSnapshot()->getClipArea(); - - bool isRectangleList = clipArea.isRectangleList(); - if (isRectangleList) { - incrementThreshold = clipArea.getRectangleList().getTransformedRectanglesCount(); - } else { - incrementThreshold = 0; - } - - mRenderState.stencil().enableWrite(incrementThreshold); - - // Clean and update the stencil, but first make sure we restrict drawing - // to the region's bounds - bool resetScissor = mRenderState.scissor().setEnabled(true); - if (resetScissor) { - // The scissor was not set so we now need to update it - setScissorFromClip(); - } - - mRenderState.stencil().clear(); - - // stash and disable the outline clip state, since stencil doesn't account for outline - bool storedSkipOutlineClip = mSkipOutlineClip; - mSkipOutlineClip = true; - - SkPaint paint; - paint.setColor(SK_ColorBLACK); - paint.setXfermodeMode(SkXfermode::kSrc_Mode); - - if (isRectangleList) { - drawRectangleList(clipArea.getRectangleList()); - } else { - // NOTE: We could use the region contour path to generate a smaller mesh - // Since we are using the stencil we could use the red book path - // drawing technique. It might increase bandwidth usage though. - - // The last parameter is important: we are not drawing in the color buffer - // so we don't want to dirty the current layer, if any - drawRegionRects(clipArea.getClipRegion(), paint, false); - } - if (resetScissor) mRenderState.scissor().setEnabled(false); - mSkipOutlineClip = storedSkipOutlineClip; - - mRenderState.stencil().enableTest(incrementThreshold); - - // Draw the region used to generate the stencil if the appropriate debug - // mode is enabled - // TODO: Implement for rectangle list clip areas - if (Properties::debugStencilClip == StencilClipDebug::ShowRegion - && !clipArea.isRectangleList()) { - paint.setColor(0x7f0000ff); - paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); - drawRegionRects(currentSnapshot()->getClipRegion(), paint); - } - } else { - EVENT_LOGD("setStencilFromClip - disabling"); - mRenderState.stencil().disable(); - } - } -} - -/** - * Returns false and sets scissor enable based upon bounds if drawing won't be clipped out. - * - * @param paint if not null, the bounds will be expanded to account for stroke depending on paint - * style, and tessellated AA ramp - */ -bool OpenGLRenderer::quickRejectSetupScissor(float left, float top, float right, float bottom, - const SkPaint* paint) { - bool snapOut = paint && paint->isAntiAlias(); - - if (paint && paint->getStyle() != SkPaint::kFill_Style) { - float outset = paint->getStrokeWidth() * 0.5f; - left -= outset; - top -= outset; - right += outset; - bottom += outset; - } - - bool clipRequired = false; - bool roundRectClipRequired = false; - if (mState.calculateQuickRejectForScissor(left, top, right, bottom, - &clipRequired, &roundRectClipRequired, snapOut)) { - return true; - } - - // not quick rejected, so enable the scissor if clipRequired - mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired); - mSkipOutlineClip = !roundRectClipRequired; - return false; -} - -void OpenGLRenderer::debugClip() { -#if DEBUG_CLIP_REGIONS - if (!currentSnapshot()->clipRegion->isEmpty()) { - SkPaint paint; - paint.setColor(0x7f00ff00); - drawRegionRects(*(currentSnapshot()->clipRegion, paint); - - } -#endif -} - -void OpenGLRenderer::renderGlop(const Glop& glop, GlopRenderType type) { - // TODO: It would be best if we could do this before quickRejectSetupScissor() - // changes the scissor test state - if (type != GlopRenderType::LayerClear) { - // Regular draws need to clear the dirty area on the layer before they start drawing on top - // of it. If this draw *is* a layer clear, it skips the clear step (since it would - // infinitely recurse) - clearLayerRegions(); - } - - if (mState.getDirtyClip()) { - if (mRenderState.scissor().isEnabled()) { - setScissorFromClip(); - } - - setStencilFromClip(); - } - mRenderState.render(glop, currentSnapshot()->getOrthoMatrix()); - if (type == GlopRenderType::Standard && !mRenderState.stencil().isWriteEnabled()) { - // TODO: specify more clearly when a draw should dirty the layer. - // is writing to the stencil the only time we should ignore this? -#if !HWUI_NEW_OPS - dirtyLayer(glop.bounds.left, glop.bounds.top, glop.bounds.right, glop.bounds.bottom); -#endif - mDirty = true; - } -} - -/////////////////////////////////////////////////////////////////////////////// -// Drawing -/////////////////////////////////////////////////////////////////////////////// - -void OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags) { - // All the usual checks and setup operations (quickReject, setupDraw, etc.) - // will be performed by the display list itself - if (renderNode && renderNode->isRenderable()) { - // compute 3d ordering - renderNode->computeOrdering(); - if (CC_UNLIKELY(Properties::drawDeferDisabled)) { - startFrame(); - ReplayStateStruct replayStruct(*this, dirty, replayFlags); - renderNode->replay(replayStruct, 0); - return; - } - - DeferredDisplayList deferredList(mState.currentRenderTargetClip()); - DeferStateStruct deferStruct(deferredList, *this, replayFlags); - renderNode->defer(deferStruct, 0); - - flushLayers(); - startFrame(); - - deferredList.flush(*this, dirty); - } else { - // Even if there is no drawing command(Ex: invisible), - // it still needs startFrame to clear buffer and start tiling. - startFrame(); - } -} - -/** - * Important note: this method is intended to draw batches of bitmaps and - * will not set the scissor enable or dirty the current layer, if any. - * The caller is responsible for properly dirtying the current layer. - */ -void OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry, - int bitmapCount, TextureVertex* vertices, bool pureTranslate, - const Rect& bounds, const SkPaint* paint) { - Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap); - if (!texture) return; - - const AutoTexture autoCleanup(texture); - - // TODO: remove layer dirty in multi-draw callers - // TODO: snap doesn't need to touch transform, only texture filter. - bool snap = pureTranslate; - const float x = floorf(bounds.left + 0.5f); - const float y = floorf(bounds.top + 0.5f); - - const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType) - ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None; - const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform; - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshTexturedMesh(vertices, bitmapCount * 6) - .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) - .setTransform(*currentSnapshot(), transformFlags) - .setModelViewOffsetRectOptionalSnap(snap, x, y, Rect(bounds.getWidth(), bounds.getHeight())) - .build(); - renderGlop(glop, GlopRenderType::Multi); -} - -void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) { - if (quickRejectSetupScissor(0, 0, bitmap->width(), bitmap->height())) { - return; - } - - mCaches.textureState().activateTexture(0); - Texture* texture = getTexture(bitmap); - if (!texture) return; - const AutoTexture autoCleanup(texture); - - const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType) - ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None; - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshTexturedUnitQuad(texture->uvMapper) - .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) - .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewMapUnitToRectSnap(Rect(texture->width(), texture->height())) - .build(); - renderGlop(glop); -} - -void OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight, - const float* vertices, const int* colors, const SkPaint* paint) { - if (!vertices || mState.currentlyIgnored()) { - return; - } - - float left = FLT_MAX; - float top = FLT_MAX; - float right = FLT_MIN; - float bottom = FLT_MIN; - - const uint32_t elementCount = meshWidth * meshHeight * 6; - - std::unique_ptr<ColorTextureVertex[]> mesh(new ColorTextureVertex[elementCount]); - ColorTextureVertex* vertex = &mesh[0]; - - std::unique_ptr<int[]> tempColors; - if (!colors) { - uint32_t colorsCount = (meshWidth + 1) * (meshHeight + 1); - tempColors.reset(new int[colorsCount]); - memset(tempColors.get(), 0xff, colorsCount * sizeof(int)); - colors = tempColors.get(); - } - - Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap->pixelRef()); - const UvMapper& mapper(getMapper(texture)); - - for (int32_t y = 0; y < meshHeight; y++) { - for (int32_t x = 0; x < meshWidth; x++) { - uint32_t i = (y * (meshWidth + 1) + x) * 2; - - float u1 = float(x) / meshWidth; - float u2 = float(x + 1) / meshWidth; - float v1 = float(y) / meshHeight; - float v2 = float(y + 1) / meshHeight; - - mapper.map(u1, v1, u2, v2); - - int ax = i + (meshWidth + 1) * 2; - int ay = ax + 1; - int bx = i; - int by = bx + 1; - int cx = i + 2; - int cy = cx + 1; - int dx = i + (meshWidth + 1) * 2 + 2; - int dy = dx + 1; - - ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]); - ColorTextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2, colors[ax / 2]); - ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]); - - ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]); - ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]); - ColorTextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1, colors[cx / 2]); - - left = std::min(left, std::min(vertices[ax], std::min(vertices[bx], vertices[cx]))); - top = std::min(top, std::min(vertices[ay], std::min(vertices[by], vertices[cy]))); - right = std::max(right, std::max(vertices[ax], std::max(vertices[bx], vertices[cx]))); - bottom = std::max(bottom, std::max(vertices[ay], std::max(vertices[by], vertices[cy]))); - } - } - - if (quickRejectSetupScissor(left, top, right, bottom)) { - return; - } - - if (!texture) { - texture = mCaches.textureCache.get(bitmap); - if (!texture) { - return; - } - } - const AutoTexture autoCleanup(texture); - - /* - * TODO: handle alpha_8 textures correctly by applying paint color, but *not* - * shader in that case to mimic the behavior in SkiaCanvas::drawBitmapMesh. - */ - const int textureFillFlags = TextureFillFlags::None; - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshColoredTexturedMesh(mesh.get(), elementCount) - .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) - .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom)) - .build(); - renderGlop(glop); -} - -void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, Rect src, Rect dst, const SkPaint* paint) { - if (quickRejectSetupScissor(dst)) { - return; - } - - Texture* texture = getTexture(bitmap); - if (!texture) return; - const AutoTexture autoCleanup(texture); - - Rect uv(std::max(0.0f, src.left / texture->width()), - std::max(0.0f, src.top / texture->height()), - std::min(1.0f, src.right / texture->width()), - std::min(1.0f, src.bottom / texture->height())); - - const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType) - ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None; - const bool tryToSnap = MathUtils::areEqual(src.getWidth(), dst.getWidth()) - && MathUtils::areEqual(src.getHeight(), dst.getHeight()); - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshTexturedUvQuad(texture->uvMapper, uv) - .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) - .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewMapUnitToRectOptionalSnap(tryToSnap, dst) - .build(); - renderGlop(glop); -} - -void OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh, - AssetAtlas::Entry* entry, float left, float top, float right, float bottom, - const SkPaint* paint) { - if (!mesh || !mesh->verticesCount || quickRejectSetupScissor(left, top, right, bottom)) { - return; - } - - Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap); - if (!texture) return; - const AutoTexture autoCleanup(texture); - - // 9 patches are built for stretching - always filter - int textureFillFlags = TextureFillFlags::ForceFilter; - if (bitmap->colorType() == kAlpha_8_SkColorType) { - textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture; - } - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshPatchQuads(*mesh) - .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) - .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewOffsetRectSnap(left, top, Rect(right - left, bottom - top)) // TODO: get minimal bounds from patch - .build(); - renderGlop(glop); -} - -/** - * Important note: this method is intended to draw batches of 9-patch objects and - * will not set the scissor enable or dirty the current layer, if any. - * The caller is responsible for properly dirtying the current layer. - */ -void OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry, - TextureVertex* vertices, uint32_t elementCount, const SkPaint* paint) { - mCaches.textureState().activateTexture(0); - Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap); - if (!texture) return; - const AutoTexture autoCleanup(texture); - - // TODO: get correct bounds from caller - const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform; - // 9 patches are built for stretching - always filter - int textureFillFlags = TextureFillFlags::ForceFilter; - if (bitmap->colorType() == kAlpha_8_SkColorType) { - textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture; - } - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshTexturedIndexedQuads(vertices, elementCount) - .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha) - .setTransform(*currentSnapshot(), transformFlags) - .setModelViewOffsetRect(0, 0, Rect()) - .build(); - renderGlop(glop, GlopRenderType::Multi); -} - -void OpenGLRenderer::drawVertexBuffer(float translateX, float translateY, - const VertexBuffer& vertexBuffer, const SkPaint* paint, int displayFlags) { - // not missing call to quickReject/dirtyLayer, always done at a higher level - if (!vertexBuffer.getVertexCount()) { - // no vertices to draw - return; - } - - bool shadowInterp = displayFlags & kVertexBuffer_ShadowInterp; - const int transformFlags = TransformFlags::OffsetByFudgeFactor; - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshVertexBuffer(vertexBuffer) - .setFillPaint(*paint, currentSnapshot()->alpha, shadowInterp) - .setTransform(*currentSnapshot(), transformFlags) - .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds()) - .build(); - renderGlop(glop); -} - -/** - * Renders a convex path via tessellation. For AA paths, this function uses a similar approach to - * that of AA lines in the drawLines() function. We expand the convex path by a half pixel in - * screen space in all directions. However, instead of using a fragment shader to compute the - * translucency of the color from its position, we simply use a varying parameter to define how far - * a given pixel is from the edge. For non-AA paths, the expansion and alpha varying are not used. - * - * Doesn't yet support joins, caps, or path effects. - */ -void OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint) { - VertexBuffer vertexBuffer; - // TODO: try clipping large paths to viewport - - PathTessellator::tessellatePath(path, paint, *currentTransform(), vertexBuffer); - drawVertexBuffer(vertexBuffer, paint); -} - -/** - * We create tristrips for the lines much like shape stroke tessellation, using a per-vertex alpha - * and additional geometry for defining an alpha slope perimeter. - * - * Using GL_LINES can be difficult because the rasterization rules for those lines produces some - * unexpected results, and may vary between hardware devices. Previously we used a varying-base - * in-shader alpha region, but found it to be taxing on some GPUs. - * - * TODO: try using a fixed input buffer for non-capped lines as in text rendering. this may reduce - * memory transfer by removing need for degenerate vertices. - */ -void OpenGLRenderer::drawLines(const float* points, int count, const SkPaint* paint) { - if (mState.currentlyIgnored() || count < 4) return; - - count &= ~0x3; // round down to nearest four - - VertexBuffer buffer; - PathTessellator::tessellateLines(points, count, paint, *currentTransform(), buffer); - const Rect& bounds = buffer.getBounds(); - - if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) { - return; - } - - int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset; - drawVertexBuffer(buffer, paint, displayFlags); -} - -void OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) { - if (mState.currentlyIgnored() || count < 2) return; - - count &= ~0x1; // round down to nearest two - - VertexBuffer buffer; - PathTessellator::tessellatePoints(points, count, paint, *currentTransform(), buffer); - - const Rect& bounds = buffer.getBounds(); - if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) { - return; - } - - int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset; - drawVertexBuffer(buffer, paint, displayFlags); - - mDirty = true; -} - -void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { - // No need to check against the clip, we fill the clip region - if (mState.currentlyIgnored()) return; - - Rect clip(mState.currentRenderTargetClip()); - clip.snapToPixelBoundaries(); - - SkPaint paint; - paint.setColor(color); - paint.setXfermodeMode(mode); - - drawColorRect(clip.left, clip.top, clip.right, clip.bottom, &paint, true); - - mDirty = true; -} - -void OpenGLRenderer::drawShape(float left, float top, PathTexture* texture, - const SkPaint* paint) { - if (!texture) return; - const AutoTexture autoCleanup(texture); - - const float x = left + texture->left - texture->offset; - const float y = top + texture->top - texture->offset; - - drawPathTexture(texture, x, y, paint); - - mDirty = true; -} - -void OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom, - float rx, float ry, const SkPaint* p) { - if (mState.currentlyIgnored() - || quickRejectSetupScissor(left, top, right, bottom, p) - || PaintUtils::paintWillNotDraw(*p)) { - return; - } - - if (p->getPathEffect() != nullptr) { - mCaches.textureState().activateTexture(0); - PathTexture* texture = mCaches.pathCache.getRoundRect( - right - left, bottom - top, rx, ry, p); - drawShape(left, top, texture, p); - } else { - const VertexBuffer* vertexBuffer = mCaches.tessellationCache.getRoundRect( - *currentTransform(), *p, right - left, bottom - top, rx, ry); - drawVertexBuffer(left, top, *vertexBuffer, p); - } -} - -void OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p) { - if (mState.currentlyIgnored() - || quickRejectSetupScissor(x - radius, y - radius, x + radius, y + radius, p) - || PaintUtils::paintWillNotDraw(*p)) { - return; - } - - if (p->getPathEffect() != nullptr) { - mCaches.textureState().activateTexture(0); - PathTexture* texture = mCaches.pathCache.getCircle(radius, p); - drawShape(x - radius, y - radius, texture, p); - return; - } - - SkPath path; - if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { - path.addCircle(x, y, radius + p->getStrokeWidth() / 2); - } else { - path.addCircle(x, y, radius); - } - -#if !HWUI_NEW_OPS - if (CC_UNLIKELY(currentSnapshot()->projectionPathMask != nullptr)) { - // mask ripples with projection mask - SkPath maskPath = *(currentSnapshot()->projectionPathMask->projectionMask); - - Matrix4 screenSpaceTransform; - currentSnapshot()->buildScreenSpaceTransform(&screenSpaceTransform); - - Matrix4 totalTransform; - totalTransform.loadInverse(screenSpaceTransform); - totalTransform.multiply(currentSnapshot()->projectionPathMask->projectionMaskTransform); - - SkMatrix skTotalTransform; - totalTransform.copyTo(skTotalTransform); - maskPath.transform(skTotalTransform); - - // Mask the ripple path by the projection mask, now that it's - // in local space. Note that this can create CCW paths. - Op(path, maskPath, kIntersect_SkPathOp, &path); - } -#endif - drawConvexPath(path, p); -} - -void OpenGLRenderer::drawOval(float left, float top, float right, float bottom, - const SkPaint* p) { - if (mState.currentlyIgnored() - || quickRejectSetupScissor(left, top, right, bottom, p) - || PaintUtils::paintWillNotDraw(*p)) { - return; - } - - if (p->getPathEffect() != nullptr) { - mCaches.textureState().activateTexture(0); - PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p); - drawShape(left, top, texture, p); - } else { - SkPath path; - SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); - if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { - rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2); - } - path.addOval(rect); - drawConvexPath(path, p); - } -} - -void OpenGLRenderer::drawArc(float left, float top, float right, float bottom, - float startAngle, float sweepAngle, bool useCenter, const SkPaint* p) { - if (mState.currentlyIgnored() - || quickRejectSetupScissor(left, top, right, bottom, p) - || PaintUtils::paintWillNotDraw(*p)) { - return; - } - - // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180) - if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != nullptr || useCenter) { - mCaches.textureState().activateTexture(0); - PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top, - startAngle, sweepAngle, useCenter, p); - drawShape(left, top, texture, p); - return; - } - SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); - if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { - rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2); - } - - SkPath path; - if (useCenter) { - path.moveTo(rect.centerX(), rect.centerY()); - } - path.arcTo(rect, startAngle, sweepAngle, !useCenter); - if (useCenter) { - path.close(); - } - drawConvexPath(path, p); -} - -void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, - const SkPaint* p) { - if (mState.currentlyIgnored() - || quickRejectSetupScissor(left, top, right, bottom, p) - || PaintUtils::paintWillNotDraw(*p)) { - return; - } - - if (p->getStyle() != SkPaint::kFill_Style) { - // only fill style is supported by drawConvexPath, since others have to handle joins - static_assert(SkPaintDefaults_MiterLimit == 4.0f, "Miter limit has changed"); - if (p->getPathEffect() != nullptr || p->getStrokeJoin() != SkPaint::kMiter_Join || - p->getStrokeMiter() != SkPaintDefaults_MiterLimit) { - mCaches.textureState().activateTexture(0); - PathTexture* texture = - mCaches.pathCache.getRect(right - left, bottom - top, p); - drawShape(left, top, texture, p); - } else { - SkPath path; - SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); - if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { - rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2); - } - path.addRect(rect); - drawConvexPath(path, p); - } - } else { - if (p->isAntiAlias() && !currentTransform()->isSimple()) { - SkPath path; - path.addRect(left, top, right, bottom); - drawConvexPath(path, p); - } else { - drawColorRect(left, top, right, bottom, p); - - mDirty = true; - } - } -} - -void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const glyph_t* glyphs, - int count, const float* positions, - FontRenderer& fontRenderer, int alpha, float x, float y) { - mCaches.textureState().activateTexture(0); - - PaintUtils::TextShadow textShadow; - if (!PaintUtils::getTextShadow(paint, &textShadow)) { - LOG_ALWAYS_FATAL("failed to query shadow attributes"); - } - - // NOTE: The drop shadow will not perform gamma correction - // if shader-based correction is enabled - mCaches.dropShadowCache.setFontRenderer(fontRenderer); - ShadowTexture* texture = mCaches.dropShadowCache.get( - paint, glyphs, count, textShadow.radius, positions); - // If the drop shadow exceeds the max texture size or couldn't be - // allocated, skip drawing - if (!texture) return; - const AutoTexture autoCleanup(texture); - - const float sx = x - texture->left + textShadow.dx; - const float sy = y - texture->top + textShadow.dy; - - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshTexturedUnitQuad(nullptr) - .setFillShadowTexturePaint(*texture, textShadow.color, *paint, currentSnapshot()->alpha) - .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width(), sy + texture->height())) - .build(); - renderGlop(glop); -} - -// TODO: remove this, once mState.currentlyIgnored captures snapshot alpha -bool OpenGLRenderer::canSkipText(const SkPaint* paint) const { - float alpha = (PaintUtils::hasTextShadow(paint) - ? 1.0f : paint->getAlpha()) * currentSnapshot()->alpha; - return MathUtils::isZero(alpha) - && PaintUtils::getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode; -} - -bool OpenGLRenderer::findBestFontTransform(const mat4& transform, SkMatrix* outMatrix) const { - if (CC_LIKELY(transform.isPureTranslate())) { - outMatrix->setIdentity(); - return false; - } else if (CC_UNLIKELY(transform.isPerspective())) { - outMatrix->setIdentity(); - return true; - } - - /** - * Input is a non-perspective, scaling transform. Generate a scale-only transform, - * with values rounded to the nearest int. - */ - float sx, sy; - transform.decomposeScale(sx, sy); - outMatrix->setScale( - roundf(std::max(1.0f, sx)), - roundf(std::max(1.0f, sy))); - return true; -} - -int OpenGLRenderer::getSaveCount() const { - return mState.getSaveCount(); -} - -int OpenGLRenderer::save(int flags) { - return mState.save(flags); -} - -void OpenGLRenderer::restore() { - mState.restore(); -} - -void OpenGLRenderer::restoreToCount(int saveCount) { - mState.restoreToCount(saveCount); -} - - -void OpenGLRenderer::translate(float dx, float dy, float dz) { - mState.translate(dx, dy, dz); -} - -void OpenGLRenderer::rotate(float degrees) { - mState.rotate(degrees); -} - -void OpenGLRenderer::scale(float sx, float sy) { - mState.scale(sx, sy); -} - -void OpenGLRenderer::skew(float sx, float sy) { - mState.skew(sx, sy); -} - -void OpenGLRenderer::setLocalMatrix(const Matrix4& matrix) { - mState.setMatrix(mBaseTransform); - mState.concatMatrix(matrix); -} - -void OpenGLRenderer::setLocalMatrix(const SkMatrix& matrix) { - mState.setMatrix(mBaseTransform); - mState.concatMatrix(matrix); -} - -void OpenGLRenderer::concatMatrix(const Matrix4& matrix) { - mState.concatMatrix(matrix); -} - -bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) { - return mState.clipRect(left, top, right, bottom, op); -} - -bool OpenGLRenderer::clipPath(const SkPath* path, SkRegion::Op op) { - return mState.clipPath(path, op); -} - -bool OpenGLRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) { - return mState.clipRegion(region, op); -} - -void OpenGLRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) { - mState.setClippingOutline(allocator, outline); -} - -void OpenGLRenderer::setClippingRoundRect(LinearAllocator& allocator, - const Rect& rect, float radius, bool highPriority) { - mState.setClippingRoundRect(allocator, rect, radius, highPriority); -} - -void OpenGLRenderer::setProjectionPathMask(LinearAllocator& allocator, const SkPath* path) { - mState.setProjectionPathMask(allocator, path); -} - -void OpenGLRenderer::drawText(const glyph_t* glyphs, int bytesCount, int count, float x, float y, - const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds, - DrawOpMode drawOpMode) { - - if (drawOpMode == DrawOpMode::kImmediate) { - // The checks for corner-case ignorable text and quick rejection is only done for immediate - // drawing as ops from DeferredDisplayList are already filtered for these - if (glyphs == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint) || - quickRejectSetupScissor(bounds)) { - return; - } - } - - const float oldX = x; - const float oldY = y; - - const mat4& transform = *currentTransform(); - const bool pureTranslate = transform.isPureTranslate(); - - if (CC_LIKELY(pureTranslate)) { - x = floorf(x + transform.getTranslateX() + 0.5f); - y = floorf(y + transform.getTranslateY() + 0.5f); - } - - int alpha = PaintUtils::getAlphaDirect(paint) * currentSnapshot()->alpha; - SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(paint); - - FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(); - - if (CC_UNLIKELY(PaintUtils::hasTextShadow(paint))) { - fontRenderer.setFont(paint, SkMatrix::I()); - drawTextShadow(paint, glyphs, count, positions, fontRenderer, - alpha, oldX, oldY); - } - - const bool hasActiveLayer = hasLayer(); - - // We only pass a partial transform to the font renderer. That partial - // matrix defines how glyphs are rasterized. Typically we want glyphs - // to be rasterized at their final size on screen, which means the partial - // matrix needs to take the scale factor into account. - // When a partial matrix is used to transform glyphs during rasterization, - // the mesh is generated with the inverse transform (in the case of scale, - // the mesh is generated at 1.0 / scale for instance.) This allows us to - // apply the full transform matrix at draw time in the vertex shader. - // Applying the full matrix in the shader is the easiest way to handle - // rotation and perspective and allows us to always generated quads in the - // font renderer which greatly simplifies the code, clipping in particular. - SkMatrix fontTransform; - bool linearFilter = findBestFontTransform(transform, &fontTransform) - || fabs(y - (int) y) > 0.0f - || fabs(x - (int) x) > 0.0f; - fontRenderer.setFont(paint, fontTransform); - fontRenderer.setTextureFiltering(linearFilter); - - // TODO: Implement better clipping for scaled/rotated text - const Rect* clip = !pureTranslate ? nullptr : &mState.currentRenderTargetClip(); - Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); - - bool status; -#if HWUI_NEW_OPS - LOG_ALWAYS_FATAL("unsupported"); - TextDrawFunctor functor(nullptr, nullptr, nullptr, x, y, pureTranslate, alpha, mode, paint); -#else - TextDrawFunctor functor(this, x, y, pureTranslate, alpha, mode, paint); -#endif - - // don't call issuedrawcommand, do it at end of batch - bool forceFinish = (drawOpMode != DrawOpMode::kDefer); - if (CC_UNLIKELY(paint->getTextAlign() != SkPaint::kLeft_Align)) { - SkPaint paintCopy(*paint); - paintCopy.setTextAlign(SkPaint::kLeft_Align); - status = fontRenderer.renderPosText(&paintCopy, clip, glyphs, count, x, y, - positions, hasActiveLayer ? &layerBounds : nullptr, &functor, forceFinish); - } else { - status = fontRenderer.renderPosText(paint, clip, glyphs, count, x, y, - positions, hasActiveLayer ? &layerBounds : nullptr, &functor, forceFinish); - } - - if ((status || drawOpMode != DrawOpMode::kImmediate) && hasActiveLayer) { - if (!pureTranslate) { - transform.mapRect(layerBounds); - } - dirtyLayerUnchecked(layerBounds, getRegion()); - } - - mDirty = true; -} - -void OpenGLRenderer::drawTextOnPath(const glyph_t* glyphs, int bytesCount, int count, - const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) { - if (glyphs == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) { - return; - } - - // TODO: avoid scissor by calculating maximum bounds using path bounds + font metrics - mRenderState.scissor().setEnabled(true); - - FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(); - fontRenderer.setFont(paint, SkMatrix::I()); - fontRenderer.setTextureFiltering(true); - - int alpha = PaintUtils::getAlphaDirect(paint) * currentSnapshot()->alpha; - SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(paint); -#if HWUI_NEW_OPS - LOG_ALWAYS_FATAL("unsupported"); - TextDrawFunctor functor(nullptr, nullptr, nullptr, 0.0f, 0.0f, false, alpha, mode, paint); -#else - TextDrawFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint); -#endif - - const Rect* clip = &writableSnapshot()->getLocalClip(); - Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f); - - if (fontRenderer.renderTextOnPath(paint, clip, glyphs, count, path, - hOffset, vOffset, hasLayer() ? &bounds : nullptr, &functor)) { - dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform()); - mDirty = true; - } -} - -void OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) { - if (mState.currentlyIgnored()) return; - - mCaches.textureState().activateTexture(0); - - PathTexture* texture = mCaches.pathCache.get(path, paint); - if (!texture) return; - - const float x = texture->left - texture->offset; - const float y = texture->top - texture->offset; - - drawPathTexture(texture, x, y, paint); - - if (texture->cleanup) { - mCaches.pathCache.remove(path, paint); - } - mDirty = true; -} - -void OpenGLRenderer::drawLayer(Layer* layer) { - if (!layer) { - return; - } - - mat4* transform = nullptr; - if (layer->isTextureLayer()) { - transform = &layer->getTransform(); - if (!transform->isIdentity()) { - save(SaveFlags::Matrix); - concatMatrix(*transform); - } - } - - bool clipRequired = false; - const bool rejected = mState.calculateQuickRejectForScissor( - 0, 0, layer->layer.getWidth(), layer->layer.getHeight(), - &clipRequired, nullptr, false); - - if (rejected) { - if (transform && !transform->isIdentity()) { - restore(); - } - return; - } - - EVENT_LOGD("drawLayer," RECT_STRING ", clipRequired %d", x, y, - x + layer->layer.getWidth(), y + layer->layer.getHeight(), clipRequired); - - updateLayer(layer, true); - - mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired); - mCaches.textureState().activateTexture(0); - - if (CC_LIKELY(!layer->region.isEmpty())) { - if (layer->region.isRect()) { - DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, - composeLayerRect(layer, layer->regionRect)); - } else if (layer->mesh) { - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshTexturedIndexedQuads(layer->mesh, layer->meshElementCount) - .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap) - .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewOffsetRectSnap(0, 0, Rect(layer->layer.getWidth(), layer->layer.getHeight())) - .build(); - DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop)); -#if DEBUG_LAYERS_AS_REGIONS - drawRegionRectsDebug(layer->region); -#endif - } - - if (layer->debugDrawUpdate) { - layer->debugDrawUpdate = false; - - SkPaint paint; - paint.setColor(0x7f00ff00); - drawColorRect(0, 0, layer->layer.getWidth(), layer->layer.getHeight(), &paint); - } - } - layer->hasDrawnSinceUpdate = true; - - if (transform && !transform->isIdentity()) { - restore(); - } - - mDirty = true; -} - -/////////////////////////////////////////////////////////////////////////////// -// Draw filters -/////////////////////////////////////////////////////////////////////////////// -void OpenGLRenderer::setDrawFilter(SkDrawFilter* filter) { - // We should never get here since we apply the draw filter when stashing - // the paints in the DisplayList. - LOG_ALWAYS_FATAL("OpenGLRenderer does not directly support DrawFilters"); -} - -/////////////////////////////////////////////////////////////////////////////// -// Drawing implementation -/////////////////////////////////////////////////////////////////////////////// - -Texture* OpenGLRenderer::getTexture(const SkBitmap* bitmap) { - Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap->pixelRef()); - if (!texture) { - return mCaches.textureCache.get(bitmap); - } - return texture; -} - -void OpenGLRenderer::drawPathTexture(PathTexture* texture, float x, float y, - const SkPaint* paint) { - if (quickRejectSetupScissor(x, y, x + texture->width(), y + texture->height())) { - return; - } - - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshTexturedUnitQuad(nullptr) - .setFillPathTexturePaint(*texture, *paint, currentSnapshot()->alpha) - .setTransform(*currentSnapshot(), TransformFlags::None) - .setModelViewMapUnitToRect(Rect(x, y, x + texture->width(), y + texture->height())) - .build(); - renderGlop(glop); -} - -void OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* paint) { - if (mState.currentlyIgnored()) { - return; - } - - drawColorRects(rects, count, paint, false, true, true); -} - -void OpenGLRenderer::drawShadow(float casterAlpha, - const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) { - if (mState.currentlyIgnored()) return; - - // TODO: use quickRejectWithScissor. For now, always force enable scissor. - mRenderState.scissor().setEnabled(true); - - SkPaint paint; - paint.setAntiAlias(true); // want to use AlphaVertex - - // The caller has made sure casterAlpha > 0. - float ambientShadowAlpha = mAmbientShadowAlpha; - if (CC_UNLIKELY(Properties::overrideAmbientShadowStrength >= 0)) { - ambientShadowAlpha = Properties::overrideAmbientShadowStrength; - } - if (ambientShadowVertexBuffer && ambientShadowAlpha > 0) { - paint.setARGB(casterAlpha * ambientShadowAlpha, 0, 0, 0); - drawVertexBuffer(*ambientShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp); - } - - float spotShadowAlpha = mSpotShadowAlpha; - if (CC_UNLIKELY(Properties::overrideSpotShadowStrength >= 0)) { - spotShadowAlpha = Properties::overrideSpotShadowStrength; - } - if (spotShadowVertexBuffer && spotShadowAlpha > 0) { - paint.setARGB(casterAlpha * spotShadowAlpha, 0, 0, 0); - drawVertexBuffer(*spotShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp); - } - - mDirty=true; -} - -void OpenGLRenderer::drawColorRects(const float* rects, int count, const SkPaint* paint, - bool ignoreTransform, bool dirty, bool clip) { - if (count == 0) { - return; - } - - float left = FLT_MAX; - float top = FLT_MAX; - float right = FLT_MIN; - float bottom = FLT_MIN; - - Vertex mesh[count]; - Vertex* vertex = mesh; - - for (int index = 0; index < count; index += 4) { - float l = rects[index + 0]; - float t = rects[index + 1]; - float r = rects[index + 2]; - float b = rects[index + 3]; - - Vertex::set(vertex++, l, t); - Vertex::set(vertex++, r, t); - Vertex::set(vertex++, l, b); - Vertex::set(vertex++, r, b); - - left = std::min(left, l); - top = std::min(top, t); - right = std::max(right, r); - bottom = std::max(bottom, b); - } - - if (clip && quickRejectSetupScissor(left, top, right, bottom)) { - return; - } - - const int transformFlags = ignoreTransform - ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None; - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshIndexedQuads(&mesh[0], count / 4) - .setFillPaint(*paint, currentSnapshot()->alpha) - .setTransform(*currentSnapshot(), transformFlags) - .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom)) - .build(); - renderGlop(glop); -} - -void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, - const SkPaint* paint, bool ignoreTransform) { - const int transformFlags = ignoreTransform - ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None; - Glop glop; - GlopBuilder(mRenderState, mCaches, &glop) - .setRoundRectClipState(currentSnapshot()->roundRectClipState) - .setMeshUnitQuad() - .setFillPaint(*paint, currentSnapshot()->alpha) - .setTransform(*currentSnapshot(), transformFlags) - .setModelViewMapUnitToRect(Rect(left, top, right, bottom)) - .build(); - renderGlop(glop); -} - -float OpenGLRenderer::getLayerAlpha(const Layer* layer) const { - return (layer->getAlpha() / 255.0f) * currentSnapshot()->alpha; -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h deleted file mode 100755 index dacd8ccaa6ea..000000000000 --- a/libs/hwui/OpenGLRenderer.h +++ /dev/null @@ -1,785 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_HWUI_OPENGL_RENDERER_H -#define ANDROID_HWUI_OPENGL_RENDERER_H - -#include "CanvasState.h" -#include "Debug.h" -#include "Extensions.h" -#include "Matrix.h" -#include "Program.h" -#include "Rect.h" -#include "Snapshot.h" -#include "UvMapper.h" -#include "Vertex.h" -#include "Caches.h" -#include "utils/PaintUtils.h" - -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> - -#include <SkBitmap.h> -#include <SkCanvas.h> -#include <SkColorFilter.h> -#include <SkDrawLooper.h> -#include <SkMatrix.h> -#include <SkPaint.h> -#include <SkRegion.h> -#include <SkXfermode.h> - -#include <utils/Blur.h> -#include <utils/Functor.h> -#include <utils/RefBase.h> -#include <utils/SortedVector.h> - -#include <cutils/compiler.h> - -#include <androidfw/ResourceTypes.h> - -#include <vector> - -class SkShader; - -namespace android { -namespace uirenderer { - -enum class DrawOpMode { - kImmediate, - kDefer, - kFlush -}; - -class DeferredDisplayState; -struct Glop; -class RenderState; -class RenderNode; -class TextDrawFunctor; -class VertexBuffer; - -enum StateDeferFlags { - kStateDeferFlag_Draw = 0x1, - kStateDeferFlag_Clip = 0x2 -}; - -enum ClipSideFlags { - kClipSide_None = 0x0, - kClipSide_Left = 0x1, - kClipSide_Top = 0x2, - kClipSide_Right = 0x4, - kClipSide_Bottom = 0x8, - kClipSide_Full = 0xF, - kClipSide_ConservativeFull = 0x1F -}; - -enum VertexBufferDisplayFlags { - kVertexBuffer_Offset = 0x1, - kVertexBuffer_ShadowInterp = 0x2, -}; - -/** - * Defines additional transformation that should be applied by the model view matrix, beyond that of - * the currentTransform() - */ -enum ModelViewMode { - /** - * Used when the model view should simply translate geometry passed to the shader. The resulting - * matrix will be a simple translation. - */ - kModelViewMode_Translate = 0, - - /** - * Used when the model view should translate and scale geometry. The resulting matrix will be a - * translation + scale. This is frequently used together with VBO 0, the (0,0,1,1) rect. - */ - kModelViewMode_TranslateAndScale = 1, -}; - -/////////////////////////////////////////////////////////////////////////////// -// Renderer -/////////////////////////////////////////////////////////////////////////////// -/** - * OpenGL Renderer implementation. - */ -class OpenGLRenderer : public CanvasStateClient { -public: - OpenGLRenderer(RenderState& renderState); - virtual ~OpenGLRenderer(); - - void initProperties(); - void initLight(float lightRadius, uint8_t ambientShadowAlpha, - uint8_t spotShadowAlpha); - void setLightCenter(const Vector3& lightCenter); - - /* - * Prepares the renderer to draw a frame. This method must be invoked - * at the beginning of each frame. Only the specified rectangle of the - * frame is assumed to be dirty. A clip will automatically be set to - * the specified rectangle. - * - * @param opaque If true, the target surface is considered opaque - * and will not be cleared. If false, the target surface - * will be cleared - */ - virtual void prepareDirty(int viewportWidth, int viewportHeight, - float left, float top, float right, float bottom, bool opaque); - - /** - * Indicates the end of a frame. This method must be invoked whenever - * the caller is done rendering a frame. - * Returns true if any drawing was done during the frame (the output - * has changed / is "dirty" and should be displayed to the user). - */ - virtual bool finish(); - - void callDrawGLFunction(Functor* functor, Rect& dirty); - - void pushLayerUpdate(Layer* layer); - void cancelLayerUpdate(Layer* layer); - void flushLayerUpdates(); - void markLayersAsBuildLayers(); - - virtual int saveLayer(float left, float top, float right, float bottom, - const SkPaint* paint, int flags) { - return saveLayer(left, top, right, bottom, paint, flags, nullptr); - } - - // Specialized saveLayer implementation, which will pass the convexMask to an FBO layer, if - // created, which will in turn clip to that mask when drawn back/restored. - int saveLayer(float left, float top, float right, float bottom, - const SkPaint* paint, int flags, const SkPath* convexMask); - - int saveLayerDeferred(float left, float top, float right, float bottom, - const SkPaint* paint, int flags); - - void drawRenderNode(RenderNode* displayList, Rect& dirty, int32_t replayFlags = 1); - void drawLayer(Layer* layer); - void drawBitmap(const SkBitmap* bitmap, const SkPaint* paint); - void drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry, int bitmapCount, - TextureVertex* vertices, bool pureTranslate, const Rect& bounds, const SkPaint* paint); - void drawBitmap(const SkBitmap* bitmap, Rect src, Rect dst, - const SkPaint* paint); - void drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight, - const float* vertices, const int* colors, const SkPaint* paint); - void drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry, - TextureVertex* vertices, uint32_t indexCount, const SkPaint* paint); - void drawPatch(const SkBitmap* bitmap, const Patch* mesh, AssetAtlas::Entry* entry, - float left, float top, float right, float bottom, const SkPaint* paint); - void drawColor(int color, SkXfermode::Mode mode); - void drawRect(float left, float top, float right, float bottom, - const SkPaint* paint); - void drawRoundRect(float left, float top, float right, float bottom, - float rx, float ry, const SkPaint* paint); - void drawCircle(float x, float y, float radius, const SkPaint* paint); - void drawOval(float left, float top, float right, float bottom, - const SkPaint* paint); - void drawArc(float left, float top, float right, float bottom, - float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint); - void drawPath(const SkPath* path, const SkPaint* paint); - void drawLines(const float* points, int count, const SkPaint* paint); - void drawPoints(const float* points, int count, const SkPaint* paint); - void drawTextOnPath(const glyph_t* glyphs, int bytesCount, int count, const SkPath* path, - float hOffset, float vOffset, const SkPaint* paint); - void drawText(const glyph_t* glyphs, int bytesCount, int count, float x, float y, - const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds, - DrawOpMode drawOpMode = DrawOpMode::kImmediate); - void drawRects(const float* rects, int count, const SkPaint* paint); - - void drawShadow(float casterAlpha, - const VertexBuffer* ambientShadowVertexBuffer, - const VertexBuffer* spotShadowVertexBuffer); - - void setDrawFilter(SkDrawFilter* filter); - - /** - * Store the current display state (most importantly, the current clip and transform), and - * additionally map the state's bounds from local to window coordinates. - * - * Returns true if quick-rejected - */ - bool storeDisplayState(DeferredDisplayState& state, int stateDeferFlags); - void restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore = false); - void setupMergedMultiDraw(const Rect* clipRect); - - bool isCurrentTransformSimple() { - return currentTransform()->isSimple(); - } - - Caches& getCaches() { - return mCaches; - } - - RenderState& renderState() { - return mRenderState; - } - - int getViewportWidth() { return mState.getViewportWidth(); } - int getViewportHeight() { return mState.getViewportHeight(); } - - /** - * Scales the alpha on the current snapshot. This alpha value will be modulated - * with other alpha values when drawing primitives. - */ - void scaleAlpha(float alpha) { mState.scaleAlpha(alpha); } - - /** - * Inserts a named event marker in the stream of GL commands. - */ - void eventMark(const char* name) const; - - /** - * Inserts a formatted event marker in the stream of GL commands. - */ - void eventMarkDEBUG(const char *fmt, ...) const; - - /** - * Inserts a named group marker in the stream of GL commands. This marker - * can be used by tools to group commands into logical groups. A call to - * this method must always be followed later on by a call to endMark(). - */ - void startMark(const char* name) const; - - /** - * Closes the last group marker opened by startMark(). - */ - void endMark() const; - - /** - * Build the best transform to use to rasterize text given a full - * transform matrix, and whether filteration is needed. - * - * Returns whether filtration is needed - */ - bool findBestFontTransform(const mat4& transform, SkMatrix* outMatrix) const; - -#if DEBUG_MERGE_BEHAVIOR - void drawScreenSpaceColorRect(float left, float top, float right, float bottom, int color) { - mCaches.setScissorEnabled(false); - - // should only be called outside of other draw ops, so stencil can only be in test state - bool stencilWasEnabled = mCaches.stencil.isTestEnabled(); - mCaches.stencil.disable(); - - drawColorRect(left, top, right, bottom, color, SkXfermode::kSrcOver_Mode, true); - - if (stencilWasEnabled) mCaches.stencil.enableTest(); - mDirty = true; - } -#endif - - const Vector3& getLightCenter() const { return mState.currentLightCenter(); } - float getLightRadius() const { return mLightRadius; } - uint8_t getAmbientShadowAlpha() const { return mAmbientShadowAlpha; } - uint8_t getSpotShadowAlpha() const { return mSpotShadowAlpha; } - - /////////////////////////////////////////////////////////////////// - /// State manipulation - - int getSaveCount() const; - int save(int flags); - void restore(); - void restoreToCount(int saveCount); - - void setGlobalMatrix(const Matrix4& matrix) { - mState.setMatrix(matrix); - } - void setLocalMatrix(const Matrix4& matrix); - void setLocalMatrix(const SkMatrix& matrix); - void concatMatrix(const SkMatrix& matrix) { mState.concatMatrix(matrix); } - - void translate(float dx, float dy, float dz = 0.0f); - void rotate(float degrees); - void scale(float sx, float sy); - void skew(float sx, float sy); - - void setMatrix(const Matrix4& matrix); // internal only convenience method - void concatMatrix(const Matrix4& matrix); // internal only convenience method - - const Rect& getLocalClipBounds() const { return mState.getLocalClipBounds(); } - const Rect& getRenderTargetClipBounds() const { return mState.getRenderTargetClipBounds(); } - bool quickRejectConservative(float left, float top, - float right, float bottom) const { - return mState.quickRejectConservative(left, top, right, bottom); - } - - bool clipRect(float left, float top, - float right, float bottom, SkRegion::Op op); - bool clipPath(const SkPath* path, SkRegion::Op op); - bool clipRegion(const SkRegion* region, SkRegion::Op op); - - /** - * Does not support different clipping Ops (that is, every call to setClippingOutline is - * effectively using SkRegion::kReplaceOp) - * - * The clipping outline is independent from the regular clip. - */ - void setClippingOutline(LinearAllocator& allocator, const Outline* outline); - void setClippingRoundRect(LinearAllocator& allocator, - const Rect& rect, float radius, bool highPriority = true); - void setProjectionPathMask(LinearAllocator& allocator, const SkPath* path); - - inline bool hasRectToRectTransform() const { return mState.hasRectToRectTransform(); } - inline const mat4* currentTransform() const { return mState.currentTransform(); } - - /////////////////////////////////////////////////////////////////// - /// CanvasStateClient interface - - virtual void onViewportInitialized() override; - virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) override; - virtual GLuint getTargetFbo() const override { return 0; } - - SkPath* allocPathForFrame() { - std::unique_ptr<SkPath> path(new SkPath()); - SkPath* returnPath = path.get(); - mTempPaths.push_back(std::move(path)); - return returnPath; - } - - void setBaseTransform(const Matrix4& matrix) { mBaseTransform = matrix; } - -protected: - /** - * Perform the setup specific to a frame. This method does not - * issue any OpenGL commands. - */ - void setupFrameState(int viewportWidth, int viewportHeight, - float left, float top, float right, float bottom, bool opaque); - - /** - * Indicates the start of rendering. This method will setup the - * initial OpenGL state (viewport, clearing the buffer, etc.) - */ - void startFrame(); - - /** - * Clears the underlying surface if needed. - */ - virtual void clear(float left, float top, float right, float bottom, bool opaque); - - /** - * Call this method after updating a layer during a drawing pass. - */ - void resumeAfterLayer(); - - /** - * This method is called whenever a stencil buffer is required. Subclasses - * should override this method and call attachStencilBufferToLayer() on the - * appropriate layer(s). - */ - virtual void ensureStencilBuffer(); - - /** - * Obtains a stencil render buffer (allocating it if necessary) and - * attaches it to the specified layer. - */ - void attachStencilBufferToLayer(Layer* layer); - - /** - * Draw a rectangle list. Currently only used for the the stencil buffer so that the stencil - * will have a value of 'n' in every unclipped pixel, where 'n' is the number of rectangles - * in the list. - */ - void drawRectangleList(const RectangleList& rectangleList); - - bool quickRejectSetupScissor(float left, float top, float right, float bottom, - const SkPaint* paint = nullptr); - bool quickRejectSetupScissor(const Rect& bounds, const SkPaint* paint = nullptr) { - return quickRejectSetupScissor(bounds.left, bounds.top, - bounds.right, bounds.bottom, paint); - } - - /** - * Compose the layer defined in the current snapshot with the layer - * defined by the previous snapshot. - * - * The current snapshot *must* be a layer (flag kFlagIsLayer set.) - * - * @param curent The current snapshot containing the layer to compose - * @param previous The previous snapshot to compose the current layer with - */ - virtual void composeLayer(const Snapshot& current, const Snapshot& previous); - - /** - * Marks the specified region as dirty at the specified bounds. - */ - void dirtyLayerUnchecked(Rect& bounds, Region* region); - - /** - * Returns the region of the current layer. - */ - virtual Region* getRegion() const { - return mState.currentRegion(); - } - - /** - * Indicates whether rendering is currently targeted at a layer. - */ - virtual bool hasLayer() const { - return (mState.currentFlags() & Snapshot::kFlagFboTarget) && mState.currentRegion(); - } - - /** - * Renders the specified layer as a textured quad. - * - * @param layer The layer to render - * @param rect The bounds of the layer - */ - void drawTextureLayer(Layer* layer, const Rect& rect); - - /** - * Gets the alpha from a layer, accounting for snapshot alpha - * - * @param layer The layer from which the alpha is extracted - */ - inline float getLayerAlpha(const Layer* layer) const; - - /** - * Set to true to suppress error checks at the end of a frame. - */ - virtual bool suppressErrorChecks() const { - return false; - } - - CanvasState mState; - Caches& mCaches; - RenderState& mRenderState; - -private: - enum class GlopRenderType { - Standard, - Multi, - LayerClear - }; - - void renderGlop(const Glop& glop, GlopRenderType type = GlopRenderType::Standard); - - /** - * Discards the content of the framebuffer if supported by the driver. - * This method should be called at the beginning of a frame to optimize - * rendering on some tiler architectures. - */ - void discardFramebuffer(float left, float top, float right, float bottom); - - /** - * Sets the clipping rectangle using glScissor. The clip is defined by - * the current snapshot's clipRect member. - */ - void setScissorFromClip(); - - /** - * Sets the clipping region using the stencil buffer. The clip region - * is defined by the current snapshot's clipRegion member. - */ - void setStencilFromClip(); - - /** - * Given the local bounds of the layer, calculates ... - */ - void calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool fboLayer); - - /** - * Given the local bounds + clip of the layer, updates current snapshot's empty/invisible - */ - void updateSnapshotIgnoreForLayer(const Rect& bounds, const Rect& clip, - bool fboLayer, int alpha); - - /** - * Creates a new layer stored in the specified snapshot. - * - * @param snapshot The snapshot associated with the new layer - * @param left The left coordinate of the layer - * @param top The top coordinate of the layer - * @param right The right coordinate of the layer - * @param bottom The bottom coordinate of the layer - * @param alpha The translucency of the layer - * @param mode The blending mode of the layer - * @param flags The layer save flags - * @param mask A mask to use when drawing the layer back, may be empty - * - * @return True if the layer was successfully created, false otherwise - */ - bool createLayer(float left, float top, float right, float bottom, - const SkPaint* paint, int flags, const SkPath* convexMask); - - /** - * Creates a new layer stored in the specified snapshot as an FBO. - * - * @param layer The layer to store as an FBO - * @param snapshot The snapshot associated with the new layer - * @param bounds The bounds of the layer - */ - bool createFboLayer(Layer* layer, Rect& bounds, Rect& clip); - - /** - * Compose the specified layer as a region. - * - * @param layer The layer to compose - * @param rect The layer's bounds - */ - void composeLayerRegion(Layer* layer, const Rect& rect); - - /** - * Restores the content in layer to the screen, swapping the blend mode, - * specifically used in the restore() of a saveLayerAlpha(). - * - * This allows e.g. a layer that would have been drawn on top of existing content (with SrcOver) - * to be drawn underneath. - * - * This will always ignore the canvas transform. - */ - void composeLayerRectSwapped(Layer* layer, const Rect& rect); - - /** - * Draws the content in layer to the screen. - */ - void composeLayerRect(Layer* layer, const Rect& rect); - - /** - * Clears all the regions corresponding to the current list of layers. - * This method MUST be invoked before any drawing operation. - */ - void clearLayerRegions(); - - /** - * Mark the layer as dirty at the specified coordinates. The coordinates - * are transformed with the supplied matrix. - */ - void dirtyLayer(const float left, const float top, - const float right, const float bottom, const Matrix4& transform); - - /** - * Mark the layer as dirty at the specified coordinates. - */ - void dirtyLayer(const float left, const float top, - const float right, const float bottom); - - /** - * Draws a colored rectangle with the specified color. The specified coordinates - * are transformed by the current snapshot's transform matrix unless specified - * otherwise. - * - * @param left The left coordinate of the rectangle - * @param top The top coordinate of the rectangle - * @param right The right coordinate of the rectangle - * @param bottom The bottom coordinate of the rectangle - * @param paint The paint containing the color, blending mode, etc. - * @param ignoreTransform True if the current transform should be ignored - */ - void drawColorRect(float left, float top, float right, float bottom, - const SkPaint* paint, bool ignoreTransform = false); - - /** - * Draws a series of colored rectangles with the specified color. The specified - * coordinates are transformed by the current snapshot's transform matrix unless - * specified otherwise. - * - * @param rects A list of rectangles, 4 floats (left, top, right, bottom) - * per rectangle - * @param paint The paint containing the color, blending mode, etc. - * @param ignoreTransform True if the current transform should be ignored - * @param dirty True if calling this method should dirty the current layer - * @param clip True if the rects should be clipped, false otherwise - */ - void drawColorRects(const float* rects, int count, const SkPaint* paint, - bool ignoreTransform = false, bool dirty = true, bool clip = true); - - /** - * Draws the shape represented by the specified path texture. - * This method invokes drawPathTexture() but takes into account - * the extra left/top offset and the texture offset to correctly - * position the final shape. - * - * @param left The left coordinate of the shape to render - * @param top The top coordinate of the shape to render - * @param texture The texture reprsenting the shape - * @param paint The paint to draw the shape with - */ - void drawShape(float left, float top, PathTexture* texture, const SkPaint* paint); - - /** - * Renders a strip of polygons with the specified paint, used for tessellated geometry. - * - * @param vertexBuffer The VertexBuffer to be drawn - * @param paint The paint to render with - * @param flags flags with which to draw - */ - void drawVertexBuffer(float translateX, float translateY, const VertexBuffer& vertexBuffer, - const SkPaint* paint, int flags = 0); - - /** - * Convenience for translating method - */ - void drawVertexBuffer(const VertexBuffer& vertexBuffer, - const SkPaint* paint, int flags = 0) { - drawVertexBuffer(0.0f, 0.0f, vertexBuffer, paint, flags); - } - - /** - * Renders the convex hull defined by the specified path as a strip of polygons. - * - * @param path The hull of the path to draw - * @param paint The paint to render with - */ - void drawConvexPath(const SkPath& path, const SkPaint* paint); - - /** - * Draws shadow layer on text (with optional positions). - * - * @param paint The paint to draw the shadow with - * @param text The text to draw - * @param count The number of glyphs in the text - * @param positions The x, y positions of individual glyphs (or NULL) - * @param fontRenderer The font renderer object - * @param alpha The alpha value for drawing the shadow - * @param x The x coordinate where the shadow will be drawn - * @param y The y coordinate where the shadow will be drawn - */ - void drawTextShadow(const SkPaint* paint, const glyph_t* glyphs, int count, - const float* positions, FontRenderer& fontRenderer, int alpha, - float x, float y); - - /** - * Draws a path texture. Path textures are alpha8 bitmaps that need special - * compositing to apply colors/filters/etc. - * - * @param texture The texture to render - * @param x The x coordinate where the texture will be drawn - * @param y The y coordinate where the texture will be drawn - * @param paint The paint to draw the texture with - */ - void drawPathTexture(PathTexture* texture, float x, float y, const SkPaint* paint); - - /** - * Resets the texture coordinates stored in mMeshVertices. Setting the values - * back to default is achieved by calling: - * - * resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); - * - * @param u1 The left coordinate of the texture - * @param v1 The bottom coordinate of the texture - * @param u2 The right coordinate of the texture - * @param v2 The top coordinate of the texture - */ - void resetDrawTextureTexCoords(float u1, float v1, float u2, float v2); - - /** - * Returns true if the specified paint will draw invisible text. - */ - bool canSkipText(const SkPaint* paint) const; - - bool updateLayer(Layer* layer, bool inFrame); - void updateLayers(); - void flushLayers(); - -#if DEBUG_LAYERS_AS_REGIONS - /** - * Renders the specified region as a series of rectangles. This method - * is used for debugging only. - */ - void drawRegionRectsDebug(const Region& region); -#endif - - /** - * Renders the specified region as a series of rectangles. The region - * must be in screen-space coordinates. - */ - void drawRegionRects(const SkRegion& region, const SkPaint& paint, bool dirty = false); - - /** - * Draws the current clip region if any. Only when DEBUG_CLIP_REGIONS - * is turned on. - */ - void debugClip(); - - void debugOverdraw(bool enable, bool clear); - void renderOverdraw(); - void countOverdraw(); - - /** - * Should be invoked every time the glScissor is modified. - */ - inline void dirtyClip() { mState.setDirtyClip(true); } - - inline const UvMapper& getMapper(const Texture* texture) { - return texture && texture->uvMapper ? *texture->uvMapper : mUvMapper; - } - - /** - * Returns a texture object for the specified bitmap. The texture can - * come from the texture cache or an atlas. If this method returns - * NULL, the texture could not be found and/or allocated. - */ - Texture* getTexture(const SkBitmap* bitmap); - - bool reportAndClearDirty() { bool ret = mDirty; mDirty = false; return ret; } - inline Snapshot* writableSnapshot() { return mState.writableSnapshot(); } - inline const Snapshot* currentSnapshot() const { return mState.currentSnapshot(); } - - // State used to define the clipping region - Rect mTilingClip; - // Is the target render surface opaque - bool mOpaque; - // Is a frame currently being rendered - bool mFrameStarted; - - // Default UV mapper - const UvMapper mUvMapper; - - // List of rectangles to clear after saveLayer() is invoked - std::vector<Rect> mLayers; - // List of layers to update at the beginning of a frame - std::vector< sp<Layer> > mLayerUpdates; - - // See PROPERTY_DISABLE_SCISSOR_OPTIMIZATION in - // Properties.h - bool mScissorOptimizationDisabled; - - bool mSkipOutlineClip; - - // True if anything has been drawn since the last call to - // reportAndClearDirty() - bool mDirty; - - // Lighting + shadows - Vector3 mLightCenter; - float mLightRadius; - uint8_t mAmbientShadowAlpha; - uint8_t mSpotShadowAlpha; - - // Paths kept alive for the duration of the frame - std::vector<std::unique_ptr<SkPath>> mTempPaths; - - /** - * Initial transform for a rendering pass; transform from global device - * coordinates to the current RenderNode's drawing content coordinates, - * with the RenderNode's RenderProperty transforms already applied. - * Calling setMatrix(mBaseTransform) will result in drawing at the origin - * of the DisplayList's recorded surface prior to any Canvas - * transformation. - */ - Matrix4 mBaseTransform; - - friend class Layer; - friend class TextDrawFunctor; - friend class DrawBitmapOp; - friend class DrawPatchOp; - -}; // class OpenGLRenderer - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_OPENGL_RENDERER_H diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h index d1c5dbfc7540..4e587fb719d4 100644 --- a/libs/hwui/PatchCache.h +++ b/libs/hwui/PatchCache.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_PATCH_CACHE_H -#define ANDROID_HWUI_PATCH_CACHE_H +#pragma once #include <GLES2/gl2.h> @@ -48,6 +47,7 @@ class Patch; /////////////////////////////////////////////////////////////////////////////// class Caches; +class RenderState; class PatchCache { public: @@ -186,5 +186,3 @@ private: }; // namespace uirenderer }; // namespace android - -#endif // ANDROID_HWUI_PATCH_CACHE_H diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 880a90e4421f..5d892fd5bcce 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -20,8 +20,7 @@ #include <cutils/properties.h> /** - * This file contains the list of system properties used to configure - * the OpenGLRenderer. + * This file contains the list of system properties used to configure libhwui. */ namespace android { @@ -167,7 +166,7 @@ enum DebugLevel { * Used to enable/disable scissor optimization. The accepted values are * "true" and "false". The default value is "false". * - * When scissor optimization is enabled, OpenGLRenderer will attempt to + * When scissor optimization is enabled, libhwui will attempt to * minimize the use of scissor by selectively enabling and disabling the * GL scissor test. * When the optimization is disabled, OpenGLRenderer will keep the GL diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h index aee9d6370083..f3078ce58503 100644 --- a/libs/hwui/RecordedOp.h +++ b/libs/hwui/RecordedOp.h @@ -14,16 +14,15 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_RECORDED_OP_H -#define ANDROID_HWUI_RECORDED_OP_H +#pragma once -#include "RecordedOp.h" #include "font/FontUtil.h" #include "Matrix.h" #include "Rect.h" #include "RenderNode.h" #include "TessellationCache.h" #include "utils/LinearAllocator.h" +#include "utils/PaintUtils.h" #include "Vector.h" #include <androidfw/ResourceTypes.h> @@ -529,5 +528,3 @@ struct LayerOp : RecordedOp { }; // namespace uirenderer }; // namespace android - -#endif // ANDROID_HWUI_RECORDED_OP_H diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index cbefccb955de..4528a3876177 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -43,7 +43,6 @@ void RecordingCanvas::resetRecording(int width, int height) { mState.initializeRecordingSaveStack(width, height); mDeferredBarrierType = DeferredBarrierType::InOrder; - mState.setDirtyClip(false); } DisplayList* RecordingCanvas::finishRecording() { diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index f8797bf63442..5330e2365d66 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -16,19 +16,17 @@ #include "RenderNode.h" +#include "BakedOpRenderer.h" #include "DamageAccumulator.h" #include "Debug.h" -#if HWUI_NEW_OPS -#include "BakedOpRenderer.h" -#include "RecordedOp.h" -#include "OpDumper.h" -#endif -#include "DisplayListOp.h" #include "LayerRenderer.h" -#include "OpenGLRenderer.h" +#include "OpDumper.h" +#include "RecordedOp.h" #include "TreeInfo.h" #include "utils/MathUtils.h" #include "utils/TraceUtils.h" +#include "VectorDrawable.h" +#include "renderstate/RenderState.h" #include "renderthread/CanvasContext.h" #include "protos/hwui.pb.h" @@ -41,23 +39,6 @@ namespace android { namespace uirenderer { -void RenderNode::debugDumpLayers(const char* prefix) { -#if HWUI_NEW_OPS - LOG_ALWAYS_FATAL("TODO: dump layer"); -#else - if (mLayer) { - ALOGD("%sNode %p (%s) has layer %p (fbo = %u, wasBuildLayered = %s)", - prefix, this, getName(), mLayer, mLayer->getFbo(), - mLayer->wasBuildLayered ? "true" : "false"); - } -#endif - if (mDisplayList) { - for (auto&& child : mDisplayList->getChildren()) { - child->renderNode->debugDumpLayers(prefix); - } - } -} - RenderNode::RenderNode() : mDirtyPropertyFields(0) , mNeedsDisplayListSync(false) @@ -70,15 +51,7 @@ RenderNode::RenderNode() RenderNode::~RenderNode() { deleteDisplayList(nullptr); delete mStagingDisplayList; -#if HWUI_NEW_OPS LOG_ALWAYS_FATAL_IF(mLayer, "layer missed detachment!"); -#else - if (mLayer) { - ALOGW("Memory Warning: Layer %p missed its detachment, held on to for far too long!", mLayer); - mLayer->postDecStrong(); - mLayer = nullptr; - } -#endif } void RenderNode::setStagingDisplayList(DisplayList* displayList, TreeObserver* observer) { @@ -96,7 +69,6 @@ void RenderNode::setStagingDisplayList(DisplayList* displayList, TreeObserver* o * This function is a simplified version of replay(), where we simply retrieve and log the * display list. This function should remain in sync with the replay() function. */ -#if HWUI_NEW_OPS void RenderNode::output(uint32_t level, const char* label) { ALOGD("%s (%s %p%s%s%s%s%s)", label, @@ -123,26 +95,6 @@ void RenderNode::output(uint32_t level, const char* label) { } ALOGD("%*s/RenderNode(%s %p)", level * 2, "", getName(), this); } -#else -void RenderNode::output(uint32_t level) { - ALOGD("%*sStart display list (%p, %s%s%s%s%s%s)", (level - 1) * 2, "", this, - getName(), - (MathUtils::isZero(properties().getAlpha()) ? ", zero alpha" : ""), - (properties().hasShadow() ? ", casting shadow" : ""), - (isRenderable() ? "" : ", empty"), - (properties().getProjectBackwards() ? ", projected" : ""), - (mLayer != nullptr ? ", on HW Layer" : "")); - ALOGD("%*s%s %d", level * 2, "", "Save", SaveFlags::MatrixClip); - properties().debugOutputProperties(level); - if (mDisplayList) { - // TODO: consider printing the chunk boundaries here - for (auto&& op : mDisplayList->getOps()) { - op->output(level, DisplayListOp::kOpLogFlag_Recurse); - } - } - ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, getName()); - } -#endif void RenderNode::copyTo(proto::RenderNode *pnode) { pnode->set_id(static_cast<uint64_t>( @@ -272,29 +224,17 @@ void RenderNode::prepareLayer(TreeInfo& info, uint32_t dirtyMask) { } } -static layer_t* createLayer(RenderState& renderState, uint32_t width, uint32_t height) { -#if HWUI_NEW_OPS +static OffscreenBuffer* createLayer(RenderState& renderState, uint32_t width, uint32_t height) { return renderState.layerPool().get(renderState, width, height); -#else - return LayerRenderer::createRenderLayer(renderState, width, height); -#endif } -static void destroyLayer(layer_t* layer) { -#if HWUI_NEW_OPS +static void destroyLayer(OffscreenBuffer* layer) { RenderState& renderState = layer->renderState; renderState.layerPool().putOrDelete(layer); -#else - LayerRenderer::destroyLayer(layer); -#endif } -static bool layerMatchesWidthAndHeight(layer_t* layer, int width, int height) { -#if HWUI_NEW_OPS +static bool layerMatchesWidthAndHeight(OffscreenBuffer* layer, int width, int height) { return layer->viewportWidth == (uint32_t) width && layer->viewportHeight == (uint32_t)height; -#else - return layer->layer.getWidth() == width && layer->layer.getHeight() == height; -#endif } void RenderNode::pushLayerUpdate(TreeInfo& info) { @@ -312,22 +252,15 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) { bool transformUpdateNeeded = false; if (!mLayer) { mLayer = createLayer(info.canvasContext.getRenderState(), getWidth(), getHeight()); -#if !HWUI_NEW_OPS - applyLayerPropertiesToLayer(info); -#endif damageSelf(info); transformUpdateNeeded = true; } else if (!layerMatchesWidthAndHeight(mLayer, getWidth(), getHeight())) { -#if HWUI_NEW_OPS // TODO: remove now irrelevant, currently enqueued damage (respecting damage ordering) // Or, ideally, maintain damage between frames on node/layer so ordering is always correct RenderState& renderState = mLayer->renderState; if (properties().fitsOnLayer()) { mLayer = renderState.layerPool().resize(mLayer, getWidth(), getHeight()); } else { -#else - if (!LayerRenderer::resizeLayer(mLayer, getWidth(), getHeight())) { -#endif destroyLayer(mLayer); mLayer = nullptr; } @@ -362,19 +295,7 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) { mLayer->setWindowTransform(windowTransform); } -#if HWUI_NEW_OPS info.layerUpdateQueue->enqueueLayerWithDamage(this, dirty); -#else - if (dirty.intersect(0, 0, getWidth(), getHeight())) { - dirty.roundOut(&dirty); - mLayer->updateDeferred(this, dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom); - } - // This is not inside the above if because we may have called - // updateDeferred on a previous prepare pass that didn't have a renderer - if (info.renderer && mLayer->deferredUpdateScheduled) { - info.renderer->pushLayerUpdate(mLayer); - } -#endif // There might be prefetched layers that need to be accounted for. // That might be us, so tell CanvasContext that this layer is in the @@ -450,9 +371,6 @@ void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) { damageSelf(info); info.damageAccumulator->popTransform(); syncProperties(); -#if !HWUI_NEW_OPS - applyLayerPropertiesToLayer(info); -#endif // We could try to be clever and only re-damage if the matrix changed. // However, we don't need to worry about that. The cost of over-damaging // here is only going to be a single additional map rect of this node @@ -463,17 +381,6 @@ void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) { } } -#if !HWUI_NEW_OPS -void RenderNode::applyLayerPropertiesToLayer(TreeInfo& info) { - if (CC_LIKELY(!mLayer)) return; - - const LayerProperties& props = properties().layerProperties(); - mLayer->setAlpha(props.alpha(), props.xferMode()); - mLayer->setColorFilter(props.colorFilter()); - mLayer->setBlend(props.needsBlending()); -} -#endif - void RenderNode::syncDisplayList(TreeInfo* info) { // Make sure we inc first so that we don't fluctuate between 0 and 1, // which would thrash the layer cache @@ -526,15 +433,8 @@ void RenderNode::prepareSubTree(TreeInfo& info, bool functorsNeedLayer, DisplayL } for (auto&& op : subtree->getChildren()) { RenderNode* childNode = op->renderNode; -#if HWUI_NEW_OPS info.damageAccumulator->pushTransform(&op->localMatrix); bool childFunctorsNeedLayer = functorsNeedLayer; // TODO! || op->mRecordedWithPotentialStencilClip; -#else - info.damageAccumulator->pushTransform(&op->localMatrix); - bool childFunctorsNeedLayer = functorsNeedLayer - // Recorded with non-rect clip, or canvas-rotated by parent - || op->mRecordedWithPotentialStencilClip; -#endif childNode->prepareTreeImpl(info, childFunctorsNeedLayer); info.damageAccumulator->popTransform(); } @@ -576,84 +476,6 @@ void RenderNode::decParentRefCount(TreeObserver* observer, TreeInfo* info) { } } -/* - * For property operations, we pass a savecount of 0, since the operations aren't part of the - * displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in - * base saveCount (i.e., how RestoreToCount uses saveCount + properties().getCount()) - */ -#define PROPERTY_SAVECOUNT 0 - -template <class T> -void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler) { -#if DEBUG_DISPLAY_LIST - properties().debugOutputProperties(handler.level() + 1); -#endif - if (properties().getLeft() != 0 || properties().getTop() != 0) { - renderer.translate(properties().getLeft(), properties().getTop()); - } - if (properties().getStaticMatrix()) { - renderer.concatMatrix(*properties().getStaticMatrix()); - } else if (properties().getAnimationMatrix()) { - renderer.concatMatrix(*properties().getAnimationMatrix()); - } - if (properties().hasTransformMatrix()) { - if (properties().isTransformTranslateOnly()) { - renderer.translate(properties().getTranslationX(), properties().getTranslationY()); - } else { - renderer.concatMatrix(*properties().getTransformMatrix()); - } - } - const bool isLayer = properties().effectiveLayerType() != LayerType::None; - int clipFlags = properties().getClippingFlags(); - if (properties().getAlpha() < 1) { - if (isLayer) { - clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer - } - if (CC_LIKELY(isLayer || !properties().getHasOverlappingRendering())) { - // simply scale rendering content's alpha - renderer.scaleAlpha(properties().getAlpha()); - } else { - // savelayer needed to create an offscreen buffer - Rect layerBounds(0, 0, getWidth(), getHeight()); - if (clipFlags) { - properties().getClippingRectForFlags(clipFlags, &layerBounds); - clipFlags = 0; // all clipping done by savelayer - } - SaveLayerOp* op = new (handler.allocator()) SaveLayerOp( - layerBounds.left, layerBounds.top, - layerBounds.right, layerBounds.bottom, - (int) (properties().getAlpha() * 255), - SaveFlags::HasAlphaLayer | SaveFlags::ClipToLayer); - handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds()); - } - - if (CC_UNLIKELY(ATRACE_ENABLED() && properties().promotedToLayer())) { - // pretend alpha always causes savelayer to warn about - // performance problem affecting old versions - ATRACE_FORMAT("%s alpha caused saveLayer %dx%d", getName(), - static_cast<int>(getWidth()), - static_cast<int>(getHeight())); - } - } - if (clipFlags) { - Rect clipRect; - properties().getClippingRectForFlags(clipFlags, &clipRect); - ClipRectOp* op = new (handler.allocator()) ClipRectOp( - clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, - SkRegion::kIntersect_Op); - handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds()); - } - - // TODO: support nesting round rect clips - if (mProperties.getRevealClip().willClip()) { - Rect bounds; - mProperties.getRevealClip().getBounds(&bounds); - renderer.setClippingRoundRect(handler.allocator(), bounds, mProperties.getRevealClip().getRadius()); - } else if (mProperties.getOutline().willClip()) { - renderer.setClippingOutline(handler.allocator(), &(mProperties.getOutline())); - } -} - /** * Apply property-based transformations to input matrix * @@ -714,14 +536,14 @@ void RenderNode::computeOrdering() { // transform properties are applied correctly to top level children if (mDisplayList == nullptr) return; for (unsigned int i = 0; i < mDisplayList->getChildren().size(); i++) { - renderNodeOp_t* childOp = mDisplayList->getChildren()[i]; + RenderNodeOp* childOp = mDisplayList->getChildren()[i]; childOp->renderNode->computeOrderingImpl(childOp, &mProjectedNodes, &mat4::identity()); } } void RenderNode::computeOrderingImpl( - renderNodeOp_t* opState, - std::vector<renderNodeOp_t*>* compositedChildrenOfProjectionSurface, + RenderNodeOp* opState, + std::vector<RenderNodeOp*>* compositedChildrenOfProjectionSurface, const mat4* transformFromProjectionSurface) { mProjectedNodes.clear(); if (mDisplayList == nullptr || mDisplayList->isEmpty()) return; @@ -745,10 +567,10 @@ void RenderNode::computeOrderingImpl( const bool isProjectionReceiver = mDisplayList->projectionReceiveIndex >= 0; bool haveAppliedPropertiesToProjection = false; for (unsigned int i = 0; i < mDisplayList->getChildren().size(); i++) { - renderNodeOp_t* childOp = mDisplayList->getChildren()[i]; + RenderNodeOp* childOp = mDisplayList->getChildren()[i]; RenderNode* child = childOp->renderNode; - std::vector<renderNodeOp_t*>* projectionChildren = nullptr; + std::vector<RenderNodeOp*>* projectionChildren = nullptr; const mat4* projectionTransform = nullptr; if (isProjectionReceiver && !child->properties().getProjectBackwards()) { // if receiving projections, collect projecting descendant @@ -771,372 +593,5 @@ void RenderNode::computeOrderingImpl( } } -class DeferOperationHandler { -public: - DeferOperationHandler(DeferStateStruct& deferStruct, int level) - : mDeferStruct(deferStruct), mLevel(level) {} - inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) { - operation->defer(mDeferStruct, saveCount, mLevel, clipToBounds); - } - inline LinearAllocator& allocator() { return *(mDeferStruct.mAllocator); } - inline void startMark(const char* name) {} // do nothing - inline void endMark() {} - inline int level() { return mLevel; } - inline int replayFlags() { return mDeferStruct.mReplayFlags; } - inline SkPath* allocPathForFrame() { return mDeferStruct.allocPathForFrame(); } - -private: - DeferStateStruct& mDeferStruct; - const int mLevel; -}; - -void RenderNode::defer(DeferStateStruct& deferStruct, const int level) { - DeferOperationHandler handler(deferStruct, level); - issueOperations<DeferOperationHandler>(deferStruct.mRenderer, handler); -} - -class ReplayOperationHandler { -public: - ReplayOperationHandler(ReplayStateStruct& replayStruct, int level) - : mReplayStruct(replayStruct), mLevel(level) {} - inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) { -#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS - mReplayStruct.mRenderer.eventMark(operation->name()); -#endif - operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds); - } - inline LinearAllocator& allocator() { return *(mReplayStruct.mAllocator); } - inline void startMark(const char* name) { - mReplayStruct.mRenderer.startMark(name); - } - inline void endMark() { - mReplayStruct.mRenderer.endMark(); - } - inline int level() { return mLevel; } - inline int replayFlags() { return mReplayStruct.mReplayFlags; } - inline SkPath* allocPathForFrame() { return mReplayStruct.allocPathForFrame(); } - -private: - ReplayStateStruct& mReplayStruct; - const int mLevel; -}; - -void RenderNode::replay(ReplayStateStruct& replayStruct, const int level) { - ReplayOperationHandler handler(replayStruct, level); - issueOperations<ReplayOperationHandler>(replayStruct.mRenderer, handler); -} - -void RenderNode::buildZSortedChildList(const DisplayList::Chunk& chunk, - std::vector<ZDrawRenderNodeOpPair>& zTranslatedNodes) { -#if !HWUI_NEW_OPS - if (chunk.beginChildIndex == chunk.endChildIndex) return; - - for (unsigned int i = chunk.beginChildIndex; i < chunk.endChildIndex; i++) { - DrawRenderNodeOp* childOp = mDisplayList->getChildren()[i]; - RenderNode* child = childOp->renderNode; - float childZ = child->properties().getZ(); - - if (!MathUtils::isZero(childZ) && chunk.reorderChildren) { - zTranslatedNodes.push_back(ZDrawRenderNodeOpPair(childZ, childOp)); - childOp->skipInOrderDraw = true; - } else if (!child->properties().getProjectBackwards()) { - // regular, in order drawing DisplayList - childOp->skipInOrderDraw = false; - } - } - - // Z sort any 3d children (stable-ness makes z compare fall back to standard drawing order) - std::stable_sort(zTranslatedNodes.begin(), zTranslatedNodes.end()); -#endif -} - -template <class T> -void RenderNode::issueDrawShadowOperation(const Matrix4& transformFromParent, T& handler) { - if (properties().getAlpha() <= 0.0f - || properties().getOutline().getAlpha() <= 0.0f - || !properties().getOutline().getPath() - || properties().getScaleX() == 0 - || properties().getScaleY() == 0) { - // no shadow to draw - return; - } - - mat4 shadowMatrixXY(transformFromParent); - applyViewPropertyTransforms(shadowMatrixXY); - - // Z matrix needs actual 3d transformation, so mapped z values will be correct - mat4 shadowMatrixZ(transformFromParent); - applyViewPropertyTransforms(shadowMatrixZ, true); - - const SkPath* casterOutlinePath = properties().getOutline().getPath(); - const SkPath* revealClipPath = properties().getRevealClip().getPath(); - if (revealClipPath && revealClipPath->isEmpty()) return; - - float casterAlpha = properties().getAlpha() * properties().getOutline().getAlpha(); - - - // holds temporary SkPath to store the result of intersections - SkPath* frameAllocatedPath = nullptr; - const SkPath* outlinePath = casterOutlinePath; - - // intersect the outline with the reveal clip, if present - if (revealClipPath) { - frameAllocatedPath = handler.allocPathForFrame(); - - Op(*outlinePath, *revealClipPath, kIntersect_SkPathOp, frameAllocatedPath); - outlinePath = frameAllocatedPath; - } - - // intersect the outline with the clipBounds, if present - if (properties().getClippingFlags() & CLIP_TO_CLIP_BOUNDS) { - if (!frameAllocatedPath) { - frameAllocatedPath = handler.allocPathForFrame(); - } - - Rect clipBounds; - properties().getClippingRectForFlags(CLIP_TO_CLIP_BOUNDS, &clipBounds); - SkPath clipBoundsPath; - clipBoundsPath.addRect(clipBounds.left, clipBounds.top, - clipBounds.right, clipBounds.bottom); - - Op(*outlinePath, clipBoundsPath, kIntersect_SkPathOp, frameAllocatedPath); - outlinePath = frameAllocatedPath; - } - - DisplayListOp* shadowOp = new (handler.allocator()) DrawShadowOp( - shadowMatrixXY, shadowMatrixZ, casterAlpha, outlinePath); - handler(shadowOp, PROPERTY_SAVECOUNT, properties().getClipToBounds()); -} - -#define SHADOW_DELTA 0.1f - -template <class T> -void RenderNode::issueOperationsOf3dChildren(ChildrenSelectMode mode, - const Matrix4& initialTransform, const std::vector<ZDrawRenderNodeOpPair>& zTranslatedNodes, - OpenGLRenderer& renderer, T& handler) { - const int size = zTranslatedNodes.size(); - if (size == 0 - || (mode == ChildrenSelectMode::NegativeZChildren && zTranslatedNodes[0].key > 0.0f) - || (mode == ChildrenSelectMode::PositiveZChildren && zTranslatedNodes[size - 1].key < 0.0f)) { - // no 3d children to draw - return; - } - - // Apply the base transform of the parent of the 3d children. This isolates - // 3d children of the current chunk from transformations made in previous chunks. - int rootRestoreTo = renderer.save(SaveFlags::Matrix); - renderer.setGlobalMatrix(initialTransform); - - /** - * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters - * with very similar Z heights to draw together. - * - * This way, if Views A & B have the same Z height and are both casting shadows, the shadows are - * underneath both, and neither's shadow is drawn on top of the other. - */ - const size_t nonNegativeIndex = findNonNegativeIndex(zTranslatedNodes); - size_t drawIndex, shadowIndex, endIndex; - if (mode == ChildrenSelectMode::NegativeZChildren) { - drawIndex = 0; - endIndex = nonNegativeIndex; - shadowIndex = endIndex; // draw no shadows - } else { - drawIndex = nonNegativeIndex; - endIndex = size; - shadowIndex = drawIndex; // potentially draw shadow for each pos Z child - } - - DISPLAY_LIST_LOGD("%*s%d %s 3d children:", (handler.level() + 1) * 2, "", - endIndex - drawIndex, mode == kNegativeZChildren ? "negative" : "positive"); - - float lastCasterZ = 0.0f; - while (shadowIndex < endIndex || drawIndex < endIndex) { - if (shadowIndex < endIndex) { - DrawRenderNodeOp* casterOp = zTranslatedNodes[shadowIndex].value; - RenderNode* caster = casterOp->renderNode; - const float casterZ = zTranslatedNodes[shadowIndex].key; - // attempt to render the shadow if the caster about to be drawn is its caster, - // OR if its caster's Z value is similar to the previous potential caster - if (shadowIndex == drawIndex || casterZ - lastCasterZ < SHADOW_DELTA) { - caster->issueDrawShadowOperation(casterOp->localMatrix, handler); - - lastCasterZ = casterZ; // must do this even if current caster not casting a shadow - shadowIndex++; - continue; - } - } - - // only the actual child DL draw needs to be in save/restore, - // since it modifies the renderer's matrix - int restoreTo = renderer.save(SaveFlags::Matrix); - - DrawRenderNodeOp* childOp = zTranslatedNodes[drawIndex].value; - - renderer.concatMatrix(childOp->localMatrix); - childOp->skipInOrderDraw = false; // this is horrible, I'm so sorry everyone - handler(childOp, renderer.getSaveCount() - 1, properties().getClipToBounds()); - childOp->skipInOrderDraw = true; - - renderer.restoreToCount(restoreTo); - drawIndex++; - } - renderer.restoreToCount(rootRestoreTo); -} - -template <class T> -void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T& handler) { - DISPLAY_LIST_LOGD("%*s%d projected children:", (handler.level() + 1) * 2, "", mProjectedNodes.size()); - const SkPath* projectionReceiverOutline = properties().getOutline().getPath(); - int restoreTo = renderer.getSaveCount(); - - LinearAllocator& alloc = handler.allocator(); - handler(new (alloc) SaveOp(SaveFlags::MatrixClip), - PROPERTY_SAVECOUNT, properties().getClipToBounds()); - - // Transform renderer to match background we're projecting onto - // (by offsetting canvas by translationX/Y of background rendernode, since only those are set) - const DisplayListOp* op = -#if HWUI_NEW_OPS - nullptr; - LOG_ALWAYS_FATAL("unsupported"); -#else - (mDisplayList->getOps()[mDisplayList->projectionReceiveIndex]); -#endif - const DrawRenderNodeOp* backgroundOp = reinterpret_cast<const DrawRenderNodeOp*>(op); - const RenderProperties& backgroundProps = backgroundOp->renderNode->properties(); - renderer.translate(backgroundProps.getTranslationX(), backgroundProps.getTranslationY()); - - // If the projection receiver has an outline, we mask projected content to it - // (which we know, apriori, are all tessellated paths) - renderer.setProjectionPathMask(alloc, projectionReceiverOutline); - - // draw projected nodes - for (size_t i = 0; i < mProjectedNodes.size(); i++) { - renderNodeOp_t* childOp = mProjectedNodes[i]; - - // matrix save, concat, and restore can be done safely without allocating operations - int restoreTo = renderer.save(SaveFlags::Matrix); - renderer.concatMatrix(childOp->transformFromCompositingAncestor); - childOp->skipInOrderDraw = false; // this is horrible, I'm so sorry everyone - handler(childOp, renderer.getSaveCount() - 1, properties().getClipToBounds()); - childOp->skipInOrderDraw = true; - renderer.restoreToCount(restoreTo); - } - - handler(new (alloc) RestoreToCountOp(restoreTo), - PROPERTY_SAVECOUNT, properties().getClipToBounds()); -} - -/** - * This function serves both defer and replay modes, and will organize the displayList's component - * operations for a single frame: - * - * Every 'simple' state operation that affects just the matrix and alpha (or other factors of - * DeferredDisplayState) may be issued directly to the renderer, but complex operations (with custom - * defer logic) and operations in displayListOps are issued through the 'handler' which handles the - * defer vs replay logic, per operation - */ -template <class T> -void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) { - if (mDisplayList->isEmpty()) { - DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", handler.level() * 2, "", - this, getName()); - return; - } - -#if HWUI_NEW_OPS - const bool drawLayer = false; -#else - const bool drawLayer = (mLayer && (&renderer != mLayer->renderer.get())); -#endif - // If we are updating the contents of mLayer, we don't want to apply any of - // the RenderNode's properties to this issueOperations pass. Those will all - // be applied when the layer is drawn, aka when this is true. - const bool useViewProperties = (!mLayer || drawLayer); - if (useViewProperties) { - const Outline& outline = properties().getOutline(); - if (properties().getAlpha() <= 0 - || (outline.getShouldClip() && outline.isEmpty()) - || properties().getScaleX() == 0 - || properties().getScaleY() == 0) { - DISPLAY_LIST_LOGD("%*sRejected display list (%p, %s)", handler.level() * 2, "", - this, getName()); - return; - } - } - - handler.startMark(getName()); - -#if DEBUG_DISPLAY_LIST - const Rect& clipRect = renderer.getLocalClipBounds(); - DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), localClipBounds: %.0f, %.0f, %.0f, %.0f", - handler.level() * 2, "", this, getName(), - clipRect.left, clipRect.top, clipRect.right, clipRect.bottom); -#endif - - LinearAllocator& alloc = handler.allocator(); - int restoreTo = renderer.getSaveCount(); - handler(new (alloc) SaveOp(SaveFlags::MatrixClip), - PROPERTY_SAVECOUNT, properties().getClipToBounds()); - - DISPLAY_LIST_LOGD("%*sSave %d %d", (handler.level() + 1) * 2, "", - SaveFlags::MatrixClip, restoreTo); - - if (useViewProperties) { - setViewProperties<T>(renderer, handler); - } - -#if HWUI_NEW_OPS - LOG_ALWAYS_FATAL("legacy op traversal not supported"); -#else - bool quickRejected = properties().getClipToBounds() - && renderer.quickRejectConservative(0, 0, properties().getWidth(), properties().getHeight()); - if (!quickRejected) { - Matrix4 initialTransform(*(renderer.currentTransform())); - renderer.setBaseTransform(initialTransform); - - if (drawLayer) { - handler(new (alloc) DrawLayerOp(mLayer), - renderer.getSaveCount() - 1, properties().getClipToBounds()); - } else { - const int saveCountOffset = renderer.getSaveCount() - 1; - const int projectionReceiveIndex = mDisplayList->projectionReceiveIndex; - for (size_t chunkIndex = 0; chunkIndex < mDisplayList->getChunks().size(); chunkIndex++) { - const DisplayList::Chunk& chunk = mDisplayList->getChunks()[chunkIndex]; - - std::vector<ZDrawRenderNodeOpPair> zTranslatedNodes; - buildZSortedChildList(chunk, zTranslatedNodes); - - issueOperationsOf3dChildren(ChildrenSelectMode::NegativeZChildren, - initialTransform, zTranslatedNodes, renderer, handler); - - for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) { - DisplayListOp *op = mDisplayList->getOps()[opIndex]; -#if DEBUG_DISPLAY_LIST - op->output(handler.level() + 1); -#endif - handler(op, saveCountOffset, properties().getClipToBounds()); - - if (CC_UNLIKELY(!mProjectedNodes.empty() && projectionReceiveIndex >= 0 && - opIndex == static_cast<size_t>(projectionReceiveIndex))) { - issueOperationsOfProjectedChildren(renderer, handler); - } - } - - issueOperationsOf3dChildren(ChildrenSelectMode::PositiveZChildren, - initialTransform, zTranslatedNodes, renderer, handler); - } - } - } -#endif - - DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (handler.level() + 1) * 2, "", restoreTo); - handler(new (alloc) RestoreToCountOp(restoreTo), - PROPERTY_SAVECOUNT, properties().getClipToBounds()); - - DISPLAY_LIST_LOGD("%*sDone (%p, %s)", handler.level() * 2, "", this, getName()); - handler.endMark(); -} - } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index f9735a231d7a..ee045aaae0a4 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef RENDERNODE_H -#define RENDERNODE_H + +#pragma once #include <SkCamera.h> #include <SkMatrix.h> @@ -44,29 +44,13 @@ namespace android { namespace uirenderer { class CanvasState; -class DisplayListCanvas; class DisplayListOp; -class OpenGLRenderer; -class Rect; -class SkiaShader; - -#if HWUI_NEW_OPS class FrameBuilder; class OffscreenBuffer; +class Rect; +class SkiaShader; struct RenderNodeOp; -typedef OffscreenBuffer layer_t; -typedef RenderNodeOp renderNodeOp_t; -#else -class Layer; -typedef Layer layer_t; -typedef DrawRenderNodeOp renderNodeOp_t; -#endif - -class ClipRectOp; -class DrawRenderNodeOp; -class SaveLayerOp; -class SaveOp; -class RestoreToCountOp; + class TreeInfo; class TreeObserver; @@ -78,9 +62,8 @@ class RenderNode; * Primary class for storing recorded canvas commands, as well as per-View/ViewGroup display properties. * * Recording of canvas commands is somewhat similar to SkPicture, except the canvas-recording - * functionality is split between DisplayListCanvas (which manages the recording), DisplayList - * (which holds the actual data), and DisplayList (which holds properties and performs playback onto - * a renderer). + * functionality is split between RecordingCanvas (which manages the recording), DisplayList + * (which holds the actual data), and RenderNode (which holds properties used for render playback). * * Note that DisplayList is swapped out from beneath an individual RenderNode when a view's * recorded stream of canvas operations is refreshed. The RenderNode (and its properties) stay @@ -115,20 +98,11 @@ public: kReplayFlag_ClipChildren = 0x1 }; - void debugDumpLayers(const char* prefix); - ANDROID_API void setStagingDisplayList(DisplayList* newData, TreeObserver* observer); void computeOrdering(); - void defer(DeferStateStruct& deferStruct, const int level); - void replay(ReplayStateStruct& replayStruct, const int level); - -#if HWUI_NEW_OPS ANDROID_API void output(uint32_t level = 0, const char* label = "Root"); -#else - ANDROID_API void output(uint32_t level = 1); -#endif ANDROID_API int getDebugSize(); void copyTo(proto::RenderNode* node); @@ -223,10 +197,8 @@ public: const DisplayList* getDisplayList() const { return mDisplayList; } -#if HWUI_NEW_OPS OffscreenBuffer* getLayer() const { return mLayer; } OffscreenBuffer** getLayerHandle() { return &mLayer; } // ugh... -#endif // Note: The position callbacks are relying on the listener using // the frameNumber to appropriately batch/synchronize these transactions. @@ -257,63 +229,10 @@ public: } private: - typedef key_value_pair_t<float, DrawRenderNodeOp*> ZDrawRenderNodeOpPair; - - static size_t findNonNegativeIndex(const std::vector<ZDrawRenderNodeOpPair>& nodes) { - for (size_t i = 0; i < nodes.size(); i++) { - if (nodes[i].key >= 0.0f) return i; - } - return nodes.size(); - } - - enum class ChildrenSelectMode { - NegativeZChildren, - PositiveZChildren - }; - - void computeOrderingImpl(renderNodeOp_t* opState, - std::vector<renderNodeOp_t*>* compositedChildrenOfProjectionSurface, + void computeOrderingImpl(RenderNodeOp* opState, + std::vector<RenderNodeOp*>* compositedChildrenOfProjectionSurface, const mat4* transformFromProjectionSurface); - template <class T> - inline void setViewProperties(OpenGLRenderer& renderer, T& handler); - - void buildZSortedChildList(const DisplayList::Chunk& chunk, - std::vector<ZDrawRenderNodeOpPair>& zTranslatedNodes); - - template<class T> - inline void issueDrawShadowOperation(const Matrix4& transformFromParent, T& handler); - - template <class T> - inline void issueOperationsOf3dChildren(ChildrenSelectMode mode, - const Matrix4& initialTransform, const std::vector<ZDrawRenderNodeOpPair>& zTranslatedNodes, - OpenGLRenderer& renderer, T& handler); - - template <class T> - inline void issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T& handler); - - /** - * Issue the RenderNode's operations into a handler, recursing for subtrees through - * DrawRenderNodeOp's defer() or replay() methods - */ - template <class T> - inline void issueOperations(OpenGLRenderer& renderer, T& handler); - - class TextContainer { - public: - size_t length() const { - return mByteLength; - } - - const char* text() const { - return (const char*) mText; - } - - size_t mByteLength; - const char* mText; - }; - - void syncProperties(); void syncDisplayList(TreeInfo* info); @@ -321,9 +240,6 @@ private: void pushStagingPropertiesChanges(TreeInfo& info); void pushStagingDisplayListChanges(TreeInfo& info); void prepareSubTree(TreeInfo& info, bool functorsNeedLayer, DisplayList* subtree); -#if !HWUI_NEW_OPS - void applyLayerPropertiesToLayer(TreeInfo& info); -#endif void prepareLayer(TreeInfo& info, uint32_t dirtyMask); void pushLayerUpdate(TreeInfo& info); void deleteDisplayList(TreeObserver* observer, TreeInfo* info = nullptr); @@ -349,14 +265,14 @@ private: // Owned by RT. Lifecycle is managed by prepareTree(), with the exception // being in ~RenderNode() which may happen on any thread. - layer_t* mLayer = nullptr; + OffscreenBuffer* mLayer = nullptr; /** * Draw time state - these properties are only set and used during rendering */ // for projection surfaces, contains a list of all children items - std::vector<renderNodeOp_t*> mProjectedNodes; + std::vector<RenderNodeOp*> mProjectedNodes; // How many references our parent(s) have to us. Typically this should alternate // between 2 and 1 (when a staging push happens we inc first then dec) @@ -371,5 +287,3 @@ private: } /* namespace uirenderer */ } /* namespace android */ - -#endif /* RENDERNODE_H */ diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp index 5ebf5458da18..7e3cad4ca9d0 100644 --- a/libs/hwui/RenderProperties.cpp +++ b/libs/hwui/RenderProperties.cpp @@ -24,7 +24,6 @@ #include <SkPathOps.h> #include "Matrix.h" -#include "OpenGLRenderer.h" #include "hwui/Canvas.h" #include "utils/MathUtils.h" diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h index c1221f7f7981..2a2e4c765c83 100644 --- a/libs/hwui/RenderProperties.h +++ b/libs/hwui/RenderProperties.h @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef RENDERNODEPROPERTIES_H -#define RENDERNODEPROPERTIES_H + +#pragma once #include "Caches.h" #include "DeviceInfo.h" @@ -22,6 +22,7 @@ #include "RevealClip.h" #include "Outline.h" #include "utils/MathUtils.h" +#include "utils/PaintUtils.h" #include <SkCamera.h> #include <SkMatrix.h> @@ -680,5 +681,3 @@ private: } /* namespace uirenderer */ } /* namespace android */ - -#endif /* RENDERNODEPROPERTIES_H */ diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp index 2c9c9d90f686..21c26f7a1d44 100644 --- a/libs/hwui/Snapshot.cpp +++ b/libs/hwui/Snapshot.cpp @@ -30,14 +30,11 @@ Snapshot::Snapshot() , previous(nullptr) , layer(nullptr) , fbo(0) - , invisible(false) - , empty(false) , alpha(1.0f) , roundRectClipState(nullptr) , projectionPathMask(nullptr) , mClipArea(&mClipAreaRoot) { transform = &mTransformRoot; - region = nullptr; } /** @@ -49,8 +46,6 @@ Snapshot::Snapshot(Snapshot* s, int saveFlags) , previous(s) , layer(s->layer) , fbo(s->fbo) - , invisible(s->invisible) - , empty(false) , alpha(s->alpha) , roundRectClipState(s->roundRectClipState) , projectionPathMask(s->projectionPathMask) @@ -70,13 +65,6 @@ Snapshot::Snapshot(Snapshot* s, int saveFlags) } else { mClipArea = s->mClipArea; } - - if (s->flags & Snapshot::kFlagFboTarget) { - flags |= Snapshot::kFlagFboTarget; - region = s->region; - } else { - region = nullptr; - } } /////////////////////////////////////////////////////////////////////////////// @@ -126,58 +114,6 @@ void Snapshot::resetClip(float left, float top, float right, float bottom) { } /////////////////////////////////////////////////////////////////////////////// -// Transforms -/////////////////////////////////////////////////////////////////////////////// - -void Snapshot::resetTransform(float x, float y, float z) { -#if HWUI_NEW_OPS - LOG_ALWAYS_FATAL("not supported - light center managed differently"); -#else - // before resetting, map current light pos with inverse of current transform - Vector3 center = mRelativeLightCenter; - mat4 inverse; - inverse.loadInverse(*transform); - inverse.mapPoint3d(center); - mRelativeLightCenter = center; - - transform = &mTransformRoot; - transform->loadTranslate(x, y, z); -#endif -} - -void Snapshot::buildScreenSpaceTransform(Matrix4* outTransform) const { -#if HWUI_NEW_OPS - LOG_ALWAYS_FATAL("not supported - not needed by new ops"); -#else - // build (reverse ordered) list of the stack of snapshots, terminated with a NULL - Vector<const Snapshot*> snapshotList; - snapshotList.push(nullptr); - const Snapshot* current = this; - do { - snapshotList.push(current); - current = current->previous; - } while (current); - - // traverse the list, adding in each transform that contributes to the total transform - outTransform->loadIdentity(); - for (size_t i = snapshotList.size() - 1; i > 0; i--) { - // iterate down the stack - const Snapshot* current = snapshotList[i]; - const Snapshot* next = snapshotList[i - 1]; - if (current->flags & kFlagIsFboLayer) { - // if we've hit a layer, translate by the layer's draw offset - outTransform->translate(current->layer->layer.left, current->layer->layer.top); - } - if (!next || (next->flags & kFlagIsFboLayer)) { - // if this snapshot is last, or if this snapshot is last before an - // FBO layer (which reset the transform), apply it - outTransform->multiply(*(current->transform)); - } - } -#endif -} - -/////////////////////////////////////////////////////////////////////////////// // Clipping round rect /////////////////////////////////////////////////////////////////////////////// @@ -226,20 +162,8 @@ void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& boun roundRectClipState = state; } -void Snapshot::setProjectionPathMask(LinearAllocator& allocator, const SkPath* path) { -#if HWUI_NEW_OPS - // TODO: remove allocator param for HWUI_NEW_OPS +void Snapshot::setProjectionPathMask(const SkPath* path) { projectionPathMask = path; -#else - if (path) { - ProjectionPathMask* mask = new (allocator) ProjectionPathMask; - mask->projectionMask = path; - buildScreenSpaceTransform(&(mask->projectionMaskTransform)); - projectionPathMask = mask; - } else { - projectionPathMask = nullptr; - } -#endif } static Snapshot* getClipRoot(Snapshot* target) { @@ -273,13 +197,9 @@ void Snapshot::applyClip(const ClipBase* recordedClip, const Matrix4& transform) // Queries /////////////////////////////////////////////////////////////////////////////// -bool Snapshot::isIgnored() const { - return invisible || empty; -} - void Snapshot::dump() const { - ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d", - this, flags, previous, getViewportHeight(), isIgnored(), !mClipArea->isSimple()); + ALOGD("Snapshot %p, flags %x, prev %p, height %d, hasComplexClip %d", + this, flags, previous, getViewportHeight(), !mClipArea->isSimple()); const Rect& clipRect(mClipArea->getClipRect()); ALOGD(" ClipRect %.1f %.1f %.1f %.1f, clip simple %d", clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, mClipArea->isSimple()); diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h index d8f926ef3925..4ab58302df8f 100644 --- a/libs/hwui/Snapshot.h +++ b/libs/hwui/Snapshot.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_SNAPSHOT_H -#define ANDROID_HWUI_SNAPSHOT_H +#pragma once #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> @@ -63,18 +62,6 @@ public: float radius; }; -// TODO: remove for HWUI_NEW_OPS -class ProjectionPathMask { -public: - static void* operator new(size_t size) = delete; - static void* operator new(size_t size, LinearAllocator& allocator) { - return allocator.alloc<ProjectionPathMask>(size); - } - - const SkPath* projectionMask; - Matrix4 projectionMaskTransform; -}; - /** * A snapshot holds information about the current state of the rendering * surface. A snapshot is usually created whenever the user calls save() @@ -113,11 +100,6 @@ public: * restored when this snapshot is restored. */ kFlagIsFboLayer = 0x4, - /** - * Indicates that this snapshot or an ancestor snapshot is - * an FBO layer. - */ - kFlagFboTarget = 0x8, // TODO: remove for HWUI_NEW_OPS }; /** @@ -179,11 +161,6 @@ public: */ void resetClip(float left, float top, float right, float bottom); - /** - * Resets the current transform to a pure 3D translation. - */ - void resetTransform(float x, float y, float z); - void initializeViewport(int width, int height) { mViewportData.initialize(width, height); mClipAreaRoot.setViewportDimensions(width, height); @@ -207,13 +184,7 @@ public: /** * Sets (and replaces) the current projection mask */ - void setProjectionPathMask(LinearAllocator& allocator, const SkPath* path); - - /** - * Indicates whether this snapshot should be ignored. A snapshot - * is typically ignored if its layer is invisible or empty. - */ - bool isIgnored() const; + void setProjectionPathMask(const SkPath* path); /** * Indicates whether the current transform has perspective components. @@ -221,13 +192,6 @@ public: bool hasPerspectiveTransform() const; /** - * Fills outTransform with the current, total transform to screen space, - * across layer boundaries. - */ - // TODO: remove for HWUI_NEW_OPS - void buildScreenSpaceTransform(Matrix4* outTransform) const; - - /** * Dirty flags. */ int flags; @@ -251,19 +215,6 @@ public: GLuint fbo; /** - * Indicates that this snapshot is invisible and nothing should be drawn - * inside it. This flag is set only when the layer clips drawing to its - * bounds and is passed to subsequent snapshots. - */ - bool invisible; - - /** - * If set to true, the layer will not be composited. This is similar to - * invisible but this flag is not passed to subsequent snapshots. - */ - bool empty; - - /** * Local transformation. Holds the current translation, scale and * rotation values. * @@ -273,14 +224,6 @@ public: mat4* transform; /** - * The ancestor layer's dirty region. - * - * This is a reference to a region owned by a layer. This pointer must - * not be freed. - */ - Region* region; - - /** * Current alpha value. This value is 1 by default, but may be set by a DisplayList which * has translucent rendering in a non-overlapping View. This value will be used by * the renderer to set the alpha in the current color being used for ensuing drawing @@ -302,11 +245,7 @@ public: /** * Current projection masking path - used exclusively to mask projected, tessellated circles. */ -#if HWUI_NEW_OPS const SkPath* projectionPathMask; -#else - const ProjectionPathMask* projectionPathMask; -#endif void dump() const; @@ -345,5 +284,3 @@ private: }; // namespace uirenderer }; // namespace android - -#endif // ANDROID_HWUI_SNAPSHOT_H diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp index d9e811684610..91e7ac39af90 100644 --- a/libs/hwui/TessellationCache.cpp +++ b/libs/hwui/TessellationCache.cpp @@ -18,7 +18,6 @@ #include <utils/Trace.h> #include "Caches.h" -#include "OpenGLRenderer.h" #include "PathTessellator.h" #include "ShadowTessellator.h" #include "TessellationCache.h" @@ -369,21 +368,6 @@ void TessellationCache::precacheShadows(const Matrix4* drawTransform, const Rect mShadowCache.put(key, task.get()); } -void TessellationCache::getShadowBuffers(const Matrix4* drawTransform, const Rect& localClip, - bool opaque, const SkPath* casterPerimeter, - const Matrix4* transformXY, const Matrix4* transformZ, - const Vector3& lightCenter, float lightRadius, vertexBuffer_pair_t& outBuffers) { - ShadowDescription key(casterPerimeter, drawTransform); - ShadowTask* task = static_cast<ShadowTask*>(mShadowCache.get(key)); - if (!task) { - precacheShadows(drawTransform, localClip, opaque, casterPerimeter, - transformXY, transformZ, lightCenter, lightRadius); - task = static_cast<ShadowTask*>(mShadowCache.get(key)); - } - LOG_ALWAYS_FATAL_IF(task == nullptr, "shadow not precached"); - outBuffers = task->getResult(); -} - sp<TessellationCache::ShadowTask> TessellationCache::getShadowTask( const Matrix4* drawTransform, const Rect& localClip, bool opaque, const SkPath* casterPerimeter, diff --git a/libs/hwui/TessellationCache.h b/libs/hwui/TessellationCache.h index 6141b4ef63d7..ccad1b7bd415 100644 --- a/libs/hwui/TessellationCache.h +++ b/libs/hwui/TessellationCache.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_HWUI_TESSELLATION_CACHE_H -#define ANDROID_HWUI_TESSELLATION_CACHE_H +#pragma once #include "Debug.h" #include "Matrix.h" @@ -161,17 +160,6 @@ public: const VertexBuffer* getRoundRect(const Matrix4& transform, const SkPaint& paint, float width, float height, float rx, float ry); - // TODO: delete these when switching to HWUI_NEW_OPS - void precacheShadows(const Matrix4* drawTransform, const Rect& localClip, - bool opaque, const SkPath* casterPerimeter, - const Matrix4* transformXY, const Matrix4* transformZ, - const Vector3& lightCenter, float lightRadius); - void getShadowBuffers(const Matrix4* drawTransform, const Rect& localClip, - bool opaque, const SkPath* casterPerimeter, - const Matrix4* transformXY, const Matrix4* transformZ, - const Vector3& lightCenter, float lightRadius, - vertexBuffer_pair_t& outBuffers); - sp<ShadowTask> getShadowTask(const Matrix4* drawTransform, const Rect& localClip, bool opaque, const SkPath* casterPerimeter, const Matrix4* transformXY, const Matrix4* transformZ, @@ -184,6 +172,11 @@ private: typedef VertexBuffer* (*Tessellator)(const Description&); + void precacheShadows(const Matrix4* drawTransform, const Rect& localClip, + bool opaque, const SkPath* casterPerimeter, + const Matrix4* transformXY, const Matrix4* transformZ, + const Vector3& lightCenter, float lightRadius); + Buffer* getRectBuffer(const Matrix4& transform, const SkPaint& paint, float width, float height); Buffer* getRoundRectBuffer(const Matrix4& transform, const SkPaint& paint, @@ -232,5 +225,3 @@ void tessellateShadows( }; // namespace uirenderer }; // namespace android - -#endif // ANDROID_HWUI_PATH_CACHE_H diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h index ac2bdccf5255..2087fca205da 100644 --- a/libs/hwui/TreeInfo.h +++ b/libs/hwui/TreeInfo.h @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef TREEINFO_H -#define TREEINFO_H + +#pragma once #include "utils/Macros.h" @@ -31,7 +31,6 @@ class CanvasContext; class DamageAccumulator; class LayerUpdateQueue; -class OpenGLRenderer; class RenderNode; class RenderState; @@ -89,13 +88,7 @@ public: // Must not be null during actual usage DamageAccumulator* damageAccumulator = nullptr; -#if HWUI_NEW_OPS LayerUpdateQueue* layerUpdateQueue = nullptr; -#else - // The renderer that will be drawing the next frame. Use this to push any - // layer updates or similar. May be NULL. - OpenGLRenderer* renderer = nullptr; -#endif ErrorHandler* errorHandler = nullptr; // Optional, may be nullptr. Used to allow things to observe interesting @@ -128,5 +121,3 @@ public: } /* namespace uirenderer */ } /* namespace android */ - -#endif /* TREEINFO_H */ diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp index dd0d72b76d4d..461363f5e8d8 100644 --- a/libs/hwui/hwui/Canvas.cpp +++ b/libs/hwui/hwui/Canvas.cpp @@ -16,7 +16,6 @@ #include "Canvas.h" -#include "DisplayListCanvas.h" #include "RecordingCanvas.h" #include "MinikinUtils.h" #include "Paint.h" @@ -27,11 +26,7 @@ namespace android { Canvas* Canvas::create_recording_canvas(int width, int height) { -#if HWUI_NEW_OPS return new uirenderer::RecordingCanvas(width, height); -#else - return new uirenderer::DisplayListCanvas(width, height); -#endif } void Canvas::drawTextDecorations(float x, float y, float length, const SkPaint& paint) { diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h index 7b3199ce11a4..0b4209925bd4 100644 --- a/libs/hwui/hwui/Canvas.h +++ b/libs/hwui/hwui/Canvas.h @@ -14,8 +14,7 @@ * limitations under the License. */ -#ifndef ANDROID_GRAPHICS_CANVAS_H -#define ANDROID_GRAPHICS_CANVAS_H +#pragma once #include <cutils/compiler.h> #include <utils/Functor.h> @@ -253,4 +252,3 @@ protected: }; }; // namespace android -#endif // ANDROID_GRAPHICS_CANVAS_H diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp index 5e600644ca19..ee4619d2c222 100644 --- a/libs/hwui/renderstate/RenderState.cpp +++ b/libs/hwui/renderstate/RenderState.cpp @@ -60,38 +60,6 @@ static void layerLostGlContext(Layer* layer) { } void RenderState::onGLContextDestroyed() { -/* - size_t size = mActiveLayers.size(); - if (CC_UNLIKELY(size != 0)) { - ALOGE("Crashing, have %d contexts and %d layers at context destruction. isempty %d", - mRegisteredContexts.size(), size, mActiveLayers.empty()); - mCaches->dumpMemoryUsage(); - for (std::set<renderthread::CanvasContext*>::iterator cit = mRegisteredContexts.begin(); - cit != mRegisteredContexts.end(); cit++) { - renderthread::CanvasContext* context = *cit; - ALOGE("Context: %p (root = %p)", context, context->mRootRenderNode.get()); - ALOGE(" Prefeteched layers: %zu", context->mPrefetechedLayers.size()); - for (std::set<RenderNode*>::iterator pit = context->mPrefetechedLayers.begin(); - pit != context->mPrefetechedLayers.end(); pit++) { - (*pit)->debugDumpLayers(" "); - } - context->mRootRenderNode->debugDumpLayers(" "); - } - - - if (mActiveLayers.begin() == mActiveLayers.end()) { - ALOGE("set has become empty. wat."); - } - for (std::set<const Layer*>::iterator lit = mActiveLayers.begin(); - lit != mActiveLayers.end(); lit++) { - const Layer* layer = *(lit); - ALOGE("Layer %p, state %d, texlayer %d, fbo %d, buildlayered %d", - layer, layer->state, layer->isTextureLayer(), layer->getFbo(), layer->wasBuildLayered); - } - LOG_ALWAYS_FATAL("%d layers have survived gl context destruction", size); - } -*/ - mLayerPool.clear(); // TODO: reset all cached state in state objects diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 9aa0dea18b6a..d36ebc77e5cc 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -21,9 +21,8 @@ #include "Caches.h" #include "DeferredLayerUpdater.h" #include "EglManager.h" -#include "LayerUpdateQueue.h" #include "LayerRenderer.h" -#include "OpenGLRenderer.h" +#include "LayerUpdateQueue.h" #include "Properties.h" #include "Readback.h" #include "RenderThread.h" @@ -109,12 +108,6 @@ void CanvasContext::destroy(TreeObserver* observer) { freePrefetchedLayers(observer); destroyHardwareResources(observer); mAnimationContext->destroy(); -#if !HWUI_NEW_OPS - if (mCanvas) { - delete mCanvas; - mCanvas = nullptr; - } -#endif } void CanvasContext::setSurface(Surface* surface) { @@ -149,11 +142,6 @@ void CanvasContext::setSwapBehavior(SwapBehavior swapBehavior) { void CanvasContext::initialize(Surface* surface) { setSurface(surface); -#if !HWUI_NEW_OPS - if (mCanvas) return; - mCanvas = new OpenGLRenderer(mRenderThread.renderState()); - mCanvas->initProperties(); -#endif } void CanvasContext::updateSurface(Surface* surface) { @@ -180,23 +168,13 @@ void CanvasContext::setStopped(bool stopped) { void CanvasContext::setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) { -#if HWUI_NEW_OPS mLightGeometry.radius = lightRadius; mLightInfo.ambientShadowAlpha = ambientShadowAlpha; mLightInfo.spotShadowAlpha = spotShadowAlpha; -#else - if (!mCanvas) return; - mCanvas->initLight(lightRadius, ambientShadowAlpha, spotShadowAlpha); -#endif } void CanvasContext::setLightCenter(const Vector3& lightCenter) { -#if HWUI_NEW_OPS mLightGeometry.center = lightCenter; -#else - if (!mCanvas) return; - mCanvas->setLightCenter(lightCenter); -#endif } void CanvasContext::setOpaque(bool opaque) { @@ -273,11 +251,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, mCurrentFrameInfo->markSyncStart(); info.damageAccumulator = &mDamageAccumulator; -#if HWUI_NEW_OPS info.layerUpdateQueue = &mLayerUpdateQueue; -#else - info.renderer = mCanvas; -#endif mAnimationContext->startFrame(info.mode); for (const sp<RenderNode>& node : mRenderNodes) { @@ -354,10 +328,8 @@ void CanvasContext::notifyFramePending() { } void CanvasContext::draw() { -#if !HWUI_NEW_OPS - LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE, - "drawRenderNode called on a context with no canvas or surface!"); -#endif + LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE, + "drawRenderNode called on a context with no surface!"); SkRect dirty; mDamageAccumulator.finish(&dirty); @@ -420,7 +392,6 @@ void CanvasContext::draw() { mEglManager.damageFrame(frame, dirty); -#if HWUI_NEW_OPS auto& caches = Caches::getInstance(); FrameBuilder frameBuilder(dirty, frame.width(), frame.height(), mLightGeometry, caches); @@ -448,122 +419,6 @@ void CanvasContext::draw() { } #endif -#else - mCanvas->prepareDirty(frame.width(), frame.height(), - dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom, mOpaque); - - Rect outBounds; - // It there are multiple render nodes, they are laid out as follows: - // #0 - backdrop (content + caption) - // #1 - content (positioned at (0,0) and clipped to - its bounds mContentDrawBounds) - // #2 - additional overlay nodes - // Usually the backdrop cannot be seen since it will be entirely covered by the content. While - // resizing however it might become partially visible. The following render loop will crop the - // backdrop against the content and draw the remaining part of it. It will then draw the content - // cropped to the backdrop (since that indicates a shrinking of the window). - // - // Additional nodes will be drawn on top with no particular clipping semantics. - - // The bounds of the backdrop against which the content should be clipped. - Rect backdropBounds = mContentDrawBounds; - // Usually the contents bounds should be mContentDrawBounds - however - we will - // move it towards the fixed edge to give it a more stable appearance (for the moment). - Rect contentBounds; - // If there is no content bounds we ignore the layering as stated above and start with 2. - int layer = (mContentDrawBounds.isEmpty() || mRenderNodes.size() == 1) ? 2 : 0; - // Draw all render nodes. Note that - for (const sp<RenderNode>& node : mRenderNodes) { - if (layer == 0) { // Backdrop. - // Draw the backdrop clipped to the inverse content bounds, but assume that the content - // was moved to the upper left corner. - const RenderProperties& properties = node->properties(); - Rect targetBounds(properties.getLeft(), properties.getTop(), - properties.getRight(), properties.getBottom()); - // Move the content bounds towards the fixed corner of the backdrop. - const int x = targetBounds.left; - const int y = targetBounds.top; - contentBounds.set(x, y, x + mContentDrawBounds.getWidth(), - y + mContentDrawBounds.getHeight()); - // Remember the intersection of the target bounds and the intersection bounds against - // which we have to crop the content. - backdropBounds.set(x, y, x + backdropBounds.getWidth(), y + backdropBounds.getHeight()); - backdropBounds.doIntersect(targetBounds); - // Check if we have to draw something on the left side ... - if (targetBounds.left < contentBounds.left) { - mCanvas->save(SaveFlags::Clip); - if (mCanvas->clipRect(targetBounds.left, targetBounds.top, - contentBounds.left, targetBounds.bottom, - SkRegion::kIntersect_Op)) { - mCanvas->drawRenderNode(node.get(), outBounds); - } - // Reduce the target area by the area we have just painted. - targetBounds.left = std::min(contentBounds.left, targetBounds.right); - mCanvas->restore(); - } - // ... or on the right side ... - if (targetBounds.right > contentBounds.right && - !targetBounds.isEmpty()) { - mCanvas->save(SaveFlags::Clip); - if (mCanvas->clipRect(contentBounds.right, targetBounds.top, - targetBounds.right, targetBounds.bottom, - SkRegion::kIntersect_Op)) { - mCanvas->drawRenderNode(node.get(), outBounds); - } - // Reduce the target area by the area we have just painted. - targetBounds.right = std::max(targetBounds.left, contentBounds.right); - mCanvas->restore(); - } - // ... or at the top ... - if (targetBounds.top < contentBounds.top && - !targetBounds.isEmpty()) { - mCanvas->save(SaveFlags::Clip); - if (mCanvas->clipRect(targetBounds.left, targetBounds.top, targetBounds.right, - contentBounds.top, - SkRegion::kIntersect_Op)) { - mCanvas->drawRenderNode(node.get(), outBounds); - } - // Reduce the target area by the area we have just painted. - targetBounds.top = std::min(contentBounds.top, targetBounds.bottom); - mCanvas->restore(); - } - // ... or at the bottom. - if (targetBounds.bottom > contentBounds.bottom && - !targetBounds.isEmpty()) { - mCanvas->save(SaveFlags::Clip); - if (mCanvas->clipRect(targetBounds.left, contentBounds.bottom, targetBounds.right, - targetBounds.bottom, SkRegion::kIntersect_Op)) { - mCanvas->drawRenderNode(node.get(), outBounds); - } - mCanvas->restore(); - } - } else if (layer == 1) { // Content - // It gets cropped against the bounds of the backdrop to stay inside. - mCanvas->save(SaveFlags::MatrixClip); - - // We shift and clip the content to match its final location in the window. - const float left = mContentDrawBounds.left; - const float top = mContentDrawBounds.top; - const float dx = backdropBounds.left - left; - const float dy = backdropBounds.top - top; - const float width = backdropBounds.getWidth(); - const float height = backdropBounds.getHeight(); - - mCanvas->translate(dx, dy); - if (mCanvas->clipRect(left, top, left + width, top + height, SkRegion::kIntersect_Op)) { - mCanvas->drawRenderNode(node.get(), outBounds); - } - mCanvas->restore(); - } else { // draw the rest on top at will! - mCanvas->drawRenderNode(node.get(), outBounds); - } - layer++; - } - - profiler().draw(mCanvas); - - bool drew = mCanvas->finish(); -#endif - waitOnFences(); GL_CHECKPOINT(LOW); @@ -614,11 +469,7 @@ void CanvasContext::draw() { // Called by choreographer to do an RT-driven animation void CanvasContext::doFrame() { -#if HWUI_NEW_OPS if (CC_UNLIKELY(mEglSurface == EGL_NO_SURFACE)) return; -#else - if (CC_UNLIKELY(!mCanvas || mEglSurface == EGL_NO_SURFACE)) return; -#endif prepareAndDraw(nullptr); } @@ -669,9 +520,6 @@ void CanvasContext::freePrefetchedLayers(TreeObserver* observer) { void CanvasContext::buildLayer(RenderNode* node, TreeObserver* observer) { ATRACE_CALL(); if (!mEglManager.hasEglContext()) return; -#if !HWUI_NEW_OPS - if (!mCanvas) return; -#endif // buildLayer() will leave the tree in an unknown state, so we must stop drawing stopDrawing(); @@ -679,11 +527,7 @@ void CanvasContext::buildLayer(RenderNode* node, TreeObserver* observer) { TreeInfo info(TreeInfo::MODE_FULL, *this); info.damageAccumulator = &mDamageAccumulator; info.observer = observer; -#if HWUI_NEW_OPS info.layerUpdateQueue = &mLayerUpdateQueue; -#else - info.renderer = mCanvas; -#endif info.runAnimations = false; node->prepareTree(info); SkRect ignore; @@ -692,7 +536,6 @@ void CanvasContext::buildLayer(RenderNode* node, TreeObserver* observer) { // purposes when the frame is actually drawn node->setPropertyFieldsDirty(RenderNode::GENERIC); -#if HWUI_NEW_OPS static const std::vector< sp<RenderNode> > emptyNodeList; auto& caches = Caches::getInstance(); FrameBuilder frameBuilder(mLayerUpdateQueue, mLightGeometry, caches); @@ -701,10 +544,6 @@ void CanvasContext::buildLayer(RenderNode* node, TreeObserver* observer) { mOpaque, mLightInfo); LOG_ALWAYS_FATAL_IF(renderer.didDraw(), "shouldn't draw in buildlayer case"); frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer); -#else - mCanvas->markLayersAsBuildLayers(); - mCanvas->flushLayerUpdates(); -#endif node->incStrong(nullptr); mPrefetchedLayers.insert(node); diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index a5f8562a8068..72f1268c279e 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -14,10 +14,12 @@ * limitations under the License. */ -#ifndef CANVASCONTEXT_H_ -#define CANVASCONTEXT_H_ +#pragma once +#include "BakedOpDispatcher.h" +#include "BakedOpRenderer.h" #include "DamageAccumulator.h" +#include "FrameBuilder.h" #include "FrameInfo.h" #include "FrameInfoVisualizer.h" #include "FrameMetricsReporter.h" @@ -30,12 +32,6 @@ #include "renderthread/RenderTask.h" #include "renderthread/RenderThread.h" -#if HWUI_NEW_OPS -#include "BakedOpDispatcher.h" -#include "BakedOpRenderer.h" -#include "FrameBuilder.h" -#endif - #include <cutils/compiler.h> #include <EGL/egl.h> #include <SkBitmap.h> @@ -53,9 +49,8 @@ namespace uirenderer { class AnimationContext; class DeferredLayerUpdater; -class OpenGLRenderer; -class Rect; class Layer; +class Rect; class RenderState; namespace renderthread { @@ -211,12 +206,8 @@ private: int64_t mFrameNumber = -1; bool mOpaque; -#if HWUI_NEW_OPS BakedOpRenderer::LightInfo mLightInfo; FrameBuilder::LightGeometry mLightGeometry = { {0, 0, 0}, 0 }; -#else - OpenGLRenderer* mCanvas = nullptr; -#endif bool mHaveNewSurface = false; DamageAccumulator mDamageAccumulator; @@ -252,4 +243,3 @@ private: } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */ -#endif /* CANVASCONTEXT_H_ */ diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index aea7edb08cf3..d860acd1edd1 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -466,11 +466,7 @@ CREATE_BRIDGE2(dumpGraphicsMemory, int fd, RenderThread* thread) { } else { fprintf(file, "\nNo caches instance.\n"); } -#if HWUI_NEW_OPS fprintf(file, "\nPipeline=FrameBuilder\n"); -#else - fprintf(file, "\nPipeline=OpenGLRenderer\n"); -#endif fflush(file); return nullptr; } diff --git a/libs/hwui/tests/common/TestScene.h b/libs/hwui/tests/common/TestScene.h index d4a66466d8f2..4813ff0de174 100644 --- a/libs/hwui/tests/common/TestScene.h +++ b/libs/hwui/tests/common/TestScene.h @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef TESTS_TESTSCENE_H -#define TESTS_TESTSCENE_H + +#pragma once #include <string> #include <unordered_map> @@ -22,14 +22,9 @@ namespace android { namespace uirenderer { class RenderNode; - -#if HWUI_NEW_OPS class RecordingCanvas; + typedef RecordingCanvas TestCanvas; -#else -class DisplayListCanvas; -typedef DisplayListCanvas TestCanvas; -#endif namespace test { @@ -76,5 +71,3 @@ public: } // namespace test } // namespace uirenderer } // namespace android - -#endif /* TESTS_TESTSCENE_H */ diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h index 4536bef6d391..9f7fee262acf 100644 --- a/libs/hwui/tests/common/TestUtils.h +++ b/libs/hwui/tests/common/TestUtils.h @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef TEST_UTILS_H -#define TEST_UTILS_H + +#pragma once #include <DeviceInfo.h> #include <DisplayList.h> @@ -25,24 +25,15 @@ #include <renderthread/RenderThread.h> #include <Snapshot.h> -#if HWUI_NEW_OPS #include <RecordedOp.h> #include <RecordingCanvas.h> -#else -#include <DisplayListOp.h> -#include <DisplayListCanvas.h> -#endif #include <memory> namespace android { namespace uirenderer { -#if HWUI_NEW_OPS typedef RecordingCanvas TestCanvas; -#else -typedef DisplayListCanvas TestCanvas; -#endif #define EXPECT_MATRIX_APPROX_EQ(a, b) \ EXPECT_TRUE(TestUtils::matricesAreApproxEqual(a, b)) @@ -251,5 +242,3 @@ private: } /* namespace uirenderer */ } /* namespace android */ - -#endif /* TEST_UTILS_H */ diff --git a/libs/hwui/tests/common/scenes/TestSceneBase.h b/libs/hwui/tests/common/scenes/TestSceneBase.h index 935ddcf9212d..792312a6a7a4 100644 --- a/libs/hwui/tests/common/scenes/TestSceneBase.h +++ b/libs/hwui/tests/common/scenes/TestSceneBase.h @@ -13,10 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef TESTS_SCENES_TESTSCENEBASE_H -#define TESTS_SCENES_TESTSCENEBASE_H -#include "DisplayListCanvas.h" +#pragma once + #include "RecordingCanvas.h" #include "RenderNode.h" #include "tests/common/TestContext.h" @@ -30,5 +29,3 @@ using namespace android; using namespace android::uirenderer; using namespace android::uirenderer::renderthread; using namespace android::uirenderer::test; - -#endif /* TESTS_SCENES_TESTSCENEBASE_H_ */ diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp index cd4a3c9be92d..ed3b84753eeb 100644 --- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp +++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp @@ -17,21 +17,13 @@ #include <benchmark/benchmark.h> #include "DisplayList.h" -#if HWUI_NEW_OPS #include "RecordingCanvas.h" -#else -#include "DisplayListCanvas.h" -#endif #include "tests/common/TestUtils.h" using namespace android; using namespace android::uirenderer; -#if HWUI_NEW_OPS typedef RecordingCanvas TestCanvas; -#else -typedef DisplayListCanvas TestCanvas; -#endif void BM_DisplayList_alloc(benchmark::State& benchState) { while (benchState.KeepRunning()) { diff --git a/libs/hwui/tests/unit/GlopBuilderTests.cpp b/libs/hwui/tests/unit/GlopBuilderTests.cpp index 95543d33b1ef..67e58e2aba0d 100644 --- a/libs/hwui/tests/unit/GlopBuilderTests.cpp +++ b/libs/hwui/tests/unit/GlopBuilderTests.cpp @@ -85,9 +85,6 @@ static void expectTransformEq(Glop::Transform& expectedTransform, Glop::Transfor } static void expectGlopEq(Glop& expectedGlop, Glop& builtGlop) { -#if !HWUI_NEW_OPS - EXPECT_EQ(expectedGlop.bounds, builtGlop.bounds); -#endif expectBlendEq(expectedGlop.blend, builtGlop.blend); expectFillEq(expectedGlop.fill, builtGlop.fill); expectMeshEq(expectedGlop.mesh, builtGlop.mesh); @@ -138,9 +135,6 @@ RENDERTHREAD_TEST(GlopBuilder, rectSnapTest) { // unit quad also should be translate by additional (0.3, 0.3) to snap to exact pixels. goldenGlop->transform.modelView.loadTranslate(1.3, 1.3, 0); goldenGlop->transform.modelView.scale(99, 99, 1); -#if !HWUI_NEW_OPS - goldenGlop->bounds = android::uirenderer::Rect(1.70, 1.70, 100.70, 100.70); -#endif goldenGlop->transform.canvas = simpleTranslate; goldenGlop->fill.texture.filter = GL_NEAREST; expectGlopEq(*goldenGlop, glop); diff --git a/libs/hwui/utils/TestWindowContext.cpp b/libs/hwui/utils/TestWindowContext.cpp index e0b2593323b2..b879f781bce1 100644 --- a/libs/hwui/utils/TestWindowContext.cpp +++ b/libs/hwui/utils/TestWindowContext.cpp @@ -16,7 +16,6 @@ #include "TestWindowContext.h" #include "AnimationContext.h" -#include "DisplayListCanvas.h" #include "IContextFactory.h" #include "RecordingCanvas.h" #include "RenderNode.h" @@ -89,11 +88,7 @@ public: android::uirenderer::Vector3 lightVector { lightX, -200.0f, 800.0f }; mProxy->setup(800.0f, 255 * 0.075f, 255 * 0.15f); mProxy->setLightCenter(lightVector); -#if HWUI_NEW_OPS mCanvas.reset(new android::uirenderer::RecordingCanvas(mSize.width(), mSize.height())); -#else - mCanvas.reset(new android::uirenderer::DisplayListCanvas(mSize.width(), mSize.height())); -#endif } SkCanvas* prepareToDraw() { @@ -171,11 +166,7 @@ private: std::unique_ptr<android::uirenderer::RenderNode> mRootNode; std::unique_ptr<android::uirenderer::renderthread::RenderProxy> mProxy; -#if HWUI_NEW_OPS std::unique_ptr<android::uirenderer::RecordingCanvas> mCanvas; -#else - std::unique_ptr<android::uirenderer::DisplayListCanvas> mCanvas; -#endif android::sp<android::IGraphicBufferProducer> mProducer; android::sp<android::IGraphicBufferConsumer> mConsumer; android::sp<android::CpuConsumer> mCpuConsumer; |