Delete old rendering pipeline
fixes: 30002246
Change-Id: I45df0e924708526cee045b14c291bd23aa1a92db
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 93ff637..2ea80ff 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -7,7 +7,6 @@
LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_CFLAGS += -Wno-non-virtual-dtor
LOCAL_CFLAGS += -Wno-maybe-uninitialized -Wno-parentheses
-LOCAL_CFLAGS += -DHWUI_NEW_OPS
LOCAL_CPPFLAGS += -Wno-conversion-null
ifeq ($(TARGET_ARCH), arm)
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index d90f88f..95b28d3 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -2,8 +2,6 @@
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 @@
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 @@
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 @@
# 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_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 @@
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 f2d344f..ef81a52 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -163,17 +163,15 @@
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 @@
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 eac9359..fe9411d 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 @@
Extensions mExtensions;
public:
TextureCache textureCache;
- LayerCache layerCache;
RenderBufferCache renderBufferCache;
GradientCache gradientCache;
PatchCache patchCache;
@@ -205,5 +202,3 @@
}; // namespace uirenderer
}; // namespace android
-
-#endif // ANDROID_HWUI_CACHES_H
diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp
index e2149d1..7e2c28c 100644
--- a/libs/hwui/CanvasState.cpp
+++ b/libs/hwui/CanvasState.cpp
@@ -23,8 +23,7 @@
CanvasState::CanvasState(CanvasStateClient& renderer)
- : mDirtyClip(false)
- , mWidth(-1)
+ : mWidth(-1)
, mHeight(-1)
, mSaveCount(1)
, mCanvas(renderer)
@@ -205,19 +204,16 @@
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::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 @@
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::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 b9e87ae..ba260d1 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 @@
* 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 @@
*/
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 @@
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 @@
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 @@
}; // 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 689179d..0000000
--- 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 98ccf11..0000000
--- 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 f833a54..f13cb8d 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 @@
, 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::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 44a24c8..389e17d 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 @@
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 28be05c..ca9e2bd 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 @@
, 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 ccf71c6..a8205c8 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 @@
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 @@
* 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 @@
// 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 @@
return allocator.usedSize();
}
bool isEmpty() {
-#if HWUI_NEW_OPS
return ops.empty();
-#else
- return !hasDrawOps;
-#endif
}
private:
@@ -203,12 +144,8 @@
// 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 bec66295..0000000
--- 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 664f79e..0000000
--- 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 2a85913..0000000
--- 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 276c18d..25dc92c 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 @@
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 @@
.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 e10a81b..dedc494 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 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 @@
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 @@
}; // namespace uirenderer
}; // namespace android
-
-#endif // ANDROID_HWUI_FONT_RENDERER_H
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index 37d9d0e7..be4fdac 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -477,7 +477,7 @@
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 adadd32..570322d 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 83adf19..fc958b8 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 @@
} /* namespace uirenderer */
} /* namespace android */
-
-#endif /* DRAWPROFILER_H */
diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h
index 6433c86..46dd598 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 @@
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 @@
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 @@
} /* namespace uirenderer */
} /* namespace android */
-
-#endif // ANDROID_HWUI_GLOP_H
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index e502725..1091736 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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
// 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 @@
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 1c520c2..1152461 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 @@
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 @@
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 @@
// 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 @@
} /* namespace uirenderer */
} /* namespace android */
-
-#endif // RENDERSTATE_GLOPBUILDER_H
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index cdbbbab..8c797d5e 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 @@
renderState.unregisterLayer(this);
SkSafeUnref(colorFilter);
- if (stencil || fbo || texture.mId) {
- removeFbo();
+ if (texture.mId) {
texture.deleteTexture();
}
@@ -64,116 +59,9 @@
}
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::bindStencilRenderBuffer() const {
- if (stencil) {
- stencil->bind();
- }
-}
-
void Layer::generateTexture() {
if (!texture.mId) {
glGenTextures(1, &texture.mId);
@@ -206,86 +88,6 @@
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 1e5498b..8ac11d1 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 @@
// 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 @@
};
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
*/
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 f5681ce..0000000
--- 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 6fe7b3a..0000000
--- 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 405165f..8d50dc2 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,69 +44,20 @@
}
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);
+ 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 (renderTarget != layer->getRenderTarget()) {
- layer->setRenderTarget(renderTarget);
- layer->bindTexture();
- layer->setFilter(GL_NEAREST, false, true);
- layer->setWrap(GL_CLAMP_TO_EDGE, false, true);
- }
+ 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);
-
- if (fbo != previousFbo) {
- renderState.bindFramebuffer(previousFbo);
- }
- }
- }
-#endif
-}
-
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index 1fb6b14..7460e3e 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 @@
// 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 ec9ffde..f4b7ee0 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 9d821f3..0000000
--- 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 dacd8cc..0000000
--- 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 d1c5dbf..4e587fb 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 Caches;
+class RenderState;
class PatchCache {
public:
@@ -186,5 +186,3 @@
}; // namespace uirenderer
}; // namespace android
-
-#endif // ANDROID_HWUI_PATCH_CACHE_H
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 880a90e..5d892fd 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 @@
* 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 aee9d63..f3078ce 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 @@
}; // namespace uirenderer
}; // namespace android
-
-#endif // ANDROID_HWUI_RECORDED_OP_H
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index cbefccb..4528a38 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -43,7 +43,6 @@
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 f8797bf..5330e23 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() {
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 @@
* 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 @@
}
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 @@
}
}
-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 @@
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 @@
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 @@
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 @@
}
}
-#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 @@
}
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 @@
}
}
-/*
- * 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 @@
// 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 @@
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 @@
}
}
-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 f9735a2..ee045aa 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 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 @@
* 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 @@
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 @@
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 @@
}
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 @@
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 @@
// 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 @@
} /* namespace uirenderer */
} /* namespace android */
-
-#endif /* RENDERNODE_H */
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index 5ebf545..7e3cad4 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 c1221f7..2a2e4c7 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 @@
} /* namespace uirenderer */
} /* namespace android */
-
-#endif /* RENDERNODEPROPERTIES_H */
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index 2c9c9d9..21c26f7 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -30,14 +30,11 @@
, 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 @@
, 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 @@
} else {
mClipArea = s->mClipArea;
}
-
- if (s->flags & Snapshot::kFlagFboTarget) {
- flags |= Snapshot::kFlagFboTarget;
- region = s->region;
- } else {
- region = nullptr;
- }
}
///////////////////////////////////////////////////////////////////////////////
@@ -126,58 +114,6 @@
}
///////////////////////////////////////////////////////////////////////////////
-// 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 @@
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 @@
// 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 d8f926e..4ab5830 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 @@
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 @@
* 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 @@
*/
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 @@
/**
* 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 @@
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 @@
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 @@
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 @@
/**
* 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 @@
}; // namespace uirenderer
}; // namespace android
-
-#endif // ANDROID_HWUI_SNAPSHOT_H
diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp
index d9e8116..91e7ac3 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 @@
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 6141b4e..ccad1b7 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 @@
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 @@
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 @@
}; // namespace uirenderer
}; // namespace android
-
-#endif // ANDROID_HWUI_PATH_CACHE_H
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index ac2bdcc..2087fca 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 DamageAccumulator;
class LayerUpdateQueue;
-class OpenGLRenderer;
class RenderNode;
class RenderState;
@@ -89,13 +88,7 @@
// 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 @@
} /* namespace uirenderer */
} /* namespace android */
-
-#endif /* TREEINFO_H */
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index dd0d72b..461363f 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 7b3199c..0b42099 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 @@
};
}; // namespace android
-#endif // ANDROID_GRAPHICS_CANVAS_H
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index 5e60064..ee4619d 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -60,38 +60,6 @@
}
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 9aa0dea..d36ebc7 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 @@
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::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::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 @@
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::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 @@
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 @@
}
#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 @@
// 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::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 @@
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 @@
// 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 @@
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 a5f8562..72f1268 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 @@
class AnimationContext;
class DeferredLayerUpdater;
-class OpenGLRenderer;
-class Rect;
class Layer;
+class Rect;
class RenderState;
namespace renderthread {
@@ -211,12 +206,8 @@
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 @@
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
-#endif /* CANVASCONTEXT_H_ */
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index aea7edb..d860acd 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -466,11 +466,7 @@
} 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 d4a6646..4813ff0 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 @@
} // 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 4536bef..9f7fee2 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 @@
} /* 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 935ddcf..792312a 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::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 cd4a3c9..ed3b847 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 95543d3..67e58e2 100644
--- a/libs/hwui/tests/unit/GlopBuilderTests.cpp
+++ b/libs/hwui/tests/unit/GlopBuilderTests.cpp
@@ -85,9 +85,6 @@
}
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 @@
// 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 e0b2593..b879f78 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 @@
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 @@
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;