summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/androidfw/ResourceTypes.cpp2
-rw-r--r--libs/hwui/AmbientShadow.cpp3
-rw-r--r--libs/hwui/AmbientShadow.h4
-rw-r--r--libs/hwui/Android.common.mk108
-rw-r--r--libs/hwui/Android.mk117
-rw-r--r--libs/hwui/AnimationContext.cpp16
-rw-r--r--libs/hwui/Animator.cpp10
-rw-r--r--libs/hwui/Animator.h32
-rw-r--r--libs/hwui/AnimatorManager.cpp14
-rw-r--r--libs/hwui/AnimatorManager.h2
-rw-r--r--libs/hwui/AssetAtlas.cpp13
-rw-r--r--libs/hwui/AssetAtlas.h4
-rw-r--r--libs/hwui/Caches.cpp402
-rw-r--r--libs/hwui/Caches.h286
-rw-r--r--libs/hwui/Canvas.h163
-rw-r--r--libs/hwui/CanvasState.cpp (renamed from libs/hwui/StatefulBaseRenderer.cpp)132
-rw-r--r--libs/hwui/CanvasState.h192
-rw-r--r--libs/hwui/ClipArea.cpp368
-rw-r--r--libs/hwui/ClipArea.h175
-rw-r--r--libs/hwui/DamageAccumulator.cpp8
-rw-r--r--libs/hwui/DeferredDisplayList.cpp89
-rw-r--r--libs/hwui/DeferredDisplayList.h4
-rw-r--r--libs/hwui/DeferredLayerUpdater.cpp20
-rw-r--r--libs/hwui/DeferredLayerUpdater.h9
-rw-r--r--libs/hwui/DisplayList.cpp20
-rw-r--r--libs/hwui/DisplayList.h18
-rw-r--r--libs/hwui/DisplayListLogBuffer.cpp112
-rw-r--r--libs/hwui/DisplayListLogBuffer.h57
-rw-r--r--libs/hwui/DisplayListOp.h498
-rw-r--r--libs/hwui/DisplayListRenderer.cpp319
-rw-r--r--libs/hwui/DisplayListRenderer.h321
-rw-r--r--libs/hwui/Dither.cpp23
-rw-r--r--libs/hwui/Dither.h10
-rw-r--r--libs/hwui/DrawProfiler.cpp4
-rw-r--r--libs/hwui/Extensions.cpp19
-rw-r--r--libs/hwui/Extensions.h11
-rw-r--r--libs/hwui/FboCache.cpp2
-rw-r--r--libs/hwui/Fence.h113
-rw-r--r--libs/hwui/FontRenderer.cpp122
-rw-r--r--libs/hwui/FontRenderer.h61
-rw-r--r--libs/hwui/GammaFontRenderer.cpp51
-rw-r--r--libs/hwui/GammaFontRenderer.h63
-rw-r--r--libs/hwui/Glop.h122
-rw-r--r--libs/hwui/GlopBuilder.cpp216
-rw-r--r--libs/hwui/GlopBuilder.h68
-rw-r--r--libs/hwui/GradientCache.cpp27
-rw-r--r--libs/hwui/GradientCache.h39
-rw-r--r--libs/hwui/Image.cpp4
-rw-r--r--libs/hwui/Interpolator.cpp16
-rw-r--r--libs/hwui/Interpolator.h23
-rw-r--r--libs/hwui/Layer.cpp53
-rw-r--r--libs/hwui/Layer.h8
-rw-r--r--libs/hwui/LayerCache.cpp30
-rw-r--r--libs/hwui/LayerCache.h13
-rw-r--r--libs/hwui/LayerRenderer.cpp74
-rw-r--r--libs/hwui/LayerRenderer.h19
-rw-r--r--libs/hwui/Matrix.h2
-rw-r--r--[-rwxr-xr-x]libs/hwui/OpenGLRenderer.cpp1316
-rwxr-xr-xlibs/hwui/OpenGLRenderer.h304
-rw-r--r--libs/hwui/Outline.h2
-rw-r--r--libs/hwui/Patch.cpp26
-rw-r--r--libs/hwui/Patch.h6
-rw-r--r--libs/hwui/PatchCache.cpp38
-rw-r--r--libs/hwui/PatchCache.h12
-rw-r--r--libs/hwui/PathCache.cpp29
-rw-r--r--libs/hwui/PathCache.h22
-rw-r--r--libs/hwui/PathTessellator.cpp6
-rw-r--r--libs/hwui/PixelBuffer.cpp67
-rw-r--r--libs/hwui/PixelBuffer.h1
-rw-r--r--libs/hwui/Program.cpp8
-rw-r--r--libs/hwui/Program.h13
-rw-r--r--libs/hwui/ProgramCache.cpp18
-rw-r--r--libs/hwui/ProgramCache.h6
-rw-r--r--libs/hwui/Properties.h2
-rw-r--r--libs/hwui/Query.h152
-rw-r--r--libs/hwui/Rect.h14
-rw-r--r--libs/hwui/RenderBufferCache.cpp4
-rw-r--r--libs/hwui/RenderBufferCache.h4
-rw-r--r--libs/hwui/RenderNode.cpp80
-rw-r--r--libs/hwui/RenderNode.h4
-rw-r--r--libs/hwui/RenderProperties.cpp12
-rw-r--r--libs/hwui/RenderProperties.h8
-rw-r--r--libs/hwui/RenderState.cpp188
-rw-r--r--libs/hwui/Renderer.h89
-rw-r--r--libs/hwui/ResourceCache.cpp179
-rw-r--r--libs/hwui/ResourceCache.h58
-rw-r--r--libs/hwui/RevealClip.h2
-rw-r--r--libs/hwui/ShadowTessellator.cpp29
-rw-r--r--libs/hwui/ShadowTessellator.h8
-rw-r--r--libs/hwui/SkiaCanvas.cpp716
-rw-r--r--libs/hwui/SkiaCanvasProxy.cpp347
-rw-r--r--libs/hwui/SkiaCanvasProxy.h104
-rw-r--r--libs/hwui/SkiaShader.cpp53
-rw-r--r--libs/hwui/SkiaShader.h10
-rw-r--r--libs/hwui/Snapshot.cpp118
-rw-r--r--libs/hwui/Snapshot.h52
-rw-r--r--libs/hwui/SpotShadow.cpp5
-rw-r--r--libs/hwui/SpotShadow.h3
-rw-r--r--libs/hwui/StatefulBaseRenderer.h171
-rw-r--r--libs/hwui/TessellationCache.cpp22
-rw-r--r--libs/hwui/TessellationCache.h9
-rw-r--r--libs/hwui/TextDropShadowCache.cpp7
-rw-r--r--libs/hwui/TextDropShadowCache.h11
-rw-r--r--libs/hwui/Texture.cpp52
-rw-r--r--libs/hwui/TextureCache.cpp57
-rw-r--r--libs/hwui/TextureCache.h14
-rw-r--r--libs/hwui/TreeInfo.h10
-rw-r--r--libs/hwui/Vector.h3
-rw-r--r--libs/hwui/Vertex.h47
-rw-r--r--libs/hwui/VertexBuffer.h29
-rw-r--r--libs/hwui/font/CacheTexture.cpp21
-rw-r--r--libs/hwui/font/CacheTexture.h5
-rw-r--r--libs/hwui/font/CachedGlyphInfo.h4
-rw-r--r--libs/hwui/font/Font.cpp37
-rw-r--r--libs/hwui/font/Font.h8
-rw-r--r--libs/hwui/renderstate/Blend.cpp136
-rw-r--r--libs/hwui/renderstate/Blend.h51
-rw-r--r--libs/hwui/renderstate/MeshState.cpp175
-rw-r--r--libs/hwui/renderstate/MeshState.h142
-rw-r--r--libs/hwui/renderstate/PixelBufferState.cpp45
-rw-r--r--libs/hwui/renderstate/PixelBufferState.h37
-rw-r--r--libs/hwui/renderstate/RenderState.cpp300
-rw-r--r--libs/hwui/renderstate/RenderState.h (renamed from libs/hwui/RenderState.h)28
-rw-r--r--libs/hwui/renderstate/Scissor.cpp91
-rw-r--r--libs/hwui/renderstate/Scissor.h46
-rw-r--r--libs/hwui/renderstate/Stencil.cpp (renamed from libs/hwui/Stencil.cpp)37
-rw-r--r--libs/hwui/renderstate/Stencil.h (renamed from libs/hwui/Stencil.h)16
-rw-r--r--libs/hwui/renderstate/TextureState.cpp103
-rw-r--r--libs/hwui/renderstate/TextureState.h88
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp46
-rw-r--r--libs/hwui/renderthread/CanvasContext.h4
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.cpp4
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.h2
-rw-r--r--libs/hwui/renderthread/EglManager.cpp34
-rw-r--r--libs/hwui/renderthread/EglManager.h2
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp74
-rw-r--r--libs/hwui/renderthread/RenderProxy.h2
-rw-r--r--libs/hwui/renderthread/RenderTask.cpp7
-rw-r--r--libs/hwui/renderthread/RenderTask.h8
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp30
-rw-r--r--libs/hwui/renderthread/RenderThread.h2
-rw-r--r--libs/hwui/tests/Android.mk47
-rw-r--r--libs/hwui/tests/ClipAreaTests.cpp116
-rw-r--r--libs/hwui/tests/TestContext.cpp65
-rw-r--r--libs/hwui/tests/TestContext.h38
-rw-r--r--libs/hwui/tests/main.cpp250
-rw-r--r--libs/hwui/thread/TaskManager.h4
-rw-r--r--libs/hwui/thread/TaskProcessor.h2
-rw-r--r--libs/hwui/utils/Macros.h4
-rw-r--r--libs/hwui/utils/PaintUtils.h74
-rw-r--r--libs/hwui/utils/Pair.h2
-rw-r--r--libs/hwui/utils/SortedList.h14
-rw-r--r--libs/hwui/utils/SortedListImpl.h2
-rw-r--r--libs/hwui/utils/Timing.h4
154 files changed, 7056 insertions, 4409 deletions
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 7241069..aca3e8c 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -4640,7 +4640,7 @@ bool ResTable::stringToFloat(const char16_t* s, size_t len, Res_value* outValue)
if (len > 0) {
return false;
}
- if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.') {
+ if ((buf[0] < '0' || buf[0] > '9') && buf[0] != '.' && buf[0] != '-' && buf[0] != '+') {
return false;
}
diff --git a/libs/hwui/AmbientShadow.cpp b/libs/hwui/AmbientShadow.cpp
index 5840107..0a210d6 100644
--- a/libs/hwui/AmbientShadow.cpp
+++ b/libs/hwui/AmbientShadow.cpp
@@ -60,6 +60,7 @@
#include "AmbientShadow.h"
#include "ShadowTessellator.h"
#include "Vertex.h"
+#include "VertexBuffer.h"
#include "utils/MathUtils.h"
namespace android {
@@ -178,7 +179,7 @@ inline bool needsExtraForEdge(float firstAlpha, float secondAlpha) {
void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
const Vector3* casterVertices, int casterVertexCount, const Vector3& centroid3d,
float heightFactor, float geomFactor, VertexBuffer& shadowVertexBuffer) {
- shadowVertexBuffer.setMode(VertexBuffer::kIndices);
+ shadowVertexBuffer.setMeshFeatureFlags(VertexBuffer::kAlpha | VertexBuffer::kIndices);
// In order to computer the outer vertices in one loop, we need pre-compute
// the normal by the vertex (n - 1) to vertex 0, and the spike and alpha value
diff --git a/libs/hwui/AmbientShadow.h b/libs/hwui/AmbientShadow.h
index 9660dc0..8eb1048 100644
--- a/libs/hwui/AmbientShadow.h
+++ b/libs/hwui/AmbientShadow.h
@@ -19,13 +19,13 @@
#define ANDROID_HWUI_AMBIENT_SHADOW_H
#include "Debug.h"
-#include "OpenGLRenderer.h"
#include "Vector.h"
-#include "VertexBuffer.h"
namespace android {
namespace uirenderer {
+class VertexBuffer;
+
/**
* AmbientShadow is used to calculate the ambient shadow value around a polygon.
*/
diff --git a/libs/hwui/Android.common.mk b/libs/hwui/Android.common.mk
new file mode 100644
index 0000000..e05dd55
--- /dev/null
+++ b/libs/hwui/Android.common.mk
@@ -0,0 +1,108 @@
+# getConfig in external/skia/include/core/SkBitmap.h is deprecated.
+# Allow Gnu extension: in-class initializer of static 'const float' member.
+LOCAL_CLANG_CFLAGS += \
+ -Wno-deprecated-declarations \
+ -Wno-gnu-static-float-init
+
+LOCAL_SRC_FILES := \
+ font/CacheTexture.cpp \
+ font/Font.cpp \
+ renderstate/Blend.cpp \
+ renderstate/MeshState.cpp \
+ renderstate/PixelBufferState.cpp \
+ renderstate/RenderState.cpp \
+ renderstate/Scissor.cpp \
+ renderstate/Stencil.cpp \
+ renderstate/TextureState.cpp \
+ renderthread/CanvasContext.cpp \
+ renderthread/DrawFrameTask.cpp \
+ renderthread/EglManager.cpp \
+ renderthread/RenderProxy.cpp \
+ renderthread/RenderTask.cpp \
+ renderthread/RenderThread.cpp \
+ renderthread/TimeLord.cpp \
+ thread/TaskManager.cpp \
+ utils/Blur.cpp \
+ utils/GLUtils.cpp \
+ utils/SortedListImpl.cpp \
+ AmbientShadow.cpp \
+ AnimationContext.cpp \
+ Animator.cpp \
+ AnimatorManager.cpp \
+ AssetAtlas.cpp \
+ Caches.cpp \
+ CanvasState.cpp \
+ ClipArea.cpp \
+ DamageAccumulator.cpp \
+ DeferredDisplayList.cpp \
+ DeferredLayerUpdater.cpp \
+ DisplayList.cpp \
+ DisplayListRenderer.cpp \
+ Dither.cpp \
+ DrawProfiler.cpp \
+ Extensions.cpp \
+ FboCache.cpp \
+ FontRenderer.cpp \
+ GammaFontRenderer.cpp \
+ GlopBuilder.cpp \
+ GradientCache.cpp \
+ Image.cpp \
+ Interpolator.cpp \
+ Layer.cpp \
+ LayerCache.cpp \
+ LayerRenderer.cpp \
+ Matrix.cpp \
+ OpenGLRenderer.cpp \
+ Patch.cpp \
+ PatchCache.cpp \
+ PathCache.cpp \
+ PathTessellator.cpp \
+ PixelBuffer.cpp \
+ Program.cpp \
+ ProgramCache.cpp \
+ RenderBufferCache.cpp \
+ RenderNode.cpp \
+ RenderProperties.cpp \
+ ResourceCache.cpp \
+ ShadowTessellator.cpp \
+ SkiaCanvas.cpp \
+ SkiaCanvasProxy.cpp \
+ SkiaShader.cpp \
+ Snapshot.cpp \
+ SpotShadow.cpp \
+ TessellationCache.cpp \
+ TextDropShadowCache.cpp \
+ Texture.cpp \
+ TextureCache.cpp
+
+intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,)
+
+LOCAL_C_INCLUDES += \
+ external/skia/src/core
+
+LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES
+LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libEGL libGLESv2 libskia libui libgui
+
+ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
+ LOCAL_CFLAGS += -DANDROID_ENABLE_RENDERSCRIPT
+ LOCAL_SHARED_LIBRARIES += libRS libRScpp
+ LOCAL_C_INCLUDES += \
+ $(intermediates) \
+ frameworks/rs/cpp \
+ frameworks/rs \
+
+endif
+
+ifndef HWUI_COMPILE_SYMBOLS
+ LOCAL_CFLAGS += -fvisibility=hidden
+endif
+
+ifdef HWUI_COMPILE_FOR_PERF
+ # TODO: Non-arm?
+ LOCAL_CFLAGS += -fno-omit-frame-pointer -marm -mapcs
+endif
+
+# Defaults for ATRACE_TAG and LOG_TAG for libhwui
+LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_VIEW -DLOG_TAG=\"OpenGLRenderer\"
+
+LOCAL_CFLAGS += -Wall -Werror -Wno-unused-parameter -Wunreachable-code
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index d0b9d82..91e289c 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -2,118 +2,11 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-# Too many unused parameters in external/skia/include and this directory.
-# getConfig in external/skia/include/core/SkBitmap.h is deprecated.
-# Allow Gnu extension: in-class initializer of static 'const float' member.
-LOCAL_CLANG_CFLAGS += \
- -Wno-gnu-static-float-init
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_MODULE := libhwui
-# Only build libhwui when USE_OPENGL_RENDERER is
-# defined in the current device/board configuration
-ifeq ($(USE_OPENGL_RENDERER),true)
- LOCAL_SRC_FILES := \
- utils/Blur.cpp \
- utils/GLUtils.cpp \
- utils/SortedListImpl.cpp \
- thread/TaskManager.cpp \
- font/CacheTexture.cpp \
- font/Font.cpp \
- AmbientShadow.cpp \
- AnimationContext.cpp \
- Animator.cpp \
- AnimatorManager.cpp \
- AssetAtlas.cpp \
- DamageAccumulator.cpp \
- FontRenderer.cpp \
- GammaFontRenderer.cpp \
- Caches.cpp \
- DisplayList.cpp \
- DeferredDisplayList.cpp \
- DeferredLayerUpdater.cpp \
- DisplayListLogBuffer.cpp \
- DisplayListRenderer.cpp \
- Dither.cpp \
- DrawProfiler.cpp \
- Extensions.cpp \
- FboCache.cpp \
- GradientCache.cpp \
- Image.cpp \
- Interpolator.cpp \
- Layer.cpp \
- LayerCache.cpp \
- LayerRenderer.cpp \
- Matrix.cpp \
- OpenGLRenderer.cpp \
- Patch.cpp \
- PatchCache.cpp \
- PathCache.cpp \
- PathTessellator.cpp \
- PixelBuffer.cpp \
- Program.cpp \
- ProgramCache.cpp \
- RenderBufferCache.cpp \
- RenderNode.cpp \
- RenderProperties.cpp \
- RenderState.cpp \
- ResourceCache.cpp \
- ShadowTessellator.cpp \
- SkiaShader.cpp \
- Snapshot.cpp \
- SpotShadow.cpp \
- StatefulBaseRenderer.cpp \
- Stencil.cpp \
- TessellationCache.cpp \
- Texture.cpp \
- TextureCache.cpp \
- TextDropShadowCache.cpp
+include $(LOCAL_PATH)/Android.common.mk
-# RenderThread stuff
- LOCAL_SRC_FILES += \
- renderthread/CanvasContext.cpp \
- renderthread/DrawFrameTask.cpp \
- renderthread/EglManager.cpp \
- renderthread/RenderProxy.cpp \
- renderthread/RenderTask.cpp \
- renderthread/RenderThread.cpp \
- renderthread/TimeLord.cpp
+include $(BUILD_SHARED_LIBRARY)
- intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,)
-
- LOCAL_C_INCLUDES += \
- external/skia/src/core
-
- LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES
- LOCAL_CFLAGS += -Wno-unused-parameter
- LOCAL_MODULE_CLASS := SHARED_LIBRARIES
- LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libEGL libGLESv2 libskia libui libgui
- LOCAL_MODULE := libhwui
- LOCAL_MODULE_TAGS := optional
-
- ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
- LOCAL_CFLAGS += -DANDROID_ENABLE_RENDERSCRIPT
- LOCAL_SHARED_LIBRARIES += libRS libRScpp
- LOCAL_C_INCLUDES += \
- $(intermediates) \
- frameworks/rs/cpp \
- frameworks/rs \
-
- endif
-
- ifndef HWUI_COMPILE_SYMBOLS
- LOCAL_CFLAGS += -fvisibility=hidden
- endif
-
- ifdef HWUI_COMPILE_FOR_PERF
- # TODO: Non-arm?
- LOCAL_CFLAGS += -fno-omit-frame-pointer -marm -mapcs
- endif
-
- # Defaults for ATRACE_TAG and LOG_TAG for libhwui
- LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_VIEW -DLOG_TAG=\"OpenGLRenderer\"
-
- LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-
- include $(BUILD_SHARED_LIBRARY)
-
- include $(call all-makefiles-under,$(LOCAL_PATH))
-endif
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libs/hwui/AnimationContext.cpp b/libs/hwui/AnimationContext.cpp
index a20bdae..097be08 100644
--- a/libs/hwui/AnimationContext.cpp
+++ b/libs/hwui/AnimationContext.cpp
@@ -59,7 +59,7 @@ void AnimationContext::startFrame(TreeInfo::TraversalMode mode) {
"Missed running animations last frame!");
AnimationHandle* head = mNextFrameAnimations.mNextHandle;
if (head) {
- mNextFrameAnimations.mNextHandle = NULL;
+ mNextFrameAnimations.mNextHandle = nullptr;
mCurrentFrameAnimations.mNextHandle = head;
head->mPreviousHandle = &mCurrentFrameAnimations;
}
@@ -84,15 +84,15 @@ void AnimationContext::callOnFinished(BaseRenderNodeAnimator* animator,
AnimationHandle::AnimationHandle(AnimationContext& context)
: mContext(context)
- , mPreviousHandle(NULL)
- , mNextHandle(NULL) {
+ , mPreviousHandle(nullptr)
+ , mNextHandle(nullptr) {
}
AnimationHandle::AnimationHandle(RenderNode& animatingNode, AnimationContext& context)
: mRenderNode(&animatingNode)
, mContext(context)
- , mPreviousHandle(NULL)
- , mNextHandle(NULL) {
+ , mPreviousHandle(nullptr)
+ , mNextHandle(nullptr) {
mRenderNode->animators().setAnimationHandle(this);
}
@@ -114,7 +114,7 @@ void AnimationHandle::release() {
LOG_ALWAYS_FATAL_IF(mRenderNode->animators().hasAnimators(),
"Releasing the handle for an RenderNode with outstanding animators!");
removeFromList();
- mRenderNode->animators().setAnimationHandle(NULL);
+ mRenderNode->animators().setAnimationHandle(nullptr);
delete this;
}
@@ -135,8 +135,8 @@ void AnimationHandle::removeFromList() {
if (mNextHandle) {
mNextHandle->mPreviousHandle = mPreviousHandle;
}
- mPreviousHandle = NULL;
- mNextHandle = NULL;
+ mPreviousHandle = nullptr;
+ mNextHandle = nullptr;
}
} /* namespace uirenderer */
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index 8bf2107..512e0e2 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -20,6 +20,7 @@
#include <set>
#include "AnimationContext.h"
+#include "Interpolator.h"
#include "RenderNode.h"
#include "RenderProperties.h"
@@ -31,11 +32,10 @@ namespace uirenderer {
************************************************************/
BaseRenderNodeAnimator::BaseRenderNodeAnimator(float finalValue)
- : mTarget(NULL)
+ : mTarget(nullptr)
, mFinalValue(finalValue)
, mDeltaValue(0)
, mFromValue(0)
- , mInterpolator(0)
, mStagingPlayState(NOT_STARTED)
, mPlayState(NOT_STARTED)
, mHasStartValue(false)
@@ -46,7 +46,6 @@ BaseRenderNodeAnimator::BaseRenderNodeAnimator(float finalValue)
}
BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {
- delete mInterpolator;
}
void BaseRenderNodeAnimator::checkMutable() {
@@ -57,8 +56,7 @@ void BaseRenderNodeAnimator::checkMutable() {
void BaseRenderNodeAnimator::setInterpolator(Interpolator* interpolator) {
checkMutable();
- delete mInterpolator;
- mInterpolator = interpolator;
+ mInterpolator.reset(interpolator);
}
void BaseRenderNodeAnimator::setStartValue(float value) {
@@ -118,7 +116,7 @@ void BaseRenderNodeAnimator::transitionToRunning(AnimationContext& context) {
}
// No interpolator was set, use the default
if (!mInterpolator) {
- mInterpolator = Interpolator::createDefaultInterpolator();
+ mInterpolator.reset(Interpolator::createDefaultInterpolator());
}
if (mDuration < 0 || mDuration > 50000) {
ALOGW("Your duration is strange and confusing: %" PRId64, mDuration);
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index 35a4a09..1b3d8e7 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -16,13 +16,12 @@
#ifndef ANIMATOR_H
#define ANIMATOR_H
+#include <memory>
#include <cutils/compiler.h>
#include <utils/RefBase.h>
#include <utils/StrongPointer.h>
+#include <utils/Timers.h>
-#include "CanvasProperty.h"
-#include "Interpolator.h"
-#include "TreeInfo.h"
#include "utils/Macros.h"
namespace android {
@@ -30,6 +29,9 @@ namespace uirenderer {
class AnimationContext;
class BaseRenderNodeAnimator;
+class CanvasPropertyPrimitive;
+class CanvasPropertyPaint;
+class Interpolator;
class RenderNode;
class RenderProperties;
@@ -62,7 +64,7 @@ public:
void attach(RenderNode* target);
virtual void onAttached() {}
- void detach() { mTarget = 0; }
+ void detach() { mTarget = nullptr; }
void pushStaging(AnimationContext& context);
bool animate(AnimationContext& context);
@@ -98,7 +100,7 @@ protected:
float mDeltaValue;
float mFromValue;
- Interpolator* mInterpolator;
+ std::unique_ptr<Interpolator> mInterpolator;
PlayState mStagingPlayState;
PlayState mPlayState;
bool mHasStartValue;
@@ -137,10 +139,10 @@ public:
ANDROID_API virtual uint32_t dirtyMask();
protected:
- virtual float getValue(RenderNode* target) const;
- virtual void setValue(RenderNode* target, float value);
- virtual void onAttached();
- virtual void onStagingPlayStateChanged();
+ virtual float getValue(RenderNode* target) const override;
+ virtual void setValue(RenderNode* target, float value) override;
+ virtual void onAttached() override;
+ virtual void onStagingPlayStateChanged() override;
private:
typedef bool (RenderProperties::*SetFloatProperty)(float value);
@@ -160,8 +162,8 @@ public:
ANDROID_API virtual uint32_t dirtyMask();
protected:
- virtual float getValue(RenderNode* target) const;
- virtual void setValue(RenderNode* target, float value);
+ virtual float getValue(RenderNode* target) const override;
+ virtual void setValue(RenderNode* target, float value) override;
private:
sp<CanvasPropertyPrimitive> mProperty;
};
@@ -179,8 +181,8 @@ public:
ANDROID_API virtual uint32_t dirtyMask();
protected:
- virtual float getValue(RenderNode* target) const;
- virtual void setValue(RenderNode* target, float value);
+ virtual float getValue(RenderNode* target) const override;
+ virtual void setValue(RenderNode* target, float value) override;
private:
sp<CanvasPropertyPaint> mProperty;
PaintField mField;
@@ -194,8 +196,8 @@ public:
ANDROID_API virtual uint32_t dirtyMask();
protected:
- virtual float getValue(RenderNode* target) const;
- virtual void setValue(RenderNode* target, float value);
+ virtual float getValue(RenderNode* target) const override;
+ virtual void setValue(RenderNode* target, float value) override;
private:
int mCenterX, mCenterY;
diff --git a/libs/hwui/AnimatorManager.cpp b/libs/hwui/AnimatorManager.cpp
index c28fb88..966959a 100644
--- a/libs/hwui/AnimatorManager.cpp
+++ b/libs/hwui/AnimatorManager.cpp
@@ -17,7 +17,9 @@
#include <algorithm>
+#include "Animator.h"
#include "AnimationContext.h"
+#include "DamageAccumulator.h"
#include "RenderNode.h"
namespace android {
@@ -27,12 +29,12 @@ using namespace std;
static void unref(BaseRenderNodeAnimator* animator) {
animator->detach();
- animator->decStrong(0);
+ animator->decStrong(nullptr);
}
AnimatorManager::AnimatorManager(RenderNode& parent)
: mParent(parent)
- , mAnimationHandle(NULL) {
+ , mAnimationHandle(nullptr) {
}
AnimatorManager::~AnimatorManager() {
@@ -41,7 +43,7 @@ AnimatorManager::~AnimatorManager() {
}
void AnimatorManager::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
- animator->incStrong(0);
+ animator->incStrong(nullptr);
animator->attach(&mParent);
mNewAnimators.push_back(animator.get());
}
@@ -85,7 +87,7 @@ public:
dirtyMask |= animator->dirtyMask();
bool remove = animator->animate(mContext);
if (remove) {
- animator->decStrong(0);
+ animator->decStrong(nullptr);
} else {
if (animator->isRunning()) {
mInfo.out.hasAnimations = true;
@@ -142,7 +144,7 @@ static void endStagingAnimator(BaseRenderNodeAnimator* animator) {
if (animator->listener()) {
animator->listener()->onAnimationFinished(animator);
}
- animator->decStrong(0);
+ animator->decStrong(nullptr);
}
void AnimatorManager::endAllStagingAnimators() {
@@ -159,7 +161,7 @@ public:
void operator() (BaseRenderNodeAnimator* animator) {
animator->forceEndNow(mContext);
- animator->decStrong(0);
+ animator->decStrong(nullptr);
}
private:
diff --git a/libs/hwui/AnimatorManager.h b/libs/hwui/AnimatorManager.h
index d03d427..fb75eb8 100644
--- a/libs/hwui/AnimatorManager.h
+++ b/libs/hwui/AnimatorManager.h
@@ -21,7 +21,6 @@
#include <cutils/compiler.h>
#include <utils/StrongPointer.h>
-#include "TreeInfo.h"
#include "utils/Macros.h"
namespace android {
@@ -30,6 +29,7 @@ namespace uirenderer {
class AnimationHandle;
class BaseRenderNodeAnimator;
class RenderNode;
+class TreeInfo;
// Responsible for managing the animators for a single RenderNode
class AnimatorManager {
diff --git a/libs/hwui/AssetAtlas.cpp b/libs/hwui/AssetAtlas.cpp
index 52ca92d..4d2e3a0 100644
--- a/libs/hwui/AssetAtlas.cpp
+++ b/libs/hwui/AssetAtlas.cpp
@@ -18,6 +18,7 @@
#include "AssetAtlas.h"
#include "Caches.h"
+#include "Image.h"
#include <GLES2/gl2ext.h>
@@ -47,7 +48,7 @@ void AssetAtlas::init(sp<GraphicBuffer> buffer, int64_t* map, int count) {
} else {
ALOGW("Could not create atlas image");
delete mImage;
- mImage = NULL;
+ mImage = nullptr;
}
updateTextureId();
@@ -56,7 +57,7 @@ void AssetAtlas::init(sp<GraphicBuffer> buffer, int64_t* map, int count) {
void AssetAtlas::terminate() {
if (mImage) {
delete mImage;
- mImage = NULL;
+ mImage = nullptr;
updateTextureId();
}
}
@@ -82,12 +83,12 @@ void AssetAtlas::updateTextureId() {
AssetAtlas::Entry* AssetAtlas::getEntry(const SkBitmap* bitmap) const {
ssize_t index = mEntries.indexOfKey(bitmap);
- return index >= 0 ? mEntries.valueAt(index) : NULL;
+ return index >= 0 ? mEntries.valueAt(index) : nullptr;
}
Texture* AssetAtlas::getEntryTexture(const SkBitmap* bitmap) const {
ssize_t index = mEntries.indexOfKey(bitmap);
- return index >= 0 ? mEntries.valueAt(index)->texture : NULL;
+ return index >= 0 ? mEntries.valueAt(index)->texture : nullptr;
}
/**
@@ -98,12 +99,12 @@ struct DelegateTexture: public Texture {
DelegateTexture(Caches& caches, Texture* delegate): Texture(caches), mDelegate(delegate) { }
virtual void setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture = false,
- bool force = false, GLenum renderTarget = GL_TEXTURE_2D) {
+ bool force = false, GLenum renderTarget = GL_TEXTURE_2D) override {
mDelegate->setWrapST(wrapS, wrapT, bindTexture, force, renderTarget);
}
virtual void setFilterMinMag(GLenum min, GLenum mag, bool bindTexture = false,
- bool force = false, GLenum renderTarget = GL_TEXTURE_2D) {
+ bool force = false, GLenum renderTarget = GL_TEXTURE_2D) override {
mDelegate->setFilterMinMag(min, mag, bindTexture, force, renderTarget);
}
diff --git a/libs/hwui/AssetAtlas.h b/libs/hwui/AssetAtlas.h
index fffd740..1772eff 100644
--- a/libs/hwui/AssetAtlas.h
+++ b/libs/hwui/AssetAtlas.h
@@ -27,7 +27,6 @@
#include <SkBitmap.h>
-#include "Image.h"
#include "Texture.h"
#include "UvMapper.h"
@@ -35,6 +34,7 @@ namespace android {
namespace uirenderer {
class Caches;
+class Image;
/**
* An asset atlas holds a collection of framework bitmaps in a single OpenGL
@@ -106,7 +106,7 @@ public:
friend class AssetAtlas;
};
- AssetAtlas(): mTexture(NULL), mImage(NULL),
+ AssetAtlas(): mTexture(nullptr), mImage(nullptr),
mBlendKey(true), mOpaqueKey(false) { }
~AssetAtlas() { terminate(); }
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index cdf8150..f4fc068 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -16,25 +16,23 @@
#define LOG_TAG "OpenGLRenderer"
-#include <utils/Log.h>
-#include <utils/String8.h>
-
#include "Caches.h"
+
#include "DisplayListRenderer.h"
-#include "Properties.h"
+#include "GammaFontRenderer.h"
#include "LayerRenderer.h"
+#include "Properties.h"
+#include "renderstate/RenderState.h"
#include "ShadowTessellator.h"
-#include "RenderState.h"
-
-namespace android {
-#ifdef USE_OPENGL_RENDERER
-using namespace uirenderer;
-ANDROID_SINGLETON_STATIC_INSTANCE(Caches);
-#endif
+#include <utils/Log.h>
+#include <utils/String8.h>
+namespace android {
namespace uirenderer {
+Caches* Caches::sInstance = nullptr;
+
///////////////////////////////////////////////////////////////////////////////
// Macros
///////////////////////////////////////////////////////////////////////////////
@@ -49,8 +47,14 @@ namespace uirenderer {
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
-Caches::Caches(): Singleton<Caches>(),
- mExtensions(Extensions::getInstance()), mInitialized(false), mRenderState(NULL) {
+Caches::Caches(RenderState& renderState)
+ : gradientCache(mExtensions)
+ , patchCache(renderState)
+ , programCache(mExtensions)
+ , dither(*this)
+ , mRenderState(&renderState)
+ , mInitialized(false) {
+ INIT_LOGD("Creating OpenGL renderer caches");
init();
initFont();
initConstraints();
@@ -60,7 +64,8 @@ Caches::Caches(): Singleton<Caches>(),
initTempProperties();
mDebugLevel = readDebugLevel();
- ALOGD("Enabling debug mode %d", mDebugLevel);
+ ALOGD_IF(mDebugLevel != kDebugDisabled,
+ "Enabling debug mode %d", mDebugLevel);
}
bool Caches::init() {
@@ -68,33 +73,8 @@ bool Caches::init() {
ATRACE_NAME("Caches::init");
- glGenBuffers(1, &meshBuffer);
- glBindBuffer(GL_ARRAY_BUFFER, meshBuffer);
- glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW);
-
- mCurrentBuffer = meshBuffer;
- mCurrentIndicesBuffer = 0;
- mCurrentPositionPointer = this;
- mCurrentPositionStride = 0;
- mCurrentTexCoordsPointer = this;
- mCurrentPixelBuffer = 0;
-
- mTexCoordsArrayEnabled = false;
-
- glDisable(GL_SCISSOR_TEST);
- scissorEnabled = false;
- mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
-
- glActiveTexture(gTextureUnits[0]);
- mTextureUnit = 0;
-
- mRegionMesh = NULL;
- mMeshIndices = 0;
- mShadowStripsIndices = 0;
- blend = false;
- lastSrcMode = GL_ZERO;
- lastDstMode = GL_ZERO;
- currentProgram = NULL;
+ mRegionMesh = nullptr;
+ mProgram = nullptr;
mFunctorsCount = 0;
@@ -102,11 +82,12 @@ bool Caches::init() {
debugOverdraw = false;
debugStencilClip = kStencilHide;
- patchCache.init(*this);
+ patchCache.init();
mInitialized = true;
- resetBoundTextures();
+ mPixelBufferState = new PixelBufferState();
+ mTextureState = new TextureState();
return true;
}
@@ -137,12 +118,6 @@ void Caches::initExtensions() {
}
void Caches::initConstraints() {
- GLint maxTextureUnits;
- glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
- if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) {
- ALOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT);
- }
-
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
}
@@ -164,7 +139,7 @@ bool Caches::initProperties() {
StencilClipDebug prevDebugStencilClip = debugStencilClip;
char property[PROPERTY_VALUE_MAX];
- if (property_get(PROPERTY_DEBUG_LAYERS_UPDATES, property, NULL) > 0) {
+ if (property_get(PROPERTY_DEBUG_LAYERS_UPDATES, property, nullptr) > 0) {
INIT_LOGD(" Layers updates debug enabled: %s", property);
debugLayersUpdates = !strcmp(property, "true");
} else {
@@ -172,7 +147,7 @@ bool Caches::initProperties() {
}
debugOverdraw = false;
- if (property_get(PROPERTY_DEBUG_OVERDRAW, property, NULL) > 0) {
+ if (property_get(PROPERTY_DEBUG_OVERDRAW, property, nullptr) > 0) {
INIT_LOGD(" Overdraw debug enabled: %s", property);
if (!strcmp(property, "show")) {
debugOverdraw = true;
@@ -184,7 +159,7 @@ bool Caches::initProperties() {
}
// See Properties.h for valid values
- if (property_get(PROPERTY_DEBUG_STENCIL_CLIP, property, NULL) > 0) {
+ if (property_get(PROPERTY_DEBUG_STENCIL_CLIP, property, nullptr) > 0) {
INIT_LOGD(" Stencil clip debug enabled: %s", property);
if (!strcmp(property, "hide")) {
debugStencilClip = kStencilHide;
@@ -213,37 +188,47 @@ bool Caches::initProperties() {
INIT_LOGD(" Draw reorder enabled");
}
- return (prevDebugLayersUpdates != debugLayersUpdates) ||
- (prevDebugOverdraw != debugOverdraw) ||
- (prevDebugStencilClip != debugStencilClip);
+ return (prevDebugLayersUpdates != debugLayersUpdates)
+ || (prevDebugOverdraw != debugOverdraw)
+ || (prevDebugStencilClip != debugStencilClip);
}
void Caches::terminate() {
if (!mInitialized) return;
-
- glDeleteBuffers(1, &meshBuffer);
- mCurrentBuffer = 0;
-
- glDeleteBuffers(1, &mMeshIndices);
- delete[] mRegionMesh;
- mMeshIndices = 0;
- mRegionMesh = NULL;
-
- glDeleteBuffers(1, &mShadowStripsIndices);
- mShadowStripsIndices = 0;
+ mRegionMesh.release();
fboCache.clear();
programCache.clear();
- currentProgram = NULL;
+ mProgram = nullptr;
patchCache.clear();
clearGarbage();
+ delete mPixelBufferState;
+ mPixelBufferState = nullptr;
+ delete mTextureState;
+ mTextureState = nullptr;
mInitialized = false;
}
+void Caches::setProgram(const ProgramDescription& description) {
+ setProgram(programCache.get(description));
+}
+
+void Caches::setProgram(Program* program) {
+ if (!program || !program->isInUse()) {
+ if (mProgram) {
+ mProgram->remove();
+ }
+ if (program) {
+ program->use();
+ }
+ mProgram = program;
+ }
+}
+
///////////////////////////////////////////////////////////////////////////////
// Debug
///////////////////////////////////////////////////////////////////////////////
@@ -371,285 +356,6 @@ void Caches::flush(FlushMode mode) {
}
///////////////////////////////////////////////////////////////////////////////
-// VBO
-///////////////////////////////////////////////////////////////////////////////
-
-bool Caches::bindMeshBuffer() {
- return bindMeshBuffer(meshBuffer);
-}
-
-bool Caches::bindMeshBuffer(const GLuint buffer) {
- if (mCurrentBuffer != buffer) {
- glBindBuffer(GL_ARRAY_BUFFER, buffer);
- mCurrentBuffer = buffer;
- return true;
- }
- return false;
-}
-
-bool Caches::unbindMeshBuffer() {
- if (mCurrentBuffer) {
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- mCurrentBuffer = 0;
- return true;
- }
- return false;
-}
-
-bool Caches::bindIndicesBufferInternal(const GLuint buffer) {
- if (mCurrentIndicesBuffer != buffer) {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
- mCurrentIndicesBuffer = buffer;
- return true;
- }
- return false;
-}
-
-bool Caches::bindQuadIndicesBuffer() {
- if (!mMeshIndices) {
- uint16_t* regionIndices = new uint16_t[gMaxNumberOfQuads * 6];
- for (uint32_t i = 0; i < gMaxNumberOfQuads; i++) {
- uint16_t quad = i * 4;
- int index = i * 6;
- regionIndices[index ] = quad; // top-left
- regionIndices[index + 1] = quad + 1; // top-right
- regionIndices[index + 2] = quad + 2; // bottom-left
- regionIndices[index + 3] = quad + 2; // bottom-left
- regionIndices[index + 4] = quad + 1; // top-right
- regionIndices[index + 5] = quad + 3; // bottom-right
- }
-
- glGenBuffers(1, &mMeshIndices);
- bool force = bindIndicesBufferInternal(mMeshIndices);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, gMaxNumberOfQuads * 6 * sizeof(uint16_t),
- regionIndices, GL_STATIC_DRAW);
-
- delete[] regionIndices;
- return force;
- }
-
- return bindIndicesBufferInternal(mMeshIndices);
-}
-
-bool Caches::bindShadowIndicesBuffer() {
- if (!mShadowStripsIndices) {
- uint16_t* shadowIndices = new uint16_t[MAX_SHADOW_INDEX_COUNT];
- ShadowTessellator::generateShadowIndices(shadowIndices);
- glGenBuffers(1, &mShadowStripsIndices);
- bool force = bindIndicesBufferInternal(mShadowStripsIndices);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_SHADOW_INDEX_COUNT * sizeof(uint16_t),
- shadowIndices, GL_STATIC_DRAW);
-
- delete[] shadowIndices;
- return force;
- }
-
- return bindIndicesBufferInternal(mShadowStripsIndices);
-}
-
-bool Caches::unbindIndicesBuffer() {
- if (mCurrentIndicesBuffer) {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- mCurrentIndicesBuffer = 0;
- return true;
- }
- return false;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// PBO
-///////////////////////////////////////////////////////////////////////////////
-
-bool Caches::bindPixelBuffer(const GLuint buffer) {
- if (mCurrentPixelBuffer != buffer) {
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer);
- mCurrentPixelBuffer = buffer;
- return true;
- }
- return false;
-}
-
-bool Caches::unbindPixelBuffer() {
- if (mCurrentPixelBuffer) {
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
- mCurrentPixelBuffer = 0;
- return true;
- }
- return false;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Meshes and textures
-///////////////////////////////////////////////////////////////////////////////
-
-void Caches::bindPositionVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
- if (force || vertices != mCurrentPositionPointer || stride != mCurrentPositionStride) {
- GLuint slot = currentProgram->position;
- glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
- mCurrentPositionPointer = vertices;
- mCurrentPositionStride = stride;
- }
-}
-
-void Caches::bindTexCoordsVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
- if (force || vertices != mCurrentTexCoordsPointer || stride != mCurrentTexCoordsStride) {
- GLuint slot = currentProgram->texCoords;
- glVertexAttribPointer(slot, 2, GL_FLOAT, GL_FALSE, stride, vertices);
- mCurrentTexCoordsPointer = vertices;
- mCurrentTexCoordsStride = stride;
- }
-}
-
-void Caches::resetVertexPointers() {
- mCurrentPositionPointer = this;
- mCurrentTexCoordsPointer = this;
-}
-
-void Caches::resetTexCoordsVertexPointer() {
- mCurrentTexCoordsPointer = this;
-}
-
-void Caches::enableTexCoordsVertexArray() {
- if (!mTexCoordsArrayEnabled) {
- glEnableVertexAttribArray(Program::kBindingTexCoords);
- mCurrentTexCoordsPointer = this;
- mTexCoordsArrayEnabled = true;
- }
-}
-
-void Caches::disableTexCoordsVertexArray() {
- if (mTexCoordsArrayEnabled) {
- glDisableVertexAttribArray(Program::kBindingTexCoords);
- mTexCoordsArrayEnabled = false;
- }
-}
-
-void Caches::activeTexture(GLuint textureUnit) {
- if (mTextureUnit != textureUnit) {
- glActiveTexture(gTextureUnits[textureUnit]);
- mTextureUnit = textureUnit;
- }
-}
-
-void Caches::resetActiveTexture() {
- mTextureUnit = -1;
-}
-
-void Caches::bindTexture(GLuint texture) {
- if (mBoundTextures[mTextureUnit] != texture) {
- glBindTexture(GL_TEXTURE_2D, texture);
- mBoundTextures[mTextureUnit] = texture;
- }
-}
-
-void Caches::bindTexture(GLenum target, GLuint texture) {
- if (target == GL_TEXTURE_2D) {
- bindTexture(texture);
- } else {
- // GLConsumer directly calls glBindTexture() with
- // target=GL_TEXTURE_EXTERNAL_OES, don't cache this target
- // since the cached state could be stale
- glBindTexture(target, texture);
- }
-}
-
-void Caches::deleteTexture(GLuint texture) {
- // When glDeleteTextures() is called on a currently bound texture,
- // OpenGL ES specifies that the texture is then considered unbound
- // Consider the following series of calls:
- //
- // glGenTextures -> creates texture name 2
- // glBindTexture(2)
- // glDeleteTextures(2) -> 2 is now unbound
- // glGenTextures -> can return 2 again
- //
- // If we don't call glBindTexture(2) after the second glGenTextures
- // call, any texture operation will be performed on the default
- // texture (name=0)
-
- unbindTexture(texture);
-
- glDeleteTextures(1, &texture);
-}
-
-void Caches::resetBoundTextures() {
- memset(mBoundTextures, 0, REQUIRED_TEXTURE_UNITS_COUNT * sizeof(GLuint));
-}
-
-void Caches::unbindTexture(GLuint texture) {
- for (int i = 0; i < REQUIRED_TEXTURE_UNITS_COUNT; i++) {
- if (mBoundTextures[i] == texture) {
- mBoundTextures[i] = 0;
- }
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Scissor
-///////////////////////////////////////////////////////////////////////////////
-
-bool Caches::setScissor(GLint x, GLint y, GLint width, GLint height) {
- if (scissorEnabled && (x != mScissorX || y != mScissorY ||
- width != mScissorWidth || height != mScissorHeight)) {
-
- if (x < 0) {
- width += x;
- x = 0;
- }
- if (y < 0) {
- height += y;
- y = 0;
- }
- if (width < 0) {
- width = 0;
- }
- if (height < 0) {
- height = 0;
- }
- glScissor(x, y, width, height);
-
- mScissorX = x;
- mScissorY = y;
- mScissorWidth = width;
- mScissorHeight = height;
-
- return true;
- }
- return false;
-}
-
-bool Caches::enableScissor() {
- if (!scissorEnabled) {
- glEnable(GL_SCISSOR_TEST);
- scissorEnabled = true;
- resetScissor();
- return true;
- }
- return false;
-}
-
-bool Caches::disableScissor() {
- if (scissorEnabled) {
- glDisable(GL_SCISSOR_TEST);
- scissorEnabled = false;
- return true;
- }
- return false;
-}
-
-void Caches::setScissorEnabled(bool enabled) {
- if (scissorEnabled != enabled) {
- if (enabled) glEnable(GL_SCISSOR_TEST);
- else glDisable(GL_SCISSOR_TEST);
- scissorEnabled = enabled;
- }
-}
-
-void Caches::resetScissor() {
- mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
-}
-
-///////////////////////////////////////////////////////////////////////////////
// Tiling
///////////////////////////////////////////////////////////////////////////////
@@ -688,10 +394,10 @@ void Caches::unregisterFunctors(uint32_t functorCount) {
TextureVertex* Caches::getRegionMesh() {
// Create the mesh, 2 triangles and 4 vertices per rectangle in the region
if (!mRegionMesh) {
- mRegionMesh = new TextureVertex[gMaxNumberOfQuads * 4];
+ mRegionMesh.reset(new TextureVertex[kMaxNumberOfQuads * 4]);
}
- return mRegionMesh;
+ return mRegionMesh.get();
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 2e179af..18bb5e6 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -21,86 +21,43 @@
#define LOG_TAG "OpenGLRenderer"
#endif
-#include <vector>
-
-#include <GLES3/gl3.h>
-
-#include <utils/KeyedVector.h>
-#include <utils/Singleton.h>
-#include <utils/Vector.h>
-
-#include <cutils/compiler.h>
-
-#include "thread/TaskProcessor.h"
-#include "thread/TaskManager.h"
#include "AssetAtlas.h"
+#include "Dither.h"
#include "Extensions.h"
-#include "FontRenderer.h"
-#include "GammaFontRenderer.h"
-#include "TextureCache.h"
-#include "LayerCache.h"
-#include "RenderBufferCache.h"
+#include "FboCache.h"
#include "GradientCache.h"
+#include "LayerCache.h"
#include "PatchCache.h"
#include "ProgramCache.h"
#include "PathCache.h"
+#include "RenderBufferCache.h"
+#include "renderstate/PixelBufferState.h"
+#include "renderstate/TextureState.h"
+#include "ResourceCache.h"
#include "TessellationCache.h"
#include "TextDropShadowCache.h"
-#include "FboCache.h"
-#include "ResourceCache.h"
-#include "Stencil.h"
-#include "Dither.h"
+#include "TextureCache.h"
+#include "thread/TaskProcessor.h"
+#include "thread/TaskManager.h"
-namespace android {
-namespace uirenderer {
+#include <vector>
+#include <memory>
-///////////////////////////////////////////////////////////////////////////////
-// Globals
-///////////////////////////////////////////////////////////////////////////////
+#include <GLES3/gl3.h>
-// GL ES 2.0 defines that at least 16 texture units must be supported
-#define REQUIRED_TEXTURE_UNITS_COUNT 3
-
-// Maximum number of quads that pre-allocated meshes can draw
-static const uint32_t gMaxNumberOfQuads = 2048;
-
-// Generates simple and textured vertices
-#define FV(x, y, u, v) { x, y, u, v }
-
-// This array is never used directly but used as a memcpy source in the
-// OpenGLRenderer constructor
-static const TextureVertex gMeshVertices[] = {
- FV(0.0f, 0.0f, 0.0f, 0.0f),
- FV(1.0f, 0.0f, 1.0f, 0.0f),
- FV(0.0f, 1.0f, 0.0f, 1.0f),
- FV(1.0f, 1.0f, 1.0f, 1.0f)
-};
-static const GLsizei gMeshStride = sizeof(TextureVertex);
-static const GLsizei gVertexStride = sizeof(Vertex);
-static const GLsizei gAlphaVertexStride = sizeof(AlphaVertex);
-static const GLsizei gMeshTextureOffset = 2 * sizeof(float);
-static const GLsizei gVertexAlphaOffset = 2 * sizeof(float);
-static const GLsizei gVertexAAWidthOffset = 2 * sizeof(float);
-static const GLsizei gVertexAALengthOffset = 3 * sizeof(float);
-static const GLsizei gMeshCount = 4;
-
-// Must define as many texture units as specified by REQUIRED_TEXTURE_UNITS_COUNT
-static const GLenum gTextureUnits[] = {
- GL_TEXTURE0,
- GL_TEXTURE1,
- GL_TEXTURE2
-};
+#include <utils/KeyedVector.h>
+#include <utils/Singleton.h>
+#include <utils/Vector.h>
-///////////////////////////////////////////////////////////////////////////////
-// Debug
-///////////////////////////////////////////////////////////////////////////////
+#include <cutils/compiler.h>
-struct CacheLogger {
- CacheLogger() {
- INIT_LOGD("Creating OpenGL renderer caches");
- }
-}; // struct CacheLogger
+#include <SkPath.h>
+
+namespace android {
+namespace uirenderer {
+
+class GammaFontRenderer;
///////////////////////////////////////////////////////////////////////////////
// Caches
@@ -109,12 +66,25 @@ struct CacheLogger {
class RenderNode;
class RenderState;
-class ANDROID_API Caches: public Singleton<Caches> {
- Caches();
+class ANDROID_API Caches {
+public:
+ static Caches& createInstance(RenderState& renderState) {
+ LOG_ALWAYS_FATAL_IF(sInstance, "double create of Caches attempted");
+ sInstance = new Caches(renderState);
+ return *sInstance;
+ }
- friend class Singleton<Caches>;
+ static Caches& getInstance() {
+ LOG_ALWAYS_FATAL_IF(!sInstance, "instance not yet created");
+ return *sInstance;
+ }
- CacheLogger mLogger;
+ static bool hasInstance() {
+ return sInstance != 0;
+ }
+private:
+ Caches(RenderState& renderState);
+ static Caches* sInstance;
public:
enum FlushMode {
@@ -133,8 +103,6 @@ public:
*/
bool initProperties();
- void setRenderState(RenderState* renderState) { mRenderState = renderState; }
-
/**
* Flush the cache.
*
@@ -173,116 +141,6 @@ public:
*/
void deleteLayerDeferred(Layer* layer);
- /**
- * Binds the VBO used to render simple textured quads.
- */
- bool bindMeshBuffer();
-
- /**
- * Binds the specified VBO if needed.
- */
- bool bindMeshBuffer(const GLuint buffer);
-
- /**
- * Unbinds the VBO used to render simple textured quads.
- */
- bool unbindMeshBuffer();
-
- /**
- * Binds a global indices buffer that can draw up to
- * gMaxNumberOfQuads quads.
- */
- bool bindQuadIndicesBuffer();
- bool bindShadowIndicesBuffer();
- bool unbindIndicesBuffer();
-
- /**
- * Binds the specified buffer as the current GL unpack pixel buffer.
- */
- bool bindPixelBuffer(const GLuint buffer);
-
- /**
- * Resets the current unpack pixel buffer to 0 (default value.)
- */
- bool unbindPixelBuffer();
-
- /**
- * Binds an attrib to the specified float vertex pointer.
- * Assumes a stride of gMeshStride and a size of 2.
- */
- void bindPositionVertexPointer(bool force, const GLvoid* vertices, GLsizei stride = gMeshStride);
-
- /**
- * Binds an attrib to the specified float vertex pointer.
- * Assumes a stride of gMeshStride and a size of 2.
- */
- void bindTexCoordsVertexPointer(bool force, const GLvoid* vertices, GLsizei stride = gMeshStride);
-
- /**
- * Resets the vertex pointers.
- */
- void resetVertexPointers();
- void resetTexCoordsVertexPointer();
-
- void enableTexCoordsVertexArray();
- void disableTexCoordsVertexArray();
-
- /**
- * Activate the specified texture unit. The texture unit must
- * be specified using an integer number (0 for GL_TEXTURE0 etc.)
- */
- void activeTexture(GLuint textureUnit);
-
- /**
- * Invalidate the cached value of the active texture unit.
- */
- void resetActiveTexture();
-
- /**
- * Binds the specified texture as a GL_TEXTURE_2D texture.
- * All texture bindings must be performed with this method or
- * bindTexture(GLenum, GLuint).
- */
- void bindTexture(GLuint texture);
-
- /**
- * Binds the specified texture with the specified render target.
- * All texture bindings must be performed with this method or
- * bindTexture(GLuint).
- */
- void bindTexture(GLenum target, GLuint texture);
-
- /**
- * Deletes the specified texture and clears it from the cache
- * of bound textures.
- * All textures must be deleted using this method.
- */
- void deleteTexture(GLuint texture);
-
- /**
- * Signals that the cache of bound textures should be cleared.
- * Other users of the context may have altered which textures are bound.
- */
- void resetBoundTextures();
-
- /**
- * Clear the cache of bound textures.
- */
- void unbindTexture(GLuint texture);
-
- /**
- * Sets the scissor for the current surface.
- */
- bool setScissor(GLint x, GLint y, GLint width, GLint height);
-
- /**
- * Resets the scissor state.
- */
- void resetScissor();
-
- bool enableScissor();
- bool disableScissor();
- void setScissorEnabled(bool enabled);
void startTiling(GLuint x, GLuint y, GLuint width, GLuint height, bool discard);
void endTiling();
@@ -304,18 +162,9 @@ public:
void registerFunctors(uint32_t functorCount);
void unregisterFunctors(uint32_t functorCount);
- bool blend;
- GLenum lastSrcMode;
- GLenum lastDstMode;
- Program* currentProgram;
- bool scissorEnabled;
-
bool drawDeferDisabled;
bool drawReorderDisabled;
- // VBO to draw with
- GLuint meshBuffer;
-
// Misc
GLint maxTextureSize;
@@ -329,14 +178,18 @@ public:
kStencilShowRegion
};
StencilClipDebug debugStencilClip;
-
+private:
+ // Declared before gradientCache and programCache which need this to initialize.
+ // TODO: cleanup / move elsewhere
+ Extensions mExtensions;
+public:
TextureCache textureCache;
LayerCache layerCache;
RenderBufferCache renderBufferCache;
GradientCache gradientCache;
- ProgramCache programCache;
- PathCache pathCache;
PatchCache patchCache;
+ PathCache pathCache;
+ ProgramCache programCache;
TessellationCache tessellationCache;
TextDropShadowCache dropShadowCache;
FboCache fboCache;
@@ -346,7 +199,6 @@ public:
TaskManager tasks;
Dither dither;
- Stencil stencil;
bool gpuPixelBuffersEnabled;
@@ -369,6 +221,14 @@ public:
int propertyAmbientShadowStrength;
int propertySpotShadowStrength;
+ void setProgram(const ProgramDescription& description);
+ void setProgram(Program* program);
+
+ Extensions& extensions() { return mExtensions; }
+ Program& program() { return *mProgram; }
+ PixelBufferState& pixelBufferState() { return *mPixelBufferState; }
+ TextureState& textureState() { return *mTextureState; }
+
private:
enum OverdrawColorSet {
kColorSet_Default = 0,
@@ -380,8 +240,6 @@ private:
void initConstraints();
void initStaticProperties();
- bool bindIndicesBufferInternal(const GLuint buffer);
-
static void eventMarkNull(GLsizei length, const GLchar* marker) { }
static void startMarkNull(GLsizei length, const GLchar* marker) { }
static void endMarkNull() { }
@@ -394,31 +252,10 @@ private:
if (label) *label = '\0';
}
- GLuint mCurrentBuffer;
- GLuint mCurrentIndicesBuffer;
- GLuint mCurrentPixelBuffer;
- const void* mCurrentPositionPointer;
- GLsizei mCurrentPositionStride;
- const void* mCurrentTexCoordsPointer;
- GLsizei mCurrentTexCoordsStride;
-
- bool mTexCoordsArrayEnabled;
-
- GLuint mTextureUnit;
-
- GLint mScissorX;
- GLint mScissorY;
- GLint mScissorWidth;
- GLint mScissorHeight;
-
- Extensions& mExtensions;
+ RenderState* mRenderState;
// Used to render layers
- TextureVertex* mRegionMesh;
-
- // Global index buffer
- GLuint mMeshIndices;
- GLuint mShadowStripsIndices;
+ std::unique_ptr<TextureVertex[]> mRegionMesh;
mutable Mutex mGarbageLock;
Vector<Layer*> mLayerGarbage;
@@ -428,12 +265,13 @@ private:
uint32_t mFunctorsCount;
- // Caches texture bindings for the GL_TEXTURE_2D target
- GLuint mBoundTextures[REQUIRED_TEXTURE_UNITS_COUNT];
-
OverdrawColorSet mOverdrawDebugColorSet;
- RenderState* mRenderState;
+ // TODO: move below to RenderState
+ PixelBufferState* mPixelBufferState = nullptr;
+ TextureState* mTextureState = nullptr;
+ Program* mProgram = nullptr; // note: object owned by ProgramCache
+
}; // class Caches
}; // namespace uirenderer
diff --git a/libs/hwui/Canvas.h b/libs/hwui/Canvas.h
new file mode 100644
index 0000000..7ad0683
--- /dev/null
+++ b/libs/hwui/Canvas.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2014 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_GRAPHICS_CANVAS_H
+#define ANDROID_GRAPHICS_CANVAS_H
+
+#include <cutils/compiler.h>
+
+#include <SkBitmap.h>
+#include <SkCanvas.h>
+#include <SkMatrix.h>
+
+namespace android {
+
+class ANDROID_API Canvas {
+public:
+ virtual ~Canvas() {};
+
+ static Canvas* create_canvas(SkBitmap* bitmap);
+
+ /**
+ * Create a new Canvas object which delegates to an SkCanvas.
+ *
+ * @param skiaCanvas Must not be NULL. All drawing calls will be
+ * delegated to this object. This function will call ref() on the
+ * SkCanvas, and the returned Canvas will unref() it upon
+ * destruction.
+ * @return new Canvas object. Will not return NULL.
+ */
+ static Canvas* create_canvas(SkCanvas* skiaCanvas);
+
+ /**
+ * Provides a Skia SkCanvas interface that acts as a proxy to this Canvas.
+ * It is useful for testing and clients (e.g. Picture/Movie) that expect to
+ * draw their contents into an SkCanvas.
+ *
+ * Further, the returned SkCanvas should NOT be unref'd and is valid until
+ * this canvas is destroyed or a new bitmap is set.
+ */
+ virtual SkCanvas* asSkCanvas() = 0;
+
+ virtual void setBitmap(SkBitmap* bitmap, bool copyState) = 0;
+
+ virtual bool isOpaque() = 0;
+ virtual int width() = 0;
+ virtual int height() = 0;
+
+// ----------------------------------------------------------------------------
+// Canvas state operations
+// ----------------------------------------------------------------------------
+ // Save (layer)
+ virtual int getSaveCount() const = 0;
+ virtual int save(SkCanvas::SaveFlags flags) = 0;
+ virtual void restore() = 0;
+ virtual void restoreToCount(int saveCount) = 0;
+
+ virtual int saveLayer(float left, float top, float right, float bottom,
+ const SkPaint* paint, SkCanvas::SaveFlags flags) = 0;
+ virtual int saveLayerAlpha(float left, float top, float right, float bottom,
+ int alpha, SkCanvas::SaveFlags flags) = 0;
+
+ // Matrix
+ virtual void getMatrix(SkMatrix* outMatrix) const = 0;
+ virtual void setMatrix(const SkMatrix& matrix) = 0;
+
+ virtual void concat(const SkMatrix& matrix) = 0;
+ virtual void rotate(float degrees) = 0;
+ virtual void scale(float sx, float sy) = 0;
+ virtual void skew(float sx, float sy) = 0;
+ virtual void translate(float dx, float dy) = 0;
+
+ // clip
+ virtual bool getClipBounds(SkRect* outRect) const = 0;
+ virtual bool quickRejectRect(float left, float top, float right, float bottom) const = 0;
+ virtual bool quickRejectPath(const SkPath& path) const = 0;
+
+ virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op) = 0;
+ virtual bool clipPath(const SkPath* path, SkRegion::Op op) = 0;
+ virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) = 0;
+
+ // filters
+ virtual SkDrawFilter* getDrawFilter() = 0;
+ virtual void setDrawFilter(SkDrawFilter* drawFilter) = 0;
+
+// ----------------------------------------------------------------------------
+// Canvas draw operations
+// ----------------------------------------------------------------------------
+ virtual void drawColor(int color, SkXfermode::Mode mode) = 0;
+ virtual void drawPaint(const SkPaint& paint) = 0;
+
+ // Geometry
+ virtual void drawPoint(float x, float y, const SkPaint& paint) = 0;
+ virtual void drawPoints(const float* points, int count, const SkPaint& paint) = 0;
+ virtual void drawLine(float startX, float startY, float stopX, float stopY,
+ const SkPaint& paint) = 0;
+ virtual void drawLines(const float* points, int count, const SkPaint& paint) = 0;
+ virtual void drawRect(float left, float top, float right, float bottom,
+ const SkPaint& paint) = 0;
+ virtual void drawRoundRect(float left, float top, float right, float bottom,
+ float rx, float ry, const SkPaint& paint) = 0;
+ virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) = 0;
+ virtual void drawOval(float left, float top, float right, float bottom,
+ const SkPaint& paint) = 0;
+ virtual void drawArc(float left, float top, float right, float bottom,
+ float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) = 0;
+ virtual void drawPath(const SkPath& path, const SkPaint& paint) = 0;
+ 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) = 0;
+
+ // Bitmap-based
+ virtual void drawBitmap(const SkBitmap& bitmap, float left, float top,
+ const SkPaint* paint) = 0;
+ virtual void drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix,
+ const SkPaint* paint) = 0;
+ 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) = 0;
+ virtual void drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
+ const float* vertices, const int* colors, const SkPaint* paint) = 0;
+
+ // Text
+ /**
+ * drawText: count is of glyphs
+ * totalAdvance is ignored in software renderering, used by hardware renderer for
+ * text decorations (underlines, strikethroughs).
+ */
+ virtual void drawText(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) = 0;
+ /** drawPosText: count is of UTF16 characters, posCount is floats (2 * glyphs) */
+ virtual void drawPosText(const uint16_t* text, const float* positions, int count,
+ int posCount, const SkPaint& paint) = 0;
+ /** drawTextOnPath: count is of glyphs */
+ virtual void drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
+ float hOffset, float vOffset, const SkPaint& paint) = 0;
+
+ /**
+ * Specifies if the positions passed to ::drawText are absolute or relative
+ * to the (x,y) value provided.
+ *
+ * If true the (x,y) values are ignored. Otherwise, those (x,y) values need
+ * to be added to each glyph's position to get its absolute position.
+ */
+ virtual bool drawTextAbsolutePos() const = 0;
+};
+
+}; // namespace android
+#endif // ANDROID_GRAPHICS_CANVAS_H
diff --git a/libs/hwui/StatefulBaseRenderer.cpp b/libs/hwui/CanvasState.cpp
index 88d6f68..85f860d 100644
--- a/libs/hwui/StatefulBaseRenderer.cpp
+++ b/libs/hwui/CanvasState.cpp
@@ -14,41 +14,45 @@
* limitations under the License.
*/
-#define LOG_TAG "OpenGLRenderer"
-
#include <SkCanvas.h>
-#include "StatefulBaseRenderer.h"
-
+#include "CanvasState.h"
#include "utils/MathUtils.h"
namespace android {
namespace uirenderer {
-StatefulBaseRenderer::StatefulBaseRenderer()
+
+CanvasState::CanvasState(CanvasStateClient& renderer)
: mDirtyClip(false)
, mWidth(-1)
, mHeight(-1)
, mSaveCount(1)
, mFirstSnapshot(new Snapshot)
+ , mCanvas(renderer)
, mSnapshot(mFirstSnapshot) {
+
}
-void StatefulBaseRenderer::initializeSaveStack(float clipLeft, float clipTop,
+CanvasState::~CanvasState() {
+
+}
+
+void CanvasState::initializeSaveStack(float clipLeft, float clipTop,
float clipRight, float clipBottom, const Vector3& lightCenter) {
mSnapshot = new Snapshot(mFirstSnapshot,
SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
mSnapshot->setClip(clipLeft, clipTop, clipRight, clipBottom);
- mSnapshot->fbo = getTargetFbo();
+ mSnapshot->fbo = mCanvas.onGetTargetFbo();
mSnapshot->setRelativeLightCenter(lightCenter);
mSaveCount = 1;
}
-void StatefulBaseRenderer::setViewport(int width, int height) {
+void CanvasState::setViewport(int width, int height) {
mWidth = width;
mHeight = height;
mFirstSnapshot->initializeViewport(width, height);
- onViewportInitialized();
+ mCanvas.onViewportInitialized();
// create a temporary 1st snapshot, so old snapshots are released,
// and viewport can be queried safely.
@@ -63,24 +67,24 @@ void StatefulBaseRenderer::setViewport(int width, int height) {
///////////////////////////////////////////////////////////////////////////////
/**
- * Non-virtual implementation of save, guaranteed to save without side-effects
+ * Guaranteed to save without side-effects
*
- * The approach here and in restoreSnapshot(), allows subclasses to directly manipulate the save
+ * This approach, here and in restoreSnapshot(), allows subclasses to directly manipulate the save
* stack, and ensures restoreToCount() doesn't call back into subclass overrides.
*/
-int StatefulBaseRenderer::saveSnapshot(int flags) {
+int CanvasState::saveSnapshot(int flags) {
mSnapshot = new Snapshot(mSnapshot, flags);
return mSaveCount++;
}
-int StatefulBaseRenderer::save(int flags) {
+int CanvasState::save(int flags) {
return saveSnapshot(flags);
}
/**
- * Non-virtual implementation of restore, guaranteed to restore without side-effects.
+ * Guaranteed to restore without side-effects.
*/
-void StatefulBaseRenderer::restoreSnapshot() {
+void CanvasState::restoreSnapshot() {
sp<Snapshot> toRemove = mSnapshot;
sp<Snapshot> toRestore = mSnapshot->previous;
@@ -88,16 +92,16 @@ void StatefulBaseRenderer::restoreSnapshot() {
mSnapshot = toRestore;
// subclass handles restore implementation
- onSnapshotRestored(*toRemove, *toRestore);
+ mCanvas.onSnapshotRestored(*toRemove, *toRestore);
}
-void StatefulBaseRenderer::restore() {
+void CanvasState::restore() {
if (mSaveCount > 1) {
restoreSnapshot();
}
}
-void StatefulBaseRenderer::restoreToCount(int saveCount) {
+void CanvasState::restoreToCount(int saveCount) {
if (saveCount < 1) saveCount = 1;
while (mSaveCount > saveCount) {
@@ -109,40 +113,40 @@ void StatefulBaseRenderer::restoreToCount(int saveCount) {
// Matrix
///////////////////////////////////////////////////////////////////////////////
-void StatefulBaseRenderer::getMatrix(SkMatrix* matrix) const {
+void CanvasState::getMatrix(SkMatrix* matrix) const {
mSnapshot->transform->copyTo(*matrix);
}
-void StatefulBaseRenderer::translate(float dx, float dy, float dz) {
+void CanvasState::translate(float dx, float dy, float dz) {
mSnapshot->transform->translate(dx, dy, dz);
}
-void StatefulBaseRenderer::rotate(float degrees) {
+void CanvasState::rotate(float degrees) {
mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f);
}
-void StatefulBaseRenderer::scale(float sx, float sy) {
+void CanvasState::scale(float sx, float sy) {
mSnapshot->transform->scale(sx, sy, 1.0f);
}
-void StatefulBaseRenderer::skew(float sx, float sy) {
+void CanvasState::skew(float sx, float sy) {
mSnapshot->transform->skew(sx, sy);
}
-void StatefulBaseRenderer::setMatrix(const SkMatrix& matrix) {
+void CanvasState::setMatrix(const SkMatrix& matrix) {
mSnapshot->transform->load(matrix);
}
-void StatefulBaseRenderer::setMatrix(const Matrix4& matrix) {
+void CanvasState::setMatrix(const Matrix4& matrix) {
mSnapshot->transform->load(matrix);
}
-void StatefulBaseRenderer::concatMatrix(const SkMatrix& matrix) {
+void CanvasState::concatMatrix(const SkMatrix& matrix) {
mat4 transform(matrix);
mSnapshot->transform->multiply(transform);
}
-void StatefulBaseRenderer::concatMatrix(const Matrix4& matrix) {
+void CanvasState::concatMatrix(const Matrix4& matrix) {
mSnapshot->transform->multiply(matrix);
}
@@ -150,51 +154,22 @@ void StatefulBaseRenderer::concatMatrix(const Matrix4& matrix) {
// Clip
///////////////////////////////////////////////////////////////////////////////
-bool StatefulBaseRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
- if (CC_LIKELY(currentTransform()->rectToRect())) {
- mDirtyClip |= mSnapshot->clip(left, top, right, bottom, op);
- return !mSnapshot->clipRect->isEmpty();
- }
-
- SkPath path;
- path.addRect(left, top, right, bottom);
-
- return StatefulBaseRenderer::clipPath(&path, op);
+bool CanvasState::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
+ mDirtyClip |= mSnapshot->clip(left, top, right, bottom, op);
+ return !mSnapshot->clipIsEmpty();
}
-bool StatefulBaseRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
- SkMatrix transform;
- currentTransform()->copyTo(transform);
-
- SkPath transformed;
- path->transform(transform, &transformed);
-
- SkRegion clip;
- if (!mSnapshot->previous->clipRegion->isEmpty()) {
- clip.setRegion(*mSnapshot->previous->clipRegion);
- } else {
- if (mSnapshot->previous == firstSnapshot()) {
- clip.setRect(0, 0, getWidth(), getHeight());
- } else {
- Rect* bounds = mSnapshot->previous->clipRect;
- clip.setRect(bounds->left, bounds->top, bounds->right, bounds->bottom);
- }
- }
-
- SkRegion region;
- region.setPath(transformed, clip);
-
- // region is the transformed input path, masked by the previous clip
- mDirtyClip |= mSnapshot->clipRegionTransformed(region, op);
- return !mSnapshot->clipRect->isEmpty();
+bool CanvasState::clipPath(const SkPath* path, SkRegion::Op op) {
+ mDirtyClip |= mSnapshot->clipPath(*path, op);
+ return !mSnapshot->clipIsEmpty();
}
-bool StatefulBaseRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
+bool CanvasState::clipRegion(const SkRegion* region, SkRegion::Op op) {
mDirtyClip |= mSnapshot->clipRegionTransformed(*region, op);
- return !mSnapshot->clipRect->isEmpty();
+ return !mSnapshot->clipIsEmpty();
}
-void StatefulBaseRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
+void CanvasState::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
Rect bounds;
float radius;
if (!outline->getAsRoundRect(&bounds, &radius)) return; // only RR supported
@@ -209,7 +184,7 @@ void StatefulBaseRenderer::setClippingOutline(LinearAllocator& allocator, const
}
}
-void StatefulBaseRenderer::setClippingRoundRect(LinearAllocator& allocator,
+void CanvasState::setClippingRoundRect(LinearAllocator& allocator,
const Rect& rect, float radius, bool highPriority) {
mSnapshot->setClippingRoundRect(allocator, rect, radius, highPriority);
}
@@ -229,7 +204,7 @@ void StatefulBaseRenderer::setClippingRoundRect(LinearAllocator& allocator,
* @param snapOut if set, the geometry will be treated as having an AA ramp.
* See Rect::snapGeometryToPixelBoundaries()
*/
-bool StatefulBaseRenderer::calculateQuickRejectForScissor(float left, float top,
+bool CanvasState::calculateQuickRejectForScissor(float left, float top,
float right, float bottom,
bool* clipRequired, bool* roundRectClipRequired,
bool snapOut) const {
@@ -241,7 +216,7 @@ bool StatefulBaseRenderer::calculateQuickRejectForScissor(float left, float top,
currentTransform()->mapRect(r);
r.snapGeometryToPixelBoundaries(snapOut);
- Rect clipRect(*currentClipRect());
+ Rect clipRect(currentClipRect());
clipRect.snapToPixelBoundaries();
if (!clipRect.intersects(r)) return true;
@@ -253,24 +228,13 @@ bool StatefulBaseRenderer::calculateQuickRejectForScissor(float left, float top,
// round rect clip is required if RR clip exists, and geometry intersects its corners
if (roundRectClipRequired) {
- *roundRectClipRequired = mSnapshot->roundRectClipState != NULL
+ *roundRectClipRequired = mSnapshot->roundRectClipState != nullptr
&& mSnapshot->roundRectClipState->areaRequiresRoundRectClip(r);
}
return false;
}
-/**
- * Returns false if drawing won't be clipped out.
- *
- * Makes the decision conservatively, by rounding out the mapped rect before comparing with the
- * clipRect. To be used when perfect, pixel accuracy is not possible (esp. with tessellation) but
- * rejection is still desired.
- *
- * This function, unlike quickRejectSetupScissor, should be used where precise geometry information
- * isn't known (esp. when geometry adjusts based on scale). Generally, this will be first pass
- * rejection where precise rejection isn't important, or precise information isn't available.
- */
-bool StatefulBaseRenderer::quickRejectConservative(float left, float top,
+bool CanvasState::quickRejectConservative(float left, float top,
float right, float bottom) const {
if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
return true;
@@ -280,7 +244,7 @@ bool StatefulBaseRenderer::quickRejectConservative(float left, float top,
currentTransform()->mapRect(r);
r.roundOut(); // rounded out to be conservative
- Rect clipRect(*currentClipRect());
+ Rect clipRect(currentClipRect());
clipRect.snapToPixelBoundaries();
if (!clipRect.intersects(r)) return true;
@@ -288,5 +252,5 @@ bool StatefulBaseRenderer::quickRejectConservative(float left, float top,
return false;
}
-}; // namespace uirenderer
-}; // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/CanvasState.h b/libs/hwui/CanvasState.h
new file mode 100644
index 0000000..121112b
--- /dev/null
+++ b/libs/hwui/CanvasState.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2014 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_CANVAS_STATE_H
+#define ANDROID_HWUI_CANVAS_STATE_H
+
+#include <SkMatrix.h>
+#include <SkPath.h>
+#include <SkRegion.h>
+
+#include "Snapshot.h"
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * Abstract base class for any class containing CanvasState.
+ * Defines three mandatory callbacks.
+ */
+class CanvasStateClient {
+public:
+ CanvasStateClient() { }
+ virtual ~CanvasStateClient() { }
+
+ /**
+ * Callback allowing embedder to take actions in the middle of a
+ * setViewport() call.
+ */
+ virtual void onViewportInitialized() = 0;
+
+ /**
+ * Callback allowing embedder to take actions in the middle of a
+ * restore() call. May be called several times sequentially.
+ */
+ virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) = 0;
+
+ /**
+ * Allows subclasses to control what value is stored in snapshot's
+ * fbo field in * initializeSaveStack.
+ */
+ virtual GLuint onGetTargetFbo() const = 0;
+
+}; // class CanvasStateClient
+
+/**
+ * Implements Canvas state methods on behalf of Renderers.
+ *
+ * Manages the Snapshot stack, implementing matrix, save/restore, and clipping methods in the
+ * Renderer interface. Drawing and recording classes that include a CanvasState will have
+ * different use cases:
+ *
+ * Drawing subclasses (i.e. OpenGLRenderer) can query attributes (such as transform) or hook into
+ * changes (e.g. save/restore) with minimal surface area for manipulating the stack itself.
+ *
+ * Recording subclasses (i.e. DisplayListRenderer) 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.
+ */
+
+class ANDROID_API CanvasState {
+public:
+ CanvasState(CanvasStateClient& renderer);
+ ~CanvasState();
+
+ /**
+ * Initializes the first snapshot, computing the projection matrix,
+ * and stores the dimensions of the render target.
+ */
+ void initializeSaveStack(float clipLeft, float clipTop, float clipRight, float clipBottom,
+ const Vector3& lightCenter);
+
+ void setViewport(int width, int height);
+
+ bool hasRectToRectTransform() const {
+ return CC_LIKELY(currentTransform()->rectToRect());
+ }
+
+ // Save (layer)
+ int getSaveCount() const { return mSaveCount; }
+ int save(int flags);
+ void restore();
+ void restoreToCount(int saveCount);
+
+ // Save/Restore without side-effects
+ int saveSnapshot(int flags);
+ void restoreSnapshot();
+
+ // Matrix
+ void getMatrix(SkMatrix* outMatrix) const;
+ 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 SkMatrix& matrix);
+ void setMatrix(const Matrix4& matrix); // internal only convenience method
+ void concatMatrix(const SkMatrix& matrix);
+ void concatMatrix(const Matrix4& matrix); // internal only convenience method
+
+ // Clip
+ const Rect& getLocalClipBounds() const { return mSnapshot->getLocalClip(); }
+ const Rect& getRenderTargetClipBounds() const { return mSnapshot->getRenderTargetClip(); }
+
+ bool quickRejectConservative(float left, float top, float right, float bottom) const;
+
+ 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);
+
+ /**
+ * Sets a "clipping outline", which is independent from the regular clip.
+ * Currently only supports rectangles or rounded rectangles; passing in a
+ * more complicated outline fails silently. Replaces any previous clipping
+ * outline.
+ */
+ void setClippingOutline(LinearAllocator& allocator, const Outline* outline);
+ void setClippingRoundRect(LinearAllocator& allocator,
+ const Rect& rect, float radius, bool highPriority = true);
+
+ /**
+ * Returns true if drawing in the rectangle (left, top, right, bottom)
+ * will be clipped out. Is conservative: might return false when subpixel-
+ * perfect tests would return true.
+ */
+ 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& currentClipRect() const { return currentSnapshot()->getClipRect(); }
+ 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() { return mWidth; }
+ int getHeight() { return mHeight; }
+
+ inline const Snapshot* currentSnapshot() const {
+ return mSnapshot != nullptr ? mSnapshot.get() : mFirstSnapshot.get();
+ }
+ inline Snapshot* writableSnapshot() { return mSnapshot.get(); }
+ inline const Snapshot* firstSnapshot() const { return mFirstSnapshot.get(); }
+
+private:
+ /// No default constructor - must supply a CanvasStateClient (mCanvas).
+ CanvasState();
+
+ /// indicates that the clip has been changed since the last time it was consumed
+ bool mDirtyClip;
+
+ /// Dimensions of the drawing surface
+ int mWidth, mHeight;
+
+ /// Number of saved states
+ int mSaveCount;
+
+ /// Base state
+ sp<Snapshot> mFirstSnapshot;
+
+ /// Host providing callbacks
+ CanvasStateClient& mCanvas;
+
+ /// Current state
+ sp<Snapshot> mSnapshot;
+
+}; // class CanvasState
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_HWUI_CANVAS_STATE_H
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp
new file mode 100644
index 0000000..852204a
--- /dev/null
+++ b/libs/hwui/ClipArea.cpp
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2015 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 "ClipArea.h"
+
+#include <SkPath.h>
+#include <limits>
+
+#include "Rect.h"
+
+namespace android {
+namespace uirenderer {
+
+static bool intersect(Rect& r, const Rect& r2) {
+ bool hasIntersection = r.intersect(r2);
+ if (!hasIntersection) {
+ r.setEmpty();
+ }
+ return hasIntersection;
+}
+
+static void handlePoint(Rect& transformedBounds, const Matrix4& transform, float x, float y) {
+ Vertex v;
+ v.x = x;
+ v.y = y;
+ transform.mapPoint(v.x, v.y);
+ transformedBounds.expandToCoverVertex(v.x, v.y);
+}
+
+Rect transformAndCalculateBounds(const Rect& r, const Matrix4& transform) {
+ const float kMinFloat = std::numeric_limits<float>::lowest();
+ const float kMaxFloat = std::numeric_limits<float>::max();
+ Rect transformedBounds = { kMaxFloat, kMaxFloat, kMinFloat, kMinFloat };
+ handlePoint(transformedBounds, transform, r.left, r.top);
+ handlePoint(transformedBounds, transform, r.right, r.top);
+ handlePoint(transformedBounds, transform, r.left, r.bottom);
+ handlePoint(transformedBounds, transform, r.right, r.bottom);
+ return transformedBounds;
+}
+
+/*
+ * TransformedRectangle
+ */
+
+TransformedRectangle::TransformedRectangle() {
+}
+
+TransformedRectangle::TransformedRectangle(const Rect& bounds,
+ const Matrix4& transform)
+ : mBounds(bounds)
+ , mTransform(transform) {
+}
+
+bool TransformedRectangle::canSimplyIntersectWith(
+ const TransformedRectangle& other) const {
+
+ return mTransform == other.mTransform;
+}
+
+bool TransformedRectangle::intersectWith(const TransformedRectangle& other) {
+ Rect translatedBounds(other.mBounds);
+ return intersect(mBounds, translatedBounds);
+}
+
+bool TransformedRectangle::isEmpty() const {
+ return mBounds.isEmpty();
+}
+
+/*
+ * RectangleList
+ */
+
+RectangleList::RectangleList()
+ : mTransformedRectanglesCount(0) {
+}
+
+bool RectangleList::isEmpty() const {
+ if (mTransformedRectanglesCount < 1) {
+ return true;
+ }
+
+ for (int i = 0; i < mTransformedRectanglesCount; i++) {
+ if (mTransformedRectangles[i].isEmpty()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+int RectangleList::getTransformedRectanglesCount() const {
+ return mTransformedRectanglesCount;
+}
+
+const TransformedRectangle& RectangleList::getTransformedRectangle(int i) const {
+ return mTransformedRectangles[i];
+}
+
+void RectangleList::setEmpty() {
+ mTransformedRectanglesCount = 0;
+}
+
+void RectangleList::set(const Rect& bounds, const Matrix4& transform) {
+ mTransformedRectanglesCount = 1;
+ mTransformedRectangles[0] = TransformedRectangle(bounds, transform);
+}
+
+bool RectangleList::intersectWith(const Rect& bounds,
+ const Matrix4& transform) {
+ TransformedRectangle newRectangle(bounds, transform);
+
+ // Try to find a rectangle with a compatible transformation
+ int index = 0;
+ for (; index < mTransformedRectanglesCount; index++) {
+ TransformedRectangle& tr(mTransformedRectangles[index]);
+ if (tr.canSimplyIntersectWith(newRectangle)) {
+ tr.intersectWith(newRectangle);
+ return true;
+ }
+ }
+
+ // Add it to the list if there is room
+ if (index < kMaxTransformedRectangles) {
+ mTransformedRectangles[index] = newRectangle;
+ mTransformedRectanglesCount += 1;
+ return true;
+ }
+
+ // This rectangle list is full
+ return false;
+}
+
+Rect RectangleList::calculateBounds() const {
+ Rect bounds;
+ for (int index = 0; index < mTransformedRectanglesCount; index++) {
+ const TransformedRectangle& tr(mTransformedRectangles[index]);
+ if (index == 0) {
+ bounds = tr.transformedBounds();
+ } else {
+ bounds.intersect(tr.transformedBounds());
+ }
+ }
+ return bounds;
+}
+
+static SkPath pathFromTransformedRectangle(const Rect& bounds,
+ const Matrix4& transform) {
+ SkPath rectPath;
+ SkPath rectPathTransformed;
+ rectPath.addRect(bounds.left, bounds.top, bounds.right, bounds.bottom);
+ SkMatrix skTransform;
+ transform.copyTo(skTransform);
+ rectPath.transform(skTransform, &rectPathTransformed);
+ return rectPathTransformed;
+}
+
+SkRegion RectangleList::convertToRegion(const SkRegion& clip) const {
+ SkRegion rectangleListAsRegion;
+ for (int index = 0; index < mTransformedRectanglesCount; index++) {
+ const TransformedRectangle& tr(mTransformedRectangles[index]);
+ SkPath rectPathTransformed = pathFromTransformedRectangle(
+ tr.getBounds(), tr.getTransform());
+ if (index == 0) {
+ rectangleListAsRegion.setPath(rectPathTransformed, clip);
+ } else {
+ SkRegion rectRegion;
+ rectRegion.setPath(rectPathTransformed, clip);
+ rectangleListAsRegion.op(rectRegion, SkRegion::kIntersect_Op);
+ }
+ }
+ return rectangleListAsRegion;
+}
+
+/*
+ * ClipArea
+ */
+
+ClipArea::ClipArea()
+ : mMode(kModeRectangle) {
+}
+
+/*
+ * Interface
+ */
+
+void ClipArea::setViewportDimensions(int width, int height) {
+ mViewportBounds.set(0, 0, width, height);
+ mClipRect = mViewportBounds;
+}
+
+void ClipArea::setEmpty() {
+ mMode = kModeRectangle;
+ mClipRect.setEmpty();
+ mClipRegion.setEmpty();
+ mRectangleList.setEmpty();
+}
+
+void ClipArea::setClip(float left, float top, float right, float bottom) {
+ mMode = kModeRectangle;
+ mClipRect.set(left, top, right, bottom);
+ mClipRegion.setEmpty();
+}
+
+bool ClipArea::clipRectWithTransform(float left, float top, float right,
+ float bottom, const mat4* transform, SkRegion::Op op) {
+ Rect r(left, top, right, bottom);
+ return clipRectWithTransform(r, transform, op);
+}
+
+bool ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform,
+ SkRegion::Op op) {
+ switch (mMode) {
+ case kModeRectangle:
+ return rectangleModeClipRectWithTransform(r, transform, op);
+ case kModeRectangleList:
+ return rectangleListModeClipRectWithTransform(r, transform, op);
+ case kModeRegion:
+ return regionModeClipRectWithTransform(r, transform, op);
+ }
+ return false;
+}
+
+bool ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) {
+ enterRegionMode();
+ mClipRegion.op(region, op);
+ setClipRectToRegionBounds();
+ return true;
+}
+
+bool ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform,
+ SkRegion::Op op) {
+ SkMatrix skTransform;
+ transform->copyTo(skTransform);
+ SkPath transformed;
+ path.transform(skTransform, &transformed);
+ SkRegion region;
+ regionFromPath(transformed, region);
+ return clipRegion(region, op);
+}
+
+/*
+ * Rectangle mode
+ */
+
+void ClipArea::enterRectangleMode() {
+ // Entering rectangle mode discards any
+ // existing clipping information from the other modes.
+ // The only way this occurs is by a clip setting operation.
+ mMode = kModeRectangle;
+}
+
+bool ClipArea::rectangleModeClipRectWithTransform(const Rect& r,
+ const mat4* transform, SkRegion::Op op) {
+
+ if (op != SkRegion::kIntersect_Op) {
+ enterRegionMode();
+ return regionModeClipRectWithTransform(r, transform, op);
+ }
+
+ if (transform->rectToRect()) {
+ Rect transformed(r);
+ transform->mapRect(transformed);
+ bool hasIntersection = mClipRect.intersect(transformed);
+ if (!hasIntersection) {
+ mClipRect.setEmpty();
+ }
+ return true;
+ }
+
+ enterRectangleListMode();
+ return rectangleListModeClipRectWithTransform(r, transform, op);
+}
+
+bool ClipArea::rectangleModeClipRectWithTransform(float left, float top,
+ float right, float bottom, const mat4* transform, SkRegion::Op op) {
+ Rect r(left, top, right, bottom);
+ bool result = rectangleModeClipRectWithTransform(r, transform, op);
+ mClipRect = mRectangleList.calculateBounds();
+ return result;
+}
+
+/*
+ * RectangleList mode implementation
+ */
+
+void ClipArea::enterRectangleListMode() {
+ // Is is only legal to enter rectangle list mode from
+ // rectangle mode, since rectangle list mode cannot represent
+ // all clip areas that can be represented by a region.
+ ALOG_ASSERT(mMode == kModeRectangle);
+ mMode = kModeRectangleList;
+ mRectangleList.set(mClipRect, Matrix4::identity());
+}
+
+bool ClipArea::rectangleListModeClipRectWithTransform(const Rect& r,
+ const mat4* transform, SkRegion::Op op) {
+ if (op != SkRegion::kIntersect_Op
+ || !mRectangleList.intersectWith(r, *transform)) {
+ enterRegionMode();
+ return regionModeClipRectWithTransform(r, transform, op);
+ }
+ return true;
+}
+
+bool ClipArea::rectangleListModeClipRectWithTransform(float left, float top,
+ float right, float bottom, const mat4* transform, SkRegion::Op op) {
+ Rect r(left, top, right, bottom);
+ return rectangleListModeClipRectWithTransform(r, transform, op);
+}
+
+/*
+ * Region mode implementation
+ */
+
+void ClipArea::enterRegionMode() {
+ if (mMode != kModeRegion) {
+ if (mMode == kModeRectangle) {
+ mClipRegion.setRect(mClipRect.left, mClipRect.top,
+ mClipRect.right, mClipRect.bottom);
+ } else {
+ mClipRegion = mRectangleList.convertToRegion(createViewportRegion());
+ setClipRectToRegionBounds();
+ }
+ mMode = kModeRegion;
+ }
+}
+
+bool ClipArea::regionModeClipRectWithTransform(const Rect& r,
+ const mat4* transform, SkRegion::Op op) {
+ SkPath transformedRect = pathFromTransformedRectangle(r, *transform);
+ SkRegion transformedRectRegion;
+ regionFromPath(transformedRect, transformedRectRegion);
+ mClipRegion.op(transformedRectRegion, op);
+ setClipRectToRegionBounds();
+ return true;
+}
+
+bool ClipArea::regionModeClipRectWithTransform(float left, float top,
+ float right, float bottom, const mat4* transform, SkRegion::Op op) {
+ return regionModeClipRectWithTransform(Rect(left, top, right, bottom),
+ transform, op);
+}
+
+void ClipArea::setClipRectToRegionBounds() {
+ if (!mClipRegion.isEmpty()) {
+ mClipRect.set(mClipRegion.getBounds());
+
+ if (mClipRegion.isRect()) {
+ mClipRegion.setEmpty();
+ }
+ } else {
+ mClipRect.setEmpty();
+ }
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/ClipArea.h b/libs/hwui/ClipArea.h
new file mode 100644
index 0000000..16e6df9
--- /dev/null
+++ b/libs/hwui/ClipArea.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2015 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 CLIPAREA_H
+#define CLIPAREA_H
+
+#include <SkRegion.h>
+
+#include "Matrix.h"
+#include "Rect.h"
+#include "utils/Pair.h"
+
+namespace android {
+namespace uirenderer {
+
+Rect transformAndCalculateBounds(const Rect& r, const Matrix4& transform);
+
+class TransformedRectangle {
+public:
+ TransformedRectangle();
+ TransformedRectangle(const Rect& bounds, const Matrix4& transform);
+
+ bool canSimplyIntersectWith(const TransformedRectangle& other) const;
+ bool intersectWith(const TransformedRectangle& other);
+
+ bool isEmpty() const;
+
+ const Rect& getBounds() const {
+ return mBounds;
+ }
+
+ Rect transformedBounds() const {
+ Rect transformedBounds(transformAndCalculateBounds(mBounds, mTransform));
+ return transformedBounds;
+ }
+
+ const Matrix4& getTransform() const {
+ return mTransform;
+ }
+
+private:
+ Rect mBounds;
+ Matrix4 mTransform;
+};
+
+class RectangleList {
+public:
+ RectangleList();
+
+ bool isEmpty() const;
+ int getTransformedRectanglesCount() const;
+ const TransformedRectangle& getTransformedRectangle(int i) const;
+
+ void setEmpty();
+ void set(const Rect& bounds, const Matrix4& transform);
+ bool intersectWith(const Rect& bounds, const Matrix4& transform);
+
+ SkRegion convertToRegion(const SkRegion& clip) const;
+ Rect calculateBounds() const;
+
+private:
+ enum {
+ kMaxTransformedRectangles = 5
+ };
+
+ int mTransformedRectanglesCount;
+ TransformedRectangle mTransformedRectangles[kMaxTransformedRectangles];
+};
+
+class ClipArea {
+public:
+ ClipArea();
+
+ void setViewportDimensions(int width, int height);
+
+ bool isEmpty() const {
+ return mClipRect.isEmpty();
+ }
+
+ void setEmpty();
+ void setClip(float left, float top, float right, float bottom);
+ bool clipRectWithTransform(float left, float top, float right, float bottom,
+ const mat4* transform, SkRegion::Op op = SkRegion::kIntersect_Op);
+ bool clipRectWithTransform(const Rect& r, const mat4* transform,
+ SkRegion::Op op = SkRegion::kIntersect_Op);
+ bool clipRegion(const SkRegion& region, SkRegion::Op op = SkRegion::kIntersect_Op);
+ bool clipPathWithTransform(const SkPath& path, const mat4* transform,
+ SkRegion::Op op);
+
+ const Rect& getClipRect() const {
+ return mClipRect;
+ }
+
+ const SkRegion& getClipRegion() const {
+ return mClipRegion;
+ }
+
+ const RectangleList& getRectangleList() const {
+ return mRectangleList;
+ }
+
+ bool isRegion() const {
+ return kModeRegion == mMode;
+ }
+
+ bool isSimple() const {
+ return mMode == kModeRectangle;
+ }
+
+ bool isRectangleList() const {
+ return mMode == kModeRectangleList;
+ }
+
+private:
+ void enterRectangleMode();
+ bool rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
+ bool rectangleModeClipRectWithTransform(float left, float top, float right,
+ float bottom, const mat4* transform, SkRegion::Op op);
+
+ void enterRectangleListMode();
+ bool rectangleListModeClipRectWithTransform(float left, float top,
+ float right, float bottom, const mat4* transform, SkRegion::Op op);
+ bool rectangleListModeClipRectWithTransform(const Rect& r,
+ const mat4* transform, SkRegion::Op op);
+
+ void enterRegionModeFromRectangleMode();
+ void enterRegionModeFromRectangleListMode();
+ void enterRegionMode();
+ bool regionModeClipRectWithTransform(const Rect& r, const mat4* transform,
+ SkRegion::Op op);
+ bool regionModeClipRectWithTransform(float left, float top, float right,
+ float bottom, const mat4* transform, SkRegion::Op op);
+
+ void ensureClipRegion();
+ void setClipRectToRegionBounds();
+ bool clipRegionOp(float left, float top, float right, float bottom,
+ SkRegion::Op op);
+
+ SkRegion createViewportRegion() {
+ return SkRegion(mViewportBounds.toSkIRect());
+ }
+
+ void regionFromPath(const SkPath& path, SkRegion& pathAsRegion) {
+ pathAsRegion.setPath(path, createViewportRegion());
+ }
+
+ enum Mode {
+ kModeRectangle,
+ kModeRegion,
+ kModeRectangleList
+ };
+
+ Mode mMode;
+ Rect mViewportBounds;
+ Rect mClipRect;
+ SkRegion mClipRegion;
+ RectangleList mRectangleList;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* CLIPAREA_H_ */
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp
index 420e331..9bd3bdc 100644
--- a/libs/hwui/DamageAccumulator.cpp
+++ b/libs/hwui/DamageAccumulator.cpp
@@ -79,7 +79,7 @@ void DamageAccumulator::computeCurrentTransform(Matrix4* outMatrix) const {
void DamageAccumulator::pushCommon() {
if (!mHead->next) {
DirtyStack* nextFrame = (DirtyStack*) mAllocator.alloc(sizeof(DirtyStack));
- nextFrame->next = 0;
+ nextFrame->next = nullptr;
nextFrame->prev = mHead;
mHead->next = nextFrame;
}
@@ -147,7 +147,7 @@ static DirtyStack* findParentRenderNode(DirtyStack* frame) {
return frame;
}
}
- return NULL;
+ return nullptr;
}
static DirtyStack* findProjectionReceiver(DirtyStack* frame) {
@@ -160,7 +160,7 @@ static DirtyStack* findProjectionReceiver(DirtyStack* frame) {
}
}
}
- return NULL;
+ return nullptr;
}
static void applyTransforms(DirtyStack* frame, DirtyStack* end) {
@@ -222,7 +222,7 @@ void DamageAccumulator::finish(SkRect* totalDirty) {
LOG_ALWAYS_FATAL_IF(mHead->prev != mHead, "Cannot finish, mismatched push/pop calls! %p vs. %p", mHead->prev, mHead);
// Root node never has a transform, so this is the fully mapped dirty rect
*totalDirty = mHead->pendingDirty;
- totalDirty->roundOut();
+ totalDirty->roundOut(totalDirty);
mHead->pendingDirty.setEmpty();
}
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index 6fd0151..c78971a 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -52,7 +52,7 @@ namespace uirenderer {
class Batch {
public:
- virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) = 0;
+ 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; }
@@ -91,12 +91,10 @@ public:
return false;
}
- virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
+ 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());
- status_t status = DrawGlInfo::kStatusDone;
- DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
for (unsigned int i = 0; i < mOps.size(); i++) {
DrawOp* op = mOps[i].op;
const DeferredDisplayState* state = mOps[i].state;
@@ -105,8 +103,7 @@ public:
#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
renderer.eventMark(op->name());
#endif
- logBuffer.writeCommand(0, op->name());
- status |= op->applyDraw(renderer, dirty);
+ op->applyDraw(renderer, dirty);
#if DEBUG_MERGE_BEHAVIOR
const Rect& bounds = state->mBounds;
@@ -118,12 +115,11 @@ public:
batchColor);
#endif
}
- return status;
}
- virtual bool purelyDrawBatch() { return true; }
+ virtual bool purelyDrawBatch() override { return true; }
- virtual bool coversBounds(const Rect& bounds) {
+ 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));
@@ -235,30 +231,11 @@ public:
return false;
}
- /* Draw Modifiers compatibility check
- *
- * Shadows are ignored, as only text uses them, and in that case they are drawn
- * per-DrawTextOp, before the unified text draw. Because of this, it's always safe to merge
- * text UNLESS a later draw's shadow should overlays a previous draw's text. This is covered
- * above with the intersection check.
- *
- * OverrideLayerAlpha is also ignored, as it's only used for drawing layers, which are never
- * merged.
- *
- * These ignore cases prevent us from simply memcmp'ing the drawModifiers
- */
- const DrawModifiers& lhsMod = lhs->mDrawModifiers;
- const DrawModifiers& rhsMod = rhs->mDrawModifiers;
-
- // Draw filter testing expects bit fields to be clear if filter not set.
- if (lhsMod.mHasDrawFilter != rhsMod.mHasDrawFilter) return false;
- if (lhsMod.mPaintFilterClearBits != rhsMod.mPaintFilterClearBits) return false;
- if (lhsMod.mPaintFilterSetBits != rhsMod.mPaintFilterSetBits) return false;
-
return true;
}
- virtual void add(DrawOp* op, const DeferredDisplayState* state, bool opaqueOverBounds) {
+ virtual void add(DrawOp* op, const DeferredDisplayState* state,
+ bool opaqueOverBounds) override {
DrawBatch::add(op, state, opaqueOverBounds);
const int newClipSideFlags = state->mClipSideFlags;
@@ -269,33 +246,29 @@ public:
if (newClipSideFlags & kClipSide_Bottom) mClipRect.bottom = state->mClip.bottom;
}
- virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
+ 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) {
- return DrawBatch::replay(renderer, dirty, -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 : NULL);
+ renderer.setupMergedMultiDraw(mClipSideFlags ? &mClipRect : nullptr);
DrawOp* op = mOps[0].op;
- DisplayListLogBuffer& buffer = DisplayListLogBuffer::getInstance();
- buffer.writeCommand(0, "multiDraw");
- buffer.writeCommand(1, op->name());
-
#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
renderer.eventMark("multiDraw");
renderer.eventMark(op->name());
#endif
- status_t status = op->multiDraw(renderer, dirty, mOps, mBounds);
+ op->multiDraw(renderer, dirty, mOps, mBounds);
#if DEBUG_MERGE_BEHAVIOR
renderer.drawScreenSpaceColorRect(mBounds.left, mBounds.top, mBounds.right, mBounds.bottom,
DEBUG_COLOR_MERGEDBATCH);
#endif
- return status;
}
private:
@@ -313,7 +286,7 @@ public:
// creates a single operation batch
StateOpBatch(const StateOp* op, const DeferredDisplayState* state) : mOp(op), mState(state) {}
- virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
+ virtual void replay(OpenGLRenderer& renderer, Rect& dirty, int index) override {
DEFER_LOGD("replaying state op batch %p", this);
renderer.restoreDisplayState(*mState);
@@ -322,7 +295,6 @@ public:
// renderer.restoreToCount directly
int saveCount = -1;
mOp->applyState(renderer, saveCount);
- return DrawGlInfo::kStatusDone;
}
private:
@@ -332,15 +304,14 @@ private:
class RestoreToCountBatch : public Batch {
public:
- RestoreToCountBatch(const StateOp* op, const DeferredDisplayState* state,
- int restoreCount) : mState(state), mRestoreCount(restoreCount) {}
+ RestoreToCountBatch(const StateOp* op, const DeferredDisplayState* state, int restoreCount) :
+ mState(state), mRestoreCount(restoreCount) {}
- virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
+ 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);
- return DrawGlInfo::kStatusDone;
}
private:
@@ -358,9 +329,8 @@ private:
#if DEBUG_MERGE_BEHAVIOR
class BarrierDebugBatch : public Batch {
- virtual status_t replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
+ virtual void replay(OpenGLRenderer& renderer, Rect& dirty, int index) {
renderer.drawScreenSpaceColorRect(0, 0, 10000, 10000, DEBUG_COLOR_BARRIER);
- return DrawGlInfo::kStatusDrew;
}
};
#endif
@@ -371,7 +341,7 @@ class BarrierDebugBatch : public Batch {
void DeferredDisplayList::resetBatchingState() {
for (int i = 0; i < kOpBatch_Count; i++) {
- mBatchLookup[i] = NULL;
+ mBatchLookup[i] = nullptr;
mMergingBatches[i].clear();
}
#if DEBUG_MERGE_BEHAVIOR
@@ -541,7 +511,7 @@ void DeferredDisplayList::addDrawOp(OpenGLRenderer& renderer, DrawOp* op) {
}
// find the latest batch of the new op's type, and try to merge the new op into it
- DrawBatch* targetBatch = NULL;
+ DrawBatch* targetBatch = nullptr;
// insertion point of a new batch, will hopefully be immediately after similar batch
// (eventually, should be similar shader)
@@ -564,7 +534,7 @@ void DeferredDisplayList::addDrawOp(OpenGLRenderer& renderer, DrawOp* op) {
// Try to merge with any existing batch with same mergeId.
if (mMergingBatches[deferInfo.batchId].get(deferInfo.mergeId, targetBatch)) {
if (!((MergingDrawBatch*) targetBatch)->canMergeWith(op, state)) {
- targetBatch = NULL;
+ targetBatch = nullptr;
}
}
} else {
@@ -590,7 +560,7 @@ void DeferredDisplayList::addDrawOp(OpenGLRenderer& renderer, DrawOp* op) {
// 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 = NULL;
+ targetBatch = nullptr;
#if DEBUG_DEFER
DEFER_LOGD("op couldn't join batch %p, was intersected by batch %d",
targetBatch, i);
@@ -647,26 +617,22 @@ void DeferredDisplayList::storeRestoreToCountBarrier(OpenGLRenderer& renderer, S
// Replay / flush
/////////////////////////////////////////////////////////////////////////////////
-static status_t replayBatchList(const Vector<Batch*>& batchList,
+static void replayBatchList(const Vector<Batch*>& batchList,
OpenGLRenderer& renderer, Rect& dirty) {
- status_t status = DrawGlInfo::kStatusDone;
for (unsigned int i = 0; i < batchList.size(); i++) {
if (batchList[i]) {
- status |= batchList[i]->replay(renderer, dirty, i);
+ batchList[i]->replay(renderer, dirty, i);
}
}
DEFER_LOGD("--flushed, drew %d batches", batchList.size());
- return status;
}
-status_t DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty) {
+void DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty) {
ATRACE_NAME("flush drawing commands");
Caches::getInstance().fontRenderer->endPrecaching();
- status_t status = DrawGlInfo::kStatusDone;
-
- if (isEmpty()) return status; // nothing to flush
+ if (isEmpty()) return; // nothing to flush
renderer.restoreToCount(1);
DEFER_LOGD("--flushing");
@@ -685,14 +651,13 @@ status_t DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty) {
}
// 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
- status |= replayBatchList(mBatches, renderer, dirty);
+ replayBatchList(mBatches, renderer, dirty);
renderer.restoreToCount(1);
renderer.setDrawModifiers(restoreDrawModifiers);
DEFER_LOGD("--flush complete, returning %x", status);
clear();
- return status;
}
void DeferredDisplayList::discardDrawingBatches(const unsigned int maxIndex) {
@@ -700,7 +665,7 @@ void DeferredDisplayList::discardDrawingBatches(const unsigned int maxIndex) {
// leave deferred state ops alone for simplicity (empty save restore pairs may now exist)
if (mBatches[i] && mBatches[i]->purelyDrawBatch()) {
delete mBatches[i];
- mBatches.replaceAt(NULL, i);
+ mBatches.replaceAt(nullptr, i);
}
}
mEarliestUnclearedIndex = maxIndex + 1;
diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
index f7f30b1..c92ab91 100644
--- a/libs/hwui/DeferredDisplayList.h
+++ b/libs/hwui/DeferredDisplayList.h
@@ -69,7 +69,7 @@ public:
class OpStatePair {
public:
OpStatePair()
- : op(NULL), state(NULL) {}
+ : op(nullptr), state(nullptr) {}
OpStatePair(DrawOp* newOp, const DeferredDisplayState* newState)
: op(newOp), state(newState) {}
OpStatePair(const OpStatePair& other)
@@ -106,7 +106,7 @@ public:
* 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
*/
- status_t flush(OpenGLRenderer& renderer, Rect& dirty);
+ void flush(OpenGLRenderer& renderer, Rect& dirty);
void addClip(OpenGLRenderer& renderer, ClipOp* op);
void addSaveLayer(OpenGLRenderer& renderer, SaveLayerOp* op, int newSaveCount);
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index d02455c..0792120 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -25,8 +25,8 @@ namespace android {
namespace uirenderer {
DeferredLayerUpdater::DeferredLayerUpdater(renderthread::RenderThread& thread, Layer* layer)
- : mSurfaceTexture(0)
- , mTransform(0)
+ : mSurfaceTexture(nullptr)
+ , mTransform(nullptr)
, mNeedsGLContextAttach(false)
, mUpdateTexImage(false)
, mLayer(layer)
@@ -42,14 +42,14 @@ DeferredLayerUpdater::DeferredLayerUpdater(renderthread::RenderThread& thread, L
DeferredLayerUpdater::~DeferredLayerUpdater() {
SkSafeUnref(mColorFilter);
- setTransform(0);
+ setTransform(nullptr);
mLayer->postDecStrong();
- mLayer = 0;
+ mLayer = nullptr;
}
void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
OpenGLRenderer::getAlphaAndModeDirect(paint, &mAlpha, &mMode);
- SkColorFilter* colorFilter = (paint) ? paint->getColorFilter() : NULL;
+ SkColorFilter* colorFilter = (paint) ? paint->getColorFilter() : nullptr;
SkRefCnt_SafeAssign(mColorFilter, colorFilter);
}
@@ -70,7 +70,7 @@ bool DeferredLayerUpdater::apply() {
}
if (mTransform) {
mLayer->getTransform().load(*mTransform);
- setTransform(0);
+ setTransform(nullptr);
}
}
return success;
@@ -95,10 +95,10 @@ void DeferredLayerUpdater::doUpdateTexImage() {
bool forceFilter = false;
sp<GraphicBuffer> buffer = mSurfaceTexture->getCurrentBuffer();
- if (buffer != NULL) {
+ if (buffer != nullptr) {
// force filtration if buffer size != layer size
- forceFilter = mWidth != buffer->getWidth()
- || mHeight != buffer->getHeight();
+ forceFilter = mWidth != static_cast<int>(buffer->getWidth())
+ || mHeight != static_cast<int>(buffer->getHeight());
}
#if DEBUG_RENDERER
@@ -122,7 +122,7 @@ void DeferredLayerUpdater::detachSurfaceTexture() {
// TODO: Elevate to fatal exception
ALOGE("Failed to detach SurfaceTexture from context %d", err);
}
- mSurfaceTexture = 0;
+ mSurfaceTexture = nullptr;
mLayer->clearTexture();
}
}
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 84411ed..38d8e4a 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -24,7 +24,6 @@
#include "Layer.h"
#include "Rect.h"
-#include "RenderNode.h"
#include "renderthread/RenderThread.h"
namespace android {
@@ -39,7 +38,7 @@ public:
ANDROID_API DeferredLayerUpdater(renderthread::RenderThread& thread, Layer* layer);
ANDROID_API ~DeferredLayerUpdater();
- ANDROID_API bool setSize(uint32_t width, uint32_t height) {
+ ANDROID_API bool setSize(int width, int height) {
if (mWidth != width || mHeight != height) {
mWidth = width;
mHeight = height;
@@ -69,7 +68,7 @@ public:
ANDROID_API void setTransform(const SkMatrix* matrix) {
delete mTransform;
- mTransform = matrix ? new SkMatrix(*matrix) : 0;
+ mTransform = matrix ? new SkMatrix(*matrix) : nullptr;
}
ANDROID_API void setPaint(const SkPaint* paint);
@@ -84,8 +83,8 @@ public:
private:
// Generic properties
- uint32_t mWidth;
- uint32_t mHeight;
+ int mWidth;
+ int mHeight;
bool mBlend;
SkColorFilter* mColorFilter;
int mAlpha;
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 8953166..317e395 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -24,7 +24,6 @@
#include "Debug.h"
#include "DisplayList.h"
#include "DisplayListOp.h"
-#include "DisplayListLogBuffer.h"
namespace android {
namespace uirenderer {
@@ -46,12 +45,6 @@ void DisplayListData::cleanupResources() {
resourceCache.decrementRefcountLocked(bitmapResources.itemAt(i));
}
- for (size_t i = 0; i < ownedBitmapResources.size(); i++) {
- const SkBitmap* bitmap = ownedBitmapResources.itemAt(i);
- resourceCache.decrementRefcountLocked(bitmap);
- resourceCache.destructorLocked(bitmap);
- }
-
for (size_t i = 0; i < patchResources.size(); i++) {
resourceCache.decrementRefcountLocked(patchResources.itemAt(i));
}
@@ -62,20 +55,7 @@ void DisplayListData::cleanupResources() {
resourceCache.unlock();
- for (size_t i = 0; i < paints.size(); i++) {
- delete paints.itemAt(i);
- }
-
- for (size_t i = 0; i < regions.size(); i++) {
- delete regions.itemAt(i);
- }
-
- for (size_t i = 0; i < paths.size(); i++) {
- delete paths.itemAt(i);
- }
-
bitmapResources.clear();
- ownedBitmapResources.clear();
patchResources.clear();
sourcePaths.clear();
paints.clear();
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index a9a9148..011b509 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -38,8 +38,9 @@
#include <androidfw/ResourceTypes.h>
#include "Debug.h"
-#include "Matrix.h"
+#include "CanvasProperty.h"
#include "DeferredDisplayList.h"
+#include "Matrix.h"
#include "RenderProperties.h"
class SkBitmap;
@@ -66,7 +67,7 @@ class DrawRenderNodeOp;
/**
* Holds data used in the playback a tree of DisplayLists.
*/
-class PlaybackStateStruct {
+struct PlaybackStateStruct {
protected:
PlaybackStateStruct(OpenGLRenderer& renderer, int replayFlags, LinearAllocator* allocator)
: mRenderer(renderer)
@@ -95,14 +96,12 @@ struct DeferStateStruct : public PlaybackStateStruct {
DeferredDisplayList& mDeferredList;
};
-class ReplayStateStruct : public PlaybackStateStruct {
-public:
+struct ReplayStateStruct : public PlaybackStateStruct {
ReplayStateStruct(OpenGLRenderer& renderer, Rect& dirty, int replayFlags)
: PlaybackStateStruct(renderer, replayFlags, &mReplayAllocator),
- mDirty(dirty), mDrawGlStatus(DrawGlInfo::kStatusDone) {}
+ mDirty(dirty) {}
Rect& mDirty;
- status_t mDrawGlStatus;
LinearAllocator mReplayAllocator;
};
@@ -135,13 +134,12 @@ public:
int projectionReceiveIndex;
Vector<const SkBitmap*> bitmapResources;
- Vector<const SkBitmap*> ownedBitmapResources;
Vector<const Res_png_9patch*> patchResources;
- Vector<const SkPaint*> paints;
- Vector<const SkPath*> paths;
+ std::vector<std::unique_ptr<const SkPaint>> paints;
+ std::vector<std::unique_ptr<const SkRegion>> regions;
+ std::vector<std::unique_ptr<const SkPath>> paths;
SortedVector<const SkPath*> sourcePaths;
- Vector<const SkRegion*> regions;
Vector<Functor*> functors;
const Vector<Chunk>& getChunks() const {
diff --git a/libs/hwui/DisplayListLogBuffer.cpp b/libs/hwui/DisplayListLogBuffer.cpp
deleted file mode 100644
index bc9e7bd..0000000
--- a/libs/hwui/DisplayListLogBuffer.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2011 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 "DisplayListLogBuffer.h"
-
-// BUFFER_SIZE size must be one more than a multiple of COMMAND_SIZE to ensure
-// that mStart always points at the next command, not just the next item
-#define NUM_COMMANDS 50
-#define BUFFER_SIZE ((NUM_COMMANDS) + 1)
-
-/**
- * DisplayListLogBuffer is a utility class which logs the most recent display
- * list operations in a circular buffer. The log is process-wide, because we
- * only care about the most recent operations, not the operations on a per-window
- * basis for a given activity. The purpose of the log is to provide more debugging
- * information in a bug report, by telling us not just where a process hung (which
- * generally is just reported as a stack trace at the Java level) or crashed, but
- * also what happened immediately before that hang or crash. This may help track down
- * problems in the native rendering code or driver interaction related to the display
- * list operations that led up to the hang or crash.
- *
- * The log is implemented as a circular buffer for both space and performance
- * reasons - we only care about the last several operations to give us context
- * leading up to the problem, and we don't want to constantly copy data around or do
- * additional mallocs to keep the most recent operations logged. Only numbers are
- * logged to make the operation fast. If and when the log is output, we process this
- * data into meaningful strings.
- *
- * There is an assumption about the format of the command (currently 2 ints: the
- * opcode and the nesting level). If the type of information logged changes (for example,
- * we may want to save a timestamp), then the size of the buffer and the way the
- * information is recorded in writeCommand() should change to suit.
- */
-
-namespace android {
-
-#ifdef USE_OPENGL_RENDERER
-using namespace uirenderer;
-ANDROID_SINGLETON_STATIC_INSTANCE(DisplayListLogBuffer);
-#endif
-
-namespace uirenderer {
-
-
-DisplayListLogBuffer::DisplayListLogBuffer() {
- mBufferFirst = (OpLog*) malloc(BUFFER_SIZE * sizeof(OpLog));
- mStart = mBufferFirst;
- mBufferLast = mBufferFirst + BUFFER_SIZE - 1;
- mEnd = mStart;
-}
-
-DisplayListLogBuffer::~DisplayListLogBuffer() {
- free(mBufferFirst);
-}
-
-/**
- * Called from DisplayListRenderer to output the current buffer into the
- * specified FILE. This only happens in a dumpsys/bugreport operation.
- */
-void DisplayListLogBuffer::outputCommands(FILE *file)
-{
- OpLog* tmpBufferPtr = mStart;
- while (true) {
- if (tmpBufferPtr == mEnd) {
- break;
- }
-
- fprintf(file, "%*s%s\n", 2 * tmpBufferPtr->level, "", tmpBufferPtr->label);
-
- tmpBufferPtr++;
- if (tmpBufferPtr > mBufferLast) {
- tmpBufferPtr = mBufferFirst;
- }
- }
-}
-
-/**
- * Store the given level and label in the buffer and increment/wrap the mEnd
- * and mStart values as appropriate. Label should point to static memory.
- */
-void DisplayListLogBuffer::writeCommand(int level, const char* label) {
- mEnd->level = level;
- mEnd->label = label;
-
- if (mEnd == mBufferLast) {
- mEnd = mBufferFirst;
- } else {
- mEnd++;
- }
- if (mEnd == mStart) {
- mStart++;
- if (mStart > mBufferLast) {
- mStart = mBufferFirst;
- }
- }
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/DisplayListLogBuffer.h b/libs/hwui/DisplayListLogBuffer.h
deleted file mode 100644
index c884789..0000000
--- a/libs/hwui/DisplayListLogBuffer.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 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_LOG_BUFFER_H
-#define ANDROID_HWUI_DISPLAY_LIST_LOG_BUFFER_H
-
-#include <utils/Singleton.h>
-
-#include <stdio.h>
-
-namespace android {
-namespace uirenderer {
-
-class DisplayListLogBuffer: public Singleton<DisplayListLogBuffer> {
- DisplayListLogBuffer();
- ~DisplayListLogBuffer();
-
- friend class Singleton<DisplayListLogBuffer>;
-
-public:
- void writeCommand(int level, const char* label);
- void outputCommands(FILE *file);
-
- bool isEmpty() {
- return (mStart == mEnd);
- }
-
- struct OpLog {
- int level;
- const char* label;
- };
-
-private:
- OpLog* mBufferFirst; // where the memory starts
- OpLog* mStart; // where the current command stream starts
- OpLog* mEnd; // where the current commands end
- OpLog* mBufferLast; // where the buffer memory ends
-
-};
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_DISPLAY_LIST_LOG_BUFFER_H
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 8a5e21d..d128ffe 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -17,29 +17,24 @@
#ifndef ANDROID_HWUI_DISPLAY_OPERATION_H
#define ANDROID_HWUI_DISPLAY_OPERATION_H
-#ifndef LOG_TAG
- #define LOG_TAG "OpenGLRenderer"
-#endif
-
-#include <SkColor.h>
-#include <SkPath.h>
-#include <SkPathOps.h>
-#include <SkXfermode.h>
-
-#include <private/hwui/DrawGlInfo.h>
-
#include "OpenGLRenderer.h"
#include "AssetAtlas.h"
#include "DeferredDisplayList.h"
#include "DisplayListRenderer.h"
-#include "RenderState.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"
-#define CRASH() do { \
- *(int *)(uintptr_t) 0xbbadbeef = 0; \
- ((void(*)())0)(); /* More reliable, but doesn't say BBADBEEF */ \
-} while(false)
+#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))
@@ -63,9 +58,9 @@ 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() { CRASH(); }
- static void operator delete(void* ptr) { CRASH(); }
- /** static void* operator new(size_t size); PURPOSELY OMITTED **/
+ 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) {
return allocator.alloc(size);
}
@@ -90,12 +85,8 @@ public:
class StateOp : public DisplayListOp {
public:
- StateOp() {};
-
- virtual ~StateOp() {}
-
virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
- bool useQuickReject) {
+ bool useQuickReject) override {
// default behavior only affects immediate, deferrable state, issue directly to renderer
applyState(deferStruct.mRenderer, saveCount);
}
@@ -105,7 +96,7 @@ public:
* list to flush
*/
virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
- bool useQuickReject) {
+ bool useQuickReject) override {
applyState(replayStruct.mRenderer, saveCount);
}
@@ -119,7 +110,7 @@ public:
: mPaint(paint), mQuickRejected(false) {}
virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
- bool useQuickReject) {
+ bool useQuickReject) override {
if (mQuickRejected && CC_LIKELY(useQuickReject)) {
return;
}
@@ -128,15 +119,15 @@ public:
}
virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
- bool useQuickReject) {
+ bool useQuickReject) override {
if (mQuickRejected && CC_LIKELY(useQuickReject)) {
return;
}
- replayStruct.mDrawGlStatus |= applyDraw(replayStruct.mRenderer, replayStruct.mDirty);
+ applyDraw(replayStruct.mRenderer, replayStruct.mDirty);
}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) = 0;
+ virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) = 0;
/**
* Draw multiple instances of an operation, must be overidden for operations that merge
@@ -145,14 +136,12 @@ public:
* and pure translation transformations. Other guarantees of similarity should be enforced by
* reducing which operations are tagged as mergeable.
*/
- virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
+ virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty,
const Vector<OpStatePair>& ops, const Rect& bounds) {
- status_t status = DrawGlInfo::kStatusDone;
for (unsigned int i = 0; i < ops.size(); i++) {
renderer.restoreDisplayState(*(ops[i].state), true);
- status |= ops[i].op->applyDraw(renderer, dirty);
+ ops[i].op->applyDraw(renderer, dirty);
}
- return status;
}
/**
@@ -199,10 +188,6 @@ public:
}
protected:
- const SkPaint* getPaint(OpenGLRenderer& renderer) {
- return renderer.filterPaint(mPaint);
- }
-
// 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) {
@@ -219,7 +204,7 @@ protected:
if (mPaint->getShader() && !mPaint->getShader()->isOpaque()) {
return false;
}
- if (Renderer::isBlendedColorFilter(mPaint->getColorFilter())) {
+ if (PaintUtils::isBlendedColorFilter(mPaint->getColorFilter())) {
return false;
}
}
@@ -232,7 +217,7 @@ protected:
}
- const SkPaint* mPaint; // should be accessed via getPaint() when applying
+ const SkPaint* mPaint;
bool mQuickRejected;
};
@@ -260,7 +245,7 @@ public:
// default empty constructor for bounds, to be overridden in child constructor body
DrawBoundedOp(const SkPaint* paint): DrawOp(paint) { }
- virtual bool getLocalBounds(Rect& localBounds) {
+ virtual bool getLocalBounds(Rect& localBounds) override {
localBounds.set(mLocalBounds);
OpenGLRenderer::TextShadow textShadow;
if (OpenGLRenderer::getTextShadow(mPaint, &textShadow)) {
@@ -287,20 +272,20 @@ public:
: mFlags(flags) {}
virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
- bool useQuickReject) {
+ bool useQuickReject) override {
int newSaveCount = deferStruct.mRenderer.save(mFlags);
deferStruct.mDeferredList.addSave(deferStruct.mRenderer, this, newSaveCount);
}
- virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
renderer.save(mFlags);
}
- virtual void output(int level, uint32_t logFlags) const {
+ virtual void output(int level, uint32_t logFlags) const override {
OP_LOG("Save flags %x", mFlags);
}
- virtual const char* name() { return "Save"; }
+ virtual const char* name() override { return "Save"; }
int getFlags() const { return mFlags; }
private:
@@ -313,21 +298,21 @@ public:
: mCount(count) {}
virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
- bool useQuickReject) {
+ bool useQuickReject) override {
deferStruct.mDeferredList.addRestoreToCount(deferStruct.mRenderer,
this, saveCount + mCount);
deferStruct.mRenderer.restoreToCount(saveCount + mCount);
}
- virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
renderer.restoreToCount(saveCount + mCount);
}
- virtual void output(int level, uint32_t logFlags) const {
+ virtual void output(int level, uint32_t logFlags) const override {
OP_LOG("Restore to count %d", mCount);
}
- virtual const char* name() { return "RestoreToCount"; }
+ virtual const char* name() override { return "RestoreToCount"; }
private:
int mCount;
@@ -339,7 +324,7 @@ public:
: mArea(left, top, right, bottom)
, mPaint(&mCachedPaint)
, mFlags(flags)
- , mConvexMask(NULL) {
+ , mConvexMask(nullptr) {
mCachedPaint.setAlpha(alpha);
}
@@ -347,11 +332,11 @@ public:
: mArea(left, top, right, bottom)
, mPaint(paint)
, mFlags(flags)
- , mConvexMask(NULL)
+ , mConvexMask(nullptr)
{}
virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
- bool useQuickReject) {
+ 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);
@@ -362,17 +347,19 @@ public:
mPaint, mFlags);
}
- virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+ 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 {
+ 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() { return isSaveLayerAlpha() ? "SaveLayerAlpha" : "SaveLayer"; }
+ virtual const char* name() override {
+ return isSaveLayerAlpha() ? "SaveLayerAlpha" : "SaveLayer";
+ }
int getFlags() { return mFlags; }
@@ -403,15 +390,15 @@ public:
TranslateOp(float dx, float dy)
: mDx(dx), mDy(dy) {}
- virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
renderer.translate(mDx, mDy);
}
- virtual void output(int level, uint32_t logFlags) const {
+ virtual void output(int level, uint32_t logFlags) const override {
OP_LOG("Translate by %f %f", mDx, mDy);
}
- virtual const char* name() { return "Translate"; }
+ virtual const char* name() override { return "Translate"; }
private:
float mDx;
@@ -423,15 +410,15 @@ public:
RotateOp(float degrees)
: mDegrees(degrees) {}
- virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
renderer.rotate(mDegrees);
}
- virtual void output(int level, uint32_t logFlags) const {
+ virtual void output(int level, uint32_t logFlags) const override {
OP_LOG("Rotate by %f degrees", mDegrees);
}
- virtual const char* name() { return "Rotate"; }
+ virtual const char* name() override { return "Rotate"; }
private:
float mDegrees;
@@ -442,15 +429,15 @@ public:
ScaleOp(float sx, float sy)
: mSx(sx), mSy(sy) {}
- virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
renderer.scale(mSx, mSy);
}
- virtual void output(int level, uint32_t logFlags) const {
+ virtual void output(int level, uint32_t logFlags) const override {
OP_LOG("Scale by %f %f", mSx, mSy);
}
- virtual const char* name() { return "Scale"; }
+ virtual const char* name() override { return "Scale"; }
private:
float mSx;
@@ -462,15 +449,15 @@ public:
SkewOp(float sx, float sy)
: mSx(sx), mSy(sy) {}
- virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
renderer.skew(mSx, mSy);
}
- virtual void output(int level, uint32_t logFlags) const {
+ virtual void output(int level, uint32_t logFlags) const override {
OP_LOG("Skew by %f %f", mSx, mSy);
}
- virtual const char* name() { return "Skew"; }
+ virtual const char* name() override { return "Skew"; }
private:
float mSx;
@@ -482,11 +469,11 @@ public:
SetMatrixOp(const SkMatrix& matrix)
: mMatrix(matrix) {}
- virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
renderer.setMatrix(mMatrix);
}
- virtual void output(int level, uint32_t logFlags) const {
+ virtual void output(int level, uint32_t logFlags) const override {
if (mMatrix.isIdentity()) {
OP_LOGS("SetMatrix (reset)");
} else {
@@ -494,7 +481,7 @@ public:
}
}
- virtual const char* name() { return "SetMatrix"; }
+ virtual const char* name() override { return "SetMatrix"; }
private:
const SkMatrix mMatrix;
@@ -505,15 +492,15 @@ public:
ConcatMatrixOp(const SkMatrix& matrix)
: mMatrix(matrix) {}
- virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
renderer.concatMatrix(mMatrix);
}
- virtual void output(int level, uint32_t logFlags) const {
+ virtual void output(int level, uint32_t logFlags) const override {
OP_LOG("ConcatMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(&mMatrix));
}
- virtual const char* name() { return "ConcatMatrix"; }
+ virtual const char* name() override { return "ConcatMatrix"; }
private:
const SkMatrix mMatrix;
@@ -524,7 +511,7 @@ public:
ClipOp(SkRegion::Op op) : mOp(op) {}
virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
- bool useQuickReject) {
+ bool useQuickReject) override {
// NOTE: must defer op BEFORE applying state, since it may read clip
deferStruct.mDeferredList.addClip(deferStruct.mRenderer, this);
@@ -547,18 +534,18 @@ 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 {
+ 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 {
+ virtual void output(int level, uint32_t logFlags) const override {
OP_LOG("ClipRect " RECT_STRING, RECT_ARGS(mArea));
}
- virtual const char* name() { return "ClipRect"; }
+ virtual const char* name() override { return "ClipRect"; }
protected:
- virtual bool isRect() { return true; }
+ virtual bool isRect() override { return true; }
private:
Rect mArea;
@@ -569,17 +556,17 @@ public:
ClipPathOp(const SkPath* path, SkRegion::Op op)
: ClipOp(op), mPath(path) {}
- virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
renderer.clipPath(mPath, mOp);
}
- virtual void output(int level, uint32_t logFlags) const {
+ 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() { return "ClipPath"; }
+ virtual const char* name() override { return "ClipPath"; }
private:
const SkPath* mPath;
@@ -590,55 +577,22 @@ public:
ClipRegionOp(const SkRegion* region, SkRegion::Op op)
: ClipOp(op), mRegion(region) {}
- virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
+ virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override {
renderer.clipRegion(mRegion, mOp);
}
- virtual void output(int level, uint32_t logFlags) const {
+ 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() { return "ClipRegion"; }
+ virtual const char* name() override { return "ClipRegion"; }
private:
const SkRegion* mRegion;
};
-class ResetPaintFilterOp : public StateOp {
-public:
- virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
- renderer.resetPaintFilter();
- }
-
- virtual void output(int level, uint32_t logFlags) const {
- OP_LOGS("ResetPaintFilter");
- }
-
- virtual const char* name() { return "ResetPaintFilter"; }
-};
-
-class SetupPaintFilterOp : public StateOp {
-public:
- SetupPaintFilterOp(int clearBits, int setBits)
- : mClearBits(clearBits), mSetBits(setBits) {}
-
- virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
- renderer.setupPaintFilter(mClearBits, mSetBits);
- }
-
- virtual void output(int level, uint32_t logFlags) const {
- OP_LOG("SetupPaintFilter, clear %#x, set %#x", mClearBits, mSetBits);
- }
-
- virtual const char* name() { return "SetupPaintFilter"; }
-
-private:
- int mClearBits;
- int mSetBits;
-};
-
///////////////////////////////////////////////////////////////////////////////
// DRAW OPERATIONS - these are operations that can draw to the canvas's device
///////////////////////////////////////////////////////////////////////////////
@@ -648,11 +602,11 @@ public:
DrawBitmapOp(const SkBitmap* bitmap, const SkPaint* paint)
: DrawBoundedOp(0, 0, bitmap->width(), bitmap->height(), paint)
, mBitmap(bitmap)
- , mEntryValid(false), mEntry(NULL) {
+ , mEntryValid(false), mEntry(nullptr) {
}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
- return renderer.drawBitmap(mBitmap, getPaint(renderer));
+ virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+ renderer.drawBitmap(mBitmap, mPaint);
}
AssetAtlas::Entry* getAtlasEntry(OpenGLRenderer& renderer) {
@@ -672,8 +626,8 @@ public:
* for each bitmap in the batch. This method is also responsible for dirtying
* the current layer, if any.
*/
- virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
- const Vector<OpStatePair>& ops, const Rect& bounds) {
+ virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty,
+ const Vector<OpStatePair>& ops, const Rect& bounds) override {
const DeferredDisplayState& firstState = *(ops[0].state);
renderer.restoreDisplayState(firstState, true); // restore all but the clip
@@ -709,19 +663,19 @@ public:
}
}
- return renderer.drawBitmaps(mBitmap, mEntry, ops.size(), &vertices[0],
+ renderer.drawBitmaps(mBitmap, mEntry, ops.size(), &vertices[0],
pureTranslate, bounds, mPaint);
}
- virtual void output(int level, uint32_t logFlags) const {
+ virtual void output(int level, uint32_t logFlags) const override {
OP_LOG("Draw bitmap %p at %f %f%s", mBitmap, mLocalBounds.left, mLocalBounds.top,
mEntry ? " using AssetAtlas" : "");
}
- virtual const char* name() { return "DrawBitmap"; }
+ virtual const char* name() override { return "DrawBitmap"; }
virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
- const DeferredDisplayState& state) {
+ const DeferredDisplayState& state) override {
deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
deferInfo.mergeId = getAtlasEntry(renderer) ?
(mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
@@ -757,21 +711,21 @@ public:
: DrawBoundedOp(dstLeft, dstTop, dstRight, dstBottom, paint),
mBitmap(bitmap), mSrc(srcLeft, srcTop, srcRight, srcBottom) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
- return renderer.drawBitmap(mBitmap, mSrc.left, mSrc.top, mSrc.right, mSrc.bottom,
+ virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+ renderer.drawBitmap(mBitmap, mSrc.left, mSrc.top, mSrc.right, mSrc.bottom,
mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
- getPaint(renderer));
+ mPaint);
}
- virtual void output(int level, uint32_t logFlags) const {
+ 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() { return "DrawBitmapRect"; }
+ virtual const char* name() override { return "DrawBitmapRect"; }
virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
- const DeferredDisplayState& state) {
+ const DeferredDisplayState& state) override {
deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
}
@@ -780,27 +734,6 @@ private:
Rect mSrc;
};
-class DrawBitmapDataOp : public DrawBitmapOp {
-public:
- DrawBitmapDataOp(const SkBitmap* bitmap, const SkPaint* paint)
- : DrawBitmapOp(bitmap, paint) {}
-
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
- return renderer.drawBitmapData(mBitmap, getPaint(renderer));
- }
-
- virtual void output(int level, uint32_t logFlags) const {
- OP_LOG("Draw bitmap %p", mBitmap);
- }
-
- virtual const char* name() { return "DrawBitmapData"; }
-
- virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
- const DeferredDisplayState& state) {
- deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
- }
-};
-
class DrawBitmapMeshOp : public DrawBoundedOp {
public:
DrawBitmapMeshOp(const SkBitmap* bitmap, int meshWidth, int meshHeight,
@@ -809,19 +742,19 @@ public:
mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight),
mVertices(vertices), mColors(colors) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
- return renderer.drawBitmapMesh(mBitmap, mMeshWidth, mMeshHeight,
- mVertices, mColors, getPaint(renderer));
+ 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 {
+ 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() { return "DrawBitmapMesh"; }
+ virtual const char* name() override { return "DrawBitmapMesh"; }
virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
- const DeferredDisplayState& state) {
+ const DeferredDisplayState& state) override {
deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
}
@@ -838,8 +771,8 @@ 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(NULL),
- mEntryValid(false), mEntry(NULL) {
+ mBitmap(bitmap), mPatch(patch), mGenerationId(0), mMesh(nullptr),
+ mEntryValid(false), mEntry(nullptr) {
};
AssetAtlas::Entry* getAtlasEntry(OpenGLRenderer& renderer) {
@@ -865,8 +798,8 @@ public:
* and transforming the vertices of each 9-patch in the batch. This method
* is also responsible for dirtying the current layer, if any.
*/
- virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
- const Vector<OpStatePair>& ops, const Rect& bounds) {
+ virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty,
+ const Vector<OpStatePair>& ops, const Rect& bounds) override {
const DeferredDisplayState& firstState = *(ops[0].state);
renderer.restoreDisplayState(firstState, true); // restore all but the clip
@@ -905,7 +838,7 @@ public:
patchOp->mLocalBounds.top + 0.5f);
// Copy & transform all the vertices for the current operation
- TextureVertex* opVertices = opMesh->vertices;
+ TextureVertex* opVertices = opMesh->vertices.get();
for (uint32_t j = 0; j < vertexCount; j++, opVertices++) {
TextureVertex::set(vertex++,
opVertices->x + tx, opVertices->y + ty,
@@ -935,27 +868,27 @@ public:
indexCount += opMesh->indexCount;
}
- return renderer.drawPatches(mBitmap, getAtlasEntry(renderer),
- &vertices[0], indexCount, getPaint(renderer));
+ renderer.drawPatches(mBitmap, getAtlasEntry(renderer),
+ &vertices[0], indexCount, mPaint);
}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
+ 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
- return renderer.drawPatch(mBitmap, getMesh(renderer), getAtlasEntry(renderer),
+ renderer.drawPatch(mBitmap, getMesh(renderer), getAtlasEntry(renderer),
mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
- getPaint(renderer));
+ mPaint);
}
- virtual void output(int level, uint32_t logFlags) const {
+ 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() { return "DrawPatch"; }
+ virtual const char* name() override { return "DrawPatch"; }
virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
- const DeferredDisplayState& state) {
+ 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() &&
@@ -977,17 +910,17 @@ private:
class DrawColorOp : public DrawOp {
public:
DrawColorOp(int color, SkXfermode::Mode mode)
- : DrawOp(NULL), mColor(color), mMode(mode) {};
+ : DrawOp(nullptr), mColor(color), mMode(mode) {};
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
- return renderer.drawColor(mColor, mMode);
+ virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+ renderer.drawColor(mColor, mMode);
}
- virtual void output(int level, uint32_t logFlags) const {
+ virtual void output(int level, uint32_t logFlags) const override {
OP_LOG("Draw color %#x, mode %d", mColor, mMode);
}
- virtual const char* name() { return "DrawColor"; }
+ virtual const char* name() override { return "DrawColor"; }
private:
int mColor;
@@ -1001,7 +934,7 @@ public:
DrawStrokableOp(const Rect& localBounds, const SkPaint* paint)
: DrawBoundedOp(localBounds, paint) {};
- virtual bool getLocalBounds(Rect& localBounds) {
+ virtual bool getLocalBounds(Rect& localBounds) override {
localBounds.set(mLocalBounds);
if (mPaint && mPaint->getStyle() != SkPaint::kFill_Style) {
localBounds.outset(strokeWidthOutset());
@@ -1010,7 +943,7 @@ public:
}
virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
- const DeferredDisplayState& state) {
+ const DeferredDisplayState& state) override {
if (mPaint->getPathEffect()) {
deferInfo.batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
} else {
@@ -1026,23 +959,23 @@ public:
DrawRectOp(float left, float top, float right, float bottom, const SkPaint* paint)
: DrawStrokableOp(left, top, right, bottom, paint) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
- return renderer.drawRect(mLocalBounds.left, mLocalBounds.top,
- mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
+ 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 {
+ 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) {
+ const DeferredDisplayState& state) override {
DrawStrokableOp::onDefer(renderer, deferInfo, state);
deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) &&
mPaint->getStyle() == SkPaint::kFill_Style;
}
- virtual const char* name() { return "DrawRect"; }
+ virtual const char* name() override { return "DrawRect"; }
};
class DrawRectsOp : public DrawBoundedOp {
@@ -1051,18 +984,18 @@ public:
: DrawBoundedOp(rects, count, paint),
mRects(rects), mCount(count) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
- return renderer.drawRects(mRects, mCount, getPaint(renderer));
+ virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+ renderer.drawRects(mRects, mCount, mPaint);
}
- virtual void output(int level, uint32_t logFlags) const {
+ virtual void output(int level, uint32_t logFlags) const override {
OP_LOG("Draw Rects count %d", mCount);
}
- virtual const char* name() { return "DrawRects"; }
+ virtual const char* name() override { return "DrawRects"; }
virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
- const DeferredDisplayState& state) {
+ const DeferredDisplayState& state) override {
deferInfo.batchId = DeferredDisplayList::kOpBatch_Vertices;
}
@@ -1077,17 +1010,17 @@ public:
float rx, float ry, const SkPaint* paint)
: DrawStrokableOp(left, top, right, bottom, paint), mRx(rx), mRy(ry) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
- return renderer.drawRoundRect(mLocalBounds.left, mLocalBounds.top,
- mLocalBounds.right, mLocalBounds.bottom, mRx, mRy, getPaint(renderer));
+ 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 {
+ 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) {
+ const DeferredDisplayState& state) override {
DrawStrokableOp::onDefer(renderer, deferInfo, state);
if (!mPaint->getPathEffect()) {
renderer.getCaches().tessellationCache.precacheRoundRect(state.mMatrix, *mPaint,
@@ -1095,7 +1028,7 @@ public:
}
}
- virtual const char* name() { return "DrawRoundRect"; }
+ virtual const char* name() override { return "DrawRoundRect"; }
private:
float mRx;
@@ -1109,17 +1042,17 @@ public:
: DrawOp(paint), mLeft(left), mTop(top), mRight(right), mBottom(bottom),
mRx(rx), mRy(ry) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
- return renderer.drawRoundRect(*mLeft, *mTop, *mRight, *mBottom,
- *mRx, *mRy, getPaint(renderer));
+ 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 {
+ 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() { return "DrawRoundRectProps"; }
+ virtual const char* name() override { return "DrawRoundRectProps"; }
private:
float* mLeft;
@@ -1136,15 +1069,15 @@ public:
: DrawStrokableOp(x - radius, y - radius, x + radius, y + radius, paint),
mX(x), mY(y), mRadius(radius) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
- return renderer.drawCircle(mX, mY, mRadius, getPaint(renderer));
+ virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+ renderer.drawCircle(mX, mY, mRadius, mPaint);
}
- virtual void output(int level, uint32_t logFlags) const {
+ 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() { return "DrawCircle"; }
+ virtual const char* name() override { return "DrawCircle"; }
private:
float mX;
@@ -1157,15 +1090,15 @@ public:
DrawCirclePropsOp(float* x, float* y, float* radius, const SkPaint* paint)
: DrawOp(paint), mX(x), mY(y), mRadius(radius) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
- return renderer.drawCircle(*mX, *mY, *mRadius, getPaint(renderer));
+ virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+ renderer.drawCircle(*mX, *mY, *mRadius, mPaint);
}
- virtual void output(int level, uint32_t logFlags) const {
+ 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() { return "DrawCircleProps"; }
+ virtual const char* name() override { return "DrawCircleProps"; }
private:
float* mX;
@@ -1178,16 +1111,16 @@ public:
DrawOvalOp(float left, float top, float right, float bottom, const SkPaint* paint)
: DrawStrokableOp(left, top, right, bottom, paint) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
- return renderer.drawOval(mLocalBounds.left, mLocalBounds.top,
- mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
+ 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 {
+ virtual void output(int level, uint32_t logFlags) const override {
OP_LOG("Draw Oval " RECT_STRING, RECT_ARGS(mLocalBounds));
}
- virtual const char* name() { return "DrawOval"; }
+ virtual const char* name() override { return "DrawOval"; }
};
class DrawArcOp : public DrawStrokableOp {
@@ -1197,18 +1130,18 @@ public:
: DrawStrokableOp(left, top, right, bottom, paint),
mStartAngle(startAngle), mSweepAngle(sweepAngle), mUseCenter(useCenter) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
- return renderer.drawArc(mLocalBounds.left, mLocalBounds.top,
+ virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+ renderer.drawArc(mLocalBounds.left, mLocalBounds.top,
mLocalBounds.right, mLocalBounds.bottom,
- mStartAngle, mSweepAngle, mUseCenter, getPaint(renderer));
+ mStartAngle, mSweepAngle, mUseCenter, mPaint);
}
- virtual void output(int level, uint32_t logFlags) const {
+ 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() { return "DrawArc"; }
+ virtual const char* name() override { return "DrawArc"; }
private:
float mStartAngle;
@@ -1228,23 +1161,22 @@ public:
mLocalBounds.set(left, top, left + width, top + height);
}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
- return renderer.drawPath(mPath, getPaint(renderer));
+ virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+ renderer.drawPath(mPath, mPaint);
}
virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
- const DeferredDisplayState& state) {
- const SkPaint* paint = getPaint(renderer);
- renderer.getCaches().pathCache.precache(mPath, paint);
+ const DeferredDisplayState& state) override {
+ renderer.getCaches().pathCache.precache(mPath, mPaint);
deferInfo.batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
}
- virtual void output(int level, uint32_t logFlags) const {
+ 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() { return "DrawPath"; }
+ virtual const char* name() override { return "DrawPath"; }
private:
const SkPath* mPath;
@@ -1258,18 +1190,18 @@ public:
mLocalBounds.outset(strokeWidthOutset());
}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
- return renderer.drawLines(mPoints, mCount, getPaint(renderer));
+ virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+ renderer.drawLines(mPoints, mCount, mPaint);
}
- virtual void output(int level, uint32_t logFlags) const {
+ virtual void output(int level, uint32_t logFlags) const override {
OP_LOG("Draw Lines count %d", mCount);
}
- virtual const char* name() { return "DrawLines"; }
+ virtual const char* name() override { return "DrawLines"; }
virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
- const DeferredDisplayState& state) {
+ const DeferredDisplayState& state) override {
deferInfo.batchId = mPaint->isAntiAlias() ?
DeferredDisplayList::kOpBatch_AlphaVertices :
DeferredDisplayList::kOpBatch_Vertices;
@@ -1285,15 +1217,15 @@ public:
DrawPointsOp(const float* points, int count, const SkPaint* paint)
: DrawLinesOp(points, count, paint) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
- return renderer.drawPoints(mPoints, mCount, getPaint(renderer));
+ virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+ renderer.drawPoints(mPoints, mCount, mPaint);
}
- virtual void output(int level, uint32_t logFlags) const {
+ virtual void output(int level, uint32_t logFlags) const override {
OP_LOG("Draw Points count %d", mCount);
}
- virtual const char* name() { return "DrawPoints"; }
+ virtual const char* name() override { return "DrawPoints"; }
};
class DrawSomeTextOp : public DrawOp {
@@ -1301,19 +1233,18 @@ public:
DrawSomeTextOp(const char* 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 {
+ virtual void output(int level, uint32_t logFlags) const override {
OP_LOG("Draw some text, %d bytes", mBytesCount);
}
- virtual bool hasTextShadow() const {
+ virtual bool hasTextShadow() const override {
return OpenGLRenderer::hasTextShadow(mPaint);
}
virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
- const DeferredDisplayState& state) {
- const SkPaint* paint = getPaint(renderer);
- FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
- fontRenderer.precache(paint, mText, mCount, SkMatrix::I());
+ const DeferredDisplayState& state) override {
+ FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(mPaint);
+ fontRenderer.precache(mPaint, mText, mCount, SkMatrix::I());
deferInfo.batchId = mPaint->getColor() == SK_ColorBLACK ?
DeferredDisplayList::kOpBatch_Text :
@@ -1335,12 +1266,12 @@ public:
/* TODO: inherit from DrawBounded and init mLocalBounds */
}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
- return renderer.drawTextOnPath(mText, mBytesCount, mCount, mPath,
- mHOffset, mVOffset, getPaint(renderer));
+ virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+ renderer.drawTextOnPath(mText, mBytesCount, mCount, mPath,
+ mHOffset, mVOffset, mPaint);
}
- virtual const char* name() { return "DrawTextOnPath"; }
+ virtual const char* name() override { return "DrawTextOnPath"; }
private:
const SkPath* mPath;
@@ -1356,11 +1287,11 @@ public:
/* TODO: inherit from DrawBounded and init mLocalBounds */
}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
- return renderer.drawPosText(mText, mBytesCount, mCount, mPositions, getPaint(renderer));
+ virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+ renderer.drawPosText(mText, mBytesCount, mCount, mPositions, mPaint);
}
- virtual const char* name() { return "DrawPosText"; }
+ virtual const char* name() override { return "DrawPosText"; }
private:
const float* mPositions;
@@ -1376,13 +1307,12 @@ public:
}
virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
- const DeferredDisplayState& state) {
- const SkPaint* paint = getPaint(renderer);
- FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
+ const DeferredDisplayState& state) override {
+ FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(mPaint);
SkMatrix transform;
renderer.findBestFontTransform(state.mMatrix, &transform);
if (mPrecacheTransform != transform) {
- fontRenderer.precache(paint, mText, mCount, transform);
+ fontRenderer.precache(mPaint, mText, mCount, transform);
mPrecacheTransform = transform;
}
deferInfo.batchId = mPaint->getColor() == SK_ColorBLACK ?
@@ -1400,16 +1330,15 @@ public:
&& OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode;
}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
+ virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
Rect bounds;
getLocalBounds(bounds);
- return renderer.drawText(mText, mBytesCount, mCount, mX, mY,
- mPositions, getPaint(renderer), mTotalAdvance, bounds);
+ renderer.drawText(mText, mBytesCount, mCount, mX, mY,
+ mPositions, mPaint, mTotalAdvance, bounds);
}
- virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
- const Vector<OpStatePair>& ops, const Rect& bounds) {
- status_t status = DrawGlInfo::kStatusDone;
+ virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty,
+ const 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) ? kDrawOpMode_Flush : kDrawOpMode_Defer;
@@ -1418,18 +1347,17 @@ public:
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()
- status |= renderer.drawText(op.mText, op.mBytesCount, op.mCount, op.mX, op.mY,
- op.mPositions, op.getPaint(renderer), op.mTotalAdvance, op.mLocalBounds,
+ renderer.drawText(op.mText, op.mBytesCount, op.mCount, op.mX, op.mY,
+ op.mPositions, op.mPaint, op.mTotalAdvance, op.mLocalBounds,
drawOpMode);
}
- return status;
}
- virtual void output(int level, uint32_t logFlags) const {
+ 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() { return "DrawText"; }
+ virtual const char* name() override { return "DrawText"; }
private:
const char* mText;
@@ -1449,20 +1377,19 @@ private:
class DrawFunctorOp : public DrawOp {
public:
DrawFunctorOp(Functor* functor)
- : DrawOp(NULL), mFunctor(functor) {}
+ : DrawOp(nullptr), mFunctor(functor) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
+ virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
renderer.startMark("GL functor");
- status_t ret = renderer.callDrawGLFunction(mFunctor, dirty);
+ renderer.callDrawGLFunction(mFunctor, dirty);
renderer.endMark();
- return ret;
}
- virtual void output(int level, uint32_t logFlags) const {
+ virtual void output(int level, uint32_t logFlags) const override {
OP_LOG("Draw Functor %p", mFunctor);
}
- virtual const char* name() { return "DrawFunctor"; }
+ virtual const char* name() override { return "DrawFunctor"; }
private:
Functor* mFunctor;
@@ -1473,36 +1400,35 @@ class DrawRenderNodeOp : public DrawBoundedOp {
friend class DisplayListData; // grant DisplayListData access to info of child
public:
DrawRenderNodeOp(RenderNode* renderNode, int flags, const mat4& transformFromParent)
- : DrawBoundedOp(0, 0, renderNode->getWidth(), renderNode->getHeight(), 0),
+ : DrawBoundedOp(0, 0, renderNode->getWidth(), renderNode->getHeight(), nullptr),
mRenderNode(renderNode), mFlags(flags), mTransformFromParent(transformFromParent) {}
virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
- bool useQuickReject) {
+ bool useQuickReject) override {
if (mRenderNode->isRenderable() && !mSkipInOrderDraw) {
mRenderNode->defer(deferStruct, level + 1);
}
}
virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
- bool useQuickReject) {
+ bool useQuickReject) override {
if (mRenderNode->isRenderable() && !mSkipInOrderDraw) {
mRenderNode->replay(replayStruct, level + 1);
}
}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
+ virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
LOG_ALWAYS_FATAL("should not be called, because replay() is overridden");
- return 0;
}
- virtual void output(int level, uint32_t logFlags) const {
+ virtual void output(int level, uint32_t logFlags) const override {
OP_LOG("Draw RenderNode %p %s, flags %#x", mRenderNode, mRenderNode->getName(), mFlags);
if (mRenderNode && (logFlags & kOpLogFlag_Recurse)) {
mRenderNode->output(level + 1);
}
}
- virtual const char* name() { return "DrawRenderNode"; }
+ virtual const char* name() override { return "DrawRenderNode"; }
RenderNode* renderNode() { return mRenderNode; }
@@ -1537,7 +1463,7 @@ class DrawShadowOp : public DrawOp {
public:
DrawShadowOp(const mat4& transformXY, const mat4& transformZ,
float casterAlpha, const SkPath* casterOutline)
- : DrawOp(NULL)
+ : DrawOp(nullptr)
, mTransformXY(transformXY)
, mTransformZ(transformZ)
, mCasterAlpha(casterAlpha)
@@ -1545,13 +1471,13 @@ public:
}
virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
- const DeferredDisplayState& state) {
+ const DeferredDisplayState& state) override {
renderer.getCaches().tessellationCache.precacheShadows(&state.mMatrix,
renderer.getLocalClipBounds(), isCasterOpaque(), mCasterOutline,
&mTransformXY, &mTransformZ, renderer.getLightCenter(), renderer.getLightRadius());
}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
+ virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
TessellationCache::vertexBuffer_pair_t buffers;
Matrix4 drawTransform(*(renderer.currentTransform()));
renderer.getCaches().tessellationCache.getShadowBuffers(&drawTransform,
@@ -1559,14 +1485,14 @@ public:
&mTransformXY, &mTransformZ, renderer.getLightCenter(), renderer.getLightRadius(),
buffers);
- return renderer.drawShadow(mCasterAlpha, buffers.first, buffers.second);
+ renderer.drawShadow(mCasterAlpha, buffers.first, buffers.second);
}
- virtual void output(int level, uint32_t logFlags) const {
+ virtual void output(int level, uint32_t logFlags) const override {
OP_LOGS("DrawShadow");
}
- virtual const char* name() { return "DrawShadow"; }
+ virtual const char* name() override { return "DrawShadow"; }
private:
bool isCasterOpaque() { return mCasterAlpha >= 1.0f; }
@@ -1580,17 +1506,17 @@ private:
class DrawLayerOp : public DrawOp {
public:
DrawLayerOp(Layer* layer, float x, float y)
- : DrawOp(NULL), mLayer(layer), mX(x), mY(y) {}
+ : DrawOp(nullptr), mLayer(layer), mX(x), mY(y) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
- return renderer.drawLayer(mLayer, mX, mY);
+ virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
+ renderer.drawLayer(mLayer, mX, mY);
}
- virtual void output(int level, uint32_t logFlags) const {
+ virtual void output(int level, uint32_t logFlags) const override {
OP_LOG("Draw Layer %p at %f %f", mLayer, mX, mY);
}
- virtual const char* name() { return "DrawLayer"; }
+ virtual const char* name() override { return "DrawLayer"; }
private:
Layer* mLayer;
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 42ac07e..23181bc 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -24,19 +24,21 @@
#include "ResourceCache.h"
#include "DeferredDisplayList.h"
#include "DeferredLayerUpdater.h"
-#include "DisplayListLogBuffer.h"
#include "DisplayListOp.h"
#include "DisplayListRenderer.h"
#include "RenderNode.h"
+#include "utils/PaintUtils.h"
namespace android {
namespace uirenderer {
DisplayListRenderer::DisplayListRenderer()
- : mResourceCache(ResourceCache::getInstance())
- , mDisplayListData(NULL)
+ : mState(*this)
+ , mResourceCache(ResourceCache::getInstance())
+ , mDisplayListData(nullptr)
, mTranslateX(0.0f)
, mTranslateY(0.0f)
+ , mHasDeferredTranslate(false)
, mDeferredBarrierType(kBarrier_None)
, mHighContrastText(false)
, mRestoreSaveCount(-1) {
@@ -56,29 +58,29 @@ DisplayListData* DisplayListRenderer::finishRecording() {
mRegionMap.clear();
mPathMap.clear();
DisplayListData* data = mDisplayListData;
- mDisplayListData = 0;
+ mDisplayListData = nullptr;
+ mSkiaCanvasProxy.reset(nullptr);
return data;
}
-status_t DisplayListRenderer::prepareDirty(float left, float top,
- float right, float bottom, bool opaque) {
+void DisplayListRenderer::prepareDirty(float left, float top,
+ float right, float bottom) {
LOG_ALWAYS_FATAL_IF(mDisplayListData,
"prepareDirty called a second time during a recording!");
mDisplayListData = new DisplayListData();
- initializeSaveStack(0, 0, getWidth(), getHeight(), Vector3());
+ mState.initializeSaveStack(0, 0, mState.getWidth(), mState.getHeight(), Vector3());
mDeferredBarrierType = kBarrier_InOrder;
- mDirtyClip = opaque;
+ mState.setDirtyClip(false);
mRestoreSaveCount = -1;
-
- return DrawGlInfo::kStatusDone; // No invalidate needed at record-time
}
-void DisplayListRenderer::finish() {
+bool DisplayListRenderer::finish() {
flushRestoreToCount();
flushTranslate();
+ return false;
}
void DisplayListRenderer::interrupt() {
@@ -87,16 +89,24 @@ void DisplayListRenderer::interrupt() {
void DisplayListRenderer::resume() {
}
-status_t DisplayListRenderer::callDrawGLFunction(Functor *functor, Rect& dirty) {
+void DisplayListRenderer::callDrawGLFunction(Functor *functor, Rect& dirty) {
// Ignore dirty during recording, it matters only when we replay
addDrawOp(new (alloc()) DrawFunctorOp(functor));
mDisplayListData->functors.add(functor);
- return DrawGlInfo::kStatusDone; // No invalidate needed at record-time
}
-int DisplayListRenderer::save(int flags) {
- addStateOp(new (alloc()) SaveOp(flags));
- return StatefulBaseRenderer::save(flags);
+SkCanvas* DisplayListRenderer::asSkCanvas() {
+ LOG_ALWAYS_FATAL_IF(!mDisplayListData,
+ "attempting to get an SkCanvas when we are not recording!");
+ if (!mSkiaCanvasProxy) {
+ mSkiaCanvasProxy.reset(new SkiaCanvasProxy(this));
+ }
+ return mSkiaCanvasProxy.get();
+}
+
+int DisplayListRenderer::save(SkCanvas::SaveFlags flags) {
+ addStateOp(new (alloc()) SaveOp((int) flags));
+ return mState.save((int) flags);
}
void DisplayListRenderer::restore() {
@@ -107,179 +117,207 @@ void DisplayListRenderer::restore() {
mRestoreSaveCount--;
flushTranslate();
- StatefulBaseRenderer::restore();
+ mState.restore();
}
void DisplayListRenderer::restoreToCount(int saveCount) {
mRestoreSaveCount = saveCount;
flushTranslate();
- StatefulBaseRenderer::restoreToCount(saveCount);
+ mState.restoreToCount(saveCount);
}
int DisplayListRenderer::saveLayer(float left, float top, float right, float bottom,
- const SkPaint* paint, int flags) {
+ const SkPaint* paint, SkCanvas::SaveFlags flags) {
// force matrix/clip isolation for layer
flags |= SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag;
paint = refPaint(paint);
- addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, paint, flags));
- return StatefulBaseRenderer::save(flags);
+ addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, paint, (int) flags));
+ return mState.save((int) flags);
}
-void DisplayListRenderer::translate(float dx, float dy, float dz) {
- // ignore dz, not used at defer time
+void DisplayListRenderer::translate(float dx, float dy) {
mHasDeferredTranslate = true;
mTranslateX += dx;
mTranslateY += dy;
flushRestoreToCount();
- StatefulBaseRenderer::translate(dx, dy, dz);
+ mState.translate(dx, dy, 0.0f);
}
void DisplayListRenderer::rotate(float degrees) {
addStateOp(new (alloc()) RotateOp(degrees));
- StatefulBaseRenderer::rotate(degrees);
+ mState.rotate(degrees);
}
void DisplayListRenderer::scale(float sx, float sy) {
addStateOp(new (alloc()) ScaleOp(sx, sy));
- StatefulBaseRenderer::scale(sx, sy);
+ mState.scale(sx, sy);
}
void DisplayListRenderer::skew(float sx, float sy) {
addStateOp(new (alloc()) SkewOp(sx, sy));
- StatefulBaseRenderer::skew(sx, sy);
+ mState.skew(sx, sy);
}
void DisplayListRenderer::setMatrix(const SkMatrix& matrix) {
addStateOp(new (alloc()) SetMatrixOp(matrix));
- StatefulBaseRenderer::setMatrix(matrix);
+ mState.setMatrix(matrix);
}
-void DisplayListRenderer::concatMatrix(const SkMatrix& matrix) {
+void DisplayListRenderer::concat(const SkMatrix& matrix) {
addStateOp(new (alloc()) ConcatMatrixOp(matrix));
- StatefulBaseRenderer::concatMatrix(matrix);
+ mState.concatMatrix(matrix);
+}
+
+bool DisplayListRenderer::getClipBounds(SkRect* outRect) const {
+ Rect bounds = mState.getLocalClipBounds();
+ *outRect = SkRect::MakeLTRB(bounds.left, bounds.top, bounds.right, bounds.bottom);
+ return !(outRect->isEmpty());
+}
+
+bool DisplayListRenderer::quickRejectRect(float left, float top, float right, float bottom) const {
+ return mState.quickRejectConservative(left, top, right, bottom);
+}
+
+bool DisplayListRenderer::quickRejectPath(const SkPath& path) const {
+ SkRect bounds = path.getBounds();
+ return mState.quickRejectConservative(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
}
+
bool DisplayListRenderer::clipRect(float left, float top, float right, float bottom,
SkRegion::Op op) {
addStateOp(new (alloc()) ClipRectOp(left, top, right, bottom, op));
- return StatefulBaseRenderer::clipRect(left, top, right, bottom, op);
+ return mState.clipRect(left, top, right, bottom, op);
}
bool DisplayListRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
path = refPath(path);
addStateOp(new (alloc()) ClipPathOp(path, op));
- return StatefulBaseRenderer::clipPath(path, op);
+ return mState.clipPath(path, op);
}
bool DisplayListRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
region = refRegion(region);
addStateOp(new (alloc()) ClipRegionOp(region, op));
- return StatefulBaseRenderer::clipRegion(region, op);
+ return mState.clipRegion(region, op);
}
-status_t DisplayListRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty,
- int32_t flags) {
+void DisplayListRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t flags) {
LOG_ALWAYS_FATAL_IF(!renderNode, "missing rendernode");
// dirty is an out parameter and should not be recorded,
// it matters only when replaying the display list
- DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp(renderNode, flags, *currentTransform());
+ DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp(renderNode, flags, *mState.currentTransform());
addRenderNodeOp(op);
-
- return DrawGlInfo::kStatusDone;
}
-status_t DisplayListRenderer::drawLayer(DeferredLayerUpdater* layerHandle, float x, float y) {
+void DisplayListRenderer::drawLayer(DeferredLayerUpdater* layerHandle, float x, float y) {
// We ref the DeferredLayerUpdater due to its thread-safe ref-counting
// semantics.
mDisplayListData->ref(layerHandle);
addDrawOp(new (alloc()) DrawLayerOp(layerHandle->backingLayer(), x, y));
- return DrawGlInfo::kStatusDone;
}
-status_t DisplayListRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
+void DisplayListRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
bitmap = refBitmap(bitmap);
paint = refPaint(paint);
addDrawOp(new (alloc()) DrawBitmapOp(bitmap, paint));
- return DrawGlInfo::kStatusDone;
}
-status_t DisplayListRenderer::drawBitmap(const SkBitmap* bitmap, float srcLeft, float srcTop,
+void DisplayListRenderer::drawBitmap(const SkBitmap& bitmap, float left, float top,
+ const SkPaint* paint) {
+ save(SkCanvas::kMatrix_SaveFlag);
+ translate(left, top);
+ drawBitmap(&bitmap, paint);
+ restore();
+}
+
+void DisplayListRenderer::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))) {
+ // 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(SkCanvas::kMatrix_SaveFlag);
+ concat(matrix);
+ drawBitmap(&bitmap, paint);
+ restore();
+ }
+}
+
+void DisplayListRenderer::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()
+ && 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(SkCanvas::kMatrix_SaveFlag);
translate(dstLeft, dstTop);
- drawBitmap(bitmap, paint);
+ drawBitmap(&bitmap, paint);
restore();
} else {
- bitmap = refBitmap(bitmap);
paint = refPaint(paint);
- addDrawOp(new (alloc()) DrawBitmapRectOp(bitmap,
+ addDrawOp(new (alloc()) DrawBitmapRectOp(refBitmap(&bitmap),
srcLeft, srcTop, srcRight, srcBottom,
dstLeft, dstTop, dstRight, dstBottom, paint));
}
- return DrawGlInfo::kStatusDone;
-}
-
-status_t DisplayListRenderer::drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint) {
- bitmap = refBitmapData(bitmap);
- paint = refPaint(paint);
-
- addDrawOp(new (alloc()) DrawBitmapDataOp(bitmap, paint));
- return DrawGlInfo::kStatusDone;
}
-status_t DisplayListRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
+void DisplayListRenderer::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
const float* vertices, const int* colors, const SkPaint* paint) {
int vertexCount = (meshWidth + 1) * (meshHeight + 1);
- bitmap = refBitmap(bitmap);
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(bitmap, meshWidth, meshHeight,
- vertices, colors, paint));
- return DrawGlInfo::kStatusDone;
+ addDrawOp(new (alloc()) DrawBitmapMeshOp(refBitmap(&bitmap), meshWidth, meshHeight,
+ vertices, colors, paint));
}
-status_t DisplayListRenderer::drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
+void DisplayListRenderer::drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
float left, float top, float right, float bottom, const SkPaint* paint) {
bitmap = refBitmap(bitmap);
patch = refPatch(patch);
paint = refPaint(paint);
addDrawOp(new (alloc()) DrawPatchOp(bitmap, patch, left, top, right, bottom, paint));
- return DrawGlInfo::kStatusDone;
}
-status_t DisplayListRenderer::drawColor(int color, SkXfermode::Mode mode) {
+void DisplayListRenderer::drawColor(int color, SkXfermode::Mode mode) {
addDrawOp(new (alloc()) DrawColorOp(color, mode));
- return DrawGlInfo::kStatusDone;
}
-status_t DisplayListRenderer::drawRect(float left, float top, float right, float bottom,
- const SkPaint* paint) {
- paint = refPaint(paint);
- addDrawOp(new (alloc()) DrawRectOp(left, top, right, bottom, paint));
- return DrawGlInfo::kStatusDone;
+void DisplayListRenderer::drawPaint(const SkPaint& paint) {
+ SkRect bounds;
+ if (getClipBounds(&bounds)) {
+ drawRect(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, paint);
+ }
}
-status_t DisplayListRenderer::drawRoundRect(float left, float top, float right, float bottom,
- float rx, float ry, const SkPaint* paint) {
- paint = refPaint(paint);
- addDrawOp(new (alloc()) DrawRoundRectOp(left, top, right, bottom, rx, ry, paint));
- return DrawGlInfo::kStatusDone;
+
+void DisplayListRenderer::drawRect(float left, float top, float right, float bottom,
+ const SkPaint& paint) {
+ addDrawOp(new (alloc()) DrawRectOp(left, top, right, bottom, refPaint(&paint)));
+}
+
+void DisplayListRenderer::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)));
}
-status_t DisplayListRenderer::drawRoundRect(
+void DisplayListRenderer::drawRoundRect(
CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top,
CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom,
CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry,
@@ -293,16 +331,13 @@ status_t DisplayListRenderer::drawRoundRect(
mDisplayListData->ref(paint);
addDrawOp(new (alloc()) DrawRoundRectPropsOp(&left->value, &top->value,
&right->value, &bottom->value, &rx->value, &ry->value, &paint->value));
- return DrawGlInfo::kStatusDone;
}
-status_t DisplayListRenderer::drawCircle(float x, float y, float radius, const SkPaint* paint) {
- paint = refPaint(paint);
- addDrawOp(new (alloc()) DrawCircleOp(x, y, radius, paint));
- return DrawGlInfo::kStatusDone;
+void DisplayListRenderer::drawCircle(float x, float y, float radius, const SkPaint& paint) {
+ addDrawOp(new (alloc()) DrawCircleOp(x, y, radius, refPaint(&paint)));
}
-status_t DisplayListRenderer::drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
+void DisplayListRenderer::drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) {
mDisplayListData->ref(x);
mDisplayListData->ref(y);
@@ -310,143 +345,121 @@ status_t DisplayListRenderer::drawCircle(CanvasPropertyPrimitive* x, CanvasPrope
mDisplayListData->ref(paint);
addDrawOp(new (alloc()) DrawCirclePropsOp(&x->value, &y->value,
&radius->value, &paint->value));
- return DrawGlInfo::kStatusDone;
}
-status_t DisplayListRenderer::drawOval(float left, float top, float right, float bottom,
- const SkPaint* paint) {
- paint = refPaint(paint);
- addDrawOp(new (alloc()) DrawOvalOp(left, top, right, bottom, paint));
- return DrawGlInfo::kStatusDone;
+void DisplayListRenderer::drawOval(float left, float top, float right, float bottom,
+ const SkPaint& paint) {
+ addDrawOp(new (alloc()) DrawOvalOp(left, top, right, bottom, refPaint(&paint)));
}
-status_t DisplayListRenderer::drawArc(float left, float top, float right, float bottom,
- float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint) {
+void DisplayListRenderer::drawArc(float left, float top, float right, float bottom,
+ float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
if (fabs(sweepAngle) >= 360.0f) {
- return drawOval(left, top, right, bottom, paint);
+ drawOval(left, top, right, bottom, paint);
+ } else {
+ addDrawOp(new (alloc()) DrawArcOp(left, top, right, bottom,
+ startAngle, sweepAngle, useCenter, refPaint(&paint)));
}
-
- paint = refPaint(paint);
- addDrawOp(new (alloc()) DrawArcOp(left, top, right, bottom,
- startAngle, sweepAngle, useCenter, paint));
- return DrawGlInfo::kStatusDone;
}
-status_t DisplayListRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
- path = refPath(path);
- paint = refPaint(paint);
-
- addDrawOp(new (alloc()) DrawPathOp(path, paint));
- return DrawGlInfo::kStatusDone;
+void DisplayListRenderer::drawPath(const SkPath& path, const SkPaint& paint) {
+ addDrawOp(new (alloc()) DrawPathOp(refPath(&path), refPaint(&paint)));
}
-status_t DisplayListRenderer::drawLines(const float* points, int count, const SkPaint* paint) {
+void DisplayListRenderer::drawLines(const float* points, int count, const SkPaint& paint) {
points = refBuffer<float>(points, count);
- paint = refPaint(paint);
- addDrawOp(new (alloc()) DrawLinesOp(points, count, paint));
- return DrawGlInfo::kStatusDone;
+ addDrawOp(new (alloc()) DrawLinesOp(points, count, refPaint(&paint)));
}
-status_t DisplayListRenderer::drawPoints(const float* points, int count, const SkPaint* paint) {
+void DisplayListRenderer::drawPoints(const float* points, int count, const SkPaint& paint) {
points = refBuffer<float>(points, count);
- paint = refPaint(paint);
- addDrawOp(new (alloc()) DrawPointsOp(points, count, paint));
- return DrawGlInfo::kStatusDone;
+ addDrawOp(new (alloc()) DrawPointsOp(points, count, refPaint(&paint)));
}
-status_t DisplayListRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
- const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) {
- if (!text || count <= 0) return DrawGlInfo::kStatusDone;
+void DisplayListRenderer::drawTextOnPath(const uint16_t* glyphs, int count,
+ const SkPath& path, float hOffset, float vOffset, const SkPaint& paint) {
+ if (!glyphs || count <= 0) return;
- text = refText(text, bytesCount);
- path = refPath(path);
- paint = refPaint(paint);
-
- DrawOp* op = new (alloc()) DrawTextOnPathOp(text, bytesCount, count, path,
- hOffset, vOffset, paint);
+ int bytesCount = 2 * count;
+ DrawOp* op = new (alloc()) DrawTextOnPathOp(refText((const char*) glyphs, bytesCount),
+ bytesCount, count, refPath(&path),
+ hOffset, vOffset, refPaint(&paint));
addDrawOp(op);
- return DrawGlInfo::kStatusDone;
}
-status_t DisplayListRenderer::drawPosText(const char* text, int bytesCount, int count,
- const float* positions, const SkPaint* paint) {
- if (!text || count <= 0) return DrawGlInfo::kStatusDone;
+void DisplayListRenderer::drawPosText(const uint16_t* text, const float* positions,
+ int count, int posCount, const SkPaint& paint) {
+ if (!text || count <= 0) return;
- text = refText(text, bytesCount);
+ int bytesCount = 2 * count;
positions = refBuffer<float>(positions, count * 2);
- paint = refPaint(paint);
- DrawOp* op = new (alloc()) DrawPosTextOp(text, bytesCount, count, positions, paint);
+ DrawOp* op = new (alloc()) DrawPosTextOp(refText((const char*) text, bytesCount),
+ bytesCount, count, positions, refPaint(&paint));
addDrawOp(op);
- return DrawGlInfo::kStatusDone;
}
static void simplifyPaint(int color, SkPaint* paint) {
paint->setColor(color);
- paint->setShader(NULL);
- paint->setColorFilter(NULL);
- paint->setLooper(NULL);
+ paint->setShader(nullptr);
+ paint->setColorFilter(nullptr);
+ paint->setLooper(nullptr);
paint->setStrokeWidth(4 + 0.04 * paint->getTextSize());
paint->setStrokeJoin(SkPaint::kRound_Join);
- paint->setLooper(NULL);
+ paint->setLooper(nullptr);
}
-status_t DisplayListRenderer::drawText(const char* text, int bytesCount, int count,
- float x, float y, const float* positions, const SkPaint* paint,
- float totalAdvance, const Rect& bounds, DrawOpMode drawOpMode) {
+void DisplayListRenderer::drawText(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 (!text || count <= 0 || paintWillNotDrawText(*paint)) return DrawGlInfo::kStatusDone;
+ if (!glyphs || count <= 0 || PaintUtils::paintWillNotDrawText(paint)) return;
- text = refText(text, bytesCount);
+ int bytesCount = count * 2;
+ const char* text = refText((const char*) glyphs, bytesCount);
positions = refBuffer<float>(positions, count * 2);
+ Rect bounds(boundsLeft, boundsTop, boundsRight, boundsBottom);
if (CC_UNLIKELY(mHighContrastText)) {
// high contrast draw path
- int color = paint->getColor();
+ int color = paint.getColor();
int channelSum = SkColorGetR(color) + SkColorGetG(color) + SkColorGetB(color);
bool darken = channelSum < (128 * 3);
// outline
- SkPaint* outlinePaint = copyPaint(paint);
+ SkPaint* outlinePaint = copyPaint(&paint);
simplifyPaint(darken ? SK_ColorWHITE : SK_ColorBLACK, outlinePaint);
outlinePaint->setStyle(SkPaint::kStrokeAndFill_Style);
addDrawOp(new (alloc()) DrawTextOp(text, bytesCount, count,
x, y, positions, outlinePaint, totalAdvance, bounds)); // bounds?
// inner
- SkPaint* innerPaint = copyPaint(paint);
+ SkPaint* innerPaint = copyPaint(&paint);
simplifyPaint(darken ? SK_ColorBLACK : SK_ColorWHITE, innerPaint);
innerPaint->setStyle(SkPaint::kFill_Style);
addDrawOp(new (alloc()) DrawTextOp(text, bytesCount, count,
x, y, positions, innerPaint, totalAdvance, bounds));
} else {
// standard draw path
- paint = refPaint(paint);
-
DrawOp* op = new (alloc()) DrawTextOp(text, bytesCount, count,
- x, y, positions, paint, totalAdvance, bounds);
+ x, y, positions, refPaint(&paint), totalAdvance, bounds);
addDrawOp(op);
}
- return DrawGlInfo::kStatusDone;
}
-status_t DisplayListRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
- if (count <= 0) return DrawGlInfo::kStatusDone;
+void DisplayListRenderer::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));
- return DrawGlInfo::kStatusDone;
-}
-
-void DisplayListRenderer::resetPaintFilter() {
- addStateOp(new (alloc()) ResetPaintFilterOp());
}
-void DisplayListRenderer::setupPaintFilter(int clearBits, int setBits) {
- addStateOp(new (alloc()) SetupPaintFilterOp(clearBits, setBits));
+void DisplayListRenderer::setDrawFilter(SkDrawFilter* filter) {
+ mDrawFilter.reset(filter);
}
void DisplayListRenderer::insertReorderBarrier(bool enableReorder) {
@@ -505,7 +518,7 @@ size_t DisplayListRenderer::addStateOp(StateOp* op) {
size_t DisplayListRenderer::addDrawOp(DrawOp* op) {
Rect localBounds;
if (op->getLocalBounds(localBounds)) {
- bool rejected = quickRejectConservative(localBounds.left, localBounds.top,
+ bool rejected = quickRejectRect(localBounds.left, localBounds.top,
localBounds.right, localBounds.bottom);
op->setQuickRejected(rejected);
}
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 2cc2be3..bd0b3b7 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -17,13 +17,20 @@
#ifndef ANDROID_HWUI_DISPLAY_LIST_RENDERER_H
#define ANDROID_HWUI_DISPLAY_LIST_RENDERER_H
+#include <SkDrawFilter.h>
#include <SkMatrix.h>
#include <SkPaint.h>
#include <SkPath.h>
+#include <SkRegion.h>
+#include <SkTLazy.h>
#include <cutils/compiler.h>
-#include "DisplayListLogBuffer.h"
+#include "Canvas.h"
+#include "CanvasState.h"
+#include "DisplayList.h"
+#include "SkiaCanvasProxy.h"
#include "RenderNode.h"
+#include "Renderer.h"
#include "ResourceCache.h"
namespace android {
@@ -48,13 +55,15 @@ class DeferredDisplayList;
class DeferredLayerUpdater;
class DisplayListRenderer;
class DisplayListOp;
+class DisplayListRenderer;
class DrawOp;
+class RenderNode;
class StateOp;
/**
* Records drawing commands in a display list for later playback into an OpenGLRenderer.
*/
-class ANDROID_API DisplayListRenderer: public StatefulBaseRenderer {
+class ANDROID_API DisplayListRenderer: public Canvas, public CanvasStateClient {
public:
DisplayListRenderer();
virtual ~DisplayListRenderer();
@@ -64,104 +73,178 @@ public:
DisplayListData* finishRecording();
// ----------------------------------------------------------------------------
-// Frame state operations
+// HWUI Frame state operations
// ----------------------------------------------------------------------------
- virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque);
- virtual void finish();
- virtual void interrupt();
- virtual void resume();
+
+ void prepareDirty(float left, float top, float right, float bottom);
+ void prepare() { prepareDirty(0.0f, 0.0f, width(), height()); }
+ bool finish();
+ void interrupt();
+ void resume();
// ----------------------------------------------------------------------------
-// Canvas state operations
+// HWUI Canvas state operations
// ----------------------------------------------------------------------------
- // Save (layer)
- virtual int save(int flags);
- virtual void restore();
- virtual void restoreToCount(int saveCount);
- virtual int saveLayer(float left, float top, float right, float bottom,
- const SkPaint* paint, int flags);
- // Matrix
- virtual void translate(float dx, float dy, float dz = 0.0f);
- virtual void rotate(float degrees);
- virtual void scale(float sx, float sy);
- virtual void skew(float sx, float sy);
-
- virtual void setMatrix(const SkMatrix& matrix);
- virtual void concatMatrix(const SkMatrix& matrix);
-
- // Clip
- virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
- virtual bool clipPath(const SkPath* path, SkRegion::Op op);
- virtual bool clipRegion(const SkRegion* region, SkRegion::Op op);
+ void setViewport(int width, int height) { mState.setViewport(width, height); }
- // Misc - should be implemented with SkPaint inspection
- virtual void resetPaintFilter();
- virtual void setupPaintFilter(int clearBits, int setBits);
+ const Rect& getRenderTargetClipBounds() const { return mState.getRenderTargetClipBounds(); }
bool isCurrentTransformSimple() {
- return currentTransform()->isSimple();
+ return mState.currentTransform()->isSimple();
}
// ----------------------------------------------------------------------------
-// Canvas draw operations
+// HWUI Canvas draw operations
// ----------------------------------------------------------------------------
- virtual status_t drawColor(int color, SkXfermode::Mode mode);
// Bitmap-based
- virtual status_t drawBitmap(const SkBitmap* bitmap, const SkPaint* paint);
- virtual status_t drawBitmap(const SkBitmap* bitmap, float srcLeft, float srcTop,
- float srcRight, float srcBottom, float dstLeft, float dstTop,
- float dstRight, float dstBottom, const SkPaint* paint);
- virtual status_t drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint);
- virtual status_t drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
- const float* vertices, const int* colors, const SkPaint* paint);
- virtual status_t drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
+ void drawBitmap(const SkBitmap* bitmap, const SkPaint* paint);
+ // TODO: move drawPatch() to Canvas.h
+ void drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
float left, float top, float right, float bottom, const SkPaint* paint);
// Shapes
- virtual status_t drawRect(float left, float top, float right, float bottom,
- const SkPaint* paint);
- virtual status_t drawRects(const float* rects, int count, const SkPaint* paint);
- virtual status_t drawRoundRect(float left, float top, float right, float bottom,
- float rx, float ry, const SkPaint* paint);
- virtual status_t drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top,
+ void drawRects(const float* rects, int count, const SkPaint* paint);
+ void drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top,
CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom,
CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry,
CanvasPropertyPaint* paint);
- virtual status_t drawCircle(float x, float y, float radius, const SkPaint* paint);
- virtual status_t drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
+ void drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint);
- virtual status_t drawOval(float left, float top, float right, float bottom,
- const SkPaint* paint);
- virtual status_t drawArc(float left, float top, float right, float bottom,
- float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint);
- virtual status_t drawPath(const SkPath* path, const SkPaint* paint);
- virtual status_t drawLines(const float* points, int count, const SkPaint* paint);
- virtual status_t drawPoints(const float* points, int count, const SkPaint* paint);
- // Text
- virtual status_t drawText(const char* text, int bytesCount, int count, float x, float y,
- const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
- DrawOpMode drawOpMode = kDrawOpMode_Immediate);
- virtual status_t drawTextOnPath(const char* text, int bytesCount, int count, const SkPath* path,
- float hOffset, float vOffset, const SkPaint* paint);
- virtual status_t drawPosText(const char* text, int bytesCount, int count,
- const float* positions, const SkPaint* paint);
// ----------------------------------------------------------------------------
-// Canvas draw operations - special
+// HWUI Canvas draw operations - special
// ----------------------------------------------------------------------------
- virtual status_t drawLayer(DeferredLayerUpdater* layerHandle, float x, float y);
- virtual status_t drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags);
+ void drawLayer(DeferredLayerUpdater* layerHandle, float x, float y);
+ void drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags);
// TODO: rename for consistency
- virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty);
+ void callDrawGLFunction(Functor* functor, Rect& dirty);
void setHighContrastText(bool highContrastText) {
mHighContrastText = highContrastText;
}
+
+// ----------------------------------------------------------------------------
+// CanvasStateClient interface
+// ----------------------------------------------------------------------------
+ virtual void onViewportInitialized() override { }
+ virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) override { }
+ virtual GLuint onGetTargetFbo() const override { return -1; }
+
+// ----------------------------------------------------------------------------
+// android/graphics/Canvas interface
+// ----------------------------------------------------------------------------
+ virtual SkCanvas* asSkCanvas() override;
+
+ virtual void setBitmap(SkBitmap* bitmap, bool copyState) override {
+ LOG_ALWAYS_FATAL("DisplayListRenderer 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(); }
+
+// ----------------------------------------------------------------------------
+// android/graphics/Canvas state operations
+// ----------------------------------------------------------------------------
+ // Save (layer)
+ virtual int getSaveCount() const override { return mState.getSaveCount(); }
+ virtual int save(SkCanvas::SaveFlags 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,
+ SkCanvas::SaveFlags flags) override;
+ virtual int saveLayerAlpha(float left, float top, float right, float bottom,
+ int alpha, SkCanvas::SaveFlags 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 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
+ { LOG_ALWAYS_FATAL("DisplayListRenderer does not support drawVertices()"); }
+
+ // 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;
+
+ // Text
+ virtual void drawText(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 drawPosText(const uint16_t* text, const float* positions, int count,
+ int posCount, const SkPaint& paint) override;
+ virtual void drawTextOnPath(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,
@@ -186,7 +269,7 @@ private:
template<class T>
inline const T* refBuffer(const T* srcBuffer, int32_t count) {
- if (!srcBuffer) return NULL;
+ if (!srcBuffer) return nullptr;
T* dstBuffer = (T*) mDisplayListData->allocator.alloc(count * sizeof(T));
memcpy(dstBuffer, srcBuffer, count * sizeof(T));
@@ -198,58 +281,62 @@ private:
}
inline const SkPath* refPath(const SkPath* path) {
- if (!path) return NULL;
+ if (!path) return nullptr;
- const SkPath* pathCopy = mPathMap.valueFor(path);
- if (pathCopy == NULL || pathCopy->getGenerationID() != path->getGenerationID()) {
+ const SkPath* cachedPath = mPathMap.valueFor(path);
+ if (cachedPath == nullptr || cachedPath->getGenerationID() != path->getGenerationID()) {
SkPath* newPathCopy = new SkPath(*path);
newPathCopy->setSourcePath(path);
+ cachedPath = newPathCopy;
+ std::unique_ptr<const SkPath> copy(newPathCopy);
+ mDisplayListData->paths.push_back(std::move(copy));
- pathCopy = newPathCopy;
// replaceValueFor() performs an add if the entry doesn't exist
- mPathMap.replaceValueFor(path, pathCopy);
- mDisplayListData->paths.add(pathCopy);
+ mPathMap.replaceValueFor(path, cachedPath);
}
if (mDisplayListData->sourcePaths.indexOf(path) < 0) {
mResourceCache.incrementRefcount(path);
mDisplayListData->sourcePaths.add(path);
}
- return pathCopy;
+ return cachedPath;
}
inline const SkPaint* refPaint(const SkPaint* paint) {
- if (!paint) return NULL;
-
- const SkPaint* paintCopy = mPaintMap.valueFor(paint);
- if (paintCopy == NULL
- || paintCopy->getGenerationID() != paint->getGenerationID()
- // We can't compare shader pointers because that will always
- // change as we do partial copying via wrapping. However, if the
- // shader changes the paint generationID will have changed and
- // so we don't hit this comparison anyway
- || !(paint->getShader() && paintCopy->getShader()
- && paint->getShader()->getGenerationID() == paintCopy->getShader()->getGenerationID())) {
- paintCopy = copyPaint(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()) {
+ paint = filteredPaint.init();
+ mDrawFilter->filter(filteredPaint.get(), SkDrawFilter::kPaint_Type);
+ }
+
+ // 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);
+ mDisplayListData->paints.push_back(std::move(copy));
+
// replaceValueFor() performs an add if the entry doesn't exist
- mPaintMap.replaceValueFor(paint, paintCopy);
+ mPaintMap.replaceValueFor(key, cachedPaint);
}
- return paintCopy;
+ return cachedPaint;
}
inline SkPaint* copyPaint(const SkPaint* paint) {
- if (!paint) return NULL;
- SkPaint* paintCopy = new SkPaint(*paint);
- if (paint->getShader()) {
- SkShader* shaderCopy = SkShader::CreateLocalMatrixShader(
- paint->getShader(), paint->getShader()->getLocalMatrix());
- paintCopy->setShader(shaderCopy);
- paintCopy->setGenerationID(paint->getGenerationID());
- shaderCopy->setGenerationID(paint->getShader()->getGenerationID());
- shaderCopy->unref();
- }
- mDisplayListData->paints.add(paintCopy);
- return paintCopy;
+ if (!paint) return nullptr;
+
+ SkPaint* returnPaint = new SkPaint(*paint);
+ std::unique_ptr<const SkPaint> copy(returnPaint);
+ mDisplayListData->paints.push_back(std::move(copy));
+
+ return returnPaint;
}
inline const SkRegion* refRegion(const SkRegion* region) {
@@ -257,16 +344,18 @@ private:
return region;
}
- const SkRegion* regionCopy = mRegionMap.valueFor(region);
+ const SkRegion* cachedRegion = mRegionMap.valueFor(region);
// TODO: Add generation ID to SkRegion
- if (regionCopy == NULL) {
- regionCopy = new SkRegion(*region);
+ if (cachedRegion == nullptr) {
+ std::unique_ptr<const SkRegion> copy(new SkRegion(*region));
+ cachedRegion = copy.get();
+ mDisplayListData->regions.push_back(std::move(copy));
+
// replaceValueFor() performs an add if the entry doesn't exist
- mRegionMap.replaceValueFor(region, regionCopy);
- mDisplayListData->regions.add(regionCopy);
+ mRegionMap.replaceValueFor(region, cachedRegion);
}
- return regionCopy;
+ return cachedRegion;
}
inline const SkBitmap* refBitmap(const SkBitmap* bitmap) {
@@ -274,15 +363,9 @@ private:
// 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.
- mDisplayListData->bitmapResources.add(bitmap);
- mResourceCache.incrementRefcount(bitmap);
- return bitmap;
- }
-
- inline const SkBitmap* refBitmapData(const SkBitmap* bitmap) {
- mDisplayListData->ownedBitmapResources.add(bitmap);
- mResourceCache.incrementRefcount(bitmap);
- return bitmap;
+ const SkBitmap* cachedBitmap = mResourceCache.insert(bitmap);
+ mDisplayListData->bitmapResources.add(cachedBitmap);
+ return cachedBitmap;
}
inline const Res_png_9patch* refPatch(const Res_png_9patch* patch) {
@@ -291,7 +374,7 @@ private:
return patch;
}
- DefaultKeyedVector<const SkPaint*, const SkPaint*> mPaintMap;
+ DefaultKeyedVector<uint32_t, const SkPaint*> mPaintMap;
DefaultKeyedVector<const SkPath*, const SkPath*> mPathMap;
DefaultKeyedVector<const SkRegion*, const SkRegion*> mRegionMap;
@@ -306,6 +389,8 @@ private:
int mRestoreSaveCount;
+ SkAutoTUnref<SkDrawFilter> mDrawFilter;
+
friend class RenderNode;
}; // class DisplayListRenderer
diff --git a/libs/hwui/Dither.cpp b/libs/hwui/Dither.cpp
index 77006a4..1ba6511 100644
--- a/libs/hwui/Dither.cpp
+++ b/libs/hwui/Dither.cpp
@@ -24,15 +24,16 @@ namespace uirenderer {
// Lifecycle
///////////////////////////////////////////////////////////////////////////////
-Dither::Dither(): mCaches(NULL), mInitialized(false), mDitherTexture(0) {
+Dither::Dither(Caches& caches)
+ : mCaches(caches)
+ , mInitialized(false)
+ , mDitherTexture(0) {
}
void Dither::bindDitherTexture() {
if (!mInitialized) {
- bool useFloatTexture = Extensions::getInstance().hasFloatTextures();
-
glGenTextures(1, &mDitherTexture);
- mCaches->bindTexture(mDitherTexture);
+ mCaches.textureState().bindTexture(mDitherTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@@ -40,7 +41,7 @@ void Dither::bindDitherTexture() {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- if (useFloatTexture) {
+ if (mCaches.extensions().hasFloatTextures()) {
// We use a R16F texture, let's remap the alpha channel to the
// red channel to avoid changing the shader sampling code on GL ES 3.0+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED);
@@ -71,13 +72,13 @@ void Dither::bindDitherTexture() {
mInitialized = true;
} else {
- mCaches->bindTexture(mDitherTexture);
+ mCaches.textureState().bindTexture(mDitherTexture);
}
}
void Dither::clear() {
if (mInitialized) {
- mCaches->deleteTexture(mDitherTexture);
+ mCaches.textureState().deleteTexture(mDitherTexture);
mInitialized = false;
}
}
@@ -86,15 +87,13 @@ void Dither::clear() {
// Program management
///////////////////////////////////////////////////////////////////////////////
-void Dither::setupProgram(Program* program, GLuint* textureUnit) {
- if (!mCaches) mCaches = &Caches::getInstance();
-
+void Dither::setupProgram(Program& program, GLuint* textureUnit) {
GLuint textureSlot = (*textureUnit)++;
- mCaches->activeTexture(textureSlot);
+ mCaches.textureState().activateTexture(textureSlot);
bindDitherTexture();
- glUniform1i(program->getUniform("ditherSampler"), textureSlot);
+ glUniform1i(program.getUniform("ditherSampler"), textureSlot);
}
}; // namespace uirenderer
diff --git a/libs/hwui/Dither.h b/libs/hwui/Dither.h
index 546236b..b589b80 100644
--- a/libs/hwui/Dither.h
+++ b/libs/hwui/Dither.h
@@ -19,12 +19,12 @@
#include <GLES3/gl3.h>
-#include "Program.h"
-
namespace android {
namespace uirenderer {
class Caches;
+class Extensions;
+class Program;
// Must be a power of two
#define DITHER_KERNEL_SIZE 4
@@ -37,15 +37,15 @@ class Caches;
*/
class Dither {
public:
- Dither();
+ Dither(Caches& caches);
void clear();
- void setupProgram(Program* program, GLuint* textureUnit);
+ void setupProgram(Program& program, GLuint* textureUnit);
private:
void bindDitherTexture();
- Caches* mCaches;
+ Caches& mCaches;
bool mInitialized;
GLuint mDitherTexture;
};
diff --git a/libs/hwui/DrawProfiler.cpp b/libs/hwui/DrawProfiler.cpp
index e590642..ecde5ff 100644
--- a/libs/hwui/DrawProfiler.cpp
+++ b/libs/hwui/DrawProfiler.cpp
@@ -59,7 +59,7 @@ static int dpToPx(int dp, float density) {
DrawProfiler::DrawProfiler()
: mType(kNone)
, mDensity(0)
- , mData(NULL)
+ , mData(nullptr)
, mDataSize(0)
, mCurrentFrame(-1)
, mPreviousTime(0)
@@ -160,7 +160,7 @@ void DrawProfiler::createData() {
void DrawProfiler::destroyData() {
delete mData;
- mData = NULL;
+ mData = nullptr;
}
void DrawProfiler::addRect(Rect& r, float data, float* shapeOutput) {
diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp
index 84e7e65..c68822b 100644
--- a/libs/hwui/Extensions.cpp
+++ b/libs/hwui/Extensions.cpp
@@ -16,18 +16,16 @@
#define LOG_TAG "OpenGLRenderer"
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
+#include "Extensions.h"
+
+#include "Debug.h"
+#include "Properties.h"
#include <EGL/egl.h>
#include <EGL/eglext.h>
-
+#include <GLES2/gl2ext.h>
#include <utils/Log.h>
-#include "Debug.h"
-#include "Extensions.h"
-#include "Properties.h"
-
namespace android {
using namespace uirenderer;
@@ -50,7 +48,7 @@ namespace uirenderer {
// Constructors
///////////////////////////////////////////////////////////////////////////////
-Extensions::Extensions(): Singleton<Extensions>() {
+Extensions::Extensions() {
// Query GL extensions
findExtensions((const char*) glGetString(GL_EXTENSIONS), mGlExtensionList);
mHasNPot = hasGlExtension("GL_OES_texture_npot");
@@ -66,7 +64,7 @@ Extensions::Extensions(): Singleton<Extensions>() {
findExtensions(eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS), mEglExtensionList);
char property[PROPERTY_VALUE_MAX];
- if (property_get(PROPERTY_DEBUG_NV_PROFILING, property, NULL) > 0) {
+ if (property_get(PROPERTY_DEBUG_NV_PROFILING, property, nullptr) > 0) {
mHasNvSystemTime = !strcmp(property, "true") && hasEglExtension("EGL_NV_system_time");
} else {
mHasNvSystemTime = false;
@@ -93,9 +91,6 @@ Extensions::Extensions(): Singleton<Extensions>() {
}
}
-Extensions::~Extensions() {
-}
-
///////////////////////////////////////////////////////////////////////////////
// Methods
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 25d4c5e..731001a 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -23,6 +23,8 @@
#include <utils/SortedVector.h>
#include <utils/String8.h>
+#include <GLES2/gl2.h>
+
namespace android {
namespace uirenderer {
@@ -30,8 +32,10 @@ namespace uirenderer {
// Classes
///////////////////////////////////////////////////////////////////////////////
-class ANDROID_API Extensions: public Singleton<Extensions> {
+class ANDROID_API Extensions {
public:
+ Extensions();
+
inline bool hasNPot() const { return mHasNPot; }
inline bool hasFramebufferFetch() const { return mHasFramebufferFetch; }
inline bool hasDiscardFramebuffer() const { return mHasDiscardFramebuffer; }
@@ -55,13 +59,8 @@ public:
void dump() const;
private:
- Extensions();
- ~Extensions();
-
void findExtensions(const char* extensions, SortedVector<String8>& list) const;
- friend class Singleton<Extensions>;
-
SortedVector<String8> mGlExtensionList;
SortedVector<String8> mEglExtensionList;
diff --git a/libs/hwui/FboCache.cpp b/libs/hwui/FboCache.cpp
index beef7be..b54d532 100644
--- a/libs/hwui/FboCache.cpp
+++ b/libs/hwui/FboCache.cpp
@@ -31,7 +31,7 @@ namespace uirenderer {
FboCache::FboCache(): mMaxSize(DEFAULT_FBO_CACHE_SIZE) {
char property[PROPERTY_VALUE_MAX];
- if (property_get(PROPERTY_FBO_CACHE_SIZE, property, NULL) > 0) {
+ if (property_get(PROPERTY_FBO_CACHE_SIZE, property, nullptr) > 0) {
INIT_LOGD(" Setting fbo cache size to %s", property);
mMaxSize = atoi(property);
} else {
diff --git a/libs/hwui/Fence.h b/libs/hwui/Fence.h
deleted file mode 100644
index f175e98..0000000
--- a/libs/hwui/Fence.h
+++ /dev/null
@@ -1,113 +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_FENCE_H
-#define ANDROID_HWUI_FENCE_H
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
-namespace android {
-namespace uirenderer {
-
-/**
- * Creating a Fence instance inserts a new sync fence in the OpenGL
- * commands stream. The caller can then wait for the fence to be signaled
- * by calling the wait method.
- */
-class Fence {
-public:
- enum {
- /**
- * Default timeout in nano-seconds for wait()
- */
- kDefaultTimeout = 1000000000
- };
-
- /**
- * Inserts a new sync fence in the OpenGL commands stream.
- */
- Fence() {
- mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- if (mDisplay != EGL_NO_DISPLAY) {
- mFence = eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, NULL);
- } else {
- mFence = EGL_NO_SYNC_KHR;
- }
- }
-
- /**
- * Destroys the fence. Any caller waiting on the fence will be
- * signaled immediately.
- */
- ~Fence() {
- if (mFence != EGL_NO_SYNC_KHR) {
- eglDestroySyncKHR(mDisplay, mFence);
- }
- }
-
- /**
- * Blocks the calling thread until this fence is signaled, or until
- * <timeout> nanoseconds have passed.
- *
- * Returns true if waiting for the fence was successful, false if
- * a timeout or an error occurred.
- */
- bool wait(EGLTimeKHR timeout = kDefaultTimeout) {
- EGLint waitStatus = eglClientWaitSyncKHR(mDisplay, mFence,
- EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, timeout);
- if (waitStatus == EGL_FALSE) {
- ALOGW("Failed to wait for the fence %#x", eglGetError());
- }
- return waitStatus == EGL_CONDITION_SATISFIED_KHR;
- }
-
-private:
- EGLDisplay mDisplay;
- EGLSyncKHR mFence;
-
-}; // class Fence
-
-/**
- * An AutoFence creates a Fence instance and waits for the fence
- * to be signaled when the AutoFence is destroyed. This is useful
- * to automatically wait for a series of OpenGL commands to be
- * executed. For example:
- *
- * void drawAndWait() {
- * glDrawElements();
- * AutoFence fence;
- * }
- */
-class AutoFence {
-public:
- AutoFence(EGLTimeKHR timeout = Fence::kDefaultTimeout): mTimeout(timeout) {
- }
-
- ~AutoFence() {
- mFence.wait(mTimeout);
- }
-
-private:
- EGLTimeKHR mTimeout;
- Fence mFence;
-
-}; // class AutoFence
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_FENCE_H
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 5b5b098..55b2d19 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -14,7 +14,17 @@
* limitations under the License.
*/
-#define LOG_TAG "OpenGLRenderer"
+#include "FontRenderer.h"
+
+#include "Caches.h"
+#include "Debug.h"
+#include "Extensions.h"
+#include "OpenGLRenderer.h"
+#include "PixelBuffer.h"
+#include "Rect.h"
+#include "renderstate/RenderState.h"
+#include "utils/Blur.h"
+#include "utils/Timing.h"
#include <SkGlyph.h>
#include <SkUtils.h>
@@ -27,17 +37,6 @@
#include <RenderScript.h>
#endif
-#include "utils/Blur.h"
-#include "utils/Timing.h"
-
-#include "Caches.h"
-#include "Debug.h"
-#include "Extensions.h"
-#include "FontRenderer.h"
-#include "OpenGLRenderer.h"
-#include "PixelBuffer.h"
-#include "Rect.h"
-
namespace android {
namespace uirenderer {
@@ -47,9 +46,7 @@ namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
// TextSetupFunctor
///////////////////////////////////////////////////////////////////////////////
-status_t TextSetupFunctor::operator ()(int what, void* data) {
- Data* typedData = reinterpret_cast<Data*>(data);
- GLenum glyphFormat = typedData ? typedData->glyphFormat : GL_ALPHA;
+status_t TextSetupFunctor::setup(GLenum glyphFormat) {
renderer->setupDraw();
renderer->setupDrawTextGamma(paint);
@@ -104,10 +101,10 @@ FontRenderer::FontRenderer() :
INIT_LOGD("Creating FontRenderer");
}
- mGammaTable = NULL;
+ mGammaTable = nullptr;
mInitialized = false;
- mCurrentCacheTexture = NULL;
+ mCurrentCacheTexture = nullptr;
mLinearFiltering = false;
@@ -117,19 +114,19 @@ FontRenderer::FontRenderer() :
mLargeCacheHeight = DEFAULT_TEXT_LARGE_CACHE_HEIGHT;
char property[PROPERTY_VALUE_MAX];
- if (property_get(PROPERTY_TEXT_SMALL_CACHE_WIDTH, property, NULL) > 0) {
+ if (property_get(PROPERTY_TEXT_SMALL_CACHE_WIDTH, property, nullptr) > 0) {
mSmallCacheWidth = atoi(property);
}
- if (property_get(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, property, NULL) > 0) {
+ if (property_get(PROPERTY_TEXT_SMALL_CACHE_HEIGHT, property, nullptr) > 0) {
mSmallCacheHeight = atoi(property);
}
- if (property_get(PROPERTY_TEXT_LARGE_CACHE_WIDTH, property, NULL) > 0) {
+ if (property_get(PROPERTY_TEXT_LARGE_CACHE_WIDTH, property, nullptr) > 0) {
mLargeCacheWidth = atoi(property);
}
- if (property_get(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, property, NULL) > 0) {
+ if (property_get(PROPERTY_TEXT_LARGE_CACHE_HEIGHT, property, nullptr) > 0) {
mLargeCacheHeight = atoi(property);
}
@@ -213,7 +210,7 @@ CacheTexture* FontRenderer::cacheBitmapInTexture(Vector<CacheTexture*>& cacheTex
}
}
// Could not fit glyph into current cache textures
- return NULL;
+ return nullptr;
}
void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
@@ -224,7 +221,7 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
// so we can avoid doing extra work later on
if (glyph.fWidth == 0 || glyph.fHeight == 0) {
cachedGlyph->mIsValid = true;
- cachedGlyph->mCacheTexture = NULL;
+ cachedGlyph->mCacheTexture = nullptr;
return;
}
@@ -232,7 +229,7 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
// choose an appropriate cache texture list for this glyph format
SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
- Vector<CacheTexture*>* cacheTextures = NULL;
+ Vector<CacheTexture*>* cacheTextures = nullptr;
switch (format) {
case SkMask::kA8_Format:
case SkMask::kBW_Format:
@@ -287,7 +284,7 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
uint32_t cacheWidth = cacheTexture->getWidth();
if (!cacheTexture->getPixelBuffer()) {
- Caches::getInstance().activeTexture(0);
+ Caches::getInstance().textureState().activateTexture(0);
// Large-glyph texture memory is allocated only as needed
cacheTexture->allocateTexture();
}
@@ -397,10 +394,10 @@ void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyp
CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
bool allocate) {
- CacheTexture* cacheTexture = new CacheTexture(width, height, format, gMaxNumberOfQuads);
+ CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
if (allocate) {
- Caches::getInstance().activeTexture(0);
+ Caches::getInstance().textureState().activateTexture(0);
cacheTexture->allocateTexture();
cacheTexture->allocateMesh();
}
@@ -446,8 +443,8 @@ void checkTextureUpdateForCache(Caches& caches, Vector<CacheTexture*>& cacheText
if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
if (cacheTexture->getTextureId() != lastTextureId) {
lastTextureId = cacheTexture->getTextureId();
- caches.activeTexture(0);
- caches.bindTexture(lastTextureId);
+ caches.textureState().activateTexture(0);
+ caches.textureState().bindTexture(lastTextureId);
}
if (cacheTexture->upload()) {
@@ -473,7 +470,7 @@ void FontRenderer::checkTextureUpdate() {
checkTextureUpdateForCache(caches, mRGBACacheTextures, resetPixelStore, lastTextureId);
// Unbind any PBO we might have used to update textures
- caches.unbindPixelBuffer();
+ caches.pixelBufferState().unbind();
// Reset to default unpack row length to avoid affecting texture
// uploads in other parts of the renderer
@@ -485,44 +482,48 @@ void FontRenderer::checkTextureUpdate() {
}
void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
- Caches& caches = Caches::getInstance();
+ if (!mFunctor) return;
+
+ Caches& caches = mFunctor->renderer->getCaches();
+ RenderState& renderState = mFunctor->renderer->renderState();
+
bool first = true;
- bool force = false;
+ bool forceRebind = false;
for (uint32_t i = 0; i < cacheTextures.size(); i++) {
CacheTexture* texture = cacheTextures[i];
if (texture->canDraw()) {
if (first) {
if (mFunctor) {
- TextSetupFunctor::Data functorData(texture->getFormat());
- (*mFunctor)(0, &functorData);
+ mFunctor->setup(texture->getFormat());
}
checkTextureUpdate();
- caches.bindQuadIndicesBuffer();
+ renderState.meshState().bindQuadIndicesBuffer();
if (!mDrawn) {
// If returns true, a VBO was bound and we must
// rebind our vertex attrib pointers even if
// they have the same values as the current pointers
- force = caches.unbindMeshBuffer();
+ forceRebind = renderState.meshState().unbindMeshBuffer();
}
- caches.activeTexture(0);
+ caches.textureState().activateTexture(0);
first = false;
}
- caches.bindTexture(texture->getTextureId());
+ caches.textureState().bindTexture(texture->getTextureId());
texture->setLinearFiltering(mLinearFiltering, false);
TextureVertex* mesh = texture->mesh();
- caches.bindPositionVertexPointer(force, &mesh[0].x);
- caches.bindTexCoordsVertexPointer(force, &mesh[0].u);
- force = false;
+ MeshState& meshState = renderState.meshState();
+ meshState.bindPositionVertexPointer(forceRebind, &mesh[0].x);
+ meshState.bindTexCoordsVertexPointer(forceRebind, &mesh[0].u);
glDrawElements(GL_TRIANGLES, texture->meshElementCount(),
GL_UNSIGNED_SHORT, texture->indices());
texture->resetMesh();
+ forceRebind = false;
}
}
}
@@ -598,7 +599,7 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, co
DropShadow image;
image.width = 0;
image.height = 0;
- image.image = NULL;
+ image.image = nullptr;
image.penX = 0;
image.penY = 0;
@@ -607,8 +608,8 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, co
}
mDrawn = false;
- mClip = NULL;
- mBounds = NULL;
+ mClip = nullptr;
+ mBounds = nullptr;
Rect bounds;
mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions);
@@ -644,10 +645,10 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, co
// NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
// TODO: don't draw pure whitespace in the first place, and avoid needing this check
mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY,
- Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions);
+ Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
// Unbind any PBO we might have used
- Caches::getInstance().unbindPixelBuffer();
+ Caches::getInstance().pixelBufferState().unbind();
blurImage(&dataBuffer, paddedWidth, paddedHeight, radius);
}
@@ -661,7 +662,7 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, co
return image;
}
-void FontRenderer::initRender(const Rect* clip, Rect* bounds, Functor* functor) {
+void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextSetupFunctor* functor) {
checkInit();
mDrawn = false;
@@ -671,8 +672,8 @@ void FontRenderer::initRender(const Rect* clip, Rect* bounds, Functor* functor)
}
void FontRenderer::finishRender() {
- mBounds = NULL;
- mClip = NULL;
+ mBounds = nullptr;
+ mClip = nullptr;
issueDrawCommand();
}
@@ -689,7 +690,7 @@ void FontRenderer::endPrecaching() {
bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
- const float* positions, Rect* bounds, Functor* functor, bool forceFinish) {
+ const float* positions, Rect* bounds, TextSetupFunctor* functor, bool forceFinish) {
if (!mCurrentFont) {
ALOGE("No font set");
return false;
@@ -707,7 +708,7 @@ bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const c
bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
uint32_t startIndex, uint32_t len, int numGlyphs, const SkPath* path,
- float hOffset, float vOffset, Rect* bounds, Functor* functor) {
+ float hOffset, float vOffset, Rect* bounds, TextSetupFunctor* functor) {
if (!mCurrentFont) {
ALOGE("No font set");
return false;
@@ -724,7 +725,7 @@ void FontRenderer::removeFont(const Font* font) {
mActiveFonts.remove(font->getDescription());
if (mCurrentFont == font) {
- mCurrentFont = NULL;
+ mCurrentFont = nullptr;
}
}
@@ -734,7 +735,7 @@ void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, flo
if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF) {
uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
- if (mRs == 0) {
+ if (mRs == nullptr) {
mRs = new RSC::RS();
// a null path is OK because there are no custom kernels used
// hence nothing gets cached by RS
@@ -746,7 +747,7 @@ void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, flo
mRsScript = RSC::ScriptIntrinsicBlur::create(mRs, mRsElement);
}
}
- if (mRs != 0) {
+ if (mRs != nullptr) {
RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
RS_ALLOCATION_MIPMAP_NONE,
@@ -770,15 +771,12 @@ void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, flo
}
#endif
- float *gaussian = new float[2 * intRadius + 1];
- Blur::generateGaussianWeights(gaussian, intRadius);
-
- uint8_t* scratch = new uint8_t[width * height];
- Blur::horizontal(gaussian, intRadius, *image, scratch, width, height);
- Blur::vertical(gaussian, intRadius, scratch, *image, width, height);
+ std::unique_ptr<float[]> gaussian(new float[2 * intRadius + 1]);
+ Blur::generateGaussianWeights(gaussian.get(), intRadius);
- delete[] gaussian;
- delete[] scratch;
+ std::unique_ptr<uint8_t[]> scratch(new uint8_t[width * height]);
+ Blur::horizontal(gaussian.get(), intRadius, *image, scratch.get(), width, height);
+ Blur::vertical(gaussian.get(), intRadius, scratch.get(), *image, width, height);
}
static uint32_t calculateCacheSize(const Vector<CacheTexture*>& cacheTextures) {
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 5c96c6b..cb63684 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -17,7 +17,12 @@
#ifndef ANDROID_HWUI_FONT_RENDERER_H
#define ANDROID_HWUI_FONT_RENDERER_H
-#include <utils/Functor.h>
+#include "font/FontUtil.h"
+#include "font/CacheTexture.h"
+#include "font/CachedGlyphInfo.h"
+#include "font/Font.h"
+#include "utils/SortedList.h"
+
#include <utils/LruCache.h>
#include <utils/Vector.h>
#include <utils/StrongPointer.h>
@@ -26,14 +31,6 @@
#include <GLES2/gl2.h>
-#include "font/FontUtil.h"
-#include "font/CacheTexture.h"
-#include "font/CachedGlyphInfo.h"
-#include "font/Font.h"
-#include "utils/SortedList.h"
-#include "Matrix.h"
-#include "Properties.h"
-
#ifdef ANDROID_ENABLE_RENDERSCRIPT
#include "RenderScript.h"
namespace RSC {
@@ -49,26 +46,20 @@ namespace uirenderer {
class OpenGLRenderer;
-///////////////////////////////////////////////////////////////////////////////
-// TextSetupFunctor
-///////////////////////////////////////////////////////////////////////////////
-class TextSetupFunctor: public Functor {
+class TextSetupFunctor {
public:
- struct Data {
- Data(GLenum glyphFormat) : glyphFormat(glyphFormat) {
- }
-
- GLenum glyphFormat;
- };
-
TextSetupFunctor(OpenGLRenderer* renderer, float x, float y, bool pureTranslate,
- int alpha, SkXfermode::Mode mode, const SkPaint* paint): Functor(),
- renderer(renderer), x(x), y(y), pureTranslate(pureTranslate),
- alpha(alpha), mode(mode), paint(paint) {
+ int alpha, SkXfermode::Mode mode, const SkPaint* paint)
+ : renderer(renderer)
+ , x(x)
+ , y(y)
+ , pureTranslate(pureTranslate)
+ , alpha(alpha)
+ , mode(mode)
+ , paint(paint) {
}
- ~TextSetupFunctor() { }
- status_t operator ()(int what, void* data);
+ status_t setup(GLenum glyphFormat);
OpenGLRenderer* renderer;
float x;
@@ -79,10 +70,6 @@ public:
const SkPaint* paint;
};
-///////////////////////////////////////////////////////////////////////////////
-// FontRenderer
-///////////////////////////////////////////////////////////////////////////////
-
class FontRenderer {
public:
FontRenderer();
@@ -103,22 +90,14 @@ public:
// bounds is an out parameter
bool renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, const float* positions,
- Rect* bounds, Functor* functor, bool forceFinish = true);
+ Rect* bounds, TextSetupFunctor* functor, bool forceFinish = true);
// bounds is an out parameter
bool renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
uint32_t startIndex, uint32_t len, int numGlyphs, const SkPath* path,
- float hOffset, float vOffset, Rect* bounds, Functor* functor);
+ float hOffset, float vOffset, Rect* bounds, TextSetupFunctor* functor);
struct DropShadow {
- DropShadow() { };
-
- DropShadow(const DropShadow& dropShadow):
- width(dropShadow.width), height(dropShadow.height),
- image(dropShadow.image), penX(dropShadow.penX),
- penY(dropShadow.penY) {
- }
-
uint32_t width;
uint32_t height;
uint8_t* image;
@@ -154,7 +133,7 @@ private:
void flushAllAndInvalidate();
void checkInit();
- void initRender(const Rect* clip, Rect* bounds, Functor* functor);
+ void initRender(const Rect* clip, Rect* bounds, TextSetupFunctor* functor);
void finishRender();
void issueDrawCommand(Vector<CacheTexture*>& cacheTextures);
@@ -195,7 +174,7 @@ private:
bool mUploadTexture;
- Functor* mFunctor;
+ TextSetupFunctor* mFunctor;
const Rect* mClip;
Rect* mBounds;
bool mDrawn;
diff --git a/libs/hwui/GammaFontRenderer.cpp b/libs/hwui/GammaFontRenderer.cpp
index 06d2aad..0bcd83a 100644
--- a/libs/hwui/GammaFontRenderer.cpp
+++ b/libs/hwui/GammaFontRenderer.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "OpenGLRenderer"
-
#include "Debug.h"
#include "GammaFontRenderer.h"
#include "Properties.h"
@@ -61,7 +59,7 @@ GammaFontRenderer::GammaFontRenderer() {
// Get the gamma
mGamma = DEFAULT_TEXT_GAMMA;
- if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
+ if (property_get(PROPERTY_TEXT_GAMMA, property, nullptr) > 0) {
INIT_LOGD(" Setting text gamma to %s", property);
mGamma = atof(property);
} else {
@@ -70,7 +68,7 @@ GammaFontRenderer::GammaFontRenderer() {
// Get the black gamma threshold
mBlackThreshold = DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD;
- if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, NULL) > 0) {
+ if (property_get(PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD, property, nullptr) > 0) {
INIT_LOGD(" Setting text black gamma threshold to %s", property);
mBlackThreshold = atoi(property);
} else {
@@ -80,7 +78,7 @@ GammaFontRenderer::GammaFontRenderer() {
// Get the white gamma threshold
mWhiteThreshold = DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD;
- if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, NULL) > 0) {
+ if (property_get(PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD, property, nullptr) > 0) {
INIT_LOGD(" Setting text white gamma threshold to %s", property);
mWhiteThreshold = atoi(property);
} else {
@@ -96,15 +94,16 @@ GammaFontRenderer::~GammaFontRenderer() {
// Shader-based renderer
///////////////////////////////////////////////////////////////////////////////
-ShaderGammaFontRenderer::ShaderGammaFontRenderer(bool multiGamma): GammaFontRenderer() {
+ShaderGammaFontRenderer::ShaderGammaFontRenderer(bool multiGamma)
+ : GammaFontRenderer() {
INIT_LOGD("Creating shader gamma font renderer");
- mRenderer = NULL;
+ mRenderer = nullptr;
mMultiGamma = multiGamma;
}
void ShaderGammaFontRenderer::describe(ProgramDescription& description,
const SkPaint* paint) const {
- if (paint->getShader() == NULL) {
+ if (paint->getShader() == nullptr) {
if (mMultiGamma) {
const int l = luminance(paint);
@@ -123,9 +122,9 @@ void ShaderGammaFontRenderer::describe(ProgramDescription& description,
}
void ShaderGammaFontRenderer::setupProgram(ProgramDescription& description,
- Program* program) const {
+ Program& program) const {
if (description.hasGammaCorrection) {
- glUniform1f(program->getUniform("gamma"), description.gamma);
+ glUniform1f(program.getUniform("gamma"), description.gamma);
}
}
@@ -139,7 +138,8 @@ void ShaderGammaFontRenderer::endPrecaching() {
// Lookup-based renderer
///////////////////////////////////////////////////////////////////////////////
-LookupGammaFontRenderer::LookupGammaFontRenderer(): GammaFontRenderer() {
+LookupGammaFontRenderer::LookupGammaFontRenderer()
+ : GammaFontRenderer() {
INIT_LOGD("Creating lookup gamma font renderer");
// Compute the gamma tables
@@ -149,7 +149,7 @@ LookupGammaFontRenderer::LookupGammaFontRenderer(): GammaFontRenderer() {
mGammaTable[i] = uint8_t((float)::floor(pow(i / 255.0f, gamma) * 255.0f + 0.5f));
}
- mRenderer = NULL;
+ mRenderer = nullptr;
}
void LookupGammaFontRenderer::endPrecaching() {
@@ -162,7 +162,8 @@ void LookupGammaFontRenderer::endPrecaching() {
// Lookup-based renderer, using 3 different correction tables
///////////////////////////////////////////////////////////////////////////////
-Lookup3GammaFontRenderer::Lookup3GammaFontRenderer(): GammaFontRenderer() {
+Lookup3GammaFontRenderer::Lookup3GammaFontRenderer()
+ : GammaFontRenderer() {
INIT_LOGD("Creating lookup3 gamma font renderer");
// Compute the gamma tables
@@ -183,12 +184,6 @@ Lookup3GammaFontRenderer::Lookup3GammaFontRenderer(): GammaFontRenderer() {
memset(mRenderersUsageCount, 0, sizeof(uint32_t) * kGammaCount);
}
-Lookup3GammaFontRenderer::~Lookup3GammaFontRenderer() {
- for (int i = 0; i < kGammaCount; i++) {
- delete mRenderers[i];
- }
-}
-
void Lookup3GammaFontRenderer::endPrecaching() {
for (int i = 0; i < kGammaCount; i++) {
if (mRenderers[i]) {
@@ -199,8 +194,7 @@ void Lookup3GammaFontRenderer::endPrecaching() {
void Lookup3GammaFontRenderer::clear() {
for (int i = 0; i < kGammaCount; i++) {
- delete mRenderers[i];
- mRenderers[i] = NULL;
+ mRenderers[i].release();
}
}
@@ -221,8 +215,7 @@ void Lookup3GammaFontRenderer::flush() {
if (count <= 1 || min < 0) return;
- delete mRenderers[min];
- mRenderers[min] = NULL;
+ mRenderers[min].release();
// Also eliminate the caches for large glyphs, as they consume significant memory
for (int i = 0; i < kGammaCount; ++i) {
@@ -233,18 +226,16 @@ void Lookup3GammaFontRenderer::flush() {
}
FontRenderer* Lookup3GammaFontRenderer::getRenderer(Gamma gamma) {
- FontRenderer* renderer = mRenderers[gamma];
- if (!renderer) {
- renderer = new FontRenderer();
- mRenderers[gamma] = renderer;
- renderer->setGammaTable(&mGammaTable[gamma * 256]);
+ if (!mRenderers[gamma]) {
+ mRenderers[gamma].reset(new FontRenderer());
+ mRenderers[gamma]->setGammaTable(&mGammaTable[gamma * 256]);
}
mRenderersUsageCount[gamma]++;
- return renderer;
+ return mRenderers[gamma].get();
}
FontRenderer& Lookup3GammaFontRenderer::getFontRenderer(const SkPaint* paint) {
- if (paint->getShader() == NULL) {
+ if (paint->getShader() == nullptr) {
const int l = luminance(paint);
if (l <= mBlackThreshold) {
diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h
index 46cfd04..ca55bf1 100644
--- a/libs/hwui/GammaFontRenderer.h
+++ b/libs/hwui/GammaFontRenderer.h
@@ -38,7 +38,7 @@ public:
virtual uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const = 0;
virtual void describe(ProgramDescription& description, const SkPaint* paint) const = 0;
- virtual void setupProgram(ProgramDescription& description, Program* program) const = 0;
+ virtual void setupProgram(ProgramDescription& description, Program& program) const = 0;
virtual void endPrecaching() = 0;
@@ -59,36 +59,36 @@ public:
delete mRenderer;
}
- void clear() {
+ void clear() override {
delete mRenderer;
- mRenderer = NULL;
+ mRenderer = nullptr;
}
- void flush() {
+ void flush() override {
if (mRenderer) {
mRenderer->flushLargeCaches();
}
}
- FontRenderer& getFontRenderer(const SkPaint* paint) {
+ FontRenderer& getFontRenderer(const SkPaint* paint) override {
if (!mRenderer) {
mRenderer = new FontRenderer;
}
return *mRenderer;
}
- uint32_t getFontRendererCount() const {
+ uint32_t getFontRendererCount() const override {
return 1;
}
- uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const {
+ uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const override {
return mRenderer ? mRenderer->getCacheSize(format) : 0;
}
- void describe(ProgramDescription& description, const SkPaint* paint) const;
- void setupProgram(ProgramDescription& description, Program* program) const;
+ void describe(ProgramDescription& description, const SkPaint* paint) const override;
+ void setupProgram(ProgramDescription& description, Program& program) const override;
- void endPrecaching();
+ void endPrecaching() override;
private:
ShaderGammaFontRenderer(bool multiGamma);
@@ -105,18 +105,18 @@ public:
delete mRenderer;
}
- void clear() {
+ void clear() override {
delete mRenderer;
- mRenderer = NULL;
+ mRenderer = nullptr;
}
- void flush() {
+ void flush() override {
if (mRenderer) {
mRenderer->flushLargeCaches();
}
}
- FontRenderer& getFontRenderer(const SkPaint* paint) {
+ FontRenderer& getFontRenderer(const SkPaint* paint) override {
if (!mRenderer) {
mRenderer = new FontRenderer;
mRenderer->setGammaTable(&mGammaTable[0]);
@@ -124,21 +124,21 @@ public:
return *mRenderer;
}
- uint32_t getFontRendererCount() const {
+ uint32_t getFontRendererCount() const override {
return 1;
}
- uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const {
+ uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const override {
return mRenderer ? mRenderer->getCacheSize(format) : 0;
}
- void describe(ProgramDescription& description, const SkPaint* paint) const {
+ void describe(ProgramDescription& description, const SkPaint* paint) const override {
}
- void setupProgram(ProgramDescription& description, Program* program) const {
+ void setupProgram(ProgramDescription& description, Program& program) const override {
}
- void endPrecaching();
+ void endPrecaching() override;
private:
LookupGammaFontRenderer();
@@ -151,33 +151,30 @@ private:
class Lookup3GammaFontRenderer: public GammaFontRenderer {
public:
- ~Lookup3GammaFontRenderer();
+ void clear() override;
+ void flush() override;
- void clear();
- void flush();
+ FontRenderer& getFontRenderer(const SkPaint* paint) override;
- FontRenderer& getFontRenderer(const SkPaint* paint);
-
- uint32_t getFontRendererCount() const {
+ uint32_t getFontRendererCount() const override {
return kGammaCount;
}
- uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const {
+ uint32_t getFontRendererSize(uint32_t fontRenderer, GLenum format) const override {
if (fontRenderer >= kGammaCount) return 0;
- FontRenderer* renderer = mRenderers[fontRenderer];
- if (!renderer) return 0;
+ if (!mRenderers[fontRenderer]) return 0;
- return renderer->getCacheSize(format);
+ return mRenderers[fontRenderer]->getCacheSize(format);
}
- void describe(ProgramDescription& description, const SkPaint* paint) const {
+ void describe(ProgramDescription& description, const SkPaint* paint) const override {
}
- void setupProgram(ProgramDescription& description, Program* program) const {
+ void setupProgram(ProgramDescription& description, Program& program) const override {
}
- void endPrecaching();
+ void endPrecaching() override;
private:
Lookup3GammaFontRenderer();
@@ -192,7 +189,7 @@ private:
FontRenderer* getRenderer(Gamma gamma);
uint32_t mRenderersUsageCount[kGammaCount];
- FontRenderer* mRenderers[kGammaCount];
+ std::unique_ptr<FontRenderer> mRenderers[kGammaCount];
uint8_t mGammaTable[256 * kGammaCount];
diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h
new file mode 100644
index 0000000..9150869
--- /dev/null
+++ b/libs/hwui/Glop.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2015 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_GLOP_H
+#define ANDROID_HWUI_GLOP_H
+
+#include "Matrix.h"
+#include "Rect.h"
+#include "utils/Macros.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <SkXfermode.h>
+
+namespace android {
+namespace uirenderer {
+
+class Program;
+
+/*
+ * Enumerates optional vertex attributes
+ *
+ * Position is always enabled by MeshState, these other attributes
+ * are enabled/disabled dynamically based on mesh content.
+ */
+enum VertexAttribFlags {
+ // NOTE: position attribute always enabled
+ kNone_Attrib = 0,
+ kTextureCoord_Attrib = 1 << 0,
+ kColor_Attrib = 1 << 1,
+ kAlpha_Attrib = 1 << 2,
+};
+
+
+/**
+ * Structure containing all data required to issue a single OpenGL draw
+ *
+ * Includes all of the mesh, fill, and GL state required to perform
+ * the operation. Pieces of data are either directly copied into the
+ * structure, or stored as a pointer or GL object reference to data
+ * managed
+ */
+// TODO: PREVENT_COPY_AND_ASSIGN(...) or similar
+struct Glop {
+ struct FloatColor {
+ float a, r, g, b;
+ };
+
+ Rect bounds;
+
+ /*
+ * Stores mesh - vertex and index data.
+ *
+ * buffer objects and void*s are mutually exclusive
+ * indices are optional
+ */
+ struct Mesh {
+ VertexAttribFlags vertexFlags;
+ GLuint primitiveMode; // GL_TRIANGLES and GL_TRIANGLE_STRIP supported
+ GLuint vertexBufferObject;
+ GLuint indexBufferObject;
+ const void* vertices;
+ const void* indices;
+ int vertexCount;
+ GLsizei stride;
+ } mesh;
+
+ struct Fill {
+ Program* program;
+ FloatColor color;
+
+ /* TODO
+ union shader {
+ //...
+ }; TODO
+ */
+ ProgramDescription::ColorFilterMode filterMode;
+ union Filter {
+ struct Matrix {
+ float matrix[16];
+ float vector[4];
+ } matrix;
+ FloatColor color;
+ } filter;
+ } fill;
+
+ struct Transform {
+ Matrix4 ortho; // TODO: out of op, since this is static per FBO
+ Matrix4 modelView;
+ Matrix4 canvas;
+ bool fudgingOffset;
+ } transform;
+
+ struct Blend {
+ GLenum src;
+ GLenum dst;
+ } blend;
+
+ /**
+ * Additional render state to enumerate:
+ * - scissor + (bits for whether each of LTRB needed?)
+ * - stencil mode (draw into, mask, count, etc)
+ */
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // ANDROID_HWUI_GLOP_H
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
new file mode 100644
index 0000000..e22af40
--- /dev/null
+++ b/libs/hwui/GlopBuilder.cpp
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2015 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 "GlopBuilder.h"
+
+#include "Caches.h"
+#include "Glop.h"
+#include "Matrix.h"
+#include "renderstate/MeshState.h"
+#include "renderstate/RenderState.h"
+#include "SkiaShader.h"
+#include "Texture.h"
+#include "utils/PaintUtils.h"
+#include "VertexBuffer.h"
+
+#include <GLES2/gl2.h>
+#include <SkPaint.h>
+
+namespace android {
+namespace uirenderer {
+
+#define TRIGGER_STAGE(stageFlag) \
+ LOG_ALWAYS_FATAL_IF(stageFlag & mStageFlags, "Stage %d cannot be run twice"); \
+ mStageFlags = static_cast<StageFlags>(mStageFlags | stageFlag)
+
+GlopBuilder::GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop)
+ : mRenderState(renderState)
+ , mCaches(caches)
+ , mOutGlop(outGlop){
+ mStageFlags = kInitialStage;
+}
+
+GlopBuilder& GlopBuilder::setMeshVertexBuffer(const VertexBuffer& vertexBuffer, bool shadowInterp) {
+ TRIGGER_STAGE(kMeshStage);
+
+ const VertexBuffer::MeshFeatureFlags flags = vertexBuffer.getMeshFeatureFlags();
+
+ bool alphaVertex = flags & VertexBuffer::kAlpha;
+ bool indices = flags & VertexBuffer::kIndices;
+ mOutGlop->mesh.vertexFlags = alphaVertex ? kAlpha_Attrib : kNone_Attrib;
+ mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
+ mOutGlop->mesh.vertexBufferObject = 0;
+ mOutGlop->mesh.vertices = vertexBuffer.getBuffer();
+ mOutGlop->mesh.indexBufferObject = 0;
+ mOutGlop->mesh.indices = vertexBuffer.getIndices();
+ mOutGlop->mesh.vertexCount = indices
+ ? vertexBuffer.getIndexCount() : vertexBuffer.getVertexCount();
+ mOutGlop->mesh.stride = alphaVertex ? kAlphaVertexStride : kVertexStride;
+
+ mDescription.hasVertexAlpha = alphaVertex;
+ mDescription.useShadowAlphaInterp = shadowInterp;
+ return *this;
+}
+
+GlopBuilder& GlopBuilder::setMeshUnitQuad() {
+ TRIGGER_STAGE(kMeshStage);
+
+ mOutGlop->mesh.vertexFlags = kNone_Attrib;
+ mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
+ mOutGlop->mesh.vertexBufferObject = mRenderState.meshState().getUnitQuadVBO();
+ mOutGlop->mesh.vertices = nullptr;
+ mOutGlop->mesh.indexBufferObject = 0;
+ mOutGlop->mesh.indices = nullptr;
+ mOutGlop->mesh.vertexCount = 4;
+ mOutGlop->mesh.stride = kTextureVertexStride;
+ return *this;
+}
+
+GlopBuilder& GlopBuilder::setTransform(const Matrix4& ortho,
+ const Matrix4& transform, bool fudgingOffset) {
+ TRIGGER_STAGE(kTransformStage);
+
+ mOutGlop->transform.ortho.load(ortho);
+ mOutGlop->transform.canvas.load(transform);
+ mOutGlop->transform.fudgingOffset = fudgingOffset;
+ return *this;
+}
+
+GlopBuilder& GlopBuilder::setModelViewMapUnitToRect(const Rect destination) {
+ TRIGGER_STAGE(kModelViewStage);
+ mOutGlop->transform.modelView.loadTranslate(destination.left, destination.top, 0.0f);
+ mOutGlop->transform.modelView.scale(destination.getWidth(), destination.getHeight(), 1.0f);
+ mOutGlop->bounds = destination;
+ return *this;
+}
+
+GlopBuilder& GlopBuilder::setModelViewOffsetRect(float offsetX, float offsetY, const Rect source) {
+ TRIGGER_STAGE(kModelViewStage);
+ mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f);
+ mOutGlop->bounds = source;
+ mOutGlop->bounds.translate(offsetX, offsetY);
+ return *this;
+}
+
+GlopBuilder& GlopBuilder::setPaint(const SkPaint* paint, float alphaScale) {
+ TRIGGER_STAGE(kFillStage);
+
+ // TODO: support null paint
+ const SkShader* shader = paint->getShader();
+ const SkColorFilter* colorFilter = paint->getColorFilter();
+
+ SkXfermode::Mode mode = PaintUtils::getXfermode(paint->getXfermode());
+ if (mode != SkXfermode::kClear_Mode) {
+ int color = paint->getColor();
+ float alpha = (SkColorGetA(color) / 255.0f) * alphaScale;
+ if (!shader) {
+ float colorScale = alpha / 255.0f;
+ mOutGlop->fill.color = {
+ alpha,
+ colorScale * SkColorGetR(color),
+ colorScale * SkColorGetG(color),
+ colorScale * SkColorGetB(color)
+ };
+ } else {
+ mOutGlop->fill.color = { alpha, 1, 1, 1 };
+ }
+ } else {
+ mOutGlop->fill.color = { 1, 0, 0, 0 };
+ }
+ const bool SWAP_SRC_DST = false;
+
+ mOutGlop->blend = { GL_ZERO, GL_ZERO };
+ if (mOutGlop->fill.color.a < 1.0f
+ || PaintUtils::isBlendedShader(shader)
+ || PaintUtils::isBlendedColorFilter(colorFilter)
+ || mode != SkXfermode::kSrcOver_Mode) {
+ if (CC_LIKELY(mode <= SkXfermode::kScreen_Mode)) {
+ Blend::getFactors(mode, SWAP_SRC_DST,
+ &mOutGlop->blend.src, &mOutGlop->blend.dst);
+ } else {
+ // These blend modes are not supported by OpenGL directly and have
+ // to be implemented using shaders. Since the shader will perform
+ // the blending, don't enable GL blending off here
+ // If the blend mode cannot be implemented using shaders, fall
+ // back to the default SrcOver blend mode instead
+ if (CC_UNLIKELY(mCaches.extensions().hasFramebufferFetch())) {
+ mDescription.framebufferMode = mode;
+ mDescription.swapSrcDst = SWAP_SRC_DST;
+ // blending in shader, don't enable
+ } else {
+ // unsupported
+ Blend::getFactors(SkXfermode::kSrcOver_Mode, SWAP_SRC_DST,
+ &mOutGlop->blend.src, &mOutGlop->blend.dst);
+ }
+ }
+ }
+
+ if (shader) {
+ SkiaShader::describe(&mCaches, mDescription, mCaches.extensions(), *shader);
+ // TODO: store shader data
+ LOG_ALWAYS_FATAL("shaders not yet supported");
+ }
+
+ if (colorFilter) {
+ SkColor color;
+ SkXfermode::Mode mode;
+ SkScalar srcColorMatrix[20];
+ if (colorFilter->asColorMode(&color, &mode)) {
+ mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::kColorBlend;
+ mDescription.colorMode = mode;
+
+ const float alpha = SkColorGetA(color) / 255.0f;
+ float colorScale = alpha / 255.0f;
+ mOutGlop->fill.filter.color = {
+ alpha,
+ colorScale * SkColorGetR(color),
+ colorScale * SkColorGetG(color),
+ colorScale * SkColorGetB(color),
+ };
+ } else if (colorFilter->asColorMatrix(srcColorMatrix)) {
+ mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::kColorMatrix;
+
+ float* colorMatrix = mOutGlop->fill.filter.matrix.matrix;
+ memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float));
+ memcpy(&colorMatrix[4], &srcColorMatrix[5], 4 * sizeof(float));
+ memcpy(&colorMatrix[8], &srcColorMatrix[10], 4 * sizeof(float));
+ memcpy(&colorMatrix[12], &srcColorMatrix[15], 4 * sizeof(float));
+
+ // Skia uses the range [0..255] for the addition vector, but we need
+ // the [0..1] range to apply the vector in GLSL
+ float* colorVector = mOutGlop->fill.filter.matrix.vector;
+ colorVector[0] = srcColorMatrix[4] / 255.0f;
+ colorVector[1] = srcColorMatrix[9] / 255.0f;
+ colorVector[2] = srcColorMatrix[14] / 255.0f;
+ colorVector[3] = srcColorMatrix[19] / 255.0f;
+ }
+ } else {
+ mOutGlop->fill.filterMode = ProgramDescription::kColorNone;
+ }
+
+ return *this;
+}
+
+void GlopBuilder::build() {
+ LOG_ALWAYS_FATAL_IF(mStageFlags != kAllStages, "glop not fully prepared!");
+
+ mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
+ mOutGlop->fill.program = mCaches.programCache.get(mDescription);
+ mOutGlop->transform.canvas.mapRect(mOutGlop->bounds);
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
+
diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h
new file mode 100644
index 0000000..c7464cd
--- /dev/null
+++ b/libs/hwui/GlopBuilder.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 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 RENDERSTATE_GLOPBUILDER_H
+#define RENDERSTATE_GLOPBUILDER_H
+
+#include "OpenGLRenderer.h"
+#include "Program.h"
+#include "utils/Macros.h"
+
+class SkPaint;
+
+namespace android {
+namespace uirenderer {
+
+class Caches;
+struct Glop;
+class Matrix4;
+class RenderState;
+class Texture;
+class VertexBuffer;
+
+class GlopBuilder {
+ PREVENT_COPY_AND_ASSIGN(GlopBuilder);
+public:
+ GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop);
+ GlopBuilder& setMeshUnitQuad();
+ GlopBuilder& setMeshVertexBuffer(const VertexBuffer& vertexBuffer, bool shadowInterp);
+
+ GlopBuilder& setTransform(const Matrix4& ortho, const Matrix4& transform, bool fudgingOffset);
+
+ GlopBuilder& setModelViewMapUnitToRect(const Rect destination);
+ GlopBuilder& setModelViewOffsetRect(float offsetX, float offsetY, const Rect source);
+
+ GlopBuilder& setPaint(const SkPaint* paint, float alphaScale);
+ void build();
+private:
+ enum StageFlags {
+ kInitialStage = 0,
+ kMeshStage = 1 << 0,
+ kTransformStage = 1 << 1,
+ kModelViewStage = 1 << 2,
+ kFillStage = 1 << 3,
+ kAllStages = kMeshStage | kTransformStage | kModelViewStage | kFillStage,
+ } mStageFlags;
+
+ ProgramDescription mDescription;
+ RenderState& mRenderState;
+ Caches& mCaches;
+ Glop* mOutGlop;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // RENDERSTATE_GLOPBUILDER_H
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index ffd1e8c..fb4c785 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -52,21 +52,24 @@ int GradientCacheEntry::compare(const GradientCacheEntry& lhs, const GradientCac
int deltaInt = int(lhs.count) - int(rhs.count);
if (deltaInt != 0) return deltaInt;
- deltaInt = memcmp(lhs.colors, rhs.colors, lhs.count * sizeof(uint32_t));
+ deltaInt = memcmp(lhs.colors.get(), rhs.colors.get(), lhs.count * sizeof(uint32_t));
if (deltaInt != 0) return deltaInt;
- return memcmp(lhs.positions, rhs.positions, lhs.count * sizeof(float));
+ return memcmp(lhs.positions.get(), rhs.positions.get(), lhs.count * sizeof(float));
}
///////////////////////////////////////////////////////////////////////////////
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
-GradientCache::GradientCache():
- mCache(LruCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity),
- mSize(0), mMaxSize(MB(DEFAULT_GRADIENT_CACHE_SIZE)) {
+GradientCache::GradientCache(Extensions& extensions)
+ : mCache(LruCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity)
+ , mSize(0)
+ , mMaxSize(MB(DEFAULT_GRADIENT_CACHE_SIZE))
+ , mUseFloatTexture(extensions.hasFloatTextures())
+ , mHasNpot(extensions.hasNPot()){
char property[PROPERTY_VALUE_MAX];
- if (property_get(PROPERTY_GRADIENT_CACHE_SIZE, property, NULL) > 0) {
+ if (property_get(PROPERTY_GRADIENT_CACHE_SIZE, property, nullptr) > 0) {
INIT_LOGD(" Setting gradient cache size to %sMB", property);
setMaxSize(MB(atof(property)));
} else {
@@ -76,16 +79,6 @@ GradientCache::GradientCache():
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
mCache.setOnEntryRemovedListener(this);
-
- const Extensions& extensions = Extensions::getInstance();
- mUseFloatTexture = extensions.hasFloatTextures();
- mHasNpot = extensions.hasNPot();
-}
-
-GradientCache::GradientCache(uint32_t maxByteSize):
- mCache(LruCache<GradientCacheEntry, Texture*>::kUnlimitedCapacity),
- mSize(0), mMaxSize(maxByteSize) {
- mCache.setOnEntryRemovedListener(this);
}
GradientCache::~GradientCache() {
@@ -285,7 +278,7 @@ void GradientCache::generateTexture(uint32_t* colors, float* positions, Texture*
memcpy(pixels + rowBytes, pixels, rowBytes);
glGenTextures(1, &texture->id);
- Caches::getInstance().bindTexture(texture->id);
+ Caches::getInstance().textureState().bindTexture(texture->id);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
if (mUseFloatTexture) {
diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h
index 6a783b1..08319ea 100644
--- a/libs/hwui/GradientCache.h
+++ b/libs/hwui/GradientCache.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_HWUI_GRADIENT_CACHE_H
#define ANDROID_HWUI_GRADIENT_CACHE_H
+#include <memory>
+
#include <GLES3/gl3.h>
#include <SkShader.h>
@@ -25,16 +27,16 @@
#include <utils/Mutex.h>
#include <utils/Vector.h>
-#include "Texture.h"
-
namespace android {
namespace uirenderer {
+class Texture;
+
struct GradientCacheEntry {
GradientCacheEntry() {
count = 0;
- colors = NULL;
- positions = NULL;
+ colors = nullptr;
+ positions = nullptr;
}
GradientCacheEntry(uint32_t* colors, float* positions, uint32_t count) {
@@ -42,20 +44,12 @@ struct GradientCacheEntry {
}
GradientCacheEntry(const GradientCacheEntry& entry) {
- copy(entry.colors, entry.positions, entry.count);
- }
-
- ~GradientCacheEntry() {
- delete[] colors;
- delete[] positions;
+ copy(entry.colors.get(), entry.positions.get(), entry.count);
}
GradientCacheEntry& operator=(const GradientCacheEntry& entry) {
if (this != &entry) {
- delete[] colors;
- delete[] positions;
-
- copy(entry.colors, entry.positions, entry.count);
+ copy(entry.colors.get(), entry.positions.get(), entry.count);
}
return *this;
@@ -73,18 +67,18 @@ struct GradientCacheEntry {
return compare(*this, other) != 0;
}
- uint32_t* colors;
- float* positions;
+ std::unique_ptr<uint32_t[]> colors;
+ std::unique_ptr<float[]> positions;
uint32_t count;
private:
void copy(uint32_t* colors, float* positions, uint32_t count) {
this->count = count;
- this->colors = new uint32_t[count];
- this->positions = new float[count];
+ this->colors.reset(new uint32_t[count]);
+ this->positions.reset(new float[count]);
- memcpy(this->colors, colors, count * sizeof(uint32_t));
- memcpy(this->positions, positions, count * sizeof(float));
+ memcpy(this->colors.get(), colors, count * sizeof(uint32_t));
+ memcpy(this->positions.get(), positions, count * sizeof(float));
}
}; // GradientCacheEntry
@@ -110,15 +104,14 @@ inline hash_t hash_type(const GradientCacheEntry& entry) {
*/
class GradientCache: public OnEntryRemoved<GradientCacheEntry, Texture*> {
public:
- GradientCache();
- GradientCache(uint32_t maxByteSize);
+ GradientCache(Extensions& extensions);
~GradientCache();
/**
* Used as a callback when an entry is removed from the cache.
* Do not invoke directly.
*/
- void operator()(GradientCacheEntry& shader, Texture*& texture);
+ void operator()(GradientCacheEntry& shader, Texture*& texture) override;
/**
* Returns the texture associated with the specified shader.
diff --git a/libs/hwui/Image.cpp b/libs/hwui/Image.cpp
index edf3930..a31c546 100644
--- a/libs/hwui/Image.cpp
+++ b/libs/hwui/Image.cpp
@@ -39,7 +39,7 @@ Image::Image(sp<GraphicBuffer> buffer) {
} else {
// Create a 2D texture to sample from the EGLImage
glGenTextures(1, &mTexture);
- Caches::getInstance().bindTexture(mTexture);
+ Caches::getInstance().textureState().bindTexture(mTexture);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, mImage);
GLenum status = GL_NO_ERROR;
@@ -54,7 +54,7 @@ Image::~Image() {
eglDestroyImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), mImage);
mImage = EGL_NO_IMAGE_KHR;
- Caches::getInstance().deleteTexture(mTexture);
+ Caches::getInstance().textureState().deleteTexture(mTexture);
mTexture = 0;
}
}
diff --git a/libs/hwui/Interpolator.cpp b/libs/hwui/Interpolator.cpp
index 0e62d77..e1b0fc3 100644
--- a/libs/hwui/Interpolator.cpp
+++ b/libs/hwui/Interpolator.cpp
@@ -14,12 +14,6 @@
* limitations under the License.
*/
-// LOG_TAG is being provided by the Makefile, reset.
-#ifdef LOG_TAG
-#undef LOG_TAG
-#endif
-#define LOG_TAG "Interpolator"
-
#include "Interpolator.h"
#include <cmath>
@@ -94,14 +88,12 @@ float OvershootInterpolator::interpolate(float t) {
return t * t * ((mTension + 1) * t + mTension) + 1.0f;
}
-LUTInterpolator::LUTInterpolator(float* values, size_t size) {
- mValues = values;
- mSize = size;
+LUTInterpolator::LUTInterpolator(float* values, size_t size)
+ : mValues(values)
+ , mSize(size) {
}
LUTInterpolator::~LUTInterpolator() {
- delete mValues;
- mValues = 0;
}
float LUTInterpolator::interpolate(float input) {
@@ -118,7 +110,7 @@ float LUTInterpolator::interpolate(float input) {
LOG_ALWAYS_FATAL_IF(i1 < 0 || i2 < 0, "negatives in interpolation!"
" i1=%d, i2=%d, input=%f, lutpos=%f, size=%zu, values=%p, ipart=%f, weight=%f",
- i1, i2, input, lutpos, mSize, mValues, ipart, weight);
+ i1, i2, input, lutpos, mSize, mValues.get(), ipart, weight);
float v1 = mValues[i1];
float v2 = mValues[i2];
diff --git a/libs/hwui/Interpolator.h b/libs/hwui/Interpolator.h
index dfa0a85..66ce119 100644
--- a/libs/hwui/Interpolator.h
+++ b/libs/hwui/Interpolator.h
@@ -17,6 +17,7 @@
#define INTERPOLATOR_H
#include <stddef.h>
+#include <memory>
#include <cutils/compiler.h>
@@ -37,13 +38,13 @@ protected:
class ANDROID_API AccelerateDecelerateInterpolator : public Interpolator {
public:
- virtual float interpolate(float input);
+ virtual float interpolate(float input) override;
};
class ANDROID_API AccelerateInterpolator : public Interpolator {
public:
AccelerateInterpolator(float factor) : mFactor(factor), mDoubleFactor(factor*2) {}
- virtual float interpolate(float input);
+ virtual float interpolate(float input) override;
private:
const float mFactor;
const float mDoubleFactor;
@@ -52,7 +53,7 @@ private:
class ANDROID_API AnticipateInterpolator : public Interpolator {
public:
AnticipateInterpolator(float tension) : mTension(tension) {}
- virtual float interpolate(float input);
+ virtual float interpolate(float input) override;
private:
const float mTension;
};
@@ -60,20 +61,20 @@ private:
class ANDROID_API AnticipateOvershootInterpolator : public Interpolator {
public:
AnticipateOvershootInterpolator(float tension) : mTension(tension) {}
- virtual float interpolate(float input);
+ virtual float interpolate(float input) override;
private:
const float mTension;
};
class ANDROID_API BounceInterpolator : public Interpolator {
public:
- virtual float interpolate(float input);
+ virtual float interpolate(float input) override;
};
class ANDROID_API CycleInterpolator : public Interpolator {
public:
CycleInterpolator(float cycles) : mCycles(cycles) {}
- virtual float interpolate(float input);
+ virtual float interpolate(float input) override;
private:
const float mCycles;
};
@@ -81,20 +82,20 @@ private:
class ANDROID_API DecelerateInterpolator : public Interpolator {
public:
DecelerateInterpolator(float factor) : mFactor(factor) {}
- virtual float interpolate(float input);
+ virtual float interpolate(float input) override;
private:
const float mFactor;
};
class ANDROID_API LinearInterpolator : public Interpolator {
public:
- virtual float interpolate(float input) { return input; }
+ virtual float interpolate(float input) override { return input; }
};
class ANDROID_API OvershootInterpolator : public Interpolator {
public:
OvershootInterpolator(float tension) : mTension(tension) {}
- virtual float interpolate(float input);
+ virtual float interpolate(float input) override;
private:
const float mTension;
};
@@ -104,10 +105,10 @@ public:
LUTInterpolator(float* values, size_t size);
~LUTInterpolator();
- virtual float interpolate(float input);
+ virtual float interpolate(float input) override;
private:
- float* mValues;
+ std::unique_ptr<float[]> mValues;
size_t mSize;
};
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 05259ff..7a026ef 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -16,17 +16,18 @@
#define LOG_TAG "OpenGLRenderer"
-#include <utils/Log.h>
+#include "Layer.h"
#include "Caches.h"
#include "DeferredDisplayList.h"
-#include "Layer.h"
#include "LayerRenderer.h"
#include "OpenGLRenderer.h"
#include "RenderNode.h"
-#include "RenderState.h"
+#include "renderstate/RenderState.h"
#include "utils/TraceUtils.h"
+#include <utils/Log.h>
+
#define ATRACE_LAYER_WORK(label) \
ATRACE_FORMAT("%s HW Layer DisplayList %s %ux%u", \
label, \
@@ -44,25 +45,23 @@ Layer::Layer(Type layerType, RenderState& renderState, const uint32_t layerWidth
, type(layerType) {
// 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(0);
- mesh = NULL;
+ incStrong(nullptr);
+ mesh = nullptr;
meshElementCount = 0;
cacheable = true;
dirty = false;
renderTarget = GL_TEXTURE_2D;
texture.width = layerWidth;
texture.height = layerHeight;
- colorFilter = NULL;
+ colorFilter = nullptr;
deferredUpdateScheduled = false;
- renderer = NULL;
- renderNode = NULL;
+ renderNode = nullptr;
fbo = 0;
- stencil = NULL;
+ stencil = nullptr;
debugDrawUpdate = false;
hasDrawnSinceUpdate = false;
forceFilter = false;
- deferredList = NULL;
- convexMask = NULL;
+ convexMask = nullptr;
rendererLightPosDirty = true;
wasBuildLayered = false;
renderState.registerLayer(this);
@@ -79,8 +78,6 @@ Layer::~Layer() {
}
delete[] mesh;
- delete deferredList;
- delete renderer;
}
void Layer::onGlContextLost() {
@@ -98,7 +95,7 @@ uint32_t Layer::computeIdealHeight(uint32_t layerHeight) {
void Layer::requireRenderer() {
if (!renderer) {
- renderer = new LayerRenderer(renderState, this);
+ renderer.reset(new LayerRenderer(renderState, this));
renderer->initProperties();
}
}
@@ -137,7 +134,7 @@ bool Layer::resize(const uint32_t width, const uint32_t height) {
setSize(desiredWidth, desiredHeight);
if (fbo) {
- caches.activeTexture(0);
+ caches.textureState().activateTexture(0);
bindTexture();
allocateTexture();
@@ -168,7 +165,7 @@ void Layer::removeFbo(bool flush) {
renderState.bindFramebuffer(previousFbo);
caches.renderBufferCache.put(stencil);
- stencil = NULL;
+ stencil = nullptr;
}
if (fbo) {
@@ -189,7 +186,7 @@ void Layer::updateDeferred(RenderNode* renderNode, int left, int top, int right,
void Layer::setPaint(const SkPaint* paint) {
OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
- setColorFilter((paint) ? paint->getColorFilter() : NULL);
+ setColorFilter((paint) ? paint->getColorFilter() : nullptr);
}
void Layer::setColorFilter(SkColorFilter* filter) {
@@ -198,7 +195,7 @@ void Layer::setColorFilter(SkColorFilter* filter) {
void Layer::bindTexture() const {
if (texture.id) {
- caches.bindTexture(renderTarget, texture.id);
+ caches.textureState().bindTexture(renderTarget, texture.id);
}
}
@@ -222,7 +219,7 @@ void Layer::deleteTexture() {
}
void Layer::clearTexture() {
- caches.unbindTexture(texture.id);
+ caches.textureState().unbindTexture(texture.id);
texture.id = 0;
}
@@ -233,7 +230,7 @@ void Layer::allocateTexture() {
if (texture.id) {
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glTexImage2D(renderTarget, 0, GL_RGBA, getWidth(), getHeight(), 0,
- GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
}
}
@@ -249,8 +246,7 @@ void Layer::defer(const OpenGLRenderer& rootRenderer) {
dirtyRect.set(0, 0, width, height);
}
- delete deferredList;
- deferredList = new DeferredDisplayList(dirtyRect);
+ deferredList.reset(new DeferredDisplayList(dirtyRect));
DeferStateStruct deferredState(*deferredList, *renderer,
RenderNode::kReplayFlag_ClipChildren);
@@ -266,19 +262,16 @@ void Layer::defer(const OpenGLRenderer& rootRenderer) {
}
void Layer::cancelDefer() {
- renderNode = NULL;
+ renderNode = nullptr;
deferredUpdateScheduled = false;
- if (deferredList) {
- delete deferredList;
- deferredList = NULL;
- }
+ deferredList.release();
}
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() != NULL) ? renderNode->getName() : "Layer");
+ renderer->startMark((renderNode.get() != nullptr) ? renderNode->getName() : "Layer");
renderer->setViewport(layer.getWidth(), layer.getHeight());
renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
@@ -289,7 +282,7 @@ void Layer::flush() {
renderer->finish();
dirtyRect.setEmpty();
- renderNode = NULL;
+ renderNode = nullptr;
renderer->endMark();
}
@@ -310,7 +303,7 @@ void Layer::render(const OpenGLRenderer& rootRenderer) {
dirtyRect.setEmpty();
deferredUpdateScheduled = false;
- renderNode = NULL;
+ renderNode = nullptr;
}
void Layer::postDecStrong() {
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index eb84991..84ff021 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -20,6 +20,8 @@
#include <cutils/compiler.h>
#include <sys/types.h>
#include <utils/StrongPointer.h>
+#include <utils/RefBase.h>
+#include <memory>
#include <GLES2/gl2.h>
@@ -43,9 +45,9 @@ namespace uirenderer {
// Forward declarations
class Caches;
+class RenderNode;
class RenderState;
class OpenGLRenderer;
-class RenderNode;
class DeferredDisplayList;
struct DeferStateStruct;
@@ -325,7 +327,7 @@ public:
* Used for deferred updates.
*/
bool deferredUpdateScheduled;
- OpenGLRenderer* renderer;
+ std::unique_ptr<OpenGLRenderer> renderer;
sp<RenderNode> renderNode;
Rect dirtyRect;
bool debugDrawUpdate;
@@ -422,7 +424,7 @@ private:
* Used to defer display lists when the layer is updated with a
* display list.
*/
- DeferredDisplayList* deferredList;
+ std::unique_ptr<DeferredDisplayList> deferredList;
/**
* This convex path should be used to mask the layer's draw to the screen.
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index 3216cd2..60d4f4f 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -33,7 +33,7 @@ namespace uirenderer {
LayerCache::LayerCache(): mSize(0), mMaxSize(MB(DEFAULT_LAYER_CACHE_SIZE)) {
char property[PROPERTY_VALUE_MAX];
- if (property_get(PROPERTY_LAYER_CACHE_SIZE, property, NULL) > 0) {
+ if (property_get(PROPERTY_LAYER_CACHE_SIZE, property, nullptr) > 0) {
INIT_LOGD(" Setting layer cache size to %sMB", property);
setMaxSize(MB(atof(property)));
} else {
@@ -80,13 +80,11 @@ int LayerCache::LayerEntry::compare(const LayerCache::LayerEntry& lhs,
void LayerCache::deleteLayer(Layer* layer) {
if (layer) {
- if (kDebugLayers) {
- ALOGD("Destroying layer %dx%d, fbo %d", layer->getWidth(), layer->getHeight(),
- layer->getFbo());
- }
+ LAYER_LOGD("Destroying layer %dx%d, fbo %d", layer->getWidth(), layer->getHeight(),
+ layer->getFbo());
mSize -= layer->getWidth() * layer->getHeight() * 4;
layer->state = Layer::kState_DeletedFromCache;
- layer->decStrong(0);
+ layer->decStrong(nullptr);
}
}
@@ -99,7 +97,7 @@ void LayerCache::clear() {
}
Layer* LayerCache::get(RenderState& renderState, const uint32_t width, const uint32_t height) {
- Layer* layer = NULL;
+ Layer* layer = nullptr;
LayerEntry entry(width, height);
ssize_t index = mCache.indexOf(entry);
@@ -112,13 +110,9 @@ Layer* LayerCache::get(RenderState& renderState, const uint32_t width, const uin
layer->state = Layer::kState_RemovedFromCache;
mSize -= layer->getWidth() * layer->getHeight() * 4;
- if (kDebugLayers) {
- ALOGD("Reusing layer %dx%d", layer->getWidth(), layer->getHeight());
- }
+ LAYER_LOGD("Reusing layer %dx%d", layer->getWidth(), layer->getHeight());
} else {
- if (kDebugLayers) {
- ALOGD("Creating new layer %dx%d", entry.mWidth, entry.mHeight);
- }
+ LAYER_LOGD("Creating new layer %dx%d", entry.mWidth, entry.mHeight);
layer = new Layer(Layer::kType_DisplayList, renderState, entry.mWidth, entry.mHeight);
layer->setBlend(true);
@@ -143,9 +137,7 @@ void LayerCache::dump() {
size_t size = mCache.size();
for (size_t i = 0; i < size; i++) {
const LayerEntry& entry = mCache.itemAt(i);
- if (kDebugLayers) {
- ALOGD(" Layer size %dx%d", entry.mWidth, entry.mHeight);
- }
+ ALOGD(" Layer size %dx%d", entry.mWidth, entry.mHeight);
}
}
@@ -165,10 +157,8 @@ bool LayerCache::put(Layer* layer) {
deleteLayer(victim);
mCache.removeAt(position);
- if (kDebugLayers) {
- ALOGD(" Deleting layer %.2fx%.2f", victim->layer.getWidth(),
- victim->layer.getHeight());
- }
+ LAYER_LOGD(" Deleting layer %.2fx%.2f", victim->layer.getWidth(),
+ victim->layer.getHeight());
}
layer->cancelDefer();
diff --git a/libs/hwui/LayerCache.h b/libs/hwui/LayerCache.h
index 81810ac..7d17b9b 100644
--- a/libs/hwui/LayerCache.h
+++ b/libs/hwui/LayerCache.h
@@ -26,11 +26,14 @@ namespace uirenderer {
class RenderState;
-// Debug
+///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
#if DEBUG_LAYERS
-static const bool kDebugLayers = true;
+ #define LAYER_LOGD(...) ALOGD(__VA_ARGS__)
#else
-static const bool kDebugLayers = false;
+ #define LAYER_LOGD(...)
#endif
///////////////////////////////////////////////////////////////////////////////
@@ -93,10 +96,10 @@ public:
private:
struct LayerEntry {
LayerEntry():
- mLayer(NULL), mWidth(0), mHeight(0) {
+ mLayer(nullptr), mWidth(0), mHeight(0) {
}
- LayerEntry(const uint32_t layerWidth, const uint32_t layerHeight): mLayer(NULL) {
+ LayerEntry(const uint32_t layerWidth, const uint32_t layerHeight): mLayer(nullptr) {
mWidth = Layer::computeIdealWidth(layerWidth);
mHeight = Layer::computeIdealHeight(layerHeight);
}
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 83f9c6a..b4b14e8 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -17,18 +17,19 @@
#define LOG_TAG "OpenGLRenderer"
#define ATRACE_TAG ATRACE_TAG_VIEW
-#include <ui/Rect.h>
-
-#include <private/hwui/DrawGlInfo.h>
-
-#include "RenderState.h"
#include "LayerCache.h"
#include "LayerRenderer.h"
#include "Matrix.h"
#include "Properties.h"
#include "Rect.h"
+#include "renderstate/RenderState.h"
#include "utils/TraceUtils.h"
+#include <ui/Rect.h>
+
+#include <private/hwui/DrawGlInfo.h>
+
+
namespace android {
namespace uirenderer {
@@ -44,11 +45,11 @@ LayerRenderer::LayerRenderer(RenderState& renderState, Layer* layer)
LayerRenderer::~LayerRenderer() {
}
-status_t LayerRenderer::prepareDirty(float left, float top, float right, float bottom,
+void LayerRenderer::prepareDirty(float left, float top, float right, float bottom,
bool opaque) {
LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->getFbo());
- renderState().bindFramebuffer(mLayer->getFbo());
+ mRenderState.bindFramebuffer(mLayer->getFbo());
const float width = mLayer->layer.getWidth();
const float height = mLayer->layer.getHeight();
@@ -65,25 +66,23 @@ status_t LayerRenderer::prepareDirty(float left, float top, float right, float b
}
mLayer->clipRect.set(dirty);
- return OpenGLRenderer::prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, opaque);
+ OpenGLRenderer::prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, opaque);
}
-status_t LayerRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
+void LayerRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
if (mLayer->isDirty()) {
- getCaches().disableScissor();
+ mRenderState.scissor().setEnabled(false);
glClear(GL_COLOR_BUFFER_BIT);
- getCaches().resetScissor();
+ mRenderState.scissor().reset();
mLayer->setDirty(false);
-
- return DrawGlInfo::kStatusDone;
+ } else {
+ OpenGLRenderer::clear(left, top, right, bottom, opaque);
}
-
- return OpenGLRenderer::clear(left, top, right, bottom, opaque);
}
-void LayerRenderer::finish() {
- OpenGLRenderer::finish();
+bool LayerRenderer::finish() {
+ bool retval = OpenGLRenderer::finish();
generateMesh();
@@ -91,9 +90,10 @@ void LayerRenderer::finish() {
// 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 {
+GLuint LayerRenderer::onGetTargetFbo() const {
return mLayer->getFbo();
}
@@ -118,7 +118,7 @@ void LayerRenderer::ensureStencilBuffer() {
///////////////////////////////////////////////////////////////////////////////
Region* LayerRenderer::getRegion() const {
- if (currentSnapshot()->flags & Snapshot::kFlagFboTarget) {
+ if (mState.currentFlags() & Snapshot::kFlagFboTarget) {
return OpenGLRenderer::getRegion();
}
return &mLayer->region;
@@ -131,7 +131,7 @@ void LayerRenderer::generateMesh() {
if (mLayer->region.isRect() || mLayer->region.isEmpty()) {
if (mLayer->mesh) {
delete[] mLayer->mesh;
- mLayer->mesh = NULL;
+ mLayer->mesh = nullptr;
mLayer->meshElementCount = 0;
}
@@ -152,7 +152,7 @@ void LayerRenderer::generateMesh() {
if (mLayer->mesh && mLayer->meshElementCount < elementCount) {
delete[] mLayer->mesh;
- mLayer->mesh = NULL;
+ mLayer->mesh = nullptr;
}
if (!mLayer->mesh) {
@@ -193,14 +193,14 @@ Layer* LayerRenderer::createRenderLayer(RenderState& renderState, uint32_t width
GLuint fbo = caches.fboCache.get();
if (!fbo) {
ALOGW("Could not obtain an FBO");
- return NULL;
+ return nullptr;
}
- caches.activeTexture(0);
+ caches.textureState().activateTexture(0);
Layer* layer = caches.layerCache.get(renderState, width, height);
if (!layer) {
ALOGW("Could not obtain a layer");
- return NULL;
+ return nullptr;
}
// We first obtain a layer before comparing against the max texture size
@@ -213,9 +213,9 @@ Layer* LayerRenderer::createRenderLayer(RenderState& renderState, uint32_t width
// 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(0);
+ layer->decStrong(nullptr);
- return NULL;
+ return nullptr;
}
layer->setFbo(fbo);
@@ -223,7 +223,7 @@ Layer* LayerRenderer::createRenderLayer(RenderState& renderState, uint32_t width
layer->texCoords.set(0.0f, height / float(layer->getHeight()),
width / float(layer->getWidth()), 0.0f);
layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
- layer->setColorFilter(NULL);
+ layer->setColorFilter(nullptr);
layer->setDirty(true);
layer->region.clear();
@@ -241,8 +241,8 @@ Layer* LayerRenderer::createRenderLayer(RenderState& renderState, uint32_t width
if (glGetError() != GL_NO_ERROR) {
ALOGE("Could not allocate texture for layer (fbo=%d %dx%d)", fbo, width, height);
renderState.bindFramebuffer(previousFbo);
- layer->decStrong(0);
- return NULL;
+ layer->decStrong(nullptr);
+ return nullptr;
}
}
@@ -283,7 +283,7 @@ Layer* LayerRenderer::createTextureLayer(RenderState& renderState) {
layer->region.clear();
layer->setRenderTarget(GL_NONE); // see ::updateTextureLayer()
- Caches::getInstance().activeTexture(0);
+ Caches::getInstance().textureState().activateTexture(0);
layer->generateTexture();
return layer;
@@ -317,7 +317,7 @@ void LayerRenderer::destroyLayer(Layer* layer) {
if (!Caches::getInstance().layerCache.put(layer)) {
LAYER_RENDERER_LOGD(" Destroyed!");
- layer->decStrong(0);
+ layer->decStrong(nullptr);
} else {
LAYER_RENDERER_LOGD(" Cached!");
#if DEBUG_LAYER_RENDERER
@@ -337,7 +337,7 @@ void LayerRenderer::flushLayer(RenderState& renderState, Layer* layer) {
if (fbo) {
// If possible, discard any enqueud operations on deferred
// rendering architectures
- if (Extensions::getInstance().hasDiscardFramebuffer()) {
+ if (Caches::getInstance().extensions().hasDiscardFramebuffer()) {
GLuint previousFbo = renderState.getFramebuffer();
if (fbo != previousFbo) {
renderState.bindFramebuffer(fbo);
@@ -412,8 +412,8 @@ bool LayerRenderer::copyLayer(RenderState& renderState, Layer* layer, SkBitmap*
glGenTextures(1, &texture);
if ((error = glGetError()) != GL_NO_ERROR) goto error;
- caches.activeTexture(0);
- caches.bindTexture(texture);
+ caches.textureState().activateTexture(0);
+ caches.textureState().bindTexture(texture);
glPixelStorei(GL_PACK_ALIGNMENT, bitmap->bytesPerPixel());
@@ -424,7 +424,7 @@ bool LayerRenderer::copyLayer(RenderState& renderState, Layer* layer, SkBitmap*
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, format, bitmap->width(), bitmap->height(),
- 0, format, type, NULL);
+ 0, format, type, nullptr);
if ((error = glGetError()) != GL_NO_ERROR) goto error;
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
@@ -437,7 +437,7 @@ bool LayerRenderer::copyLayer(RenderState& renderState, Layer* layer, SkBitmap*
renderer.OpenGLRenderer::prepareDirty(0.0f, 0.0f,
bitmap->width(), bitmap->height(), !layer->isBlend());
- caches.disableScissor();
+ renderState.scissor().setEnabled(false);
renderer.translate(0.0f, bitmap->height());
renderer.scale(1.0f, -1.0f);
@@ -475,7 +475,7 @@ error:
renderState.bindFramebuffer(previousFbo);
layer->setAlpha(alpha, mode);
layer->setFbo(previousLayerFbo);
- caches.deleteTexture(texture);
+ caches.textureState().deleteTexture(texture);
caches.fboCache.put(fbo);
renderState.setViewport(previousViewportWidth, previousViewportHeight);
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index 4d8620b..5e1e835 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -49,10 +49,11 @@ public:
LayerRenderer(RenderState& renderState, Layer* layer);
virtual ~LayerRenderer();
- virtual void onViewportInitialized() { /* do nothing */ }
- virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque);
- virtual status_t clear(float left, float top, float right, float bottom, bool opaque);
- virtual void finish();
+ virtual void onViewportInitialized() override { /* do nothing */ }
+ virtual void prepareDirty(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);
@@ -65,11 +66,11 @@ public:
static void flushLayer(RenderState& renderState, Layer* layer);
protected:
- virtual void ensureStencilBuffer();
- virtual bool hasLayer() const;
- virtual Region* getRegion() const;
- virtual GLuint getTargetFbo() const;
- virtual bool suppressErrorChecks() const;
+ virtual void ensureStencilBuffer() override;
+ virtual bool hasLayer() const override;
+ virtual Region* getRegion() const override;
+ virtual GLuint onGetTargetFbo() const override;
+ virtual bool suppressErrorChecks() const override;
private:
void generateMesh();
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 1c5c578..a760135 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -210,7 +210,7 @@ public:
void decomposeScale(float& sx, float& sy) const;
- void dump(const char* label = NULL) const;
+ void dump(const char* label = nullptr) const;
static const Matrix4& identity();
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 355a31f..5a0cc1e 100755..100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -14,7 +14,26 @@
* limitations under the License.
*/
-#define LOG_TAG "OpenGLRenderer"
+#include "OpenGLRenderer.h"
+
+#include "DeferredDisplayList.h"
+#include "DisplayListRenderer.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 "utils/GLUtils.h"
+#include "utils/PaintUtils.h"
+#include "utils/TraceUtils.h"
#include <stdlib.h>
#include <stdint.h>
@@ -32,20 +51,6 @@
#include <ui/Rect.h>
-#include "OpenGLRenderer.h"
-#include "DeferredDisplayList.h"
-#include "DisplayListRenderer.h"
-#include "Fence.h"
-#include "RenderState.h"
-#include "PathTessellator.h"
-#include "Properties.h"
-#include "ShadowTessellator.h"
-#include "SkiaShader.h"
-#include "utils/GLUtils.h"
-#include "utils/TraceUtils.h"
-#include "Vector.h"
-#include "VertexBuffer.h"
-
#if DEBUG_DETAILED_EVENTS
#define EVENT_LOGD(...) eventMarkDEBUG(__VA_ARGS__)
#else
@@ -66,55 +71,6 @@ static GLenum getFilter(const SkPaint* paint) {
// Globals
///////////////////////////////////////////////////////////////////////////////
-/**
- * Structure mapping Skia xfermodes to OpenGL blending factors.
- */
-struct Blender {
- SkXfermode::Mode mode;
- GLenum src;
- GLenum dst;
-}; // struct Blender
-
-// In this array, the index of each Blender equals the value of the first
-// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
-static const Blender gBlends[] = {
- { SkXfermode::kClear_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kSrc_Mode, GL_ONE, GL_ZERO },
- { SkXfermode::kDst_Mode, GL_ZERO, GL_ONE },
- { SkXfermode::kSrcOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE },
- { SkXfermode::kSrcIn_Mode, GL_DST_ALPHA, GL_ZERO },
- { SkXfermode::kDstIn_Mode, GL_ZERO, GL_SRC_ALPHA },
- { SkXfermode::kSrcOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
- { SkXfermode::kDstOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kSrcATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kDstATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
- { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kPlus_Mode, GL_ONE, GL_ONE },
- { SkXfermode::kModulate_Mode, GL_ZERO, GL_SRC_COLOR },
- { SkXfermode::kScreen_Mode, GL_ONE, GL_ONE_MINUS_SRC_COLOR }
-};
-
-// This array contains the swapped version of each SkXfermode. For instance
-// this array's SrcOver blending mode is actually DstOver. You can refer to
-// createLayer() for more information on the purpose of this array.
-static const Blender gBlendsSwap[] = {
- { SkXfermode::kClear_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
- { SkXfermode::kSrc_Mode, GL_ZERO, GL_ONE },
- { SkXfermode::kDst_Mode, GL_ONE, GL_ZERO },
- { SkXfermode::kSrcOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE },
- { SkXfermode::kDstOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kSrcIn_Mode, GL_ZERO, GL_SRC_ALPHA },
- { SkXfermode::kDstIn_Mode, GL_DST_ALPHA, GL_ZERO },
- { SkXfermode::kSrcOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kDstOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
- { SkXfermode::kSrcATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
- { SkXfermode::kDstATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
- { SkXfermode::kPlus_Mode, GL_ONE, GL_ONE },
- { SkXfermode::kModulate_Mode, GL_DST_COLOR, GL_ZERO },
- { SkXfermode::kScreen_Mode, GL_ONE_MINUS_DST_COLOR, GL_ONE }
-};
///////////////////////////////////////////////////////////////////////////////
// Functions
@@ -130,13 +86,14 @@ static inline T min(T a, T b) {
///////////////////////////////////////////////////////////////////////////////
OpenGLRenderer::OpenGLRenderer(RenderState& renderState)
- : mFrameStarted(false)
+ : mState(*this)
, mCaches(Caches::getInstance())
- , mExtensions(Extensions::getInstance())
, mRenderState(renderState)
+ , mFrameStarted(false)
, mScissorOptimizationDisabled(false)
, mSuppressTiling(false)
, mFirstFrameAfterResize(true)
+ , mDirty(false)
, mLightCenter((Vector3){FLT_MIN, FLT_MIN, FLT_MIN})
, mLightRadius(FLT_MIN)
, mAmbientShadowAlpha(0)
@@ -145,7 +102,7 @@ OpenGLRenderer::OpenGLRenderer(RenderState& renderState)
memset(&mDrawModifiers, 0, sizeof(mDrawModifiers));
mDrawModifiers.mOverrideLayerAlpha = 1.0f;
- memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
+ memcpy(mMeshVertices, kUnitQuadVertices, sizeof(kUnitQuadVertices));
}
OpenGLRenderer::~OpenGLRenderer() {
@@ -179,28 +136,26 @@ void OpenGLRenderer::initLight(const Vector3& lightCenter, float lightRadius,
void OpenGLRenderer::onViewportInitialized() {
glDisable(GL_DITHER);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-
- glEnableVertexAttribArray(Program::kBindingPosition);
mFirstFrameAfterResize = true;
}
void OpenGLRenderer::setupFrameState(float left, float top,
float right, float bottom, bool opaque) {
mCaches.clearGarbage();
- initializeSaveStack(left, top, right, bottom, mLightCenter);
+ mState.initializeSaveStack(left, top, right, bottom, mLightCenter);
mOpaque = opaque;
mTilingClip.set(left, top, right, bottom);
}
-status_t OpenGLRenderer::startFrame() {
- if (mFrameStarted) return DrawGlInfo::kStatusDone;
+void OpenGLRenderer::startFrame() {
+ if (mFrameStarted) return;
mFrameStarted = true;
- mDirtyClip = true;
+ mState.setDirtyClip(true);
discardFramebuffer(mTilingClip.left, mTilingClip.top, mTilingClip.right, mTilingClip.bottom);
- mRenderState.setViewport(getWidth(), getHeight());
+ mRenderState.setViewport(mState.getWidth(), mState.getHeight());
// Functors break the tiling extension in pretty spectacular ways
// This ensures we don't use tiling when a functor is going to be
@@ -213,11 +168,11 @@ status_t OpenGLRenderer::startFrame() {
debugOverdraw(true, true);
- return clear(mTilingClip.left, mTilingClip.top,
+ clear(mTilingClip.left, mTilingClip.top,
mTilingClip.right, mTilingClip.bottom, mOpaque);
}
-status_t OpenGLRenderer::prepareDirty(float left, float top,
+void OpenGLRenderer::prepareDirty(float left, float top,
float right, float bottom, bool opaque) {
setupFrameState(left, top, right, bottom, opaque);
@@ -227,22 +182,20 @@ status_t OpenGLRenderer::prepareDirty(float left, float top,
// for each layer and wait until the first drawing command
// to start the frame
if (currentSnapshot()->fbo == 0) {
- syncState();
+ mRenderState.blend().syncEnabled();
updateLayers();
} else {
- return startFrame();
+ startFrame();
}
-
- return DrawGlInfo::kStatusDone;
}
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 (mExtensions.hasDiscardFramebuffer() &&
- left <= 0.0f && top <= 0.0f && right >= getWidth() && bottom >= getHeight()) {
- const bool isFbo = getTargetFbo() == 0;
+ if (mCaches.extensions().hasDiscardFramebuffer() &&
+ left <= 0.0f && top <= 0.0f && right >= mState.getWidth() && bottom >= mState.getHeight()) {
+ const bool isFbo = onGetTargetFbo() == 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 };
@@ -250,24 +203,16 @@ void OpenGLRenderer::discardFramebuffer(float left, float top, float right, floa
}
}
-status_t OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
+void OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
if (!opaque) {
- mCaches.enableScissor();
- mCaches.setScissor(left, getViewportHeight() - bottom, right - left, bottom - top);
+ mRenderState.scissor().setEnabled(true);
+ mRenderState.scissor().set(left, getViewportHeight() - bottom, right - left, bottom - top);
glClear(GL_COLOR_BUFFER_BIT);
- return DrawGlInfo::kStatusDrew;
+ mDirty = true;
+ return;
}
- mCaches.resetScissor();
- return DrawGlInfo::kStatusDone;
-}
-
-void OpenGLRenderer::syncState() {
- if (mCaches.blend) {
- glEnable(GL_BLEND);
- } else {
- glDisable(GL_BLEND);
- }
+ mRenderState.scissor().reset();
}
void OpenGLRenderer::startTilingCurrentClip(bool opaque, bool expand) {
@@ -307,18 +252,14 @@ void OpenGLRenderer::endTiling() {
if (!mSuppressTiling) mCaches.endTiling();
}
-void OpenGLRenderer::finish() {
+bool OpenGLRenderer::finish() {
renderOverdraw();
endTiling();
-
- for (size_t i = 0; i < mTempPaths.size(); i++) {
- delete mTempPaths[i];
- }
mTempPaths.clear();
// When finish() is invoked on FBO 0 we've reached the end
// of the current frame
- if (getTargetFbo() == 0) {
+ if (onGetTargetFbo() == 0) {
mCaches.pathCache.trim();
mCaches.tessellationCache.trim();
}
@@ -338,6 +279,8 @@ void OpenGLRenderer::finish() {
}
mFrameStarted = false;
+
+ return reportAndClearDirty();
}
void OpenGLRenderer::resumeAfterLayer() {
@@ -345,14 +288,14 @@ void OpenGLRenderer::resumeAfterLayer() {
mRenderState.bindFramebuffer(currentSnapshot()->fbo);
debugOverdraw(true, false);
- mCaches.resetScissor();
+ mRenderState.scissor().reset();
dirtyClip();
}
-status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
- if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
+void OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
+ if (mState.currentlyIgnored()) return;
- Rect clip(*currentClipRect());
+ Rect clip(mState.currentClipRect());
clip.snapToPixelBoundaries();
// Since we don't know what the functor will draw, let's dirty
@@ -371,12 +314,12 @@ status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
info.height = getViewportHeight();
currentTransform()->copyTo(&info.transform[0]);
- bool prevDirtyClip = mDirtyClip;
+ bool prevDirtyClip = mState.getDirtyClip();
// setup GL state for functor
- if (mDirtyClip) {
+ if (mState.getDirtyClip()) {
setStencilFromClip(); // can issue draws, so must precede enableScissor()/interrupt()
}
- if (mCaches.enableScissor() || prevDirtyClip) {
+ if (mRenderState.scissor().setEnabled(true) || prevDirtyClip) {
setScissorFromClip();
}
@@ -384,7 +327,7 @@ status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
// Scissor may have been modified, reset dirty clip
dirtyClip();
- return DrawGlInfo::kStatusDrew;
+ mDirty = true;
}
///////////////////////////////////////////////////////////////////////////////
@@ -402,8 +345,6 @@ void OpenGLRenderer::eventMarkDEBUG(const char* fmt, ...) const {
va_end(ap);
eventMark(buf);
-#else
- (void)fmt;
#endif
}
@@ -425,30 +366,32 @@ void OpenGLRenderer::debugOverdraw(bool enable, bool clear) {
}
void OpenGLRenderer::renderOverdraw() {
- if (mCaches.debugOverdraw && getTargetFbo() == 0) {
+ if (mCaches.debugOverdraw && onGetTargetFbo() == 0) {
const Rect* clip = &mTilingClip;
- mCaches.enableScissor();
- mCaches.setScissor(clip->left, firstSnapshot()->getViewportHeight() - clip->bottom,
- clip->right - clip->left, clip->bottom - clip->top);
+ mRenderState.scissor().setEnabled(true);
+ mRenderState.scissor().set(clip->left,
+ mState.firstSnapshot()->getViewportHeight() - clip->bottom,
+ clip->right - clip->left,
+ clip->bottom - clip->top);
// 1x overdraw
- mCaches.stencil.enableDebugTest(2);
+ mRenderState.stencil().enableDebugTest(2);
drawColor(mCaches.getOverdrawColor(1), SkXfermode::kSrcOver_Mode);
// 2x overdraw
- mCaches.stencil.enableDebugTest(3);
+ mRenderState.stencil().enableDebugTest(3);
drawColor(mCaches.getOverdrawColor(2), SkXfermode::kSrcOver_Mode);
// 3x overdraw
- mCaches.stencil.enableDebugTest(4);
+ mRenderState.stencil().enableDebugTest(4);
drawColor(mCaches.getOverdrawColor(3), SkXfermode::kSrcOver_Mode);
// 4x overdraw and higher
- mCaches.stencil.enableDebugTest(4, true);
+ mRenderState.stencil().enableDebugTest(4, true);
drawColor(mCaches.getOverdrawColor(4), SkXfermode::kSrcOver_Mode);
- mCaches.stencil.disable();
+ mRenderState.stencil().disable();
}
}
@@ -505,7 +448,7 @@ void OpenGLRenderer::updateLayers() {
if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
mLayerUpdates.clear();
- mRenderState.bindFramebuffer(getTargetFbo());
+ mRenderState.bindFramebuffer(onGetTargetFbo());
}
endMark();
}
@@ -522,7 +465,7 @@ void OpenGLRenderer::flushLayers() {
}
mLayerUpdates.clear();
- mRenderState.bindFramebuffer(getTargetFbo());
+ mRenderState.bindFramebuffer(onGetTargetFbo());
endMark();
}
@@ -556,11 +499,11 @@ void OpenGLRenderer::cancelLayerUpdate(Layer* layer) {
void OpenGLRenderer::flushLayerUpdates() {
ATRACE_NAME("Update HW Layers");
- syncState();
+ mRenderState.blend().syncEnabled();
updateLayers();
flushLayers();
// Wait for all the layer updates to be executed
- AutoFence fence;
+ glFinish();
}
void OpenGLRenderer::markLayersAsBuildLayers() {
@@ -604,9 +547,9 @@ int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
// force matrix/clip isolation for layer
flags |= SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag;
- const int count = saveSnapshot(flags);
+ const int count = mState.saveSnapshot(flags);
- if (!currentSnapshot()->isIgnored()) {
+ if (!mState.currentlyIgnored()) {
createLayer(left, top, right, bottom, paint, flags, convexMask);
}
@@ -619,7 +562,7 @@ void OpenGLRenderer::calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool
currentTransform()->mapRect(bounds);
// Layers only make sense if they are in the framebuffer's bounds
- if (bounds.intersect(*currentClipRect())) {
+ if (bounds.intersect(mState.currentClipRect())) {
// We cannot work with sub-pixels in this case
bounds.snapToPixelBoundaries();
@@ -653,17 +596,17 @@ void OpenGLRenderer::updateSnapshotIgnoreForLayer(const Rect& bounds, const Rect
if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize ||
bounds.getHeight() > mCaches.maxTextureSize ||
(fboLayer && clip.isEmpty())) {
- mSnapshot->empty = fboLayer;
+ writableSnapshot()->empty = fboLayer;
} else {
- mSnapshot->invisible = mSnapshot->invisible || (alpha <= 0 && fboLayer);
+ 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 = saveSnapshot(flags);
+ const int count = mState.saveSnapshot(flags);
- if (!currentSnapshot()->isIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) {
+ if (!mState.currentlyIgnored() && (flags & SkCanvas::kClipToLayer_SaveFlag)) {
// 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)
@@ -673,11 +616,11 @@ int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float
calculateLayerBoundsAndClip(bounds, clip, true);
updateSnapshotIgnoreForLayer(bounds, clip, true, getAlphaDirect(paint));
- if (!currentSnapshot()->isIgnored()) {
- mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
- mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
- mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
- mSnapshot->roundRectClipState = NULL;
+ 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;
}
}
@@ -737,10 +680,8 @@ int OpenGLRenderer::saveLayerDeferred(float left, float top, float right, float
*/
bool OpenGLRenderer::createLayer(float left, float top, float right, float bottom,
const SkPaint* paint, int flags, const SkPath* convexMask) {
- if (kDebugLayers) {
- ALOGD("Requesting layer %.2fx%.2f", right - left, bottom - top);
- ALOGD("Layer cache size = %d", mCaches.layerCache.getSize());
- }
+ LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top);
+ LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
const bool fboLayer = flags & SkCanvas::kClipToLayer_SaveFlag;
@@ -751,11 +692,11 @@ bool OpenGLRenderer::createLayer(float left, float top, float right, float botto
updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, getAlphaDirect(paint));
// Bail out if we won't draw in this snapshot
- if (currentSnapshot()->isIgnored()) {
+ if (mState.currentlyIgnored()) {
return false;
}
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
Layer* layer = mCaches.layerCache.get(mRenderState, bounds.getWidth(), bounds.getHeight());
if (!layer) {
return false;
@@ -771,8 +712,8 @@ bool OpenGLRenderer::createLayer(float left, float top, float right, float botto
layer->setConvexMask(convexMask); // note: the mask must be cleared before returning to the cache
// Save the layer in the snapshot
- mSnapshot->flags |= Snapshot::kFlagIsLayer;
- mSnapshot->layer = layer;
+ writableSnapshot()->flags |= Snapshot::kFlagIsLayer;
+ writableSnapshot()->layer = layer;
ATRACE_FORMAT_BEGIN("%ssaveLayer %ux%u",
fboLayer ? "" : "unclipped ",
@@ -790,7 +731,7 @@ bool OpenGLRenderer::createLayer(float left, float top, float right, float botto
// 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, NULL);
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
layer->setEmpty(false);
}
@@ -799,7 +740,7 @@ bool OpenGLRenderer::createLayer(float left, float top, float right, float botto
bounds.getWidth(), bounds.getHeight());
// Enqueue the buffer coordinates to clear the corresponding region later
- mLayers.push(new Rect(bounds));
+ mLayers.push_back(Rect(bounds));
}
}
@@ -810,13 +751,13 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {
layer->clipRect.set(clip);
layer->setFbo(mCaches.fboCache.get());
- mSnapshot->region = &mSnapshot->layer->region;
- mSnapshot->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
- mSnapshot->fbo = layer->getFbo();
- mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
- mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
- mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
- mSnapshot->roundRectClipState = NULL;
+ 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;
endTiling();
debugOverdraw(false, false);
@@ -837,8 +778,8 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {
startTilingCurrentClip(true, true);
// Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
- mCaches.enableScissor();
- mCaches.setScissor(clip.left - 1.0f, bounds.getHeight() - clip.bottom - 1.0f,
+ 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);
@@ -863,9 +804,9 @@ void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& resto
const bool fboLayer = removed.flags & Snapshot::kFlagIsFboLayer;
bool clipRequired = false;
- calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom,
- &clipRequired, NULL, false); // safely ignore return, should never be rejected
- mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
+ 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) {
endTiling();
@@ -893,9 +834,9 @@ void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& resto
layer->setAlpha(255);
}
- mCaches.unbindMeshBuffer();
+ mRenderState.meshState().unbindMeshBuffer();
- mCaches.activeTexture(0);
+ 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
@@ -908,7 +849,7 @@ void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& resto
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)
- mSnapshot->alpha = 1.0f;
+ writableSnapshot()->alpha = 1.0f;
composeLayerRect(layer, rect, true);
restore();
}
@@ -916,12 +857,10 @@ void OpenGLRenderer::composeLayer(const Snapshot& removed, const Snapshot& resto
dirtyClip();
// Failing to add the layer to the cache should happen only if the layer is too large
- layer->setConvexMask(NULL);
+ layer->setConvexMask(nullptr);
if (!mCaches.layerCache.put(layer)) {
- if (kDebugLayers) {
- ALOGD("Deleting layer");
- }
- layer->decStrong(0);
+ LAYER_LOGD("Deleting layer");
+ layer->decStrong(nullptr);
}
}
@@ -964,7 +903,7 @@ void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
setupDrawTextureTransformUniforms(layer->getTexTransform());
setupDrawMesh(&mMeshVertices[0].x, &mMeshVertices[0].u);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
}
void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
@@ -1006,7 +945,7 @@ void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap)
drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
layer->getTexture(), &layerPaint, blend,
&mMeshVertices[0].x, &mMeshVertices[0].u,
- GL_TRIANGLE_STRIP, gMeshCount, swap, swap || simpleTransform);
+ GL_TRIANGLE_STRIP, kUnitQuadCount, swap, swap || simpleTransform);
resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
}
@@ -1018,13 +957,13 @@ void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap)
* 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(mCaches.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_IF(COND, DRAW_COMMAND) { \
+ DRAW_COMMAND; \
+ if (CC_UNLIKELY(mCaches.debugOverdraw && onGetTargetFbo() == 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)
@@ -1038,14 +977,14 @@ public:
, mLayer(layer) {
}
- virtual bool asACustomShader(void** data) const {
+ virtual bool asACustomShader(void** data) const override {
if (data) {
*data = static_cast<void*>(mLayer);
}
return true;
}
- virtual bool isOpaque() const {
+ virtual bool isOpaque() const override {
return !mLayer->isBlend();
}
@@ -1054,13 +993,13 @@ protected:
LOG_ALWAYS_FATAL("LayerShader should never be drawn with raster backend.");
}
- virtual void flatten(SkWriteBuffer&) const {
+ virtual void flatten(SkWriteBuffer&) const override {
LOG_ALWAYS_FATAL("LayerShader should never be flattened.");
}
- virtual Factory getFactory() const {
+ virtual Factory getFactory() const override {
LOG_ALWAYS_FATAL("LayerShader should never be created from a stream.");
- return NULL;
+ return nullptr;
}
private:
// Unowned.
@@ -1093,7 +1032,7 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
const SkPath* maskPath = layer->getConvexMask();
DRAW_DOUBLE_STENCIL(drawConvexPath(*maskPath, &paint));
- paint.setShader(NULL);
+ paint.setShader(nullptr);
restore();
return;
@@ -1172,9 +1111,9 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
numQuads++;
- if (numQuads >= gMaxNumberOfQuads) {
+ if (numQuads >= kMaxNumberOfQuads) {
DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
- GL_UNSIGNED_SHORT, NULL));
+ GL_UNSIGNED_SHORT, nullptr));
numQuads = 0;
mesh = mCaches.getRegionMesh();
}
@@ -1182,7 +1121,7 @@ void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
if (numQuads > 0) {
DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
- GL_UNSIGNED_SHORT, NULL));
+ GL_UNSIGNED_SHORT, nullptr));
}
#if DEBUG_LAYERS_AS_REGIONS
@@ -1253,7 +1192,7 @@ void OpenGLRenderer::dirtyLayer(const float left, const float top,
}
void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) {
- if (bounds.intersect(*currentClipRect())) {
+ if (bounds.intersect(mState.currentClipRect())) {
bounds.snapToPixelBoundaries();
android::Rect dirty(bounds.left, bounds.top, bounds.right, bounds.bottom);
if (!dirty.isEmpty()) {
@@ -1265,10 +1204,10 @@ void OpenGLRenderer::dirtyLayerUnchecked(Rect& bounds, Region* region) {
void OpenGLRenderer::issueIndexedQuadDraw(Vertex* mesh, GLsizei quadsCount) {
GLsizei elementsCount = quadsCount * 6;
while (elementsCount > 0) {
- GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6);
+ GLsizei drawCount = min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
setupDrawIndexedVertices(&mesh[0].x);
- glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, NULL);
+ glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, nullptr);
elementsCount -= drawCount;
// Though there are 4 vertices in a quad, we use 6 indices per
@@ -1281,7 +1220,7 @@ void OpenGLRenderer::clearLayerRegions() {
const size_t count = mLayers.size();
if (count == 0) return;
- if (!currentSnapshot()->isIgnored()) {
+ if (!mState.currentlyIgnored()) {
EVENT_LOGD("clearLayerRegions");
// Doing several glScissor/glClear here can negatively impact
// GPUs with a tiler architecture, instead we draw quads with
@@ -1290,20 +1229,18 @@ void OpenGLRenderer::clearLayerRegions() {
// 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 = mCaches.disableScissor();
+ bool scissorChanged = mRenderState.scissor().setEnabled(false);
Vertex mesh[count * 4];
Vertex* vertex = mesh;
for (uint32_t i = 0; i < count; i++) {
- Rect* bounds = mLayers.itemAt(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);
-
- delete bounds;
+ 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 setupDraw() to prevent stencil setup to do
@@ -1323,11 +1260,8 @@ void OpenGLRenderer::clearLayerRegions() {
issueIndexedQuadDraw(&mesh[0], count);
- if (scissorChanged) mCaches.enableScissor();
+ if (scissorChanged) mRenderState.scissor().setEnabled(true);
} else {
- for (uint32_t i = 0; i < count; i++) {
- delete mLayers.itemAt(i);
- }
mLayers.clear();
}
}
@@ -1337,7 +1271,7 @@ void OpenGLRenderer::clearLayerRegions() {
///////////////////////////////////////////////////////////////////////////////
bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDeferFlags) {
- const Rect* currentClip = currentClipRect();
+ const Rect& currentClip = mState.currentClipRect();
const mat4* currentMatrix = currentTransform();
if (stateDeferFlags & kStateDeferFlag_Draw) {
@@ -1349,32 +1283,32 @@ bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDef
// is used, it should more closely duplicate the quickReject logic (in how it uses
// snapToPixelBoundaries)
- if(!clippedBounds.intersect(*currentClip)) {
+ if (!clippedBounds.intersect(currentClip)) {
// quick rejected
return true;
}
state.mClipSideFlags = kClipSide_None;
- if (!currentClip->contains(state.mBounds)) {
+ 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;
+ 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.mBounds.set(currentClip);
}
}
state.mClipValid = (stateDeferFlags & kStateDeferFlag_Clip);
if (state.mClipValid) {
- state.mClip.set(*currentClip);
+ state.mClip.set(currentClip);
}
// Transform, drawModifiers, and alpha always deferred, since they are used by state operations
@@ -1390,12 +1324,12 @@ bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDef
void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) {
setMatrix(state.mMatrix);
- mSnapshot->alpha = state.mAlpha;
+ writableSnapshot()->alpha = state.mAlpha;
mDrawModifiers = state.mDrawModifiers;
- mSnapshot->roundRectClipState = state.mRoundRectClipState;
+ writableSnapshot()->roundRectClipState = state.mRoundRectClipState;
if (state.mClipValid && !skipClipRestore) {
- mSnapshot->setClip(state.mClip.left, state.mClip.top,
+ writableSnapshot()->setClip(state.mClip.left, state.mClip.top,
state.mClip.right, state.mClip.bottom);
dirtyClip();
}
@@ -1409,13 +1343,14 @@ void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool
* This method should be called when restoreDisplayState() won't be restoring the clip
*/
void OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) {
- if (clipRect != NULL) {
- mSnapshot->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
+ if (clipRect != nullptr) {
+ writableSnapshot()->setClip(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
} else {
- mSnapshot->setClip(0, 0, getWidth(), getHeight());
+ writableSnapshot()->setClip(0, 0, mState.getWidth(), mState.getHeight());
}
dirtyClip();
- mCaches.setScissorEnabled(clipRect != NULL || mScissorOptimizationDisabled);
+ bool enableScissor = (clipRect != nullptr) || mScissorOptimizationDisabled;
+ mRenderState.scissor().setEnabled(enableScissor);
}
///////////////////////////////////////////////////////////////////////////////
@@ -1423,12 +1358,12 @@ void OpenGLRenderer::setupMergedMultiDraw(const Rect* clipRect) {
///////////////////////////////////////////////////////////////////////////////
void OpenGLRenderer::setScissorFromClip() {
- Rect clip(*currentClipRect());
+ Rect clip(mState.currentClipRect());
clip.snapToPixelBoundaries();
- if (mCaches.setScissor(clip.left, getViewportHeight() - clip.bottom,
+ if (mRenderState.scissor().set(clip.left, getViewportHeight() - clip.bottom,
clip.getWidth(), clip.getHeight())) {
- mDirtyClip = false;
+ mState.setDirtyClip(false);
}
}
@@ -1450,34 +1385,110 @@ void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) {
endTiling();
RenderBuffer* buffer = mCaches.renderBufferCache.get(
- Stencil::getSmallestStencilFormat(), layer->getWidth(), layer->getHeight());
+ Stencil::getSmallestStencilFormat(),
+ layer->getWidth(), layer->getHeight());
layer->setStencilRenderBuffer(buffer);
startTiling(layer->clipRect, layer->layer.getHeight());
}
}
+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 count = rectangleList.getTransformedRectanglesCount();
+ std::vector<Vertex> rectangleVertices(count * 4);
+ Rect scissorBox = rectangleList.calculateBounds();
+ scissorBox.snapToPixelBoundaries();
+ for (int i = 0; i < count; ++i) {
+ const TransformedRectangle& tr(rectangleList.getTransformedRectangle(i));
+ const Matrix4& transform = tr.getTransform();
+ Rect bounds = tr.getBounds();
+ if (transform.rectToRect()) {
+ transform.mapRect(bounds);
+ if (!bounds.intersect(scissorBox)) {
+ bounds.setEmpty();
+ } else {
+ 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 SkPaint* paint = nullptr;
+ setupDraw();
+ setupDrawNoTexture();
+ setupDrawColor(0, 0xff * currentSnapshot()->alpha);
+ setupDrawShader(getShader(paint));
+ setupDrawColorFilter(getColorFilter(paint));
+ setupDrawBlending(paint);
+ setupDrawProgram();
+ setupDrawDirtyRegionsDisabled();
+ setupDrawModelView(kModelViewMode_Translate, false,
+ 0.0f, 0.0f, 0.0f, 0.0f, true);
+ setupDrawColorUniforms(getShader(paint));
+ setupDrawShaderUniforms(getShader(paint));
+ setupDrawColorFilterUniforms(getColorFilter(paint));
+
+ issueIndexedQuadDraw(&rectangleVertices[0], rectangleVertices.size() / 4);
+}
+
void OpenGLRenderer::setStencilFromClip() {
if (!mCaches.debugOverdraw) {
- if (!currentSnapshot()->clipRegion->isEmpty()) {
+ 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
- mDirtyClip = false;
+ mState.setDirtyClip(false);
ensureStencilBuffer();
- mCaches.stencil.enableWrite();
+ const ClipArea& clipArea = currentSnapshot()->getClipArea();
+
+ bool isRectangleList = clipArea.isRectangleList();
+ if (isRectangleList) {
+ incrementThreshold = clipArea.getRectangleList().getTransformedRectanglesCount();
+ } else {
+ incrementThreshold = 0;
+ }
+
+ mRenderState.stencil().enableWrite(incrementThreshold);
- // Clear and update the stencil, but first make sure we restrict drawing
+ // Clean and update the stencil, but first make sure we restrict drawing
// to the region's bounds
- bool resetScissor = mCaches.enableScissor();
+ bool resetScissor = mRenderState.scissor().setEnabled(true);
if (resetScissor) {
// The scissor was not set so we now need to update it
setScissorFromClip();
}
- mCaches.stencil.clear();
+
+ mRenderState.stencil().clear();
// stash and disable the outline clip state, since stencil doesn't account for outline
bool storedSkipOutlineClip = mSkipOutlineClip;
@@ -1487,28 +1498,34 @@ void OpenGLRenderer::setStencilFromClip() {
paint.setColor(SK_ColorBLACK);
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
- // 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.
+ 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(*(currentSnapshot()->clipRegion), paint, false);
- if (resetScissor) mCaches.disableScissor();
+ // 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;
- mCaches.stencil.enableTest();
+ mRenderState.stencil().enableTest(incrementThreshold);
// Draw the region used to generate the stencil if the appropriate debug
// mode is enabled
- if (mCaches.debugStencilClip == Caches::kStencilShowRegion) {
+ // TODO: Implement for rectangle list clip areas
+ if (mCaches.debugStencilClip == Caches::kStencilShowRegion &&
+ !clipArea.isRectangleList()) {
paint.setColor(0x7f0000ff);
paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
- drawRegionRects(*(currentSnapshot()->clipRegion), paint);
+ drawRegionRects(currentSnapshot()->getClipRegion(), paint);
}
} else {
EVENT_LOGD("setStencilFromClip - disabling");
- mCaches.stencil.disable();
+ mRenderState.stencil().disable();
}
}
}
@@ -1533,13 +1550,13 @@ bool OpenGLRenderer::quickRejectSetupScissor(float left, float top, float right,
bool clipRequired = false;
bool roundRectClipRequired = false;
- if (calculateQuickRejectForScissor(left, top, right, bottom,
+ if (mState.calculateQuickRejectForScissor(left, top, right, bottom,
&clipRequired, &roundRectClipRequired, snapOut)) {
return true;
}
// not quick rejected, so enable the scissor if clipRequired
- mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
+ mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
mSkipOutlineClip = !roundRectClipRequired;
return false;
}
@@ -1555,6 +1572,18 @@ void OpenGLRenderer::debugClip() {
#endif
}
+void OpenGLRenderer::renderGlop(const Glop& glop) {
+ if (mState.getDirtyClip()) {
+ if (mRenderState.scissor().isEnabled()) {
+ setScissorFromClip();
+ }
+
+ setStencilFromClip();
+ }
+ mRenderState.render(glop);
+ dirtyLayer(glop.bounds.left, glop.bounds.top, glop.bounds.right, glop.bounds.bottom);
+}
+
///////////////////////////////////////////////////////////////////////////////
// Drawing commands
///////////////////////////////////////////////////////////////////////////////
@@ -1565,8 +1594,8 @@ void OpenGLRenderer::setupDraw(bool clearLayer) {
if (clearLayer) clearLayerRegions();
// Make sure setScissor & setStencil happen at the beginning of
// this method
- if (mDirtyClip) {
- if (mCaches.scissorEnabled) {
+ if (mState.getDirtyClip()) {
+ if (mRenderState.scissor().isEnabled()) {
setScissorFromClip();
}
@@ -1583,9 +1612,9 @@ void OpenGLRenderer::setupDraw(bool clearLayer) {
// Enable debug highlight when what we're about to draw is tested against
// the stencil buffer and if stencil highlight debugging is on
- mDescription.hasDebugHighlight = !mCaches.debugOverdraw &&
- mCaches.debugStencilClip == Caches::kStencilShowHighlight &&
- mCaches.stencil.isTestEnabled();
+ mDescription.hasDebugHighlight = !mCaches.debugOverdraw
+ && mCaches.debugStencilClip == Caches::kStencilShowHighlight
+ && mRenderState.stencil().isTestEnabled();
}
void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
@@ -1604,7 +1633,7 @@ void OpenGLRenderer::setupDrawWithExternalTexture() {
}
void OpenGLRenderer::setupDrawNoTexture() {
- mCaches.disableTexCoordsVertexArray();
+ mRenderState.meshState().disableTexCoordsVertexArray();
}
void OpenGLRenderer::setupDrawVertexAlpha(bool useShadowAlphaInterp) {
@@ -1644,21 +1673,21 @@ void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) {
}
void OpenGLRenderer::setupDrawShader(const SkShader* shader) {
- if (shader != NULL) {
- SkiaShader::describe(&mCaches, mDescription, mExtensions, *shader);
+ if (shader != nullptr) {
+ SkiaShader::describe(&mCaches, mDescription, mCaches.extensions(), *shader);
}
}
void OpenGLRenderer::setupDrawColorFilter(const SkColorFilter* filter) {
- if (filter == NULL) {
+ if (filter == nullptr) {
return;
}
SkXfermode::Mode mode;
- if (filter->asColorMode(NULL, &mode)) {
+ if (filter->asColorMode(nullptr, &mode)) {
mDescription.colorOp = ProgramDescription::kColorBlend;
mDescription.colorMode = mode;
- } else if (filter->asColorMatrix(NULL)) {
+ } else if (filter->asColorMatrix(nullptr)) {
mDescription.colorOp = ProgramDescription::kColorMatrix;
}
}
@@ -1677,8 +1706,10 @@ void OpenGLRenderer::setupDrawBlending(const Layer* layer, bool swapSrcDst) {
// argb=1,0,0,0
accountForClear(mode);
// TODO: check shader blending, once we have shader drawing support for layers.
- bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f ||
- (mColorSet && mColorA < 1.0f) || isBlendedColorFilter(layer->getColorFilter());
+ bool blend = layer->isBlend()
+ || getLayerAlpha(layer) < 1.0f
+ || (mColorSet && mColorA < 1.0f)
+ || PaintUtils::isBlendedColorFilter(layer->getColorFilter());
chooseBlending(blend, mode, mDescription, swapSrcDst);
}
@@ -1687,27 +1718,27 @@ void OpenGLRenderer::setupDrawBlending(const SkPaint* paint, bool blend, bool sw
// When the blending mode is kClear_Mode, we need to use a modulate color
// argb=1,0,0,0
accountForClear(mode);
- blend |= (mColorSet && mColorA < 1.0f) ||
- (getShader(paint) && !getShader(paint)->isOpaque()) ||
- isBlendedColorFilter(getColorFilter(paint));
+ blend |= (mColorSet && mColorA < 1.0f)
+ || (getShader(paint) && !getShader(paint)->isOpaque())
+ || PaintUtils::isBlendedColorFilter(getColorFilter(paint));
chooseBlending(blend, mode, mDescription, swapSrcDst);
}
void OpenGLRenderer::setupDrawProgram() {
- useProgram(mCaches.programCache.get(mDescription));
+ mCaches.setProgram(mDescription);
if (mDescription.hasRoundRectClip) {
// TODO: avoid doing this repeatedly, stashing state pointer in program
- const RoundRectClipState* state = mSnapshot->roundRectClipState;
+ const RoundRectClipState* state = writableSnapshot()->roundRectClipState;
const Rect& innerRect = state->innerRect;
- glUniform4f(mCaches.currentProgram->getUniform("roundRectInnerRectLTRB"),
+ glUniform4f(mCaches.program().getUniform("roundRectInnerRectLTRB"),
innerRect.left, innerRect.top,
innerRect.right, innerRect.bottom);
- glUniformMatrix4fv(mCaches.currentProgram->getUniform("roundRectInvTransform"),
+ glUniformMatrix4fv(mCaches.program().getUniform("roundRectInvTransform"),
1, GL_FALSE, &state->matrix.data[0]);
// add half pixel to round out integer rect space to cover pixel centers
float roundedOutRadius = state->radius + 0.5f;
- glUniform1f(mCaches.currentProgram->getUniform("roundRectRadius"),
+ glUniform1f(mCaches.program().getUniform("roundRectRadius"),
roundedOutRadius);
}
}
@@ -1725,7 +1756,9 @@ void OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset,
bool dirty = right - left > 0.0f && bottom - top > 0.0f;
const Matrix4& transformMatrix = ignoreTransform ? Matrix4::identity() : *currentTransform();
- mCaches.currentProgram->set(mSnapshot->getOrthoMatrix(), mModelViewMatrix, transformMatrix, offset);
+
+ mCaches.program().set(currentSnapshot()->getOrthoMatrix(),
+ mModelViewMatrix, transformMatrix, offset);
if (dirty && mTrackDirtyRegions) {
if (!ignoreTransform) {
dirtyLayer(left, top, right, bottom, *currentTransform());
@@ -1737,18 +1770,18 @@ void OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset,
void OpenGLRenderer::setupDrawColorUniforms(bool hasShader) {
if ((mColorSet && !hasShader) || (hasShader && mSetShaderColor)) {
- mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
+ mCaches.program().setColor(mColorR, mColorG, mColorB, mColorA);
}
}
void OpenGLRenderer::setupDrawPureColorUniforms() {
if (mSetShaderColor) {
- mCaches.currentProgram->setColor(mColorR, mColorG, mColorB, mColorA);
+ mCaches.program().setColor(mColorR, mColorG, mColorB, mColorA);
}
}
void OpenGLRenderer::setupDrawShaderUniforms(const SkShader* shader, bool ignoreTransform) {
- if (shader == NULL) {
+ if (shader == nullptr) {
return;
}
@@ -1762,11 +1795,12 @@ void OpenGLRenderer::setupDrawShaderUniforms(const SkShader* shader, bool ignore
mModelViewMatrix.load(modelViewWithoutTransform);
}
- SkiaShader::setupProgram(&mCaches, mModelViewMatrix, &mTextureUnit, mExtensions, *shader);
+ SkiaShader::setupProgram(&mCaches, mModelViewMatrix, &mTextureUnit,
+ mCaches.extensions(), *shader);
}
void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) {
- if (NULL == filter) {
+ if (nullptr == filter) {
return;
}
@@ -1778,7 +1812,7 @@ void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) {
const GLfloat r = a * SkColorGetR(color) / 255.0f;
const GLfloat g = a * SkColorGetG(color) / 255.0f;
const GLfloat b = a * SkColorGetB(color) / 255.0f;
- glUniform4f(mCaches.currentProgram->getUniform("colorBlend"), r, g, b, a);
+ glUniform4f(mCaches.program().getUniform("colorBlend"), r, g, b, a);
return;
}
@@ -1799,9 +1833,9 @@ void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) {
colorVector[2] = srcColorMatrix[14] / 255.0f;
colorVector[3] = srcColorMatrix[19] / 255.0f;
- glUniformMatrix4fv(mCaches.currentProgram->getUniform("colorMatrix"), 1,
+ glUniformMatrix4fv(mCaches.program().getUniform("colorMatrix"), 1,
GL_FALSE, colorMatrix);
- glUniform4fv(mCaches.currentProgram->getUniform("colorMatrixVector"), 1, colorVector);
+ glUniform4fv(mCaches.program().getUniform("colorMatrixVector"), 1, colorVector);
return;
}
@@ -1809,25 +1843,25 @@ void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) {
}
void OpenGLRenderer::setupDrawTextGammaUniforms() {
- mCaches.fontRenderer->setupProgram(mDescription, mCaches.currentProgram);
+ mCaches.fontRenderer->setupProgram(mDescription, mCaches.program());
}
void OpenGLRenderer::setupDrawSimpleMesh() {
- bool force = mCaches.bindMeshBuffer();
- mCaches.bindPositionVertexPointer(force, 0);
- mCaches.unbindIndicesBuffer();
+ bool force = mRenderState.meshState().bindMeshBuffer();
+ mRenderState.meshState().bindPositionVertexPointer(force, nullptr);
+ mRenderState.meshState().unbindIndicesBuffer();
}
void OpenGLRenderer::setupDrawTexture(GLuint texture) {
- if (texture) bindTexture(texture);
+ if (texture) mCaches.textureState().bindTexture(texture);
mTextureUnit++;
- mCaches.enableTexCoordsVertexArray();
+ mRenderState.meshState().enableTexCoordsVertexArray();
}
void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) {
- bindExternalTexture(texture);
+ mCaches.textureState().bindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
mTextureUnit++;
- mCaches.enableTexCoordsVertexArray();
+ mRenderState.meshState().enableTexCoordsVertexArray();
}
void OpenGLRenderer::setupDrawTextureTransform() {
@@ -1835,7 +1869,7 @@ void OpenGLRenderer::setupDrawTextureTransform() {
}
void OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) {
- glUniformMatrix4fv(mCaches.currentProgram->getUniform("mainTextureTransform"), 1,
+ glUniformMatrix4fv(mCaches.program().getUniform("mainTextureTransform"), 1,
GL_FALSE, &transform.data[0]);
}
@@ -1843,35 +1877,35 @@ void OpenGLRenderer::setupDrawMesh(const GLvoid* vertices,
const GLvoid* texCoords, GLuint vbo) {
bool force = false;
if (!vertices || vbo) {
- force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
+ force = mRenderState.meshState().bindMeshBuffer(vbo);
} else {
- force = mCaches.unbindMeshBuffer();
+ force = mRenderState.meshState().unbindMeshBuffer();
}
- mCaches.bindPositionVertexPointer(force, vertices);
- if (mCaches.currentProgram->texCoords >= 0) {
- mCaches.bindTexCoordsVertexPointer(force, texCoords);
+ mRenderState.meshState().bindPositionVertexPointer(force, vertices);
+ if (mCaches.program().texCoords >= 0) {
+ mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords);
}
- mCaches.unbindIndicesBuffer();
+ mRenderState.meshState().unbindIndicesBuffer();
}
void OpenGLRenderer::setupDrawMesh(const GLvoid* vertices,
const GLvoid* texCoords, const GLvoid* colors) {
- bool force = mCaches.unbindMeshBuffer();
+ bool force = mRenderState.meshState().unbindMeshBuffer();
GLsizei stride = sizeof(ColorTextureVertex);
- mCaches.bindPositionVertexPointer(force, vertices, stride);
- if (mCaches.currentProgram->texCoords >= 0) {
- mCaches.bindTexCoordsVertexPointer(force, texCoords, stride);
+ mRenderState.meshState().bindPositionVertexPointer(force, vertices, stride);
+ if (mCaches.program().texCoords >= 0) {
+ mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords, stride);
}
- int slot = mCaches.currentProgram->getAttrib("colors");
+ int slot = mCaches.program().getAttrib("colors");
if (slot >= 0) {
glEnableVertexAttribArray(slot);
glVertexAttribPointer(slot, 4, GL_FLOAT, GL_FALSE, stride, colors);
}
- mCaches.unbindIndicesBuffer();
+ mRenderState.meshState().unbindIndicesBuffer();
}
void OpenGLRenderer::setupDrawMeshIndices(const GLvoid* vertices,
@@ -1879,63 +1913,63 @@ void OpenGLRenderer::setupDrawMeshIndices(const GLvoid* vertices,
bool force = false;
// If vbo is != 0 we want to treat the vertices parameter as an offset inside
// a VBO. However, if vertices is set to NULL and vbo == 0 then we want to
- // use the default VBO found in Caches
+ // use the default VBO found in RenderState
if (!vertices || vbo) {
- force = mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
+ force = mRenderState.meshState().bindMeshBuffer(vbo);
} else {
- force = mCaches.unbindMeshBuffer();
+ force = mRenderState.meshState().unbindMeshBuffer();
}
- mCaches.bindQuadIndicesBuffer();
+ mRenderState.meshState().bindQuadIndicesBuffer();
- mCaches.bindPositionVertexPointer(force, vertices);
- if (mCaches.currentProgram->texCoords >= 0) {
- mCaches.bindTexCoordsVertexPointer(force, texCoords);
+ mRenderState.meshState().bindPositionVertexPointer(force, vertices);
+ if (mCaches.program().texCoords >= 0) {
+ mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords);
}
}
void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) {
- bool force = mCaches.unbindMeshBuffer();
- mCaches.bindQuadIndicesBuffer();
- mCaches.bindPositionVertexPointer(force, vertices, gVertexStride);
+ bool force = mRenderState.meshState().unbindMeshBuffer();
+ mRenderState.meshState().bindQuadIndicesBuffer();
+ mRenderState.meshState().bindPositionVertexPointer(force, vertices, kVertexStride);
}
///////////////////////////////////////////////////////////////////////////////
// Drawing
///////////////////////////////////////////////////////////////////////////////
-status_t OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags) {
- status_t status;
+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(mCaches.drawDeferDisabled)) {
- status = startFrame();
+ startFrame();
ReplayStateStruct replayStruct(*this, dirty, replayFlags);
renderNode->replay(replayStruct, 0);
- return status | replayStruct.mDrawGlStatus;
+ return;
}
// Don't avoid overdraw when visualizing, since that makes it harder to
// debug where it's coming from, and when the problem occurs.
bool avoidOverdraw = !mCaches.debugOverdraw;
- DeferredDisplayList deferredList(*currentClipRect(), avoidOverdraw);
+ DeferredDisplayList deferredList(mState.currentClipRect(), avoidOverdraw);
DeferStateStruct deferStruct(deferredList, *this, replayFlags);
renderNode->defer(deferStruct, 0);
flushLayers();
- status = startFrame();
+ startFrame();
- return deferredList.flush(*this, dirty) | status;
+ 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();
}
-
- // Even if there is no drawing command(Ex: invisible),
- // it still needs startFrame to clear buffer and start tiling.
- return startFrame();
}
-void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, const SkPaint* paint) {
+void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top,
+ const SkPaint* paint) {
float x = left;
float y = top;
@@ -1955,8 +1989,8 @@ void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, co
// No need to check for a UV mapper on the texture object, only ARGB_8888
// bitmaps get packed in the atlas
drawAlpha8TextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
- paint, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset,
- GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
+ paint, (GLvoid*) nullptr, (GLvoid*) kMeshTextureOffset,
+ GL_TRIANGLE_STRIP, kUnitQuadCount, ignoreTransform);
}
/**
@@ -1964,12 +1998,12 @@ void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, co
* will not set the scissor enable or dirty the current layer, if any.
* The caller is responsible for properly dirtying the current layer.
*/
-status_t OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
+void OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
int bitmapCount, TextureVertex* vertices, bool pureTranslate,
const Rect& bounds, const SkPaint* paint) {
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
- if (!texture) return DrawGlInfo::kStatusDone;
+ if (!texture) return;
const AutoTexture autoCleanup(texture);
@@ -1990,35 +2024,17 @@ status_t OpenGLRenderer::drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry*
kModelViewMode_Translate, false);
}
- return DrawGlInfo::kStatusDrew;
+ mDirty = true;
}
-status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
+void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
if (quickRejectSetupScissor(0, 0, bitmap->width(), bitmap->height())) {
- return DrawGlInfo::kStatusDone;
+ return;
}
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
Texture* texture = getTexture(bitmap);
- if (!texture) return DrawGlInfo::kStatusDone;
- const AutoTexture autoCleanup(texture);
-
- if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
- drawAlphaBitmap(texture, 0, 0, paint);
- } else {
- drawTextureRect(0, 0, bitmap->width(), bitmap->height(), texture, paint);
- }
-
- return DrawGlInfo::kStatusDrew;
-}
-
-status_t OpenGLRenderer::drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint) {
- if (quickRejectSetupScissor(0, 0, bitmap->width(), bitmap->height())) {
- return DrawGlInfo::kStatusDone;
- }
-
- mCaches.activeTexture(0);
- Texture* texture = mCaches.textureCache.getTransient(bitmap);
+ if (!texture) return;
const AutoTexture autoCleanup(texture);
if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
@@ -2027,17 +2043,17 @@ status_t OpenGLRenderer::drawBitmapData(const SkBitmap* bitmap, const SkPaint* p
drawTextureRect(0, 0, bitmap->width(), bitmap->height(), texture, paint);
}
- return DrawGlInfo::kStatusDrew;
+ mDirty = true;
}
-status_t OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
+void OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
const float* vertices, const int* colors, const SkPaint* paint) {
- if (!vertices || currentSnapshot()->isIgnored()) {
- return DrawGlInfo::kStatusDone;
+ if (!vertices || mState.currentlyIgnored()) {
+ return;
}
// TODO: use quickReject on bounds from vertices
- mCaches.enableScissor();
+ mRenderState.scissor().setEnabled(true);
float left = FLT_MAX;
float top = FLT_MAX;
@@ -2046,20 +2062,18 @@ status_t OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, i
const uint32_t count = meshWidth * meshHeight * 6;
- Vector<ColorTextureVertex> mesh; // TODO: use C++11 unique_ptr
- mesh.setCapacity(count);
- ColorTextureVertex* vertex = mesh.editArray();
+ std::unique_ptr<ColorTextureVertex[]> mesh(new ColorTextureVertex[count]);
+ ColorTextureVertex* vertex = &mesh[0];
- bool cleanupColors = false;
+ std::unique_ptr<int[]> tempColors;
if (!colors) {
uint32_t colorsCount = (meshWidth + 1) * (meshHeight + 1);
- int* newColors = new int[colorsCount];
- memset(newColors, 0xff, colorsCount * sizeof(int));
- colors = newColors;
- cleanupColors = true;
+ tempColors.reset(new int[colorsCount]);
+ memset(tempColors.get(), 0xff, colorsCount * sizeof(int));
+ colors = tempColors.get();
}
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap);
const UvMapper& mapper(getMapper(texture));
@@ -2099,15 +2113,13 @@ status_t OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, i
}
if (quickRejectSetupScissor(left, top, right, bottom)) {
- if (cleanupColors) delete[] colors;
- return DrawGlInfo::kStatusDone;
+ return;
}
if (!texture) {
texture = mCaches.textureCache.get(bitmap);
if (!texture) {
- if (cleanupColors) delete[] colors;
- return DrawGlInfo::kStatusDone;
+ return;
}
}
const AutoTexture autoCleanup(texture);
@@ -2132,7 +2144,7 @@ status_t OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, i
setupDrawBlending(paint, true);
setupDrawProgram();
setupDrawDirtyRegionsDisabled();
- setupDrawModelView(kModelViewMode_TranslateAndScale, false, 0.0f, 0.0f, 1.0f, 1.0f);
+ setupDrawModelView(kModelViewMode_Translate, false, 0, 0, 0, 0);
setupDrawTexture(texture->id);
setupDrawPureColorUniforms();
setupDrawColorFilterUniforms(getColorFilter(paint));
@@ -2140,27 +2152,25 @@ status_t OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, i
glDrawArrays(GL_TRIANGLES, 0, count);
- int slot = mCaches.currentProgram->getAttrib("colors");
+ int slot = mCaches.program().getAttrib("colors");
if (slot >= 0) {
glDisableVertexAttribArray(slot);
}
- if (cleanupColors) delete[] colors;
-
- return DrawGlInfo::kStatusDrew;
+ mDirty = true;
}
-status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap,
+void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap,
float srcLeft, float srcTop, float srcRight, float srcBottom,
float dstLeft, float dstTop, float dstRight, float dstBottom,
const SkPaint* paint) {
if (quickRejectSetupScissor(dstLeft, dstTop, dstRight, dstBottom)) {
- return DrawGlInfo::kStatusDone;
+ return;
}
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
Texture* texture = getTexture(bitmap);
- if (!texture) return DrawGlInfo::kStatusDone;
+ if (!texture) return;
const AutoTexture autoCleanup(texture);
const float width = texture->width;
@@ -2173,7 +2183,7 @@ status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap,
getMapper(texture).map(u1, v1, u2, v2);
- mCaches.unbindMeshBuffer();
+ mRenderState.meshState().unbindMeshBuffer();
resetDrawTextureTexCoords(u1, v1, u2, v2);
texture->setWrap(GL_CLAMP_TO_EDGE, true);
@@ -2220,12 +2230,12 @@ status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap,
drawAlpha8TextureMesh(dstLeft, dstTop, dstRight, dstBottom,
texture->id, paint,
&mMeshVertices[0].x, &mMeshVertices[0].u,
- GL_TRIANGLE_STRIP, gMeshCount, ignoreTransform);
+ GL_TRIANGLE_STRIP, kUnitQuadCount, ignoreTransform);
} else {
drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom,
texture->id, paint, texture->blend,
&mMeshVertices[0].x, &mMeshVertices[0].u,
- GL_TRIANGLE_STRIP, gMeshCount, false, ignoreTransform);
+ GL_TRIANGLE_STRIP, kUnitQuadCount, false, ignoreTransform);
}
if (CC_UNLIKELY(useScaleTransform)) {
@@ -2234,33 +2244,33 @@ status_t OpenGLRenderer::drawBitmap(const SkBitmap* bitmap,
resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
- return DrawGlInfo::kStatusDrew;
+ mDirty = true;
}
-status_t OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
+void OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
float left, float top, float right, float bottom, const SkPaint* paint) {
if (quickRejectSetupScissor(left, top, right, bottom)) {
- return DrawGlInfo::kStatusDone;
+ return;
}
AssetAtlas::Entry* entry = mRenderState.assetAtlas().getEntry(bitmap);
const Patch* mesh = mCaches.patchCache.get(entry, bitmap->width(), bitmap->height(),
right - left, bottom - top, patch);
- return drawPatch(bitmap, mesh, entry, left, top, right, bottom, paint);
+ drawPatch(bitmap, mesh, entry, left, top, right, bottom, paint);
}
-status_t OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh,
+void OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh,
AssetAtlas::Entry* entry, float left, float top, float right, float bottom,
const SkPaint* paint) {
if (quickRejectSetupScissor(left, top, right, bottom)) {
- return DrawGlInfo::kStatusDone;
+ return;
}
if (CC_LIKELY(mesh && mesh->verticesCount > 0)) {
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
- if (!texture) return DrawGlInfo::kStatusDone;
+ if (!texture) return;
const AutoTexture autoCleanup(texture);
texture->setWrap(GL_CLAMP_TO_EDGE, true);
@@ -2302,7 +2312,7 @@ status_t OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh,
mCaches.patchCache.getMeshBuffer(), kModelViewMode_Translate, !mesh->hasEmptyQuads);
}
- return DrawGlInfo::kStatusDrew;
+ mDirty = true;
}
/**
@@ -2310,11 +2320,11 @@ status_t OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh,
* will not set the scissor enable or dirty the current layer, if any.
* The caller is responsible for properly dirtying the current layer.
*/
-status_t OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
+void OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
TextureVertex* vertices, uint32_t indexCount, const SkPaint* paint) {
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
- if (!texture) return DrawGlInfo::kStatusDone;
+ if (!texture) return;
const AutoTexture autoCleanup(texture);
texture->setWrap(GL_CLAMP_TO_EDGE, true);
@@ -2324,28 +2334,44 @@ status_t OpenGLRenderer::drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry*
texture->blend, &vertices[0].x, &vertices[0].u,
GL_TRIANGLES, indexCount, false, true, 0, kModelViewMode_Translate, false);
- return DrawGlInfo::kStatusDrew;
+ mDirty = true;
}
-status_t OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
+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 DrawGlInfo::kStatusDone;
+ return;
}
+ if (!paint->getShader() && !currentSnapshot()->roundRectClipState) {
+ Glop glop;
+ GlopBuilder aBuilder(mRenderState, mCaches, &glop);
+ bool fudgeOffset = displayFlags & kVertexBuffer_Offset;
+ bool shadowInterp = displayFlags & kVertexBuffer_ShadowInterp;
+ aBuilder.setMeshVertexBuffer(vertexBuffer, shadowInterp)
+ .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), fudgeOffset)
+ .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds())
+ .setPaint(paint, currentSnapshot()->alpha)
+ .build();
+ renderGlop(glop);
+ return;
+ }
+
+
+ const VertexBuffer::MeshFeatureFlags meshFeatureFlags = vertexBuffer.getMeshFeatureFlags();
Rect bounds(vertexBuffer.getBounds());
bounds.translate(translateX, translateY);
dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform());
int color = paint->getColor();
- bool isAA = paint->isAntiAlias();
+ bool isAA = meshFeatureFlags & VertexBuffer::kAlpha;
setupDraw();
setupDrawNoTexture();
if (isAA) setupDrawVertexAlpha((displayFlags & kVertexBuffer_ShadowInterp));
- setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
+ setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
setupDrawColorFilter(getColorFilter(paint));
setupDrawShader(getShader(paint));
setupDrawBlending(paint, isAA);
@@ -2357,40 +2383,34 @@ status_t OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
setupDrawShaderUniforms(getShader(paint));
const void* vertices = vertexBuffer.getBuffer();
- mCaches.unbindMeshBuffer();
- mCaches.bindPositionVertexPointer(true, vertices, isAA ? gAlphaVertexStride : gVertexStride);
- mCaches.resetTexCoordsVertexPointer();
+ mRenderState.meshState().unbindMeshBuffer();
+ mRenderState.meshState().bindPositionVertexPointer(true, vertices,
+ isAA ? kAlphaVertexStride : kVertexStride);
+ mRenderState.meshState().resetTexCoordsVertexPointer();
int alphaSlot = -1;
if (isAA) {
- void* alphaCoords = ((GLbyte*) vertices) + gVertexAlphaOffset;
- alphaSlot = mCaches.currentProgram->getAttrib("vtxAlpha");
+ void* alphaCoords = ((GLbyte*) vertices) + kVertexAlphaOffset;
+ alphaSlot = mCaches.program().getAttrib("vtxAlpha");
// TODO: avoid enable/disable in back to back uses of the alpha attribute
glEnableVertexAttribArray(alphaSlot);
- glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords);
+ glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, kAlphaVertexStride, alphaCoords);
}
- const VertexBuffer::Mode mode = vertexBuffer.getMode();
- if (mode == VertexBuffer::kStandard) {
- mCaches.unbindIndicesBuffer();
+ if (meshFeatureFlags & VertexBuffer::kIndices) {
+ mRenderState.meshState().unbindIndicesBuffer();
+ glDrawElements(GL_TRIANGLE_STRIP, vertexBuffer.getIndexCount(),
+ GL_UNSIGNED_SHORT, vertexBuffer.getIndices());
+ } else {
+ mRenderState.meshState().unbindIndicesBuffer();
glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
- } else if (mode == VertexBuffer::kOnePolyRingShadow) {
- mCaches.bindShadowIndicesBuffer();
- glDrawElements(GL_TRIANGLE_STRIP, ONE_POLY_RING_SHADOW_INDEX_COUNT, GL_UNSIGNED_SHORT, 0);
- } else if (mode == VertexBuffer::kTwoPolyRingShadow) {
- mCaches.bindShadowIndicesBuffer();
- glDrawElements(GL_TRIANGLE_STRIP, TWO_POLY_RING_SHADOW_INDEX_COUNT, GL_UNSIGNED_SHORT, 0);
- } else if (mode == VertexBuffer::kIndices) {
- mCaches.unbindIndicesBuffer();
- glDrawElements(GL_TRIANGLE_STRIP, vertexBuffer.getIndexCount(), GL_UNSIGNED_SHORT,
- vertexBuffer.getIndices());
}
if (isAA) {
glDisableVertexAttribArray(alphaSlot);
}
- return DrawGlInfo::kStatusDrew;
+ mDirty = true;
}
/**
@@ -2402,11 +2422,11 @@ status_t OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
*
* Doesn't yet support joins, caps, or path effects.
*/
-status_t OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint) {
+void OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint) {
VertexBuffer vertexBuffer;
// TODO: try clipping large paths to viewport
PathTessellator::tessellatePath(path, paint, *currentTransform(), vertexBuffer);
- return drawVertexBuffer(vertexBuffer, paint);
+ drawVertexBuffer(vertexBuffer, paint);
}
/**
@@ -2420,8 +2440,8 @@ status_t OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint
* 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.
*/
-status_t OpenGLRenderer::drawLines(const float* points, int count, const SkPaint* paint) {
- if (currentSnapshot()->isIgnored() || count < 4) return DrawGlInfo::kStatusDone;
+void OpenGLRenderer::drawLines(const float* points, int count, const SkPaint* paint) {
+ if (mState.currentlyIgnored() || count < 4) return;
count &= ~0x3; // round down to nearest four
@@ -2430,15 +2450,15 @@ status_t OpenGLRenderer::drawLines(const float* points, int count, const SkPaint
const Rect& bounds = buffer.getBounds();
if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
- return DrawGlInfo::kStatusDone;
+ return;
}
int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset;
- return drawVertexBuffer(buffer, paint, displayFlags);
+ drawVertexBuffer(buffer, paint, displayFlags);
}
-status_t OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) {
- if (currentSnapshot()->isIgnored() || count < 2) return DrawGlInfo::kStatusDone;
+void OpenGLRenderer::drawPoints(const float* points, int count, const SkPaint* paint) {
+ if (mState.currentlyIgnored() || count < 2) return;
count &= ~0x1; // round down to nearest two
@@ -2447,18 +2467,20 @@ status_t OpenGLRenderer::drawPoints(const float* points, int count, const SkPain
const Rect& bounds = buffer.getBounds();
if (quickRejectSetupScissor(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
- return DrawGlInfo::kStatusDone;
+ return;
}
int displayFlags = paint->isAntiAlias() ? 0 : kVertexBuffer_Offset;
- return drawVertexBuffer(buffer, paint, displayFlags);
+ drawVertexBuffer(buffer, paint, displayFlags);
+
+ mDirty = true;
}
-status_t OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
+void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
// No need to check against the clip, we fill the clip region
- if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
+ if (mState.currentlyIgnored()) return;
- Rect clip(*currentClipRect());
+ Rect clip(mState.currentClipRect());
clip.snapToPixelBoundaries();
SkPaint paint;
@@ -2467,12 +2489,12 @@ status_t OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
drawColorRect(clip.left, clip.top, clip.right, clip.bottom, &paint, true);
- return DrawGlInfo::kStatusDrew;
+ mDirty = true;
}
-status_t OpenGLRenderer::drawShape(float left, float top, const PathTexture* texture,
+void OpenGLRenderer::drawShape(float left, float top, const PathTexture* texture,
const SkPaint* paint) {
- if (!texture) return DrawGlInfo::kStatusDone;
+ if (!texture) return;
const AutoTexture autoCleanup(texture);
const float x = left + texture->left - texture->offset;
@@ -2480,89 +2502,89 @@ status_t OpenGLRenderer::drawShape(float left, float top, const PathTexture* tex
drawPathTexture(texture, x, y, paint);
- return DrawGlInfo::kStatusDrew;
+ mDirty = true;
}
-status_t OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
+void OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
float rx, float ry, const SkPaint* p) {
- if (currentSnapshot()->isIgnored()
+ if (mState.currentlyIgnored()
|| quickRejectSetupScissor(left, top, right, bottom, p)
- || paintWillNotDraw(*p)) {
- return DrawGlInfo::kStatusDone;
+ || PaintUtils::paintWillNotDraw(*p)) {
+ return;
}
- if (p->getPathEffect() != 0) {
- mCaches.activeTexture(0);
+ if (p->getPathEffect() != nullptr) {
+ mCaches.textureState().activateTexture(0);
const PathTexture* texture = mCaches.pathCache.getRoundRect(
right - left, bottom - top, rx, ry, p);
- return drawShape(left, top, texture, 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);
}
-
- const VertexBuffer* vertexBuffer = mCaches.tessellationCache.getRoundRect(
- *currentTransform(), *p, right - left, bottom - top, rx, ry);
- return drawVertexBuffer(left, top, *vertexBuffer, p);
}
-status_t OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p) {
- if (currentSnapshot()->isIgnored()
+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)
- || paintWillNotDraw(*p)) {
- return DrawGlInfo::kStatusDone;
+ || PaintUtils::paintWillNotDraw(*p)) {
+ return;
}
- if (p->getPathEffect() != 0) {
- mCaches.activeTexture(0);
+ if (p->getPathEffect() != nullptr) {
+ mCaches.textureState().activateTexture(0);
const PathTexture* texture = mCaches.pathCache.getCircle(radius, p);
- return drawShape(x - radius, y - radius, texture, p);
- }
-
- SkPath path;
- if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
- path.addCircle(x, y, radius + p->getStrokeWidth() / 2);
+ drawShape(x - radius, y - radius, texture, p);
} else {
- path.addCircle(x, y, radius);
+ SkPath path;
+ if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
+ path.addCircle(x, y, radius + p->getStrokeWidth() / 2);
+ } else {
+ path.addCircle(x, y, radius);
+ }
+ drawConvexPath(path, p);
}
- return drawConvexPath(path, p);
}
-status_t OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
+void OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
const SkPaint* p) {
- if (currentSnapshot()->isIgnored()
+ if (mState.currentlyIgnored()
|| quickRejectSetupScissor(left, top, right, bottom, p)
- || paintWillNotDraw(*p)) {
- return DrawGlInfo::kStatusDone;
+ || PaintUtils::paintWillNotDraw(*p)) {
+ return;
}
- if (p->getPathEffect() != 0) {
- mCaches.activeTexture(0);
+ if (p->getPathEffect() != nullptr) {
+ mCaches.textureState().activateTexture(0);
const PathTexture* texture = mCaches.pathCache.getOval(right - left, bottom - top, p);
- return drawShape(left, top, texture, p);
- }
-
- SkPath path;
- SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
- if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
- rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
+ 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);
}
- path.addOval(rect);
- return drawConvexPath(path, p);
}
-status_t OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
+void OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
float startAngle, float sweepAngle, bool useCenter, const SkPaint* p) {
- if (currentSnapshot()->isIgnored()
+ if (mState.currentlyIgnored()
|| quickRejectSetupScissor(left, top, right, bottom, p)
- || paintWillNotDraw(*p)) {
- return DrawGlInfo::kStatusDone;
+ || PaintUtils::paintWillNotDraw(*p)) {
+ return;
}
// TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
- if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != 0 || useCenter) {
- mCaches.activeTexture(0);
+ if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != nullptr || useCenter) {
+ mCaches.textureState().activateTexture(0);
const PathTexture* texture = mCaches.pathCache.getArc(right - left, bottom - top,
startAngle, sweepAngle, useCenter, p);
- return drawShape(left, top, texture, 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);
@@ -2576,53 +2598,54 @@ status_t OpenGLRenderer::drawArc(float left, float top, float right, float botto
if (useCenter) {
path.close();
}
- return drawConvexPath(path, p);
+ drawConvexPath(path, p);
}
// See SkPaintDefaults.h
#define SkPaintDefaults_MiterLimit SkIntToScalar(4)
-status_t OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
+void OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
const SkPaint* p) {
- if (currentSnapshot()->isIgnored()
+ if (mState.currentlyIgnored()
|| quickRejectSetupScissor(left, top, right, bottom, p)
- || paintWillNotDraw(*p)) {
- return DrawGlInfo::kStatusDone;
+ || PaintUtils::paintWillNotDraw(*p)) {
+ return;
}
if (p->getStyle() != SkPaint::kFill_Style) {
// only fill style is supported by drawConvexPath, since others have to handle joins
- if (p->getPathEffect() != 0 || p->getStrokeJoin() != SkPaint::kMiter_Join ||
+ if (p->getPathEffect() != nullptr || p->getStrokeJoin() != SkPaint::kMiter_Join ||
p->getStrokeMiter() != SkPaintDefaults_MiterLimit) {
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
const PathTexture* texture =
mCaches.pathCache.getRect(right - left, bottom - top, p);
- return drawShape(left, top, texture, 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);
- SkPath path;
- SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
- if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
- rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
+ mDirty = true;
}
- path.addRect(rect);
- return drawConvexPath(path, p);
- }
-
- if (p->isAntiAlias() && !currentTransform()->isSimple()) {
- SkPath path;
- path.addRect(left, top, right, bottom);
- return drawConvexPath(path, p);
- } else {
- drawColorRect(left, top, right, bottom, p);
- return DrawGlInfo::kStatusDrew;
}
}
void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text,
int bytesCount, int count, const float* positions,
FontRenderer& fontRenderer, int alpha, float x, float y) {
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
TextShadow textShadow;
if (!getTextShadow(paint, &textShadow)) {
@@ -2642,7 +2665,7 @@ void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text,
const float sx = x - shadow->left + textShadow.dx;
const float sy = y - shadow->top + textShadow.dy;
- const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * mSnapshot->alpha;
+ const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * writableSnapshot()->alpha;
if (getShader(paint)) {
textShadow.color = SK_ColorWHITE;
}
@@ -2660,28 +2683,29 @@ void OpenGLRenderer::drawTextShadow(const SkPaint* paint, const char* text,
setupDrawPureColorUniforms();
setupDrawColorFilterUniforms(getColorFilter(paint));
setupDrawShaderUniforms(getShader(paint));
- setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
+ setupDrawMesh(nullptr, (GLvoid*) kMeshTextureOffset);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
}
bool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
- float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * mSnapshot->alpha;
- return alpha == 0.0f && getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
+ float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * currentSnapshot()->alpha;
+ return MathUtils::isZero(alpha)
+ && PaintUtils::getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
}
-status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
+void OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
const float* positions, const SkPaint* paint) {
- if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint)) {
- return DrawGlInfo::kStatusDone;
+ if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) {
+ return;
}
// NOTE: Skia does not support perspective transform on drawPosText yet
if (!currentTransform()->isSimple()) {
- return DrawGlInfo::kStatusDone;
+ return;
}
- mCaches.enableScissor();
+ mRenderState.scissor().setEnabled(true);
float x = 0.0f;
float y = 0.0f;
@@ -2710,14 +2734,14 @@ status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count
}
fontRenderer.setTextureFiltering(linearFilter);
- const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip();
+ const Rect& clip(pureTranslate ? writableSnapshot()->getClipRect() : writableSnapshot()->getLocalClip());
Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
const bool hasActiveLayer = hasLayer();
TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
- if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
- positions, hasActiveLayer ? &bounds : NULL, &functor)) {
+ if (fontRenderer.renderPosText(paint, &clip, text, 0, bytesCount, count, x, y,
+ positions, hasActiveLayer ? &bounds : nullptr, &functor)) {
if (hasActiveLayer) {
if (!pureTranslate) {
currentTransform()->mapRect(bounds);
@@ -2726,7 +2750,7 @@ status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count
}
}
- return DrawGlInfo::kStatusDrew;
+ mDirty = true;
}
bool OpenGLRenderer::findBestFontTransform(const mat4& transform, SkMatrix* outMatrix) const {
@@ -2750,16 +2774,77 @@ bool OpenGLRenderer::findBestFontTransform(const mat4& transform, SkMatrix* outM
return true;
}
-status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float x, float y,
+int OpenGLRenderer::getSaveCount() const {
+ return mState.getSaveCount();
+}
+
+int OpenGLRenderer::save(int flags) {
+ return mState.save(flags);
+}
+
+void OpenGLRenderer::restore() {
+ return mState.restore();
+}
+
+void OpenGLRenderer::restoreToCount(int saveCount) {
+ return mState.restoreToCount(saveCount);
+}
+
+void OpenGLRenderer::translate(float dx, float dy, float dz) {
+ return mState.translate(dx, dy, dz);
+}
+
+void OpenGLRenderer::rotate(float degrees) {
+ return mState.rotate(degrees);
+}
+
+void OpenGLRenderer::scale(float sx, float sy) {
+ return mState.scale(sx, sy);
+}
+
+void OpenGLRenderer::skew(float sx, float sy) {
+ return mState.skew(sx, sy);
+}
+
+void OpenGLRenderer::setMatrix(const Matrix4& matrix) {
+ mState.setMatrix(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::drawText(const char* text, int bytesCount, int count, float x, float y,
const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
DrawOpMode drawOpMode) {
if (drawOpMode == kDrawOpMode_Immediate) {
// 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 (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint) ||
+ if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint) ||
quickRejectSetupScissor(bounds)) {
- return DrawGlInfo::kStatusDone;
+ return;
}
}
@@ -2807,7 +2892,7 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, f
fontRenderer.setTextureFiltering(linearFilter);
// TODO: Implement better clipping for scaled/rotated text
- const Rect* clip = !pureTranslate ? NULL : currentClipRect();
+ const Rect* clip = !pureTranslate ? nullptr : &mState.currentClipRect();
Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
bool status;
@@ -2819,10 +2904,10 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, f
SkPaint paintCopy(*paint);
paintCopy.setTextAlign(SkPaint::kLeft_Align);
status = fontRenderer.renderPosText(&paintCopy, clip, text, 0, bytesCount, count, x, y,
- positions, hasActiveLayer ? &layerBounds : NULL, &functor, forceFinish);
+ positions, hasActiveLayer ? &layerBounds : nullptr, &functor, forceFinish);
} else {
status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
- positions, hasActiveLayer ? &layerBounds : NULL, &functor, forceFinish);
+ positions, hasActiveLayer ? &layerBounds : nullptr, &functor, forceFinish);
}
if ((status || drawOpMode != kDrawOpMode_Immediate) && hasActiveLayer) {
@@ -2834,17 +2919,17 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, f
drawTextDecorations(totalAdvance, oldX, oldY, paint);
- return DrawGlInfo::kStatusDrew;
+ mDirty = true;
}
-status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
+void OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int count,
const SkPath* path, float hOffset, float vOffset, const SkPaint* paint) {
- if (text == NULL || count == 0 || currentSnapshot()->isIgnored() || canSkipText(paint)) {
- return DrawGlInfo::kStatusDone;
+ if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint)) {
+ return;
}
// TODO: avoid scissor by calculating maximum bounds using path bounds + font metrics
- mCaches.enableScissor();
+ mRenderState.scissor().setEnabled(true);
FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
fontRenderer.setFont(paint, SkMatrix::I());
@@ -2855,45 +2940,44 @@ status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int co
getAlphaAndMode(paint, &alpha, &mode);
TextSetupFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint);
- const Rect* clip = &mSnapshot->getLocalClip();
+ const Rect* clip = &writableSnapshot()->getLocalClip();
Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
const bool hasActiveLayer = hasLayer();
if (fontRenderer.renderTextOnPath(paint, clip, text, 0, bytesCount, count, path,
- hOffset, vOffset, hasActiveLayer ? &bounds : NULL, &functor)) {
+ hOffset, vOffset, hasActiveLayer ? &bounds : nullptr, &functor)) {
if (hasActiveLayer) {
currentTransform()->mapRect(bounds);
dirtyLayerUnchecked(bounds, getRegion());
}
}
- return DrawGlInfo::kStatusDrew;
+ mDirty = true;
}
-status_t OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
- if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
+void OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
+ if (mState.currentlyIgnored()) return;
- mCaches.activeTexture(0);
+ mCaches.textureState().activateTexture(0);
const PathTexture* texture = mCaches.pathCache.get(path, paint);
- if (!texture) return DrawGlInfo::kStatusDone;
+ if (!texture) return;
const AutoTexture autoCleanup(texture);
const float x = texture->left - texture->offset;
const float y = texture->top - texture->offset;
drawPathTexture(texture, x, y, paint);
-
- return DrawGlInfo::kStatusDrew;
+ mDirty = true;
}
-status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
+void OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
if (!layer) {
- return DrawGlInfo::kStatusDone;
+ return;
}
- mat4* transform = NULL;
+ mat4* transform = nullptr;
if (layer->isTextureLayer()) {
transform = &layer->getTransform();
if (!transform->isIdentity()) {
@@ -2903,14 +2987,15 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
}
bool clipRequired = false;
- const bool rejected = calculateQuickRejectForScissor(x, y,
- x + layer->layer.getWidth(), y + layer->layer.getHeight(), &clipRequired, NULL, false);
+ const bool rejected = mState.calculateQuickRejectForScissor(
+ x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(),
+ &clipRequired, nullptr, false);
if (rejected) {
if (transform && !transform->isIdentity()) {
restore();
}
- return DrawGlInfo::kStatusDone;
+ return;
}
EVENT_LOGD("drawLayer," RECT_STRING ", clipRequired %d", x, y,
@@ -2918,8 +3003,8 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
updateLayer(layer, true);
- mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
- mCaches.activeTexture(0);
+ mRenderState.scissor().setEnabled(mScissorOptimizationDisabled || clipRequired);
+ mCaches.textureState().activateTexture(0);
if (CC_LIKELY(!layer->region.isEmpty())) {
if (layer->region.isRect()) {
@@ -2954,11 +3039,11 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
GLsizei elementsCount = layer->meshElementCount;
while (elementsCount > 0) {
- GLsizei drawCount = min(elementsCount, (GLsizei) gMaxNumberOfQuads * 6);
+ GLsizei drawCount = min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
- glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, NULL));
+ glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, nullptr));
elementsCount -= drawCount;
// Though there are 4 vertices in a quad, we use 6 indices per
@@ -2985,53 +3070,16 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
restore();
}
- return DrawGlInfo::kStatusDrew;
+ mDirty = true;
}
///////////////////////////////////////////////////////////////////////////////
// Draw filters
///////////////////////////////////////////////////////////////////////////////
-
-void OpenGLRenderer::resetPaintFilter() {
- // when clearing the PaintFilter, the masks should also be cleared for simple DrawModifier
- // comparison, see MergingDrawBatch::canMergeWith
- mDrawModifiers.mHasDrawFilter = false;
- mDrawModifiers.mPaintFilterClearBits = 0;
- mDrawModifiers.mPaintFilterSetBits = 0;
-}
-
-void OpenGLRenderer::setupPaintFilter(int clearBits, int setBits) {
- // TODO: don't bother with boolean, it's redundant with clear/set bits
- mDrawModifiers.mHasDrawFilter = true;
- mDrawModifiers.mPaintFilterClearBits = clearBits & SkPaint::kAllFlags;
- mDrawModifiers.mPaintFilterSetBits = setBits & SkPaint::kAllFlags;
-}
-
-const SkPaint* OpenGLRenderer::filterPaint(const SkPaint* paint) {
- // TODO: use CompatFlagsDrawFilter here, and combine logic with android/graphics/DrawFilter.cpp
- // to avoid clobbering 0x02 paint flag
-
- // Equivalent to the Java Paint's FILTER_BITMAP_FLAG.
- static const uint32_t sFilterBitmapFlag = 0x02;
-
- if (CC_LIKELY(!mDrawModifiers.mHasDrawFilter || !paint)) {
- return paint;
- }
-
- const uint32_t clearBits = mDrawModifiers.mPaintFilterClearBits;
- const uint32_t setBits = mDrawModifiers.mPaintFilterSetBits;
-
- const uint32_t flags = (paint->getFlags() & ~clearBits) | setBits;
- mFilteredPaint = *paint;
- mFilteredPaint.setFlags(flags);
-
- // check if paint filter trying to override bitmap filter
- if ((clearBits | setBits) & sFilterBitmapFlag) {
- mFilteredPaint.setFilterLevel(flags & sFilterBitmapFlag
- ? SkPaint::kLow_FilterLevel : SkPaint::kNone_FilterLevel);
- }
-
- return &mFilteredPaint;
+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");
}
///////////////////////////////////////////////////////////////////////////////
@@ -3069,9 +3117,9 @@ void OpenGLRenderer::drawPathTexture(const PathTexture* texture,
setupDrawPureColorUniforms();
setupDrawColorFilterUniforms(getColorFilter(paint));
setupDrawShaderUniforms(getShader(paint));
- setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset);
+ setupDrawMesh(nullptr, (GLvoid*) kMeshTextureOffset);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
}
// Same values used by Skia
@@ -3124,20 +3172,20 @@ void OpenGLRenderer::drawTextDecorations(float underlineWidth, float x, float y,
}
}
-status_t OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
- if (currentSnapshot()->isIgnored()) {
- return DrawGlInfo::kStatusDone;
+void OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
+ if (mState.currentlyIgnored()) {
+ return;
}
- return drawColorRects(rects, count, paint, false, true, true);
+ drawColorRects(rects, count, paint, false, true, true);
}
-status_t OpenGLRenderer::drawShadow(float casterAlpha,
+void OpenGLRenderer::drawShadow(float casterAlpha,
const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) {
- if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
+ if (mState.currentlyIgnored()) return;
// TODO: use quickRejectWithScissor. For now, always force enable scissor.
- mCaches.enableScissor();
+ mRenderState.scissor().setEnabled(true);
SkPaint paint;
paint.setAntiAlias(true); // want to use AlphaVertex
@@ -3161,13 +3209,13 @@ status_t OpenGLRenderer::drawShadow(float casterAlpha,
drawVertexBuffer(*spotShadowVertexBuffer, &paint, kVertexBuffer_ShadowInterp);
}
- return DrawGlInfo::kStatusDrew;
+ mDirty=true;
}
-status_t OpenGLRenderer::drawColorRects(const float* rects, int count, const SkPaint* paint,
+void OpenGLRenderer::drawColorRects(const float* rects, int count, const SkPaint* paint,
bool ignoreTransform, bool dirty, bool clip) {
if (count == 0) {
- return DrawGlInfo::kStatusDone;
+ return;
}
int color = paint->getColor();
@@ -3202,7 +3250,7 @@ status_t OpenGLRenderer::drawColorRects(const float* rects, int count, const SkP
}
if (clip && quickRejectSetupScissor(left, top, right, bottom)) {
- return DrawGlInfo::kStatusDone;
+ return;
}
setupDraw();
@@ -3225,11 +3273,25 @@ status_t OpenGLRenderer::drawColorRects(const float* rects, int count, const SkP
issueIndexedQuadDraw(&mesh[0], count / 4);
- return DrawGlInfo::kStatusDrew;
+ mDirty = true;
}
void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
const SkPaint* paint, bool ignoreTransform) {
+
+ if (!paint->getShader() && !currentSnapshot()->roundRectClipState) {
+ const Matrix4& transform = ignoreTransform ? Matrix4::identity() : *currentTransform();
+ Glop glop;
+ GlopBuilder aBuilder(mRenderState, mCaches, &glop);
+ aBuilder.setMeshUnitQuad()
+ .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
+ .setModelViewMapUnitToRect(Rect(left, top, right, bottom))
+ .setPaint(paint, currentSnapshot()->alpha)
+ .build();
+ renderGlop(glop);
+ return;
+ }
+
int color = paint->getColor();
// If a shader is set, preserve only the alpha
if (getShader(paint)) {
@@ -3250,15 +3312,15 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot
setupDrawColorFilterUniforms(getColorFilter(paint));
setupDrawSimpleMesh();
- glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
}
void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
Texture* texture, const SkPaint* paint) {
texture->setWrap(GL_CLAMP_TO_EDGE, true);
- GLvoid* vertices = (GLvoid*) NULL;
- GLvoid* texCoords = (GLvoid*) gMeshTextureOffset;
+ GLvoid* vertices = (GLvoid*) nullptr;
+ GLvoid* texCoords = (GLvoid*) kMeshTextureOffset;
if (texture->uvMapper) {
vertices = &mMeshVertices[0].x;
@@ -3277,11 +3339,11 @@ void OpenGLRenderer::drawTextureRect(float left, float top, float right, float b
texture->setFilter(GL_NEAREST, true);
drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
paint, texture->blend, vertices, texCoords,
- GL_TRIANGLE_STRIP, gMeshCount, false, true);
+ GL_TRIANGLE_STRIP, kUnitQuadCount, false, true);
} else {
texture->setFilter(getFilter(paint), true);
drawTextureMesh(left, top, right, bottom, texture->id, paint,
- texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, gMeshCount);
+ texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, kUnitQuadCount);
}
if (texture->uvMapper) {
@@ -3340,7 +3402,7 @@ void OpenGLRenderer::drawIndexedTextureMesh(float left, float top, float right,
setupDrawColorFilterUniforms(getColorFilter(paint));
setupDrawMeshIndices(vertices, texCoords, vbo);
- glDrawElements(drawMode, elementsCount, GL_UNSIGNED_SHORT, NULL);
+ glDrawElements(drawMode, elementsCount, GL_UNSIGNED_SHORT, nullptr);
}
void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom,
@@ -3348,14 +3410,14 @@ void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, f
GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
bool ignoreTransform, ModelViewMode modelViewMode, bool dirty) {
- int color = paint != NULL ? paint->getColor() : 0;
+ int color = paint != nullptr ? paint->getColor() : 0;
int alpha;
SkXfermode::Mode mode;
getAlphaAndMode(paint, &alpha, &mode);
setupDraw();
setupDrawWithTexture(true);
- if (paint != NULL) {
+ if (paint != nullptr) {
setupDrawAlpha8Color(color, alpha);
}
setupDrawColorFilter(getColorFilter(paint));
@@ -3376,7 +3438,7 @@ void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, f
void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
ProgramDescription& description, bool swapSrcDst) {
- if (mSnapshot->roundRectClipState != NULL /*&& !mSkipOutlineClip*/) {
+ if (currentSnapshot()->roundRectClipState != nullptr /*&& !mSkipOutlineClip*/) {
blend = true;
mDescription.hasRoundRectClip = true;
}
@@ -3391,47 +3453,20 @@ void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
// If the blend mode cannot be implemented using shaders, fall
// back to the default SrcOver blend mode instead
if (CC_UNLIKELY(mode > SkXfermode::kScreen_Mode)) {
- if (CC_UNLIKELY(mExtensions.hasFramebufferFetch())) {
+ if (CC_UNLIKELY(mCaches.extensions().hasFramebufferFetch())) {
description.framebufferMode = mode;
description.swapSrcDst = swapSrcDst;
- if (mCaches.blend) {
- glDisable(GL_BLEND);
- mCaches.blend = false;
- }
-
+ mRenderState.blend().disable();
return;
} else {
mode = SkXfermode::kSrcOver_Mode;
}
}
-
- if (!mCaches.blend) {
- glEnable(GL_BLEND);
- }
-
- GLenum sourceMode = swapSrcDst ? gBlendsSwap[mode].src : gBlends[mode].src;
- GLenum destMode = swapSrcDst ? gBlendsSwap[mode].dst : gBlends[mode].dst;
-
- if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) {
- glBlendFunc(sourceMode, destMode);
- mCaches.lastSrcMode = sourceMode;
- mCaches.lastDstMode = destMode;
- }
- } else if (mCaches.blend) {
- glDisable(GL_BLEND);
- }
- mCaches.blend = blend;
-}
-
-bool OpenGLRenderer::useProgram(Program* program) {
- if (!program->isInUse()) {
- if (mCaches.currentProgram != NULL) mCaches.currentProgram->remove();
- program->use();
- mCaches.currentProgram = program;
- return false;
+ mRenderState.blend().enable(mode, swapSrcDst);
+ } else {
+ mRenderState.blend().disable();
}
- return true;
}
void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
@@ -3442,7 +3477,8 @@ void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, flo
TextureVertex::setUV(v++, u2, v2);
}
-void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) const {
+void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha,
+ SkXfermode::Mode* mode) const {
getAlphaAndModeDirect(paint, alpha, mode);
if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
// if drawing a layer, ignore the paint's alpha
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 5eee2e2..f097041 100755
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -38,6 +38,7 @@
#include <androidfw/ResourceTypes.h>
+#include "CanvasState.h"
#include "Debug.h"
#include "Extensions.h"
#include "Matrix.h"
@@ -45,11 +46,10 @@
#include "Rect.h"
#include "Renderer.h"
#include "Snapshot.h"
-#include "StatefulBaseRenderer.h"
#include "UvMapper.h"
#include "Vertex.h"
#include "Caches.h"
-#include "CanvasProperty.h"
+#include "utils/PaintUtils.h"
class SkShader;
@@ -57,26 +57,21 @@ namespace android {
namespace uirenderer {
class DeferredDisplayState;
+struct Glop;
class RenderState;
class RenderNode;
class TextSetupFunctor;
class VertexBuffer;
struct DrawModifiers {
- DrawModifiers() {
- reset();
- }
+ DrawModifiers()
+ : mOverrideLayerAlpha(0.0f) {}
void reset() {
- memset(this, 0, sizeof(DrawModifiers));
+ mOverrideLayerAlpha = 0.0f;
}
float mOverrideLayerAlpha;
-
- // Draw filters
- bool mHasDrawFilter;
- int mPaintFilterClearBits;
- int mPaintFilterSetBits;
};
enum StateDeferFlags {
@@ -123,7 +118,7 @@ enum ModelViewMode {
/**
* OpenGL Renderer implementation.
*/
-class OpenGLRenderer : public StatefulBaseRenderer {
+class OpenGLRenderer : public Renderer, public CanvasStateClient {
public:
OpenGLRenderer(RenderState& renderState);
virtual ~OpenGLRenderer();
@@ -132,11 +127,14 @@ public:
void initLight(const Vector3& lightCenter, float lightRadius,
uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
- virtual void onViewportInitialized();
- virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque);
- virtual void finish();
+ virtual void prepareDirty(float left, float top, float right, float bottom,
+ bool opaque) override;
+ virtual void prepare(bool opaque) override {
+ prepareDirty(0.0f, 0.0f, mState.getWidth(), mState.getHeight(), opaque);
+ }
+ virtual bool finish() override;
- virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty);
+ virtual void callDrawGLFunction(Functor* functor, Rect& dirty) override;
void pushLayerUpdate(Layer* layer);
void cancelLayerUpdate(Layer* layer);
@@ -144,8 +142,8 @@ public:
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, NULL);
+ const SkPaint* paint, int flags) override {
+ return saveLayer(left, top, right, bottom, paint, flags, nullptr);
}
// Specialized saveLayer implementation, which will pass the convexMask to an FBO layer, if
@@ -156,56 +154,54 @@ public:
int saveLayerDeferred(float left, float top, float right, float bottom,
const SkPaint* paint, int flags);
- virtual status_t drawRenderNode(RenderNode* displayList, Rect& dirty, int32_t replayFlags = 1);
- virtual status_t drawLayer(Layer* layer, float x, float y);
- virtual status_t drawBitmap(const SkBitmap* bitmap, const SkPaint* paint);
- status_t drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry, int bitmapCount,
+ virtual void drawRenderNode(RenderNode* displayList, Rect& dirty,
+ int32_t replayFlags = 1) override;
+ virtual void drawLayer(Layer* layer, float x, float y);
+ virtual void drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) override;
+ void drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry, int bitmapCount,
TextureVertex* vertices, bool pureTranslate, const Rect& bounds, const SkPaint* paint);
- virtual status_t drawBitmap(const SkBitmap* bitmap, float srcLeft, float srcTop,
+ 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);
- virtual status_t drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint);
- virtual status_t drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
- const float* vertices, const int* colors, const SkPaint* paint);
- status_t drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
+ 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;
+ void drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
TextureVertex* vertices, uint32_t indexCount, const SkPaint* paint);
- virtual status_t drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
- float left, float top, float right, float bottom, const SkPaint* paint);
- status_t drawPatch(const SkBitmap* bitmap, const Patch* mesh, AssetAtlas::Entry* entry,
+ virtual void drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
+ float left, float top, float right, float bottom, const SkPaint* paint) override;
+ void drawPatch(const SkBitmap* bitmap, const Patch* mesh, AssetAtlas::Entry* entry,
float left, float top, float right, float bottom, const SkPaint* paint);
- virtual status_t drawColor(int color, SkXfermode::Mode mode);
- virtual status_t drawRect(float left, float top, float right, float bottom,
- const SkPaint* paint);
- virtual status_t drawRoundRect(float left, float top, float right, float bottom,
- float rx, float ry, const SkPaint* paint);
- virtual status_t drawCircle(float x, float y, float radius, const SkPaint* paint);
- virtual status_t drawOval(float left, float top, float right, float bottom,
- const SkPaint* paint);
- virtual status_t drawArc(float left, float top, float right, float bottom,
- float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint);
- virtual status_t drawPath(const SkPath* path, const SkPaint* paint);
- virtual status_t drawLines(const float* points, int count, const SkPaint* paint);
- virtual status_t drawPoints(const float* points, int count, const SkPaint* paint);
- virtual status_t drawTextOnPath(const char* text, int bytesCount, int count, const SkPath* path,
- float hOffset, float vOffset, const SkPaint* paint);
- virtual status_t drawPosText(const char* text, int bytesCount, int count,
- const float* positions, const SkPaint* paint);
- virtual status_t drawText(const char* text, int bytesCount, int count, float x, float y,
+ virtual void drawColor(int color, SkXfermode::Mode mode) override;
+ virtual void drawRect(float left, float top, float right, float bottom,
+ 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 drawLines(const float* points, int count, const SkPaint* paint) override;
+ virtual void drawPoints(const float* points, int count, const SkPaint* paint) override;
+ virtual void drawTextOnPath(const char* text, int bytesCount, int count, const SkPath* path,
+ float hOffset, float vOffset, const SkPaint* paint) override;
+ virtual void drawPosText(const char* text, int bytesCount, int count,
+ const float* positions, const SkPaint* paint) override;
+ virtual void drawText(const char* text, int bytesCount, int count, float x, float y,
const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
- DrawOpMode drawOpMode = kDrawOpMode_Immediate);
- virtual status_t drawRects(const float* rects, int count, const SkPaint* paint);
+ DrawOpMode drawOpMode = kDrawOpMode_Immediate) override;
+ virtual void drawRects(const float* rects, int count, const SkPaint* paint) override;
- status_t drawShadow(float casterAlpha,
- const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer);
+ void drawShadow(float casterAlpha,
+ const VertexBuffer* ambientShadowVertexBuffer,
+ const VertexBuffer* spotShadowVertexBuffer);
- virtual void resetPaintFilter();
- virtual void setupPaintFilter(int clearBits, int setBits);
+ virtual void setDrawFilter(SkDrawFilter* filter) override;
// If this value is set to < 1.0, it overrides alpha set on layer (see drawBitmap, drawLayer)
void setOverrideLayerAlpha(float alpha) { mDrawModifiers.mOverrideLayerAlpha = alpha; }
- const SkPaint* filterPaint(const SkPaint* paint);
-
/**
* Store the current display state (most importantly, the current clip and transform), and
* additionally map the state's bounds from local to window coordinates.
@@ -227,21 +223,18 @@ public:
return mCaches;
}
- // simple rect clip
- bool isCurrentClipSimple() {
- return mSnapshot->clipRegion->isEmpty();
+ RenderState& renderState() {
+ return mRenderState;
}
- int getViewportWidth() { return currentSnapshot()->getViewportWidth(); }
- int getViewportHeight() { return currentSnapshot()->getViewportHeight(); }
+ 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) {
- mSnapshot->alpha *= alpha;
- }
+ void scaleAlpha(float alpha) { mState.scaleAlpha(alpha); }
/**
* Inserts a named event marker in the stream of GL commands.
@@ -275,14 +268,15 @@ public:
* @param alpha Where to store the resulting alpha
* @param mode Where to store the resulting xfermode
*/
- static inline void getAlphaAndModeDirect(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) {
+ static inline void getAlphaAndModeDirect(const SkPaint* paint, int* alpha,
+ SkXfermode::Mode* mode) {
*mode = getXfermodeDirect(paint);
*alpha = getAlphaDirect(paint);
}
static inline SkXfermode::Mode getXfermodeDirect(const SkPaint* paint) {
if (!paint) return SkXfermode::kSrcOver_Mode;
- return getXfermode(paint->getXfermode());
+ return PaintUtils::getXfermode(paint->getXfermode());
}
static inline int getAlphaDirect(const SkPaint* paint) {
@@ -312,7 +306,7 @@ public:
}
static inline bool hasTextShadow(const SkPaint* paint) {
- return getTextShadow(paint, NULL);
+ return getTextShadow(paint, nullptr);
}
/**
@@ -334,18 +328,74 @@ public:
drawColorRect(left, top, right, bottom, color, SkXfermode::kSrcOver_Mode, true);
if (stencilWasEnabled) mCaches.stencil.enableTest();
+ mDirty = true;
}
#endif
- const Vector3& getLightCenter() const { return currentSnapshot()->getRelativeLightCenter(); }
+ 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
+
+ virtual void setViewport(int width, int height) override { mState.setViewport(width, height); }
+
+ virtual int getSaveCount() const override;
+ virtual int save(int flags) override;
+ virtual void restore() override;
+ virtual void restoreToCount(int saveCount) override;
+
+ virtual void getMatrix(SkMatrix* outMatrix) const override { mState.getMatrix(outMatrix); }
+ virtual void setMatrix(const SkMatrix& matrix) override { mState.setMatrix(matrix); }
+ virtual void concatMatrix(const SkMatrix& matrix) override { mState.concatMatrix(matrix); }
+
+ virtual void translate(float dx, float dy, float dz = 0.0f) override;
+ virtual void rotate(float degrees) override;
+ virtual void scale(float sx, float sy) override;
+ virtual void skew(float sx, float sy) override;
+
+ void setMatrix(const Matrix4& matrix); // internal only convenience method
+ void concatMatrix(const Matrix4& matrix); // internal only convenience method
+
+ virtual const Rect& getLocalClipBounds() const override { return mState.getLocalClipBounds(); }
+ const Rect& getRenderTargetClipBounds() const { return mState.getRenderTargetClipBounds(); }
+ virtual bool quickRejectConservative(float left, float top,
+ float right, float bottom) const override {
+ return mState.quickRejectConservative(left, top, right, bottom);
+ }
+
+ 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;
+
+ /**
+ * 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);
+
+ 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 onGetTargetFbo() const override { return 0; }
+
SkPath* allocPathForFrame() {
- SkPath* path = new SkPath();
- mTempPaths.push_back(path);
- return path;
+ std::unique_ptr<SkPath> path(new SkPath());
+ SkPath* returnPath = path.get();
+ mTempPaths.push_back(std::move(path));
+ return returnPath;
}
protected:
@@ -359,12 +409,12 @@ protected:
* Indicates the start of rendering. This method will setup the
* initial OpenGL state (viewport, clearing the buffer, etc.)
*/
- status_t startFrame();
+ void startFrame();
/**
* Clears the underlying surface if needed.
*/
- virtual status_t clear(float left, float top, float right, float bottom, bool opaque);
+ virtual void clear(float left, float top, float right, float bottom, bool opaque);
/**
* Call this method after updating a layer during a drawing pass.
@@ -384,9 +434,16 @@ protected:
*/
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 = NULL);
- bool quickRejectSetupScissor(const Rect& bounds, const SkPaint* paint = NULL) {
+ const SkPaint* paint = nullptr);
+ bool quickRejectSetupScissor(const Rect& bounds, const SkPaint* paint = nullptr) {
return quickRejectSetupScissor(bounds.left, bounds.top,
bounds.right, bounds.bottom, paint);
}
@@ -411,22 +468,16 @@ protected:
* Returns the region of the current layer.
*/
virtual Region* getRegion() const {
- return mSnapshot->region;
+ return mState.currentRegion();
}
/**
* Indicates whether rendering is currently targeted at a layer.
*/
virtual bool hasLayer() const {
- return (mSnapshot->flags & Snapshot::kFlagFboTarget) && mSnapshot->region;
+ return (mState.currentFlags() & Snapshot::kFlagFboTarget) && mState.currentRegion();
}
- /**
- * Returns the name of the FBO this renderer is rendering into.
- */
- virtual GLuint getTargetFbo() const {
- return 0;
- }
/**
* Renders the specified layer as a textured quad.
@@ -459,7 +510,7 @@ protected:
* null then null is returned.
*/
static inline SkColorFilter* getColorFilter(const SkPaint* paint) {
- return paint ? paint->getColorFilter() : NULL;
+ return paint ? paint->getColorFilter() : nullptr;
}
/**
@@ -467,7 +518,7 @@ protected:
* null then null is returned.
*/
static inline const SkShader* getShader(const SkPaint* paint) {
- return paint ? paint->getShader() : NULL;
+ return paint ? paint->getShader() : nullptr;
}
/**
@@ -477,9 +528,13 @@ protected:
return false;
}
- inline RenderState& renderState() { return mRenderState; }
+ CanvasState mState;
+ Caches& mCaches;
+ RenderState& mRenderState;
private:
+ void renderGlop(const Glop& glop);
+
/**
* Discards the content of the framebuffer if supported by the driver.
* This method should be called at the beginning of a frame to optimize
@@ -488,12 +543,6 @@ private:
void discardFramebuffer(float left, float top, float right, float bottom);
/**
- * Ensures the state of the renderer is the same as the state of
- * the GL context.
- */
- void syncState();
-
- /**
* Tells the GPU what part of the screen is about to be redrawn.
* This method will use the current layer space clip rect.
* This method needs to be invoked every time getTargetFbo() is
@@ -514,8 +563,6 @@ private:
*/
void endTiling();
- void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored);
-
/**
* Sets the clipping rectangle using glScissor. The clip is defined by
* the current snapshot's clipRect member.
@@ -629,7 +676,7 @@ private:
* @param dirty True if calling this method should dirty the current layer
* @param clip True if the rects should be clipped, false otherwise
*/
- status_t drawColorRects(const float* rects, int count, const SkPaint* paint,
+ void drawColorRects(const float* rects, int count, const SkPaint* paint,
bool ignoreTransform = false, bool dirty = true, bool clip = true);
/**
@@ -643,7 +690,7 @@ private:
* @param texture The texture reprsenting the shape
* @param paint The paint to draw the shape with
*/
- status_t drawShape(float left, float top, const PathTexture* texture, const SkPaint* paint);
+ void drawShape(float left, float top, const PathTexture* texture, const SkPaint* paint);
/**
* Draws the specified texture as an alpha bitmap. Alpha bitmaps obey
@@ -663,15 +710,15 @@ private:
* @param paint The paint to render with
* @param flags flags with which to draw
*/
- status_t drawVertexBuffer(float translateX, float translateY, const VertexBuffer& vertexBuffer,
+ void drawVertexBuffer(float translateX, float translateY, const VertexBuffer& vertexBuffer,
const SkPaint* paint, int flags = 0);
/**
* Convenience for translating method
*/
- status_t drawVertexBuffer(const VertexBuffer& vertexBuffer,
+ void drawVertexBuffer(const VertexBuffer& vertexBuffer,
const SkPaint* paint, int flags = 0) {
- return drawVertexBuffer(0.0f, 0.0f, vertexBuffer, paint, flags);
+ drawVertexBuffer(0.0f, 0.0f, vertexBuffer, paint, flags);
}
/**
@@ -680,7 +727,7 @@ private:
* @param path The hull of the path to draw
* @param paint The paint to render with
*/
- status_t drawConvexPath(const SkPath& path, const SkPaint* paint);
+ void drawConvexPath(const SkPath& path, const SkPaint* paint);
/**
* Draws a textured rectangle with the specified texture. The specified coordinates
@@ -801,22 +848,6 @@ private:
bool canSkipText(const SkPaint* paint) const;
/**
- * Binds the specified texture. The texture unit must have been selected
- * prior to calling this method.
- */
- inline void bindTexture(GLuint texture) {
- mCaches.bindTexture(texture);
- }
-
- /**
- * Binds the specified EGLImage texture. The texture unit must have been selected
- * prior to calling this method.
- */
- inline void bindExternalTexture(GLuint texture) {
- mCaches.bindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
- }
-
- /**
* Enable or disable blending as necessary. This function sets the appropriate
* blend function based on the specified xfermode.
*/
@@ -824,18 +855,6 @@ private:
bool swapSrcDst = false);
/**
- * Use the specified program with the current GL context. If the program is already
- * in use, it will not be bound again. If it is not in use, the current program is
- * marked unused and the specified program becomes used and becomes the new
- * current program.
- *
- * @param program The program to use
- *
- * @return true If the specified program was already in use, false otherwise.
- */
- inline bool useProgram(Program* program);
-
- /**
* Invoked before any drawing operation. This sets required state.
*/
void setupDraw(bool clear = true);
@@ -867,8 +886,8 @@ private:
* space must be scaled up and translated to fill the quad provided in (l,t,r,b). These
* transformations are stored in the modelView matrix and uploaded to the shader.
*
- * @param offset Set to true if the the matrix should be fudged (translated) slightly to disambiguate
- * geometry pixel positioning. See Vertex::GeometryFudgeFactor().
+ * @param offset Set to true if the the matrix should be fudged (translated) slightly to
+ * disambiguate geometry pixel positioning. See Vertex::GeometryFudgeFactor().
*
* @param ignoreTransform Set to true if l,t,r,b coordinates already in layer space,
* currentTransform() will be ignored. (e.g. when drawing clip in layer coordinates to stencil,
@@ -894,7 +913,7 @@ private:
void setupDrawTextureTransform();
void setupDrawTextureTransformUniforms(mat4& transform);
void setupDrawTextGammaUniforms();
- void setupDrawMesh(const GLvoid* vertices, const GLvoid* texCoords = NULL, GLuint vbo = 0);
+ void setupDrawMesh(const GLvoid* vertices, const GLvoid* texCoords = nullptr, GLuint vbo = 0);
void setupDrawMesh(const GLvoid* vertices, const GLvoid* texCoords, const GLvoid* colors);
void setupDrawMeshIndices(const GLvoid* vertices, const GLvoid* texCoords, GLuint vbo = 0);
void setupDrawIndexedVertices(GLvoid* vertices);
@@ -931,9 +950,7 @@ private:
/**
* Should be invoked every time the glScissor is modified.
*/
- inline void dirtyClip() {
- mDirtyClip = true;
- }
+ inline void dirtyClip() { mState.setDirtyClip(true); }
inline const UvMapper& getMapper(const Texture* texture) {
return texture && texture->uvMapper ? *texture->uvMapper : mUvMapper;
@@ -946,6 +963,10 @@ private:
*/
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(); }
+
/**
* Model-view matrix used to position/size objects
*
@@ -979,13 +1000,8 @@ private:
DrawModifiers mDrawModifiers;
SkPaint mFilteredPaint;
- // Various caches
- Caches& mCaches;
- Extensions& mExtensions;
- RenderState& mRenderState;
-
// List of rectangles to clear after saveLayer() is invoked
- Vector<Rect*> mLayers;
+ std::vector<Rect> mLayers;
// List of layers to update at the beginning of a frame
Vector< sp<Layer> > mLayerUpdates;
@@ -1014,6 +1030,10 @@ private:
bool mSkipOutlineClip;
+ // True if anything has been drawn since the last call to
+ // reportAndClearDirty()
+ bool mDirty;
+
// Lighting + shadows
Vector3 mLightCenter;
float mLightRadius;
@@ -1021,7 +1041,7 @@ private:
uint8_t mSpotShadowAlpha;
// Paths kept alive for the duration of the frame
- std::vector<SkPath*> mTempPaths;
+ std::vector<std::unique_ptr<SkPath>> mTempPaths;
friend class Layer;
friend class TextSetupFunctor;
diff --git a/libs/hwui/Outline.h b/libs/hwui/Outline.h
index 6dacd5e..5e9b213 100644
--- a/libs/hwui/Outline.h
+++ b/libs/hwui/Outline.h
@@ -95,7 +95,7 @@ public:
}
const SkPath* getPath() const {
- if (mType == kOutlineType_None || mType == kOutlineType_Empty) return NULL;
+ if (mType == kOutlineType_None || mType == kOutlineType_Empty) return nullptr;
return &mPath;
}
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index 442e9ba..8a4d65b 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -32,11 +32,7 @@ namespace uirenderer {
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
-Patch::Patch(): vertices(NULL), verticesCount(0), indexCount(0), hasEmptyQuads(false) {
-}
-
-Patch::~Patch() {
- delete[] vertices;
+Patch::Patch(): vertices(), verticesCount(0), indexCount(0), hasEmptyQuads(false) {
}
///////////////////////////////////////////////////////////////////////////////
@@ -55,7 +51,7 @@ TextureVertex* Patch::createMesh(const float bitmapWidth, const float bitmapHeig
TextureVertex* Patch::createMesh(const float bitmapWidth, const float bitmapHeight,
float width, float height, const UvMapper& mapper, const Res_png_9patch* patch) {
- if (vertices) return vertices;
+ if (vertices) return vertices.get();
int8_t emptyQuads = 0;
mColors = patch->getColors();
@@ -75,10 +71,10 @@ TextureVertex* Patch::createMesh(const float bitmapWidth, const float bitmapHeig
uint32_t yCount = patch->numYDivs;
uint32_t maxVertices = ((xCount + 1) * (yCount + 1) - emptyQuads) * 4;
- if (maxVertices == 0) return NULL;
+ if (maxVertices == 0) return nullptr;
- TextureVertex* tempVertices = new TextureVertex[maxVertices];
- TextureVertex* vertex = tempVertices;
+ vertices.reset(new TextureVertex[maxVertices]);
+ TextureVertex* vertex = vertices.get();
const int32_t* xDivs = patch->getXDivs();
const int32_t* yDivs = patch->getYDivs();
@@ -157,15 +153,13 @@ TextureVertex* Patch::createMesh(const float bitmapWidth, const float bitmapHeig
width, bitmapWidth, quadCount);
}
- if (verticesCount == maxVertices) {
- vertices = tempVertices;
- } else {
- vertices = new TextureVertex[verticesCount];
- memcpy(vertices, tempVertices, verticesCount * sizeof(TextureVertex));
- delete[] tempVertices;
+ if (verticesCount != maxVertices) {
+ std::unique_ptr<TextureVertex[]> reducedVertices(new TextureVertex[verticesCount]);
+ memcpy(reducedVertices.get(), vertices.get(), verticesCount * sizeof(TextureVertex));
+ vertices = std::move(reducedVertices);
}
- return vertices;
+ return vertices.get();
}
void Patch::generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex,
diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h
index 1ba045d..ea8c8c2 100644
--- a/libs/hwui/Patch.h
+++ b/libs/hwui/Patch.h
@@ -27,11 +27,12 @@
#include "Rect.h"
#include "UvMapper.h"
-#include "Vertex.h"
namespace android {
namespace uirenderer {
+struct TextureVertex;
+
///////////////////////////////////////////////////////////////////////////////
// 9-patch structures
///////////////////////////////////////////////////////////////////////////////
@@ -39,14 +40,13 @@ namespace uirenderer {
class Patch {
public:
Patch();
- ~Patch();
/**
* Returns the size of this patch's mesh in bytes.
*/
uint32_t getSize() const;
- TextureVertex* vertices;
+ std::unique_ptr<TextureVertex[]> vertices;
uint32_t verticesCount;
uint32_t indexCount;
bool hasEmptyQuads;
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
index 2f2debc..af403b4 100644
--- a/libs/hwui/PatchCache.cpp
+++ b/libs/hwui/PatchCache.cpp
@@ -20,8 +20,10 @@
#include <utils/Log.h>
#include "Caches.h"
+#include "Patch.h"
#include "PatchCache.h"
#include "Properties.h"
+#include "renderstate/RenderState.h"
namespace android {
namespace uirenderer {
@@ -30,11 +32,15 @@ namespace uirenderer {
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
-PatchCache::PatchCache():
- mSize(0), mCache(LruCache<PatchDescription, Patch*>::kUnlimitedCapacity),
- mMeshBuffer(0), mFreeBlocks(NULL), mGenerationId(0) {
+PatchCache::PatchCache(RenderState& renderState)
+ : mRenderState(renderState)
+ , mSize(0)
+ , mCache(LruCache<PatchDescription, Patch*>::kUnlimitedCapacity)
+ , mMeshBuffer(0)
+ , mFreeBlocks(nullptr)
+ , mGenerationId(0) {
char property[PROPERTY_VALUE_MAX];
- if (property_get(PROPERTY_PATCH_CACHE_SIZE, property, NULL) > 0) {
+ if (property_get(PROPERTY_PATCH_CACHE_SIZE, property, nullptr) > 0) {
INIT_LOGD(" Setting patch cache size to %skB", property);
mMaxSize = KB(atoi(property));
} else {
@@ -47,15 +53,15 @@ PatchCache::~PatchCache() {
clear();
}
-void PatchCache::init(Caches& caches) {
+void PatchCache::init() {
bool created = false;
if (!mMeshBuffer) {
glGenBuffers(1, &mMeshBuffer);
created = true;
}
- caches.bindMeshBuffer(mMeshBuffer);
- caches.resetVertexPointers();
+ mRenderState.meshState().bindMeshBuffer(mMeshBuffer);
+ mRenderState.meshState().resetVertexPointers();
if (created) {
createVertexBuffer();
@@ -84,7 +90,7 @@ void PatchCache::clear() {
clearCache();
if (mMeshBuffer) {
- Caches::getInstance().unbindMeshBuffer();
+ mRenderState.meshState().unbindMeshBuffer();
glDeleteBuffers(1, &mMeshBuffer);
mMeshBuffer = 0;
mSize = 0;
@@ -104,7 +110,7 @@ void PatchCache::clearCache() {
delete block;
block = next;
}
- mFreeBlocks = NULL;
+ mFreeBlocks = nullptr;
}
void PatchCache::remove(Vector<patch_pair_t>& patchesToRemove, Res_png_9patch* patch) {
@@ -124,11 +130,11 @@ void PatchCache::removeDeferred(Res_png_9patch* patch) {
size_t count = mGarbage.size();
for (size_t i = 0; i < count; i++) {
if (patch == mGarbage[i]) {
- patch = NULL;
+ patch = nullptr;
break;
}
}
- LOG_ALWAYS_FATAL_IF(patch == NULL);
+ LOG_ALWAYS_FATAL_IF(patch == nullptr);
mGarbage.push(patch);
}
@@ -174,7 +180,7 @@ void PatchCache::clearGarbage() {
}
void PatchCache::createVertexBuffer() {
- glBufferData(GL_ARRAY_BUFFER, mMaxSize, NULL, GL_DYNAMIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, mMaxSize, nullptr, GL_DYNAMIC_DRAW);
mSize = 0;
mFreeBlocks = new BufferBlock(0, mMaxSize);
mGenerationId++;
@@ -186,7 +192,7 @@ void PatchCache::createVertexBuffer() {
*/
void PatchCache::setupMesh(Patch* newMesh, TextureVertex* vertices) {
// This call ensures the VBO exists and that it is bound
- init(Caches::getInstance());
+ init();
// If we're running out of space, let's clear the entire cache
uint32_t size = newMesh->getSize();
@@ -196,7 +202,7 @@ void PatchCache::setupMesh(Patch* newMesh, TextureVertex* vertices) {
}
// Find a block where we can fit the mesh
- BufferBlock* previous = NULL;
+ BufferBlock* previous = nullptr;
BufferBlock* block = mFreeBlocks;
while (block) {
// The mesh fits
@@ -212,13 +218,13 @@ void PatchCache::setupMesh(Patch* newMesh, TextureVertex* vertices) {
if (!block) {
clearCache();
createVertexBuffer();
- previous = NULL;
+ previous = nullptr;
block = mFreeBlocks;
}
// Copy the 9patch mesh in the VBO
newMesh->offset = (GLintptr) (block->offset);
- newMesh->textureOffset = newMesh->offset + gMeshTextureOffset;
+ newMesh->textureOffset = newMesh->offset + kMeshTextureOffset;
glBufferSubData(GL_ARRAY_BUFFER, newMesh->offset, size, vertices);
// Remove the block since we've used it entirely
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
index 9f2c9a5..e038720 100644
--- a/libs/hwui/PatchCache.h
+++ b/libs/hwui/PatchCache.h
@@ -25,12 +25,13 @@
#include "AssetAtlas.h"
#include "Debug.h"
-#include "Patch.h"
#include "utils/Pair.h"
namespace android {
namespace uirenderer {
+class Patch;
+
///////////////////////////////////////////////////////////////////////////////
// Defines
///////////////////////////////////////////////////////////////////////////////
@@ -50,9 +51,9 @@ class Caches;
class PatchCache {
public:
- PatchCache();
+ PatchCache(RenderState& renderState);
~PatchCache();
- void init(Caches& caches);
+ void init();
const Patch* get(const AssetAtlas::Entry* entry,
const uint32_t bitmapWidth, const uint32_t bitmapHeight,
@@ -90,7 +91,7 @@ public:
private:
struct PatchDescription {
- PatchDescription(): mPatch(NULL), mBitmapWidth(0), mBitmapHeight(0),
+ PatchDescription(): mPatch(nullptr), mBitmapWidth(0), mBitmapHeight(0),
mPixelWidth(0), mPixelHeight(0) {
}
@@ -145,7 +146,7 @@ private:
* to track available regions of memory in the VBO.
*/
struct BufferBlock {
- BufferBlock(uint32_t offset, uint32_t size): offset(offset), size(size), next(NULL) {
+ BufferBlock(uint32_t offset, uint32_t size): offset(offset), size(size), next(nullptr) {
}
uint32_t offset;
@@ -167,6 +168,7 @@ private:
void dumpFreeBlocks(const char* prefix);
#endif
+ RenderState& mRenderState;
uint32_t mMaxSize;
uint32_t mSize;
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index f3d1b34..e2caf8b 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -31,7 +31,6 @@
#include "PathCache.h"
#include "thread/Signal.h"
-#include "thread/Task.h"
#include "thread/TaskProcessor.h"
namespace android {
@@ -48,7 +47,7 @@ PathDescription::PathDescription():
style(SkPaint::kFill_Style),
miter(4.0f),
strokeWidth(1.0f),
- pathEffect(NULL) {
+ pathEffect(nullptr) {
memset(&shape, 0, sizeof(Shape));
}
@@ -81,7 +80,7 @@ hash_t PathDescription::hash() const {
bool PathCache::canDrawAsConvexPath(SkPath* path, const SkPaint* paint) {
// NOTE: This should only be used after PathTessellator handles joins properly
- return paint->getPathEffect() == NULL && path->getConvexity() == SkPath::kConvex_Convexity;
+ return paint->getPathEffect() == nullptr && path->getConvexity() == SkPath::kConvex_Convexity;
}
void PathCache::computePathBounds(const SkPath* path, const SkPaint* paint,
@@ -114,9 +113,9 @@ static void initPaint(SkPaint& paint) {
// will be applied later when compositing the alpha8 texture
paint.setColor(SK_ColorBLACK);
paint.setAlpha(255);
- paint.setColorFilter(NULL);
- paint.setMaskFilter(NULL);
- paint.setShader(NULL);
+ paint.setColorFilter(nullptr);
+ paint.setMaskFilter(nullptr);
+ paint.setShader(nullptr);
SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrc_Mode);
SkSafeUnref(paint.setXfermode(mode));
}
@@ -153,7 +152,7 @@ PathCache::PathCache():
mCache(LruCache<PathDescription, PathTexture*>::kUnlimitedCapacity),
mSize(0), mMaxSize(MB(DEFAULT_PATH_CACHE_SIZE)) {
char property[PROPERTY_VALUE_MAX];
- if (property_get(PROPERTY_PATH_CACHE_SIZE, property, NULL) > 0) {
+ if (property_get(PROPERTY_PATH_CACHE_SIZE, property, nullptr) > 0) {
INIT_LOGD(" Setting %s cache size to %sMB", name, property);
setMaxSize(MB(atof(property)));
} else {
@@ -211,7 +210,7 @@ void PathCache::removeTexture(PathTexture* texture) {
// If there is a pending task we must wait for it to return
// before attempting our cleanup
const sp<Task<SkBitmap*> >& task = texture->task();
- if (task != NULL) {
+ if (task != nullptr) {
task->getResult();
texture->clearTask();
} else {
@@ -231,7 +230,7 @@ void PathCache::removeTexture(PathTexture* texture) {
}
if (texture->id) {
- Caches::getInstance().deleteTexture(texture->id);
+ Caches::getInstance().textureState().deleteTexture(texture->id);
}
delete texture;
}
@@ -261,7 +260,7 @@ PathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath *p
uint32_t width, height;
computePathBounds(path, paint, left, top, offset, width, height);
- if (!checkTextureSize(width, height)) return NULL;
+ if (!checkTextureSize(width, height)) return nullptr;
purgeCache(width, height);
@@ -313,7 +312,7 @@ void PathCache::generateTexture(SkBitmap& bitmap, Texture* texture) {
glGenTextures(1, &texture->id);
- Caches::getInstance().bindTexture(texture->id);
+ Caches::getInstance().textureState().bindTexture(texture->id);
// Textures are Alpha8
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
@@ -355,7 +354,7 @@ void PathCache::PathProcessor::onProcess(const sp<Task<SkBitmap*> >& task) {
} else {
texture->width = 0;
texture->height = 0;
- t->setResult(NULL);
+ t->setResult(nullptr);
}
}
@@ -430,7 +429,7 @@ PathTexture* PathCache::get(const SkPath* path, const SkPaint* paint) {
// A bitmap is attached to the texture, this means we need to
// upload it as a GL texture
const sp<Task<SkBitmap*> >& task = texture->task();
- if (task != NULL) {
+ if (task != nullptr) {
// But we must first wait for the worker thread to be done
// producing the bitmap, so let's wait
SkBitmap* bitmap = task->getResult();
@@ -440,7 +439,7 @@ PathTexture* PathCache::get(const SkPath* path, const SkPaint* paint) {
} else {
ALOGW("Path too large to be rendered into a texture");
texture->clearTask();
- texture = NULL;
+ texture = nullptr;
mCache.remove(entry);
}
} else if (path->getGenerationID() != texture->generation) {
@@ -490,7 +489,7 @@ void PathCache::precache(const SkPath* path, const SkPaint* paint) {
// be enforced.
mCache.put(entry, texture);
- if (mProcessor == NULL) {
+ if (mProcessor == nullptr) {
mProcessor = new PathProcessor(Caches::getInstance());
}
if (!mProcessor->add(task)) {
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index bc34188..7378018 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -17,22 +17,22 @@
#ifndef ANDROID_HWUI_PATH_CACHE_H
#define ANDROID_HWUI_PATH_CACHE_H
-#include <GLES2/gl2.h>
-
-#include <utils/LruCache.h>
-#include <utils/Mutex.h>
-#include <utils/Vector.h>
-
#include "Debug.h"
-#include "Properties.h"
#include "Texture.h"
+#include "thread/Task.h"
+#include "thread/TaskProcessor.h"
#include "utils/Macros.h"
#include "utils/Pair.h"
+#include <GLES2/gl2.h>
+#include <SkPath.h>
+#include <utils/LruCache.h>
+#include <utils/Mutex.h>
+#include <utils/Vector.h>
+
class SkBitmap;
class SkCanvas;
class SkPaint;
-class SkPath;
struct SkRect;
namespace android {
@@ -88,7 +88,7 @@ struct PathTexture: public Texture {
}
void clearTask() {
- if (mTask != NULL) {
+ if (mTask != nullptr) {
mTask.clear();
}
}
@@ -166,7 +166,7 @@ public:
* Used as a callback when an entry is removed from the cache.
* Do not invoke directly.
*/
- void operator()(PathDescription& path, PathTexture*& texture);
+ void operator()(PathDescription& path, PathTexture*& texture) override;
/**
* Clears the cache. This causes all textures to be deleted.
@@ -293,7 +293,7 @@ private:
PathProcessor(Caches& caches);
~PathProcessor() { }
- virtual void onProcess(const sp<Task<SkBitmap*> >& task);
+ virtual void onProcess(const sp<Task<SkBitmap*> >& task) override;
private:
uint32_t mMaxTextureSize;
diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp
index 9f7dd50..3d8a749 100644
--- a/libs/hwui/PathTessellator.cpp
+++ b/libs/hwui/PathTessellator.cpp
@@ -229,7 +229,6 @@ void getStrokeVerticesFromPerimeter(const PaintInfo& paintInfo, const Vector<Ver
current->x - totalOffset.x,
current->y - totalOffset.y);
- last = current;
current = next;
lastNormal = nextNormal;
}
@@ -372,7 +371,6 @@ void getFillVerticesFromPerimeterAA(const PaintInfo& paintInfo, const Vector<Ver
current->y - totalOffset.y,
maxAlpha);
- last = current;
current = next;
lastNormal = nextNormal;
}
@@ -700,7 +698,6 @@ void getStrokeVerticesFromPerimeterAA(const PaintInfo& paintInfo, const Vector<V
current->y - outerOffset.y,
0.0f);
- last = current;
current = next;
lastNormal = nextNormal;
}
@@ -786,6 +783,7 @@ void PathTessellator::tessellatePath(const SkPath &path, const SkPaint* paint,
Rect bounds(path.getBounds());
paintInfo.expandBoundsForStroke(&bounds);
vertexBuffer.setBounds(bounds);
+ vertexBuffer.setMeshFeatureFlags(paintInfo.isAA ? VertexBuffer::kAlpha : VertexBuffer::kNone);
}
template <class TYPE>
@@ -843,6 +841,7 @@ void PathTessellator::tessellatePoints(const float* points, int count, const SkP
// expand bounds from vertex coords to pixel data
paintInfo.expandBoundsForStroke(&bounds);
vertexBuffer.setBounds(bounds);
+ vertexBuffer.setMeshFeatureFlags(paintInfo.isAA ? VertexBuffer::kAlpha : VertexBuffer::kNone);
}
void PathTessellator::tessellateLines(const float* points, int count, const SkPaint* paint,
@@ -893,6 +892,7 @@ void PathTessellator::tessellateLines(const float* points, int count, const SkPa
// expand bounds from vertex coords to pixel data
paintInfo.expandBoundsForStroke(&bounds);
vertexBuffer.setBounds(bounds);
+ vertexBuffer.setMeshFeatureFlags(paintInfo.isAA ? VertexBuffer::kAlpha : VertexBuffer::kNone);
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/PixelBuffer.cpp b/libs/hwui/PixelBuffer.cpp
index 5b642b9..9665a68 100644
--- a/libs/hwui/PixelBuffer.cpp
+++ b/libs/hwui/PixelBuffer.cpp
@@ -16,13 +16,14 @@
#define LOG_TAG "OpenGLRenderer"
-#include <utils/Log.h>
+#include "PixelBuffer.h"
-#include "Caches.h"
#include "Debug.h"
#include "Extensions.h"
-#include "PixelBuffer.h"
#include "Properties.h"
+#include "renderstate/RenderState.h"
+
+#include <utils/Log.h>
namespace android {
namespace uirenderer {
@@ -34,33 +35,28 @@ namespace uirenderer {
class CpuPixelBuffer: public PixelBuffer {
public:
CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height);
- ~CpuPixelBuffer();
- uint8_t* map(AccessMode mode = kAccessMode_ReadWrite);
- void unmap();
+ uint8_t* map(AccessMode mode = kAccessMode_ReadWrite) override;
+ void unmap() override;
- uint8_t* getMappedPointer() const;
+ uint8_t* getMappedPointer() const override;
- void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset);
+ void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) override;
private:
- uint8_t* mBuffer;
+ std::unique_ptr<uint8_t[]> mBuffer;
};
-CpuPixelBuffer::CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height):
- PixelBuffer(format, width, height) {
- mBuffer = new uint8_t[width * height * formatSize(format)];
-}
-
-CpuPixelBuffer::~CpuPixelBuffer() {
- delete[] mBuffer;
+CpuPixelBuffer::CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height)
+ : PixelBuffer(format, width, height)
+ , mBuffer(new uint8_t[width * height * formatSize(format)]) {
}
uint8_t* CpuPixelBuffer::map(AccessMode mode) {
if (mAccessMode == kAccessMode_None) {
mAccessMode = mode;
}
- return mBuffer;
+ return mBuffer.get();
}
void CpuPixelBuffer::unmap() {
@@ -68,12 +64,12 @@ void CpuPixelBuffer::unmap() {
}
uint8_t* CpuPixelBuffer::getMappedPointer() const {
- return mAccessMode == kAccessMode_None ? NULL : mBuffer;
+ return mAccessMode == kAccessMode_None ? nullptr : mBuffer.get();
}
void CpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) {
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height,
- mFormat, GL_UNSIGNED_BYTE, mBuffer + offset);
+ mFormat, GL_UNSIGNED_BYTE, &mBuffer[offset]);
}
///////////////////////////////////////////////////////////////////////////////
@@ -85,12 +81,12 @@ public:
GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height);
~GpuPixelBuffer();
- uint8_t* map(AccessMode mode = kAccessMode_ReadWrite);
- void unmap();
+ uint8_t* map(AccessMode mode = kAccessMode_ReadWrite) override;
+ void unmap() override;
- uint8_t* getMappedPointer() const;
+ uint8_t* getMappedPointer() const override;
- void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset);
+ void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) override;
private:
GLuint mBuffer;
@@ -98,12 +94,16 @@ private:
Caches& mCaches;
};
-GpuPixelBuffer::GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height):
- PixelBuffer(format, width, height), mMappedPointer(0), mCaches(Caches::getInstance()) {
+GpuPixelBuffer::GpuPixelBuffer(GLenum format,
+ uint32_t width, uint32_t height)
+ : PixelBuffer(format, width, height)
+ , mMappedPointer(nullptr)
+ , mCaches(Caches::getInstance()){
glGenBuffers(1, &mBuffer);
- mCaches.bindPixelBuffer(mBuffer);
- glBufferData(GL_PIXEL_UNPACK_BUFFER, getSize(), NULL, GL_DYNAMIC_DRAW);
- mCaches.unbindPixelBuffer();
+
+ mCaches.pixelBufferState().bind(mBuffer);
+ glBufferData(GL_PIXEL_UNPACK_BUFFER, getSize(), nullptr, GL_DYNAMIC_DRAW);
+ mCaches.pixelBufferState().unbind();
}
GpuPixelBuffer::~GpuPixelBuffer() {
@@ -112,7 +112,7 @@ GpuPixelBuffer::~GpuPixelBuffer() {
uint8_t* GpuPixelBuffer::map(AccessMode mode) {
if (mAccessMode == kAccessMode_None) {
- mCaches.bindPixelBuffer(mBuffer);
+ mCaches.pixelBufferState().bind(mBuffer);
mMappedPointer = (uint8_t*) glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, getSize(), mode);
#if DEBUG_OPENGL
if (!mMappedPointer) {
@@ -131,14 +131,14 @@ uint8_t* GpuPixelBuffer::map(AccessMode mode) {
void GpuPixelBuffer::unmap() {
if (mAccessMode != kAccessMode_None) {
if (mMappedPointer) {
- mCaches.bindPixelBuffer(mBuffer);
+ mCaches.pixelBufferState().bind(mBuffer);
GLboolean status = glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
if (status == GL_FALSE) {
ALOGE("Corrupted GPU pixel buffer");
}
}
mAccessMode = kAccessMode_None;
- mMappedPointer = NULL;
+ mMappedPointer = nullptr;
}
}
@@ -148,7 +148,7 @@ uint8_t* GpuPixelBuffer::getMappedPointer() const {
void GpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) {
// If the buffer is not mapped, unmap() will not bind it
- mCaches.bindPixelBuffer(mBuffer);
+ mCaches.pixelBufferState().bind(mBuffer);
unmap();
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat,
GL_UNSIGNED_BYTE, reinterpret_cast<void*>(offset));
@@ -158,7 +158,8 @@ void GpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t hei
// Factory
///////////////////////////////////////////////////////////////////////////////
-PixelBuffer* PixelBuffer::create(GLenum format, uint32_t width, uint32_t height, BufferType type) {
+PixelBuffer* PixelBuffer::create(GLenum format,
+ uint32_t width, uint32_t height, BufferType type) {
if (type == kBufferType_Auto && Caches::getInstance().gpuPixelBuffersEnabled) {
return new GpuPixelBuffer(format, width, height);
}
diff --git a/libs/hwui/PixelBuffer.h b/libs/hwui/PixelBuffer.h
index 04225a2..aac5ec4 100644
--- a/libs/hwui/PixelBuffer.h
+++ b/libs/hwui/PixelBuffer.h
@@ -18,6 +18,7 @@
#define ANDROID_HWUI_PIXEL_BUFFER_H
#include <GLES3/gl3.h>
+#include <cutils/log.h>
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index e6fd2dc..5f34b34 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -46,7 +46,7 @@ Program::Program(const ProgramDescription& description, const char* vertex, cons
glAttachShader(mProgramId, mVertexShader);
glAttachShader(mProgramId, mFragmentShader);
- position = bindAttrib("position", kBindingPosition);
+ bindAttrib("position", kBindingPosition);
if (description.hasTexture || description.hasExternalTexture) {
texCoords = bindAttrib("texCoords", kBindingTexCoords);
} else {
@@ -64,7 +64,7 @@ Program::Program(const ProgramDescription& description, const char* vertex, cons
glGetProgramiv(mProgramId, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
GLchar log[infoLen];
- glGetProgramInfoLog(mProgramId, infoLen, 0, &log[0]);
+ glGetProgramInfoLog(mProgramId, infoLen, nullptr, &log[0]);
ALOGE("%s", log);
}
LOG_ALWAYS_FATAL("Error while linking shaders");
@@ -135,7 +135,7 @@ GLuint Program::buildShader(const char* source, GLenum type) {
ATRACE_NAME("Build GL Shader");
GLuint shader = glCreateShader(type);
- glShaderSource(shader, 1, &source, 0);
+ glShaderSource(shader, 1, &source, nullptr);
glCompileShader(shader);
GLint status;
@@ -145,7 +145,7 @@ GLuint Program::buildShader(const char* source, GLenum type) {
// Some drivers return wrong values for GL_INFO_LOG_LENGTH
// use a fixed size instead
GLchar log[512];
- glGetShaderInfoLog(shader, sizeof(log), 0, &log[0]);
+ glGetShaderInfoLog(shader, sizeof(log), nullptr, &log[0]);
LOG_ALWAYS_FATAL("Shader info log: %s", log);
return 0;
}
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index fc7d134..01231b5 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -102,7 +102,7 @@ typedef uint64_t programid;
* A ProgramDescription must be used in conjunction with a ProgramCache.
*/
struct ProgramDescription {
- enum ColorModifier {
+ enum ColorFilterMode {
kColorNone = 0,
kColorMatrix,
kColorBlend
@@ -148,7 +148,7 @@ struct ProgramDescription {
GLenum bitmapWrapT;
// Color operations
- ColorModifier colorOp;
+ ColorFilterMode colorOp;
SkXfermode::Mode colorMode;
// Framebuffer blending (requires Extensions.hasFramebufferFetch())
@@ -281,8 +281,6 @@ struct ProgramDescription {
programid k = key();
PROGRAM_LOGD("%s (key = 0x%.8x%.8x)", message, uint32_t(k >> 32),
uint32_t(k & 0xffffffff));
-#else
- (void)message;
#endif
}
@@ -368,12 +366,7 @@ public:
void setColor(const float r, const float g, const float b, const float a);
/**
- * Name of the position attribute.
- */
- int position;
-
- /**
- * Name of the texCoords attribute if it exists, -1 otherwise.
+ * Name of the texCoords attribute if it exists (kBindingTexCoords), -1 otherwise.
*/
int texCoords;
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 62835e0..8c6a91cc 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -404,7 +404,8 @@ const char* gBlendOps[18] = {
// Constructors/destructors
///////////////////////////////////////////////////////////////////////////////
-ProgramCache::ProgramCache(): mHasES3(Extensions::getInstance().getMajorGlVersion() >= 3) {
+ProgramCache::ProgramCache(Extensions& extensions)
+ : mHasES3(extensions.getMajorGlVersion() >= 3) {
}
ProgramCache::~ProgramCache() {
@@ -417,11 +418,6 @@ ProgramCache::~ProgramCache() {
void ProgramCache::clear() {
PROGRAM_LOGD("Clearing program cache");
-
- size_t count = mCache.size();
- for (size_t i = 0; i < count; i++) {
- delete mCache.valueAt(i);
- }
mCache.clear();
}
@@ -433,14 +429,14 @@ Program* ProgramCache::get(const ProgramDescription& description) {
key = PROGRAM_KEY_TEXTURE;
}
- ssize_t index = mCache.indexOfKey(key);
- Program* program = NULL;
- if (index < 0) {
+ auto iter = mCache.find(key);
+ Program* program = nullptr;
+ if (iter == mCache.end()) {
description.log("Could not find program");
program = generateProgram(description, key);
- mCache.add(key, program);
+ mCache[key] = std::unique_ptr<Program>(program);
} else {
- program = mCache.valueAt(index);
+ program = iter->second.get();
}
return program;
}
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index 38f6f99..1dadda1 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -20,12 +20,12 @@
#include <utils/KeyedVector.h>
#include <utils/Log.h>
#include <utils/String8.h>
+#include <map>
#include <GLES2/gl2.h>
#include "Debug.h"
#include "Program.h"
-#include "Properties.h"
namespace android {
namespace uirenderer {
@@ -40,7 +40,7 @@ namespace uirenderer {
*/
class ProgramCache {
public:
- ProgramCache();
+ ProgramCache(Extensions& extensions);
~ProgramCache();
Program* get(const ProgramDescription& description);
@@ -56,7 +56,7 @@ private:
void printLongString(const String8& shader) const;
- KeyedVector<programid, Program*> mCache;
+ std::map<programid, std::unique_ptr<Program>> mCache;
const bool mHasES3;
}; // class ProgramCache
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 7b9459a..a0312e1 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -255,7 +255,7 @@ enum DebugLevel {
static inline DebugLevel readDebugLevel() {
char property[PROPERTY_VALUE_MAX];
- if (property_get(PROPERTY_DEBUG, property, NULL) > 0) {
+ if (property_get(PROPERTY_DEBUG, property, nullptr) > 0) {
return (DebugLevel) atoi(property);
}
return kDebugDisabled;
diff --git a/libs/hwui/Query.h b/libs/hwui/Query.h
deleted file mode 100644
index e25b16b..0000000
--- a/libs/hwui/Query.h
+++ /dev/null
@@ -1,152 +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_QUERY_H
-#define ANDROID_HWUI_QUERY_H
-
-#include <GLES3/gl3.h>
-
-#include "Extensions.h"
-
-namespace android {
-namespace uirenderer {
-
-/**
- * A Query instance can be used to perform occlusion queries. If the device
- * does not support occlusion queries, the result of a query will always be
- * 0 and the result will always be marked available.
- *
- * To run an occlusion query successfully, you must start end end the query:
- *
- * Query query;
- * query.begin();
- * // execute OpenGL calls
- * query.end();
- * GLuint result = query.getResult();
- */
-class Query {
-public:
- /**
- * Possible query targets.
- */
- enum Target {
- /**
- * Indicates if any sample passed the depth & stencil tests.
- */
- kTargetSamples = GL_ANY_SAMPLES_PASSED,
- /**
- * Indicates if any sample passed the depth & stencil tests.
- * The implementation may choose to use a less precise version
- * of the test, potentially resulting in false positives.
- */
- kTargetConservativeSamples = GL_ANY_SAMPLES_PASSED_CONSERVATIVE,
- };
-
- /**
- * Creates a new query with the specified target. The default
- * target is kTargetSamples (of GL_ANY_SAMPLES_PASSED in OpenGL.)
- */
- Query(Target target = kTargetSamples): mActive(false), mTarget(target),
- mCanQuery(Extensions::getInstance().hasOcclusionQueries()),
- mQuery(0) {
- }
-
- ~Query() {
- if (mQuery) {
- glDeleteQueries(1, &mQuery);
- }
- }
-
- /**
- * Begins the query. If the query has already begun or if the device
- * does not support occlusion queries, calling this method as no effect.
- * After calling this method successfully, the query is marked active.
- */
- void begin() {
- if (!mActive && mCanQuery) {
- if (!mQuery) {
- glGenQueries(1, &mQuery);
- }
-
- glBeginQuery(mTarget, mQuery);
- mActive = true;
- }
- }
-
- /**
- * Ends the query. If the query has already begun or if the device
- * does not support occlusion queries, calling this method as no effect.
- * After calling this method successfully, the query is marked inactive.
- */
- void end() {
- if (mQuery && mActive) {
- glEndQuery(mTarget);
- mActive = false;
- }
- }
-
- /**
- * Returns true if the query is active, false otherwise.
- */
- bool isActive() {
- return mActive;
- }
-
- /**
- * Returns true if the result of the query is available,
- * false otherwise. Calling getResult() before the result
- * is available may result in the calling thread being blocked.
- * If the device does not support queries, this method always
- * returns true.
- */
- bool isResultAvailable() {
- if (!mQuery) return true;
-
- GLuint result;
- glGetQueryObjectuiv(mQuery, GL_QUERY_RESULT_AVAILABLE, &result);
- return result == GL_TRUE;
- }
-
- /**
- * Returns the result of the query. If the device does not
- * support queries this method will return 0.
- *
- * Calling this method implicitely calls end() if the query
- * is currently active.
- */
- GLuint getResult() {
- if (!mQuery) return 0;
-
- end();
-
- GLuint result;
- glGetQueryObjectuiv(mQuery, GL_QUERY_RESULT, &result);
- return result;
- }
-
-
-private:
- bool mActive;
- GLenum mTarget;
- bool mCanQuery;
- GLuint mQuery;
-
-}; // class Query
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_QUERY_H
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 13265a9..1716cf0 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -111,6 +111,10 @@ public:
set(r.left, r.top, r.right, r.bottom);
}
+ inline void set(const SkIRect& r) {
+ set(r.left(), r.top(), r.right(), r.bottom());
+ }
+
inline float getWidth() const {
return right - left;
}
@@ -248,7 +252,15 @@ public:
bottom = fmaxf(bottom, y);
}
- void dump(const char* label = NULL) const {
+ SkRect toSkRect() const {
+ return SkRect::MakeLTRB(left, top, right, bottom);
+ }
+
+ SkIRect toSkIRect() const {
+ return SkIRect::MakeLTRB(left, top, right, bottom);
+ }
+
+ void dump(const char* label = nullptr) const {
ALOGD("%s[l=%f t=%f r=%f b=%f]", label ? label : "Rect", left, top, right, bottom);
}
diff --git a/libs/hwui/RenderBufferCache.cpp b/libs/hwui/RenderBufferCache.cpp
index 830a13a..0380c51 100644
--- a/libs/hwui/RenderBufferCache.cpp
+++ b/libs/hwui/RenderBufferCache.cpp
@@ -42,7 +42,7 @@ namespace uirenderer {
RenderBufferCache::RenderBufferCache(): mSize(0), mMaxSize(MB(DEFAULT_RENDER_BUFFER_CACHE_SIZE)) {
char property[PROPERTY_VALUE_MAX];
- if (property_get(PROPERTY_RENDER_BUFFER_CACHE_SIZE, property, NULL) > 0) {
+ if (property_get(PROPERTY_RENDER_BUFFER_CACHE_SIZE, property, nullptr) > 0) {
INIT_LOGD(" Setting render buffer cache size to %sMB", property);
setMaxSize(MB(atof(property)));
} else {
@@ -108,7 +108,7 @@ void RenderBufferCache::clear() {
}
RenderBuffer* RenderBufferCache::get(GLenum format, const uint32_t width, const uint32_t height) {
- RenderBuffer* buffer = NULL;
+ RenderBuffer* buffer = nullptr;
RenderBufferEntry entry(format, width, height);
ssize_t index = mCache.indexOf(entry);
diff --git a/libs/hwui/RenderBufferCache.h b/libs/hwui/RenderBufferCache.h
index af8060f..6c668b0 100644
--- a/libs/hwui/RenderBufferCache.h
+++ b/libs/hwui/RenderBufferCache.h
@@ -78,11 +78,11 @@ public:
private:
struct RenderBufferEntry {
RenderBufferEntry():
- mBuffer(NULL), mWidth(0), mHeight(0) {
+ mBuffer(nullptr), mWidth(0), mHeight(0) {
}
RenderBufferEntry(GLenum format, const uint32_t width, const uint32_t height):
- mBuffer(NULL), mFormat(format), mWidth(width), mHeight(height) {
+ mBuffer(nullptr), mFormat(format), mWidth(width), mHeight(height) {
}
RenderBufferEntry(RenderBuffer* buffer):
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index c993556..659ef6c 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -29,9 +29,9 @@
#include "DamageAccumulator.h"
#include "Debug.h"
#include "DisplayListOp.h"
-#include "DisplayListLogBuffer.h"
#include "LayerRenderer.h"
#include "OpenGLRenderer.h"
+#include "TreeInfo.h"
#include "utils/MathUtils.h"
#include "utils/TraceUtils.h"
#include "renderthread/CanvasContext.h"
@@ -39,28 +39,6 @@
namespace android {
namespace uirenderer {
-void RenderNode::outputLogBuffer(int fd) {
- DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
- if (logBuffer.isEmpty()) {
- return;
- }
-
- FILE *file = fdopen(fd, "a");
-
- fprintf(file, "\nRecent DisplayList operations\n");
- logBuffer.outputCommands(file);
-
- if (Caches::hasInstance()) {
- String8 cachesLog;
- Caches::getInstance().dumpMemoryUsage(cachesLog);
- fprintf(file, "\nCaches:\n%s\n", cachesLog.string());
- } else {
- fprintf(file, "\nNo caches instance.\n");
- }
-
- fflush(file);
-}
-
void RenderNode::debugDumpLayers(const char* prefix) {
if (mLayer) {
ALOGD("%sNode %p (%s) has layer %p (fbo = %u, wasBuildLayered = %s)",
@@ -77,10 +55,10 @@ void RenderNode::debugDumpLayers(const char* prefix) {
RenderNode::RenderNode()
: mDirtyPropertyFields(0)
, mNeedsDisplayListDataSync(false)
- , mDisplayListData(0)
- , mStagingDisplayListData(0)
+ , mDisplayListData(nullptr)
+ , mStagingDisplayListData(nullptr)
, mAnimatorManager(*this)
- , mLayer(0)
+ , mLayer(nullptr)
, mParentCount(0) {
}
@@ -90,7 +68,7 @@ RenderNode::~RenderNode() {
if (mLayer) {
ALOGW("Memory Warning: Layer %p missed its detachment, held on to for far too long!", mLayer);
mLayer->postDecStrong();
- mLayer = 0;
+ mLayer = nullptr;
}
}
@@ -109,7 +87,7 @@ void RenderNode::output(uint32_t level) {
getName(),
(properties().hasShadow() ? ", casting shadow" : ""),
(isRenderable() ? "" : ", empty"),
- (mLayer != NULL ? ", on HW Layer" : ""));
+ (mLayer != nullptr ? ", on HW Layer" : ""));
ALOGD("%*s%s %d", level * 2, "", "Save",
SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
@@ -181,7 +159,7 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) {
if (CC_LIKELY(layerType != kLayerTypeRenderLayer) || CC_UNLIKELY(!isRenderable())) {
if (CC_UNLIKELY(mLayer)) {
LayerRenderer::destroyLayer(mLayer);
- mLayer = NULL;
+ mLayer = nullptr;
}
return;
}
@@ -195,7 +173,7 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) {
} else if (mLayer->layer.getWidth() != getWidth() || mLayer->layer.getHeight() != getHeight()) {
if (!LayerRenderer::resizeLayer(mLayer, getWidth(), getHeight())) {
LayerRenderer::destroyLayer(mLayer);
- mLayer = 0;
+ mLayer = nullptr;
}
damageSelf(info);
transformUpdateNeeded = true;
@@ -222,7 +200,7 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) {
}
if (dirty.intersect(0, 0, getWidth(), getHeight())) {
- dirty.roundOut();
+ 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
@@ -310,10 +288,10 @@ void RenderNode::pushStagingDisplayListChanges(TreeInfo& info) {
Caches::getInstance().registerFunctors(mStagingDisplayListData->functors.size());
}
mDisplayListData = mStagingDisplayListData;
- mStagingDisplayListData = NULL;
+ mStagingDisplayListData = nullptr;
if (mDisplayListData) {
for (size_t i = 0; i < mDisplayListData->functors.size(); i++) {
- (*mDisplayListData->functors[i])(DrawGlInfo::kModeSync, NULL);
+ (*mDisplayListData->functors[i])(DrawGlInfo::kModeSync, nullptr);
}
}
damageSelf(info);
@@ -330,18 +308,13 @@ void RenderNode::deleteDisplayListData() {
}
}
delete mDisplayListData;
- mDisplayListData = NULL;
+ mDisplayListData = nullptr;
}
void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
if (subtree) {
TextureCache& cache = Caches::getInstance().textureCache;
info.out.hasFunctors |= subtree->functors.size();
- // TODO: Fix ownedBitmapResources to not require disabling prepareTextures
- // and thus falling out of async drawing path.
- if (subtree->ownedBitmapResources.size()) {
- info.prepareTextures = false;
- }
for (size_t i = 0; info.prepareTextures && i < subtree->bitmapResources.size(); i++) {
info.prepareTextures = cache.prefetchAndMarkInUse(subtree->bitmapResources[i]);
}
@@ -358,7 +331,7 @@ void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
void RenderNode::destroyHardwareResources() {
if (mLayer) {
LayerRenderer::destroyLayer(mLayer);
- mLayer = NULL;
+ mLayer = nullptr;
}
if (mDisplayListData) {
for (size_t i = 0; i < mDisplayListData->children().size(); i++) {
@@ -516,7 +489,7 @@ void RenderNode::computeOrdering() {
// TODO: create temporary DDLOp and call computeOrderingImpl on top DisplayList so that
// transform properties are applied correctly to top level children
- if (mDisplayListData == NULL) return;
+ if (mDisplayListData == nullptr) return;
for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) {
DrawRenderNodeOp* childOp = mDisplayListData->children()[i];
childOp->mRenderNode->computeOrderingImpl(childOp,
@@ -530,7 +503,7 @@ void RenderNode::computeOrderingImpl(
Vector<DrawRenderNodeOp*>* compositedChildrenOfProjectionSurface,
const mat4* transformFromProjectionSurface) {
mProjectedNodes.clear();
- if (mDisplayListData == NULL || mDisplayListData->isEmpty()) return;
+ if (mDisplayListData == nullptr || mDisplayListData->isEmpty()) return;
// TODO: should avoid this calculation in most cases
// TODO: just calculate single matrix, down to all leaf composited elements
@@ -554,9 +527,9 @@ void RenderNode::computeOrderingImpl(
DrawRenderNodeOp* childOp = mDisplayListData->children()[i];
RenderNode* child = childOp->mRenderNode;
- const SkPath* projectionOutline = NULL;
- Vector<DrawRenderNodeOp*>* projectionChildren = NULL;
- const mat4* projectionTransform = NULL;
+ const SkPath* projectionOutline = nullptr;
+ Vector<DrawRenderNodeOp*>* projectionChildren = nullptr;
+ const mat4* projectionTransform = nullptr;
if (isProjectionReceiver && !child->properties().getProjectBackwards()) {
// if receiving projections, collect projecting descendent
@@ -682,7 +655,7 @@ void RenderNode::issueDrawShadowOperation(const Matrix4& transformFromParent, T&
// holds temporary SkPath to store the result of intersections
- SkPath* frameAllocatedPath = NULL;
+ SkPath* frameAllocatedPath = nullptr;
const SkPath* outlinePath = casterOutlinePath;
// intersect the outline with the reveal clip, if present
@@ -809,9 +782,9 @@ void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T&
// If the projection reciever has an outline, we mask each of the projected rendernodes to it
// Either with clipRect, or special saveLayer masking
- if (projectionReceiverOutline != NULL) {
+ if (projectionReceiverOutline != nullptr) {
const SkRect& outlineBounds = projectionReceiverOutline->getBounds();
- if (projectionReceiverOutline->isRect(NULL)) {
+ if (projectionReceiverOutline->isRect(nullptr)) {
// mask to the rect outline simply with clipRect
ClipRectOp* clipOp = new (alloc) ClipRectOp(
outlineBounds.left(), outlineBounds.top(),
@@ -846,7 +819,7 @@ void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T&
renderer.restoreToCount(restoreTo);
}
- if (projectionReceiverOutline != NULL) {
+ if (projectionReceiverOutline != nullptr) {
handler(new (alloc) RestoreToCountOp(restoreTo),
PROPERTY_SAVECOUNT, properties().getClipToBounds());
}
@@ -863,13 +836,12 @@ void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T&
*/
template <class T>
void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
- const int level = handler.level();
if (mDisplayListData->isEmpty()) {
DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, getName());
return;
}
- const bool drawLayer = (mLayer && (&renderer != mLayer->renderer));
+ const bool drawLayer = (mLayer && (&renderer != mLayer->renderer.get()));
// 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.
@@ -887,7 +859,7 @@ void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
#if DEBUG_DISPLAY_LIST
const Rect& clipRect = renderer.getLocalClipBounds();
DISPLAY_LIST_LOGD("%*sStart display list (%p, %s), localClipBounds: %.0f, %.0f, %.0f, %.0f",
- level * 2, "", this, getName(),
+ handler.level() * 2, "", this, getName(),
clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
#endif
@@ -914,7 +886,6 @@ void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
} else {
const int saveCountOffset = renderer.getSaveCount() - 1;
const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
- DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
for (size_t chunkIndex = 0; chunkIndex < mDisplayListData->getChunks().size(); chunkIndex++) {
const DisplayListData::Chunk& chunk = mDisplayListData->getChunks()[chunkIndex];
@@ -928,9 +899,8 @@ void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
DisplayListOp *op = mDisplayListData->displayListOps[opIndex];
#if DEBUG_DISPLAY_LIST
- op->output(level + 1);
+ op->output(handler.level() + 1);
#endif
- logBuffer.writeCommand(level, op->name());
handler(op, saveCountOffset, properties().getClipToBounds());
if (CC_UNLIKELY(!mProjectedNodes.isEmpty() && projectionReceiveIndex >= 0 &&
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 2ce7cb7..bbe53ff 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -33,13 +33,10 @@
#include <androidfw/ResourceTypes.h>
#include "AnimatorManager.h"
-#include "DamageAccumulator.h"
#include "Debug.h"
#include "Matrix.h"
-#include "DeferredDisplayList.h"
#include "DisplayList.h"
#include "RenderProperties.h"
-#include "TreeInfo.h"
class SkBitmap;
class SkPaint;
@@ -61,6 +58,7 @@ class SaveLayerOp;
class SaveOp;
class RestoreToCountOp;
class DrawRenderNodeOp;
+class TreeInfo;
/**
* Primary class for storing recorded canvas commands, as well as per-View/ViewGroup display properties.
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index 250cadc..bb6d087 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -35,7 +35,7 @@ namespace uirenderer {
LayerProperties::LayerProperties()
: mType(kLayerTypeNone)
- , mColorFilter(NULL) {
+ , mColorFilter(nullptr) {
reset();
}
@@ -45,7 +45,7 @@ LayerProperties::~LayerProperties() {
void LayerProperties::reset() {
mOpaque = false;
- setFromPaint(NULL);
+ setFromPaint(nullptr);
}
bool LayerProperties::setColorFilter(SkColorFilter* filter) {
@@ -61,7 +61,7 @@ bool LayerProperties::setFromPaint(const SkPaint* paint) {
OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
changed |= setAlpha(static_cast<uint8_t>(alpha));
changed |= setXferMode(mode);
- changed |= setColorFilter(paint ? paint->getColorFilter() : NULL);
+ changed |= setColorFilter(paint ? paint->getColorFilter() : nullptr);
return changed;
}
@@ -92,7 +92,7 @@ RenderProperties::PrimitiveFields::PrimitiveFields()
}
RenderProperties::ComputedFields::ComputedFields()
- : mTransformMatrix(NULL) {
+ : mTransformMatrix(nullptr) {
}
RenderProperties::ComputedFields::~ComputedFields() {
@@ -100,8 +100,8 @@ RenderProperties::ComputedFields::~ComputedFields() {
}
RenderProperties::RenderProperties()
- : mStaticMatrix(NULL)
- , mAnimationMatrix(NULL) {
+ : mStaticMatrix(nullptr)
+ , mAnimationMatrix(nullptr) {
}
RenderProperties::~RenderProperties() {
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 31c4f22..f0e22d6 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -26,8 +26,8 @@
#include <SkCamera.h>
#include <SkMatrix.h>
#include <SkRegion.h>
+#include <SkXfermode.h>
-#include "Animator.h"
#include "Rect.h"
#include "RevealClip.h"
#include "Outline.h"
@@ -188,7 +188,7 @@ public:
if (matrix) {
mStaticMatrix = new SkMatrix(*matrix);
} else {
- mStaticMatrix = NULL;
+ mStaticMatrix = nullptr;
}
return true;
}
@@ -203,7 +203,7 @@ public:
if (matrix) {
mAnimationMatrix = new SkMatrix(*matrix);
} else {
- mAnimationMatrix = NULL;
+ mAnimationMatrix = nullptr;
}
return true;
}
@@ -571,7 +571,7 @@ public:
bool hasShadow() const {
return getZ() > 0.0f
- && getOutline().getPath() != NULL
+ && getOutline().getPath() != nullptr
&& getOutline().getAlpha() != 0.0f;
}
diff --git a/libs/hwui/RenderState.cpp b/libs/hwui/RenderState.cpp
deleted file mode 100644
index ca640e5..0000000
--- a/libs/hwui/RenderState.cpp
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2014 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 "RenderState.h"
-
-#include "renderthread/CanvasContext.h"
-#include "renderthread/EglManager.h"
-
-namespace android {
-namespace uirenderer {
-
-RenderState::RenderState(renderthread::RenderThread& thread)
- : mRenderThread(thread)
- , mCaches(NULL)
- , mViewportWidth(0)
- , mViewportHeight(0)
- , mFramebuffer(0) {
- mThreadId = pthread_self();
-}
-
-RenderState::~RenderState() {
-}
-
-void RenderState::onGLContextCreated() {
- // This is delayed because the first access of Caches makes GL calls
- mCaches = &Caches::getInstance();
- mCaches->init();
- mCaches->setRenderState(this);
- mCaches->textureCache.setAssetAtlas(&mAssetAtlas);
-}
-
-static void layerLostGlContext(Layer* layer) {
- layer->onGlContextLost();
-}
-
-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);
- }
-*/
- std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerLostGlContext);
- mAssetAtlas.terminate();
-}
-
-void RenderState::setViewport(GLsizei width, GLsizei height) {
- mViewportWidth = width;
- mViewportHeight = height;
- glViewport(0, 0, mViewportWidth, mViewportHeight);
-}
-
-
-void RenderState::getViewport(GLsizei* outWidth, GLsizei* outHeight) {
- *outWidth = mViewportWidth;
- *outHeight = mViewportHeight;
-}
-
-void RenderState::bindFramebuffer(GLuint fbo) {
- if (mFramebuffer != fbo) {
- mFramebuffer = fbo;
- glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
- }
-}
-
-void RenderState::invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlInfo* info) {
- interruptForFunctorInvoke();
- (*functor)(mode, info);
- resumeFromFunctorInvoke();
-}
-
-void RenderState::interruptForFunctorInvoke() {
- if (mCaches->currentProgram) {
- if (mCaches->currentProgram->isInUse()) {
- mCaches->currentProgram->remove();
- mCaches->currentProgram = NULL;
- }
- }
- mCaches->resetActiveTexture();
- mCaches->unbindMeshBuffer();
- mCaches->unbindIndicesBuffer();
- mCaches->resetVertexPointers();
- mCaches->disableTexCoordsVertexArray();
- debugOverdraw(false, false);
-}
-
-void RenderState::resumeFromFunctorInvoke() {
- glViewport(0, 0, mViewportWidth, mViewportHeight);
- glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
- debugOverdraw(false, false);
-
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-
- mCaches->scissorEnabled = glIsEnabled(GL_SCISSOR_TEST);
- mCaches->enableScissor();
- mCaches->resetScissor();
-
- mCaches->activeTexture(0);
- mCaches->resetBoundTextures();
-
- mCaches->blend = true;
- glEnable(GL_BLEND);
- glBlendFunc(mCaches->lastSrcMode, mCaches->lastDstMode);
- glBlendEquation(GL_FUNC_ADD);
-}
-
-void RenderState::debugOverdraw(bool enable, bool clear) {
- if (mCaches->debugOverdraw && mFramebuffer == 0) {
- if (clear) {
- mCaches->disableScissor();
- mCaches->stencil.clear();
- }
- if (enable) {
- mCaches->stencil.enableDebugWrite();
- } else {
- mCaches->stencil.disable();
- }
- }
-}
-
-void RenderState::requireGLContext() {
- assertOnGLThread();
- mRenderThread.eglManager().requireGlContext();
-}
-
-void RenderState::assertOnGLThread() {
- pthread_t curr = pthread_self();
- LOG_ALWAYS_FATAL_IF(!pthread_equal(mThreadId, curr), "Wrong thread!");
-}
-
-
-class DecStrongTask : public renderthread::RenderTask {
-public:
- DecStrongTask(VirtualLightRefBase* object) : mObject(object) {}
-
- virtual void run() {
- mObject->decStrong(0);
- mObject = 0;
- delete this;
- }
-
-private:
- VirtualLightRefBase* mObject;
-};
-
-void RenderState::postDecStrong(VirtualLightRefBase* object) {
- mRenderThread.queue(new DecStrongTask(object));
-}
-
-} /* namespace uirenderer */
-} /* namespace android */
diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h
index 3159d1e..48d83b9 100644
--- a/libs/hwui/Renderer.h
+++ b/libs/hwui/Renderer.h
@@ -20,11 +20,12 @@
#include <SkColorFilter.h>
#include <SkPaint.h>
#include <SkRegion.h>
-
#include <utils/String8.h>
#include "AssetAtlas.h"
+class SkDrawFilter;
+
namespace android {
class Functor;
@@ -56,40 +57,6 @@ class ANDROID_API Renderer {
public:
virtual ~Renderer() {}
- /**
- * Safely retrieves the mode from the specified xfermode. If the specified
- * xfermode is null, the mode is assumed to be SkXfermode::kSrcOver_Mode.
- */
- static inline SkXfermode::Mode getXfermode(SkXfermode* mode) {
- SkXfermode::Mode resultMode;
- if (!SkXfermode::AsMode(mode, &resultMode)) {
- resultMode = SkXfermode::kSrcOver_Mode;
- }
- return resultMode;
- }
-
- // TODO: move to a method on android:Paint
- static inline bool paintWillNotDraw(const SkPaint& paint) {
- return paint.getAlpha() == 0
- && !paint.getColorFilter()
- && getXfermode(paint.getXfermode()) == SkXfermode::kSrcOver_Mode;
- }
-
- // TODO: move to a method on android:Paint
- static inline bool paintWillNotDrawText(const SkPaint& paint) {
- return paint.getAlpha() == 0
- && paint.getLooper() == NULL
- && !paint.getColorFilter()
- && getXfermode(paint.getXfermode()) == SkXfermode::kSrcOver_Mode;
- }
-
- static bool isBlendedColorFilter(const SkColorFilter* filter) {
- if (filter == NULL) {
- return false;
- }
- return (filter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag) == 0;
- }
-
// ----------------------------------------------------------------------------
// Frame state operations
// ----------------------------------------------------------------------------
@@ -111,7 +78,7 @@ public:
* and will not be cleared. If false, the target surface
* will be cleared
*/
- virtual status_t prepare(bool opaque) = 0;
+ virtual void prepare(bool opaque) = 0;
/**
* Prepares the renderer to draw a frame. This method must be invoked
@@ -127,14 +94,16 @@ public:
* and will not be cleared. If false, the target surface
* will be cleared in the specified dirty rectangle
*/
- virtual status_t prepareDirty(float left, float top, float right, float bottom,
+ virtual void prepareDirty(float left, float top, float right, float bottom,
bool opaque) = 0;
/**
* 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 void finish() = 0;
+ virtual bool finish() = 0;
// ----------------------------------------------------------------------------
// Canvas state operations
@@ -173,58 +142,56 @@ public:
virtual bool clipPath(const SkPath* path, SkRegion::Op op) = 0;
virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) = 0;
- // Misc - should be implemented with SkPaint inspection
- virtual void resetPaintFilter() = 0;
- virtual void setupPaintFilter(int clearBits, int setBits) = 0;
+ // Misc
+ virtual void setDrawFilter(SkDrawFilter* filter) = 0;
// ----------------------------------------------------------------------------
// Canvas draw operations
// ----------------------------------------------------------------------------
- virtual status_t drawColor(int color, SkXfermode::Mode mode) = 0;
+ virtual void drawColor(int color, SkXfermode::Mode mode) = 0;
// Bitmap-based
- virtual status_t drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) = 0;
- virtual status_t drawBitmap(const SkBitmap* bitmap, float srcLeft, float srcTop,
+ virtual void drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) = 0;
+ 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) = 0;
- virtual status_t drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint) = 0;
- virtual status_t drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
+ virtual void drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
const float* vertices, const int* colors, const SkPaint* paint) = 0;
- virtual status_t drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
+ virtual void drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
float left, float top, float right, float bottom, const SkPaint* paint) = 0;
// Shapes
- virtual status_t drawRect(float left, float top, float right, float bottom,
+ virtual void drawRect(float left, float top, float right, float bottom,
const SkPaint* paint) = 0;
- virtual status_t drawRects(const float* rects, int count, const SkPaint* paint) = 0;
- virtual status_t drawRoundRect(float left, float top, float right, float bottom,
+ virtual void drawRects(const float* rects, int count, const SkPaint* paint) = 0;
+ virtual void drawRoundRect(float left, float top, float right, float bottom,
float rx, float ry, const SkPaint* paint) = 0;
- virtual status_t drawCircle(float x, float y, float radius, const SkPaint* paint) = 0;
- virtual status_t drawOval(float left, float top, float right, float bottom,
+ virtual void drawCircle(float x, float y, float radius, const SkPaint* paint) = 0;
+ virtual void drawOval(float left, float top, float right, float bottom,
const SkPaint* paint) = 0;
- virtual status_t drawArc(float left, float top, float right, float bottom,
+ virtual void drawArc(float left, float top, float right, float bottom,
float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint) = 0;
- virtual status_t drawPath(const SkPath* path, const SkPaint* paint) = 0;
- virtual status_t drawLines(const float* points, int count, const SkPaint* paint) = 0;
- virtual status_t drawPoints(const float* points, int count, const SkPaint* paint) = 0;
+ virtual void drawPath(const SkPath* path, const SkPaint* paint) = 0;
+ virtual void drawLines(const float* points, int count, const SkPaint* paint) = 0;
+ virtual void drawPoints(const float* points, int count, const SkPaint* paint) = 0;
// Text
- virtual status_t drawText(const char* text, int bytesCount, int count, float x, float y,
+ virtual void drawText(const char* text, int bytesCount, int count, float x, float y,
const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
DrawOpMode drawOpMode = kDrawOpMode_Immediate) = 0;
- virtual status_t drawTextOnPath(const char* text, int bytesCount, int count, const SkPath* path,
+ virtual void drawTextOnPath(const char* text, int bytesCount, int count, const SkPath* path,
float hOffset, float vOffset, const SkPaint* paint) = 0;
- virtual status_t drawPosText(const char* text, int bytesCount, int count,
+ virtual void drawPosText(const char* text, int bytesCount, int count,
const float* positions, const SkPaint* paint) = 0;
// ----------------------------------------------------------------------------
// Canvas draw operations - special
// ----------------------------------------------------------------------------
- virtual status_t drawRenderNode(RenderNode* renderNode, Rect& dirty,
+ virtual void drawRenderNode(RenderNode* renderNode, Rect& dirty,
int32_t replayFlags) = 0;
// TODO: rename for consistency
- virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty) = 0;
+ virtual void callDrawGLFunction(Functor* functor, Rect& dirty) = 0;
}; // class Renderer
}; // namespace uirenderer
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
index 31bd637..2d1adc5 100644
--- a/libs/hwui/ResourceCache.cpp
+++ b/libs/hwui/ResourceCache.cpp
@@ -16,16 +16,13 @@
#define LOG_TAG "OpenGLRenderer"
-#include <SkPixelRef.h>
#include "ResourceCache.h"
#include "Caches.h"
namespace android {
-#ifdef USE_OPENGL_RENDERER
using namespace uirenderer;
ANDROID_SINGLETON_STATIC_INSTANCE(ResourceCache);
-#endif
namespace uirenderer {
@@ -39,8 +36,8 @@ void ResourceCache::logCache() {
ResourceReference* ref = mCache->valueAt(i);
ALOGD(" ResourceCache: mCache(%zu): resource, ref = 0x%p, 0x%p",
i, mCache->keyAt(i), mCache->valueAt(i));
- ALOGD(" ResourceCache: mCache(%zu): refCount, recycled, destroyed, type = %d, %d, %d, %d",
- i, ref->refCount, ref->recycled, ref->destroyed, ref->resourceType);
+ ALOGD(" ResourceCache: mCache(%zu): refCount, destroyed, type = %d, %d, %d",
+ i, ref->refCount, ref->destroyed, ref->resourceType);
}
}
@@ -62,13 +59,24 @@ void ResourceCache::unlock() {
mLock.unlock();
}
-void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) {
+const SkBitmap* ResourceCache::insert(const SkBitmap* bitmapResource) {
Mutex::Autolock _l(mLock);
- incrementRefcountLocked(resource, resourceType);
+
+ BitmapKey bitmapKey(bitmapResource);
+ ssize_t index = mBitmapCache.indexOfKey(bitmapKey);
+ if (index == NAME_NOT_FOUND) {
+ SkBitmap* cachedBitmap = new SkBitmap(*bitmapResource);
+ index = mBitmapCache.add(bitmapKey, cachedBitmap);
+ return cachedBitmap;
+ }
+
+ mBitmapCache.keyAt(index).mRefCount++;
+ return mBitmapCache.valueAt(index);
}
-void ResourceCache::incrementRefcount(const SkBitmap* bitmapResource) {
- incrementRefcount((void*) bitmapResource, kBitmap);
+void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) {
+ Mutex::Autolock _l(mLock);
+ incrementRefcountLocked(resource, resourceType);
}
void ResourceCache::incrementRefcount(const SkPath* pathResource) {
@@ -81,33 +89,22 @@ void ResourceCache::incrementRefcount(const Res_png_9patch* patchResource) {
void ResourceCache::incrementRefcountLocked(void* resource, ResourceType resourceType) {
ssize_t index = mCache->indexOfKey(resource);
- ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
- if (ref == NULL || mCache->size() == 0) {
+ ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : nullptr;
+ if (ref == nullptr || mCache->size() == 0) {
ref = new ResourceReference(resourceType);
mCache->add(resource, ref);
}
ref->refCount++;
}
-void ResourceCache::incrementRefcountLocked(const SkBitmap* bitmapResource) {
- incrementRefcountLocked((void*) bitmapResource, kBitmap);
-}
-
-void ResourceCache::incrementRefcountLocked(const SkPath* pathResource) {
- incrementRefcountLocked((void*) pathResource, kPath);
-}
-
-void ResourceCache::incrementRefcountLocked(const Res_png_9patch* patchResource) {
- incrementRefcountLocked((void*) patchResource, kNinePatch);
-}
-
void ResourceCache::decrementRefcount(void* resource) {
Mutex::Autolock _l(mLock);
decrementRefcountLocked(resource);
}
void ResourceCache::decrementRefcount(const SkBitmap* bitmapResource) {
- decrementRefcount((void*) bitmapResource);
+ Mutex::Autolock _l(mLock);
+ decrementRefcountLocked(bitmapResource);
}
void ResourceCache::decrementRefcount(const SkPath* pathResource) {
@@ -120,8 +117,8 @@ void ResourceCache::decrementRefcount(const Res_png_9patch* patchResource) {
void ResourceCache::decrementRefcountLocked(void* resource) {
ssize_t index = mCache->indexOfKey(resource);
- ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
- if (ref == NULL) {
+ ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : nullptr;
+ if (ref == nullptr) {
// Should not get here - shouldn't get a call to decrement if we're not yet tracking it
return;
}
@@ -132,7 +129,20 @@ void ResourceCache::decrementRefcountLocked(void* resource) {
}
void ResourceCache::decrementRefcountLocked(const SkBitmap* bitmapResource) {
- decrementRefcountLocked((void*) bitmapResource);
+ BitmapKey bitmapKey(bitmapResource);
+ ssize_t index = mBitmapCache.indexOfKey(bitmapKey);
+
+ LOG_ALWAYS_FATAL_IF(index == NAME_NOT_FOUND,
+ "Decrementing the reference of an untracked Bitmap");
+
+ const BitmapKey& cacheEntry = mBitmapCache.keyAt(index);
+ if (cacheEntry.mRefCount == 1) {
+ // delete the bitmap and remove it from the cache
+ delete mBitmapCache.valueAt(index);
+ mBitmapCache.removeItemsAt(index);
+ } else {
+ cacheEntry.mRefCount--;
+ }
}
void ResourceCache::decrementRefcountLocked(const SkPath* pathResource) {
@@ -150,8 +160,8 @@ void ResourceCache::destructor(SkPath* resource) {
void ResourceCache::destructorLocked(SkPath* resource) {
ssize_t index = mCache->indexOfKey(resource);
- ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
- if (ref == NULL) {
+ ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : nullptr;
+ if (ref == nullptr) {
// If we're not tracking this resource, just delete it
if (Caches::hasInstance()) {
Caches::getInstance().pathCache.removeDeferred(resource);
@@ -166,28 +176,6 @@ void ResourceCache::destructorLocked(SkPath* resource) {
}
}
-void ResourceCache::destructor(const SkBitmap* resource) {
- Mutex::Autolock _l(mLock);
- destructorLocked(resource);
-}
-
-void ResourceCache::destructorLocked(const SkBitmap* resource) {
- ssize_t index = mCache->indexOfKey(resource);
- ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
- if (ref == NULL) {
- // If we're not tracking this resource, just delete it
- if (Caches::hasInstance()) {
- Caches::getInstance().textureCache.releaseTexture(resource);
- }
- delete resource;
- return;
- }
- ref->destroyed = true;
- if (ref->refCount == 0) {
- deleteResourceReferenceLocked(resource, ref);
- }
-}
-
void ResourceCache::destructor(Res_png_9patch* resource) {
Mutex::Autolock _l(mLock);
destructorLocked(resource);
@@ -195,8 +183,8 @@ void ResourceCache::destructor(Res_png_9patch* resource) {
void ResourceCache::destructorLocked(Res_png_9patch* resource) {
ssize_t index = mCache->indexOfKey(resource);
- ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
- if (ref == NULL) {
+ ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : nullptr;
+ if (ref == nullptr) {
// If we're not tracking this resource, just delete it
if (Caches::hasInstance()) {
Caches::getInstance().patchCache.removeDeferred(resource);
@@ -214,64 +202,12 @@ void ResourceCache::destructorLocked(Res_png_9patch* resource) {
}
/**
- * Return value indicates whether resource was actually recycled, which happens when RefCnt
- * reaches 0.
- */
-bool ResourceCache::recycle(SkBitmap* resource) {
- Mutex::Autolock _l(mLock);
- return recycleLocked(resource);
-}
-
-/**
- * Return value indicates whether resource was actually recycled, which happens when RefCnt
- * reaches 0.
- */
-bool ResourceCache::recycleLocked(SkBitmap* resource) {
- ssize_t index = mCache->indexOfKey(resource);
- if (index < 0) {
- if (Caches::hasInstance()) {
- Caches::getInstance().textureCache.releaseTexture(resource);
- }
- // not tracking this resource; just recycle the pixel data
- resource->setPixels(NULL, NULL);
- return true;
- }
- ResourceReference* ref = mCache->valueAt(index);
- if (ref == NULL) {
- // Should not get here - shouldn't get a call to recycle if we're not yet tracking it
- return true;
- }
- ref->recycled = true;
- if (ref->refCount == 0) {
- deleteResourceReferenceLocked(resource, ref);
- return true;
- }
- // Still referring to resource, don't recycle yet
- return false;
-}
-
-/**
* This method should only be called while the mLock mutex is held (that mutex is grabbed
* by the various destructor() and recycle() methods which call this method).
*/
void ResourceCache::deleteResourceReferenceLocked(const void* resource, ResourceReference* ref) {
- if (ref->recycled && ref->resourceType == kBitmap) {
- SkBitmap* bitmap = (SkBitmap*) resource;
- if (Caches::hasInstance()) {
- Caches::getInstance().textureCache.releaseTexture(bitmap);
- }
- bitmap->setPixels(NULL, NULL);
- }
if (ref->destroyed) {
switch (ref->resourceType) {
- case kBitmap: {
- SkBitmap* bitmap = (SkBitmap*) resource;
- if (Caches::hasInstance()) {
- Caches::getInstance().textureCache.releaseTexture(bitmap);
- }
- delete bitmap;
- }
- break;
case kPath: {
SkPath* path = (SkPath*) resource;
if (Caches::hasInstance()) {
@@ -298,5 +234,38 @@ void ResourceCache::deleteResourceReferenceLocked(const void* resource, Resource
delete ref;
}
+///////////////////////////////////////////////////////////////////////////////
+// Bitmap Key
+///////////////////////////////////////////////////////////////////////////////
+
+void BitmapKey::operator=(const BitmapKey& other) {
+ this->mRefCount = other.mRefCount;
+ this->mBitmapDimensions = other.mBitmapDimensions;
+ this->mPixelRefOrigin = other.mPixelRefOrigin;
+ this->mPixelRefStableID = other.mPixelRefStableID;
+}
+
+bool BitmapKey::operator==(const BitmapKey& other) const {
+ return mPixelRefStableID == other.mPixelRefStableID &&
+ mPixelRefOrigin == other.mPixelRefOrigin &&
+ mBitmapDimensions == other.mBitmapDimensions;
+}
+
+bool BitmapKey::operator<(const BitmapKey& other) const {
+ if (mPixelRefStableID != other.mPixelRefStableID) {
+ return mPixelRefStableID < other.mPixelRefStableID;
+ }
+ if (mPixelRefOrigin.x() != other.mPixelRefOrigin.x()) {
+ return mPixelRefOrigin.x() < other.mPixelRefOrigin.x();
+ }
+ if (mPixelRefOrigin.y() != other.mPixelRefOrigin.y()) {
+ return mPixelRefOrigin.y() < other.mPixelRefOrigin.y();
+ }
+ if (mBitmapDimensions.width() != other.mBitmapDimensions.width()) {
+ return mBitmapDimensions.width() < other.mBitmapDimensions.width();
+ }
+ return mBitmapDimensions.height() < other.mBitmapDimensions.height();
+}
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
index f12f2a4..4333792 100644
--- a/libs/hwui/ResourceCache.h
+++ b/libs/hwui/ResourceCache.h
@@ -20,22 +20,23 @@
#include <cutils/compiler.h>
#include <SkBitmap.h>
+#include <SkPath.h>
+#include <SkPixelRef.h>
#include <utils/KeyedVector.h>
#include <utils/Singleton.h>
#include <androidfw/ResourceTypes.h>
-#include "Layer.h"
-
namespace android {
namespace uirenderer {
+class Layer;
+
/**
* Type of Resource being cached
*/
enum ResourceType {
- kBitmap,
kNinePatch,
kPath
};
@@ -44,15 +45,45 @@ class ResourceReference {
public:
ResourceReference(ResourceType type) {
- refCount = 0; recycled = false; destroyed = false; resourceType = type;
+ refCount = 0; destroyed = false; resourceType = type;
}
int refCount;
- bool recycled;
bool destroyed;
ResourceType resourceType;
};
+class BitmapKey {
+public:
+ BitmapKey(const SkBitmap* bitmap)
+ : mRefCount(1)
+ , mBitmapDimensions(bitmap->dimensions())
+ , mPixelRefOrigin(bitmap->pixelRefOrigin())
+ , mPixelRefStableID(bitmap->pixelRef()->getStableID()) { }
+
+ void operator=(const BitmapKey& other);
+ bool operator==(const BitmapKey& other) const;
+ bool operator<(const BitmapKey& other) const;
+
+private:
+ // This constructor is only used by the KeyedVector implementation
+ BitmapKey()
+ : mRefCount(-1)
+ , mBitmapDimensions(SkISize::Make(0,0))
+ , mPixelRefOrigin(SkIPoint::Make(0,0))
+ , mPixelRefStableID(0) { }
+
+ // reference count of all HWUI object using this bitmap
+ mutable int mRefCount;
+
+ SkISize mBitmapDimensions;
+ SkIPoint mPixelRefOrigin;
+ uint32_t mPixelRefStableID;
+
+ friend class ResourceCache;
+ friend struct android::key_value_pair_t<BitmapKey, SkBitmap*>;
+};
+
class ANDROID_API ResourceCache: public Singleton<ResourceCache> {
ResourceCache();
~ResourceCache();
@@ -68,14 +99,15 @@ public:
void lock();
void unlock();
+ /**
+ * The cache stores a copy of the provided resource or refs an existing resource
+ * if the bitmap has previously been inserted and returns the cached copy.
+ */
+ const SkBitmap* insert(const SkBitmap* resource);
+
void incrementRefcount(const SkPath* resource);
- void incrementRefcount(const SkBitmap* resource);
void incrementRefcount(const Res_png_9patch* resource);
- void incrementRefcountLocked(const SkPath* resource);
- void incrementRefcountLocked(const SkBitmap* resource);
- void incrementRefcountLocked(const Res_png_9patch* resource);
-
void decrementRefcount(const SkBitmap* resource);
void decrementRefcount(const SkPath* resource);
void decrementRefcount(const Res_png_9patch* resource);
@@ -85,16 +117,11 @@ public:
void decrementRefcountLocked(const Res_png_9patch* resource);
void destructor(SkPath* resource);
- void destructor(const SkBitmap* resource);
void destructor(Res_png_9patch* resource);
void destructorLocked(SkPath* resource);
- void destructorLocked(const SkBitmap* resource);
void destructorLocked(Res_png_9patch* resource);
- bool recycle(SkBitmap* resource);
- bool recycleLocked(SkBitmap* resource);
-
private:
void deleteResourceReferenceLocked(const void* resource, ResourceReference* ref);
@@ -114,6 +141,7 @@ private:
mutable Mutex mLock;
KeyedVector<const void*, ResourceReference*>* mCache;
+ KeyedVector<BitmapKey, SkBitmap*> mBitmapCache;
};
}; // namespace uirenderer
diff --git a/libs/hwui/RevealClip.h b/libs/hwui/RevealClip.h
index a9600f1..0084a8e 100644
--- a/libs/hwui/RevealClip.h
+++ b/libs/hwui/RevealClip.h
@@ -54,7 +54,7 @@ public:
float getRadius() const { return mRadius; }
const SkPath* getPath() const {
- if (!mShouldClip) return NULL;
+ if (!mShouldClip) return nullptr;
return &mPath;
}
diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp
index 93d4b31..ca7f48d 100644
--- a/libs/hwui/ShadowTessellator.cpp
+++ b/libs/hwui/ShadowTessellator.cpp
@@ -113,33 +113,6 @@ void ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque,
#endif
}
-void ShadowTessellator::generateShadowIndices(uint16_t* shadowIndices) {
- int currentIndex = 0;
- const int rays = SHADOW_RAY_COUNT;
- // For the penumbra area.
- for (int layer = 0; layer < 2; layer ++) {
- int baseIndex = layer * rays;
- for (int i = 0; i < rays; i++) {
- shadowIndices[currentIndex++] = i + baseIndex;
- shadowIndices[currentIndex++] = rays + i + baseIndex;
- }
- // To close the loop, back to the ray 0.
- shadowIndices[currentIndex++] = 0 + baseIndex;
- // Note this is the same as the first index of next layer loop.
- shadowIndices[currentIndex++] = rays + baseIndex;
- }
-
-#if DEBUG_SHADOW
- if (currentIndex != MAX_SHADOW_INDEX_COUNT) {
- ALOGW("vertex index count is wrong. current %d, expected %d",
- currentIndex, MAX_SHADOW_INDEX_COUNT);
- }
- for (int i = 0; i < MAX_SHADOW_INDEX_COUNT; i++) {
- ALOGD("vertex index is (%d, %d)", i, shadowIndices[i]);
- }
-#endif
-}
-
/**
* Calculate the centroid of a 2d polygon.
*
@@ -193,7 +166,7 @@ Vector2 ShadowTessellator::calculateNormal(const Vector2& p1, const Vector2& p2)
* @param len the number of points of the polygon
*/
bool ShadowTessellator::isClockwise(const Vector2* polygon, int len) {
- if (len < 2 || polygon == NULL) {
+ if (len < 2 || polygon == nullptr) {
return true;
}
double sum = 0;
diff --git a/libs/hwui/ShadowTessellator.h b/libs/hwui/ShadowTessellator.h
index 8f19b5c..c04d8ef 100644
--- a/libs/hwui/ShadowTessellator.h
+++ b/libs/hwui/ShadowTessellator.h
@@ -18,14 +18,16 @@
#ifndef ANDROID_HWUI_SHADOW_TESSELLATOR_H
#define ANDROID_HWUI_SHADOW_TESSELLATOR_H
+#include <SkPath.h>
+
#include "Debug.h"
#include "Matrix.h"
-#include "OpenGLRenderer.h"
-#include "VertexBuffer.h"
namespace android {
namespace uirenderer {
+class VertexBuffer;
+
// All SHADOW_* are used to define all the geometry property of shadows.
// Use a simplified example to illustrate the geometry setup here.
// Assuming we use 6 rays and only 1 layer, Then we will have 2 hexagons, which
@@ -76,8 +78,6 @@ public:
const mat4& receiverTransform, const Vector3& lightCenter, int lightRadius,
const Rect& casterBounds, const Rect& localClip, VertexBuffer& shadowVertexBuffer);
- static void generateShadowIndices(uint16_t* shadowIndices);
-
static Vector2 centroid2d(const Vector2* poly, int polyLength);
static bool isClockwise(const Vector2* polygon, int len);
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
new file mode 100644
index 0000000..efbb709
--- /dev/null
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -0,0 +1,716 @@
+/*
+ * Copyright (C) 2014 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 "Canvas.h"
+
+#include <SkCanvas.h>
+#include <SkClipStack.h>
+#include <SkDevice.h>
+#include <SkDeque.h>
+#include <SkDrawFilter.h>
+#include <SkGraphics.h>
+#include <SkPorterDuff.h>
+#include <SkShader.h>
+#include <SkTArray.h>
+#include <SkTemplates.h>
+
+namespace android {
+
+// Holds an SkCanvas reference plus additional native data.
+class SkiaCanvas : public Canvas {
+public:
+ explicit SkiaCanvas(SkBitmap* bitmap);
+
+ /**
+ * Create a new SkiaCanvas.
+ *
+ * @param canvas SkCanvas to handle calls made to this SkiaCanvas. Must
+ * not be NULL. This constructor will ref() the SkCanvas, and unref()
+ * it in its destructor.
+ */
+ explicit SkiaCanvas(SkCanvas* canvas) : mCanvas(canvas) {
+ SkASSERT(canvas);
+ canvas->ref();
+ }
+
+ virtual SkCanvas* asSkCanvas() override {
+ return mCanvas.get();
+ }
+
+ virtual void setBitmap(SkBitmap* bitmap, bool copyState) override;
+
+ virtual bool isOpaque() override;
+ virtual int width() override;
+ virtual int height() override;
+
+ virtual int getSaveCount() const override;
+ virtual int save(SkCanvas::SaveFlags 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, SkCanvas::SaveFlags flags) override;
+ virtual int saveLayerAlpha(float left, float top, float right, float bottom,
+ int alpha, SkCanvas::SaveFlags flags) override;
+
+ virtual void getMatrix(SkMatrix* outMatrix) const override;
+ 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;
+
+ 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;
+
+ virtual SkDrawFilter* getDrawFilter() override;
+ virtual void setDrawFilter(SkDrawFilter* drawFilter) override;
+
+ virtual void drawColor(int color, SkXfermode::Mode mode) override;
+ virtual void drawPaint(const SkPaint& paint) override;
+
+ virtual void drawPoint(float x, float y, const SkPaint& paint) override;
+ 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;
+ 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 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;
+
+ 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 drawText(const uint16_t* text, 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 drawPosText(const uint16_t* text, const float* positions, int count,
+ int posCount, const SkPaint& paint) override;
+ virtual void drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
+ float hOffset, float vOffset, const SkPaint& paint) override;
+
+ virtual bool drawTextAbsolutePos() const override { return true; }
+
+private:
+ struct SaveRec {
+ int saveCount;
+ SkCanvas::SaveFlags saveFlags;
+ };
+
+ void recordPartialSave(SkCanvas::SaveFlags flags);
+ void saveClipsForFrame(SkTArray<SkClipStack::Element>& clips, int frameSaveCount);
+ void applyClips(const SkTArray<SkClipStack::Element>& clips);
+
+ void drawPoints(const float* points, int count, const SkPaint& paint,
+ SkCanvas::PointMode mode);
+ void drawTextDecorations(float x, float y, float length, const SkPaint& paint);
+
+ SkAutoTUnref<SkCanvas> mCanvas;
+ SkAutoTDelete<SkDeque> mSaveStack; // lazily allocated, tracks partial saves.
+};
+
+// Construct an SkCanvas from the bitmap.
+static SkCanvas* createCanvas(SkBitmap* bitmap) {
+ if (bitmap) {
+ return SkNEW_ARGS(SkCanvas, (*bitmap));
+ }
+
+ // Create an empty bitmap device to prevent callers from crashing
+ // if they attempt to draw into this canvas.
+ SkBitmap emptyBitmap;
+ return new SkCanvas(emptyBitmap);
+}
+
+Canvas* Canvas::create_canvas(SkBitmap* bitmap) {
+ return new SkiaCanvas(bitmap);
+}
+
+Canvas* Canvas::create_canvas(SkCanvas* skiaCanvas) {
+ return new SkiaCanvas(skiaCanvas);
+}
+
+SkiaCanvas::SkiaCanvas(SkBitmap* bitmap) {
+ mCanvas.reset(createCanvas(bitmap));
+}
+
+// ----------------------------------------------------------------------------
+// Canvas state operations: Replace Bitmap
+// ----------------------------------------------------------------------------
+
+class ClipCopier : public SkCanvas::ClipVisitor {
+public:
+ ClipCopier(SkCanvas* dstCanvas) : m_dstCanvas(dstCanvas) {}
+
+ virtual void clipRect(const SkRect& rect, SkRegion::Op op, bool antialias) {
+ m_dstCanvas->clipRect(rect, op, antialias);
+ }
+ virtual void clipRRect(const SkRRect& rrect, SkRegion::Op op, bool antialias) {
+ m_dstCanvas->clipRRect(rrect, op, antialias);
+ }
+ virtual void clipPath(const SkPath& path, SkRegion::Op op, bool antialias) {
+ m_dstCanvas->clipPath(path, op, antialias);
+ }
+
+private:
+ SkCanvas* m_dstCanvas;
+};
+
+void SkiaCanvas::setBitmap(SkBitmap* bitmap, bool copyState) {
+ SkCanvas* newCanvas = createCanvas(bitmap);
+ SkASSERT(newCanvas);
+
+ if (copyState) {
+ // Copy the canvas matrix & clip state.
+ newCanvas->setMatrix(mCanvas->getTotalMatrix());
+ if (NULL != mCanvas->getDevice() && NULL != newCanvas->getDevice()) {
+ ClipCopier copier(newCanvas);
+ mCanvas->replayClips(&copier);
+ }
+ }
+
+ // unrefs the existing canvas
+ mCanvas.reset(newCanvas);
+
+ // clean up the old save stack
+ mSaveStack.reset(NULL);
+}
+
+// ----------------------------------------------------------------------------
+// Canvas state operations
+// ----------------------------------------------------------------------------
+
+bool SkiaCanvas::isOpaque() {
+ return mCanvas->getDevice()->accessBitmap(false).isOpaque();
+}
+
+int SkiaCanvas::width() {
+ return mCanvas->getBaseLayerSize().width();
+}
+
+int SkiaCanvas::height() {
+ return mCanvas->getBaseLayerSize().height();
+}
+
+// ----------------------------------------------------------------------------
+// Canvas state operations: Save (layer)
+// ----------------------------------------------------------------------------
+
+int SkiaCanvas::getSaveCount() const {
+ return mCanvas->getSaveCount();
+}
+
+int SkiaCanvas::save(SkCanvas::SaveFlags flags) {
+ int count = mCanvas->save();
+ recordPartialSave(flags);
+ return count;
+}
+
+void SkiaCanvas::restore() {
+ const SaveRec* rec = (NULL == mSaveStack.get())
+ ? NULL
+ : static_cast<SaveRec*>(mSaveStack->back());
+ int currentSaveCount = mCanvas->getSaveCount() - 1;
+ SkASSERT(NULL == rec || currentSaveCount >= rec->saveCount);
+
+ if (NULL == rec || rec->saveCount != currentSaveCount) {
+ // Fast path - no record for this frame.
+ mCanvas->restore();
+ return;
+ }
+
+ bool preserveMatrix = !(rec->saveFlags & SkCanvas::kMatrix_SaveFlag);
+ bool preserveClip = !(rec->saveFlags & SkCanvas::kClip_SaveFlag);
+
+ SkMatrix savedMatrix;
+ if (preserveMatrix) {
+ savedMatrix = mCanvas->getTotalMatrix();
+ }
+
+ SkTArray<SkClipStack::Element> savedClips;
+ if (preserveClip) {
+ saveClipsForFrame(savedClips, currentSaveCount);
+ }
+
+ mCanvas->restore();
+
+ if (preserveMatrix) {
+ mCanvas->setMatrix(savedMatrix);
+ }
+
+ if (preserveClip && !savedClips.empty()) {
+ applyClips(savedClips);
+ }
+
+ mSaveStack->pop_back();
+}
+
+void SkiaCanvas::restoreToCount(int restoreCount) {
+ while (mCanvas->getSaveCount() > restoreCount) {
+ this->restore();
+ }
+}
+
+int SkiaCanvas::saveLayer(float left, float top, float right, float bottom,
+ const SkPaint* paint, SkCanvas::SaveFlags flags) {
+ SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
+ int count = mCanvas->saveLayer(&bounds, paint, flags | SkCanvas::kMatrixClip_SaveFlag);
+ recordPartialSave(flags);
+ return count;
+}
+
+int SkiaCanvas::saveLayerAlpha(float left, float top, float right, float bottom,
+ int alpha, SkCanvas::SaveFlags flags) {
+ SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
+ int count = mCanvas->saveLayerAlpha(&bounds, alpha, flags | SkCanvas::kMatrixClip_SaveFlag);
+ recordPartialSave(flags);
+ return count;
+}
+
+// ----------------------------------------------------------------------------
+// functions to emulate legacy SaveFlags (i.e. independent matrix/clip flags)
+// ----------------------------------------------------------------------------
+
+void SkiaCanvas::recordPartialSave(SkCanvas::SaveFlags flags) {
+ // A partial save is a save operation which doesn't capture the full canvas state.
+ // (either kMatrix_SaveFlags or kClip_SaveFlag is missing).
+
+ // Mask-out non canvas state bits.
+ flags = static_cast<SkCanvas::SaveFlags>(flags & SkCanvas::kMatrixClip_SaveFlag);
+
+ if (SkCanvas::kMatrixClip_SaveFlag == flags) {
+ // not a partial save.
+ return;
+ }
+
+ if (NULL == mSaveStack.get()) {
+ mSaveStack.reset(SkNEW_ARGS(SkDeque, (sizeof(struct SaveRec), 8)));
+ }
+
+ SaveRec* rec = static_cast<SaveRec*>(mSaveStack->push_back());
+ // Store the save counter in the SkClipStack domain.
+ // (0-based, equal to the number of save ops on the stack).
+ rec->saveCount = mCanvas->getSaveCount() - 1;
+ rec->saveFlags = flags;
+}
+
+void SkiaCanvas::saveClipsForFrame(SkTArray<SkClipStack::Element>& clips, int frameSaveCount) {
+ SkClipStack::Iter clipIterator(*mCanvas->getClipStack(),
+ SkClipStack::Iter::kTop_IterStart);
+ while (const SkClipStack::Element* elem = clipIterator.next()) {
+ if (elem->getSaveCount() < frameSaveCount) {
+ // done with the current frame.
+ break;
+ }
+ SkASSERT(elem->getSaveCount() == frameSaveCount);
+ clips.push_back(*elem);
+ }
+}
+
+void SkiaCanvas::applyClips(const SkTArray<SkClipStack::Element>& clips) {
+ ClipCopier clipCopier(mCanvas);
+
+ // The clip stack stores clips in device space.
+ SkMatrix origMatrix = mCanvas->getTotalMatrix();
+ mCanvas->resetMatrix();
+
+ // We pushed the clips in reverse order.
+ for (int i = clips.count() - 1; i >= 0; --i) {
+ clips[i].replay(&clipCopier);
+ }
+
+ mCanvas->setMatrix(origMatrix);
+}
+
+// ----------------------------------------------------------------------------
+// Canvas state operations: Matrix
+// ----------------------------------------------------------------------------
+
+void SkiaCanvas::getMatrix(SkMatrix* outMatrix) const {
+ *outMatrix = mCanvas->getTotalMatrix();
+}
+
+void SkiaCanvas::setMatrix(const SkMatrix& matrix) {
+ mCanvas->setMatrix(matrix);
+}
+
+void SkiaCanvas::concat(const SkMatrix& matrix) {
+ mCanvas->concat(matrix);
+}
+
+void SkiaCanvas::rotate(float degrees) {
+ mCanvas->rotate(degrees);
+}
+
+void SkiaCanvas::scale(float sx, float sy) {
+ mCanvas->scale(sx, sy);
+}
+
+void SkiaCanvas::skew(float sx, float sy) {
+ mCanvas->skew(sx, sy);
+}
+
+void SkiaCanvas::translate(float dx, float dy) {
+ mCanvas->translate(dx, dy);
+}
+
+// ----------------------------------------------------------------------------
+// Canvas state operations: Clips
+// ----------------------------------------------------------------------------
+
+// This function is a mirror of SkCanvas::getClipBounds except that it does
+// not outset the edge of the clip to account for anti-aliasing. There is
+// a skia bug to investigate pushing this logic into back into skia.
+// (see https://code.google.com/p/skia/issues/detail?id=1303)
+bool SkiaCanvas::getClipBounds(SkRect* outRect) const {
+ SkIRect ibounds;
+ if (!mCanvas->getClipDeviceBounds(&ibounds)) {
+ return false;
+ }
+
+ SkMatrix inverse;
+ // if we can't invert the CTM, we can't return local clip bounds
+ if (!mCanvas->getTotalMatrix().invert(&inverse)) {
+ if (outRect) {
+ outRect->setEmpty();
+ }
+ return false;
+ }
+
+ if (NULL != outRect) {
+ SkRect r = SkRect::Make(ibounds);
+ inverse.mapRect(outRect, r);
+ }
+ return true;
+}
+
+bool SkiaCanvas::quickRejectRect(float left, float top, float right, float bottom) const {
+ SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
+ return mCanvas->quickReject(bounds);
+}
+
+bool SkiaCanvas::quickRejectPath(const SkPath& path) const {
+ return mCanvas->quickReject(path);
+}
+
+bool SkiaCanvas::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
+ SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
+ mCanvas->clipRect(rect, op);
+ return mCanvas->isClipEmpty();
+}
+
+bool SkiaCanvas::clipPath(const SkPath* path, SkRegion::Op op) {
+ mCanvas->clipPath(*path, op);
+ return mCanvas->isClipEmpty();
+}
+
+bool SkiaCanvas::clipRegion(const SkRegion* region, SkRegion::Op op) {
+ SkPath rgnPath;
+ if (region->getBoundaryPath(&rgnPath)) {
+ // The region is specified in device space.
+ SkMatrix savedMatrix = mCanvas->getTotalMatrix();
+ mCanvas->resetMatrix();
+ mCanvas->clipPath(rgnPath, op);
+ mCanvas->setMatrix(savedMatrix);
+ } else {
+ mCanvas->clipRect(SkRect::MakeEmpty(), op);
+ }
+ return mCanvas->isClipEmpty();
+}
+
+// ----------------------------------------------------------------------------
+// Canvas state operations: Filters
+// ----------------------------------------------------------------------------
+
+SkDrawFilter* SkiaCanvas::getDrawFilter() {
+ return mCanvas->getDrawFilter();
+}
+
+void SkiaCanvas::setDrawFilter(SkDrawFilter* drawFilter) {
+ mCanvas->setDrawFilter(drawFilter);
+}
+
+// ----------------------------------------------------------------------------
+// Canvas draw operations
+// ----------------------------------------------------------------------------
+
+void SkiaCanvas::drawColor(int color, SkXfermode::Mode mode) {
+ mCanvas->drawColor(color, mode);
+}
+
+void SkiaCanvas::drawPaint(const SkPaint& paint) {
+ mCanvas->drawPaint(paint);
+}
+
+// ----------------------------------------------------------------------------
+// Canvas draw operations: Geometry
+// ----------------------------------------------------------------------------
+
+void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint,
+ SkCanvas::PointMode mode) {
+ // convert the floats into SkPoints
+ count >>= 1; // now it is the number of points
+ SkAutoSTMalloc<32, SkPoint> storage(count);
+ SkPoint* pts = storage.get();
+ for (int i = 0; i < count; i++) {
+ pts[i].set(points[0], points[1]);
+ points += 2;
+ }
+ mCanvas->drawPoints(mode, count, pts, paint);
+}
+
+
+void SkiaCanvas::drawPoint(float x, float y, const SkPaint& paint) {
+ mCanvas->drawPoint(x, y, paint);
+}
+
+void SkiaCanvas::drawPoints(const float* points, int count, const SkPaint& paint) {
+ this->drawPoints(points, count, paint, SkCanvas::kPoints_PointMode);
+}
+
+void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY,
+ const SkPaint& paint) {
+ mCanvas->drawLine(startX, startY, stopX, stopY, paint);
+}
+
+void SkiaCanvas::drawLines(const float* points, int count, const SkPaint& paint) {
+ this->drawPoints(points, count, paint, SkCanvas::kLines_PointMode);
+}
+
+void SkiaCanvas::drawRect(float left, float top, float right, float bottom,
+ const SkPaint& paint) {
+ mCanvas->drawRectCoords(left, top, right, bottom, paint);
+
+}
+
+void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom,
+ float rx, float ry, const SkPaint& paint) {
+ SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
+ mCanvas->drawRoundRect(rect, rx, ry, paint);
+}
+
+void SkiaCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) {
+ mCanvas->drawCircle(x, y, radius, paint);
+}
+
+void SkiaCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) {
+ SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
+ mCanvas->drawOval(oval, paint);
+}
+
+void SkiaCanvas::drawArc(float left, float top, float right, float bottom,
+ float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
+ SkRect arc = SkRect::MakeLTRB(left, top, right, bottom);
+ mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, paint);
+}
+
+void SkiaCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
+ mCanvas->drawPath(path, paint);
+}
+
+void SkiaCanvas::drawVertices(SkCanvas::VertexMode vertexMode, int vertexCount,
+ const float* verts, const float* texs, const int* colors,
+ const uint16_t* indices, int indexCount, const SkPaint& paint) {
+#ifndef SK_SCALAR_IS_FLOAT
+ SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid");
+#endif
+ const int ptCount = vertexCount >> 1;
+ mCanvas->drawVertices(vertexMode, ptCount, (SkPoint*)verts, (SkPoint*)texs,
+ (SkColor*)colors, NULL, indices, indexCount, paint);
+}
+
+// ----------------------------------------------------------------------------
+// Canvas draw operations: Bitmaps
+// ----------------------------------------------------------------------------
+
+void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, float left, float top, const SkPaint* paint) {
+ mCanvas->drawBitmap(bitmap, left, top, paint);
+}
+
+void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) {
+ SkAutoCanvasRestore acr(mCanvas, true);
+ mCanvas->concat(matrix);
+ mCanvas->drawBitmap(bitmap, 0, 0, paint);
+}
+
+void SkiaCanvas::drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop,
+ float srcRight, float srcBottom, float dstLeft, float dstTop,
+ float dstRight, float dstBottom, const SkPaint* paint) {
+ SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
+ SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
+ mCanvas->drawBitmapRectToRect(bitmap, &srcRect, dstRect, paint);
+}
+
+void SkiaCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
+ const float* vertices, const int* colors, const SkPaint* paint) {
+
+ const int ptCount = (meshWidth + 1) * (meshHeight + 1);
+ const int indexCount = meshWidth * meshHeight * 6;
+
+ /* Our temp storage holds 2 or 3 arrays.
+ texture points [ptCount * sizeof(SkPoint)]
+ optionally vertex points [ptCount * sizeof(SkPoint)] if we need a
+ copy to convert from float to fixed
+ indices [ptCount * sizeof(uint16_t)]
+ */
+ ssize_t storageSize = ptCount * sizeof(SkPoint); // texs[]
+ storageSize += indexCount * sizeof(uint16_t); // indices[]
+
+
+#ifndef SK_SCALAR_IS_FLOAT
+ SkDEBUGFAIL("SkScalar must be a float for these conversions to be valid");
+#endif
+ SkAutoMalloc storage(storageSize);
+ SkPoint* texs = (SkPoint*)storage.get();
+ uint16_t* indices = (uint16_t*)(texs + ptCount);
+
+ // cons up texture coordinates and indices
+ {
+ const SkScalar w = SkIntToScalar(bitmap.width());
+ const SkScalar h = SkIntToScalar(bitmap.height());
+ const SkScalar dx = w / meshWidth;
+ const SkScalar dy = h / meshHeight;
+
+ SkPoint* texsPtr = texs;
+ SkScalar y = 0;
+ for (int i = 0; i <= meshHeight; i++) {
+ if (i == meshHeight) {
+ y = h; // to ensure numerically we hit h exactly
+ }
+ SkScalar x = 0;
+ for (int j = 0; j < meshWidth; j++) {
+ texsPtr->set(x, y);
+ texsPtr += 1;
+ x += dx;
+ }
+ texsPtr->set(w, y);
+ texsPtr += 1;
+ y += dy;
+ }
+ SkASSERT(texsPtr - texs == ptCount);
+ }
+
+ // cons up indices
+ {
+ uint16_t* indexPtr = indices;
+ int index = 0;
+ for (int i = 0; i < meshHeight; i++) {
+ for (int j = 0; j < meshWidth; j++) {
+ // lower-left triangle
+ *indexPtr++ = index;
+ *indexPtr++ = index + meshWidth + 1;
+ *indexPtr++ = index + meshWidth + 2;
+ // upper-right triangle
+ *indexPtr++ = index;
+ *indexPtr++ = index + meshWidth + 2;
+ *indexPtr++ = index + 1;
+ // bump to the next cell
+ index += 1;
+ }
+ // bump to the next row
+ index += 1;
+ }
+ SkASSERT(indexPtr - indices == indexCount);
+ SkASSERT((char*)indexPtr - (char*)storage.get() == storageSize);
+ }
+
+ // double-check that we have legal indices
+#ifdef SK_DEBUG
+ {
+ for (int i = 0; i < indexCount; i++) {
+ SkASSERT((unsigned)indices[i] < (unsigned)ptCount);
+ }
+ }
+#endif
+
+ // cons-up a shader for the bitmap
+ SkPaint tmpPaint;
+ if (paint) {
+ tmpPaint = *paint;
+ }
+ SkShader* shader = SkShader::CreateBitmapShader(bitmap,
+ SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode);
+ SkSafeUnref(tmpPaint.setShader(shader));
+
+ mCanvas->drawVertices(SkCanvas::kTriangles_VertexMode, ptCount, (SkPoint*)vertices,
+ texs, (const SkColor*)colors, NULL, indices,
+ indexCount, tmpPaint);
+}
+
+// ----------------------------------------------------------------------------
+// Canvas draw operations: Text
+// ----------------------------------------------------------------------------
+
+void SkiaCanvas::drawText(const uint16_t* text, const float* positions, int count,
+ const SkPaint& paint, float x, float y,
+ float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
+ float totalAdvance) {
+ // Set align to left for drawing, as we don't want individual
+ // glyphs centered or right-aligned; the offset above takes
+ // care of all alignment.
+ SkPaint paintCopy(paint);
+ paintCopy.setTextAlign(SkPaint::kLeft_Align);
+
+ SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
+ mCanvas->drawPosText(text, count << 1, reinterpret_cast<const SkPoint*>(positions), paintCopy);
+}
+
+void SkiaCanvas::drawPosText(const uint16_t* text, const float* positions, int count, int posCount,
+ const SkPaint& paint) {
+ SkPoint* posPtr = posCount > 0 ? new SkPoint[posCount] : NULL;
+ int indx;
+ for (indx = 0; indx < posCount; indx++) {
+ posPtr[indx].fX = positions[indx << 1];
+ posPtr[indx].fY = positions[(indx << 1) + 1];
+ }
+
+ SkPaint paintCopy(paint);
+ paintCopy.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+ mCanvas->drawPosText(text, count, posPtr, paintCopy);
+
+ delete[] posPtr;
+}
+
+void SkiaCanvas::drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
+ float hOffset, float vOffset, const SkPaint& paint) {
+ mCanvas->drawTextOnPathHV(glyphs, count, path, hOffset, vOffset, paint);
+}
+
+} // namespace android
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
new file mode 100644
index 0000000..de5f91c
--- /dev/null
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2015 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 "SkiaCanvasProxy.h"
+
+#include <cutils/log.h>
+#include <SkPatchUtils.h>
+
+namespace android {
+namespace uirenderer {
+
+SkiaCanvasProxy::SkiaCanvasProxy(Canvas* canvas)
+ : INHERITED(canvas->width(), canvas->height())
+ , mCanvas(canvas) {}
+
+void SkiaCanvasProxy::onDrawPaint(const SkPaint& paint) {
+ mCanvas->drawPaint(paint);
+}
+
+void SkiaCanvasProxy::onDrawPoints(PointMode pointMode, size_t count, const SkPoint pts[],
+ const SkPaint& paint) {
+ // convert the SkPoints into floats
+ SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
+ const size_t floatCount = count << 1;
+ const float* floatArray = &pts[0].fX;
+
+ switch (pointMode) {
+ case kPoints_PointMode: {
+ mCanvas->drawPoints(floatArray, floatCount, paint);
+ break;
+ }
+ case kLines_PointMode: {
+ mCanvas->drawLines(floatArray, floatCount, paint);
+ break;
+ }
+ case kPolygon_PointMode: {
+ SkPaint strokedPaint(paint);
+ strokedPaint.setStyle(SkPaint::kStroke_Style);
+
+ SkPath path;
+ for (size_t i = 0; i < count - 1; i++) {
+ path.moveTo(pts[i]);
+ path.lineTo(pts[i+1]);
+ this->drawPath(path, strokedPaint);
+ path.rewind();
+ }
+ break;
+ }
+ default:
+ LOG_ALWAYS_FATAL("Unknown point type");
+ }
+}
+
+void SkiaCanvasProxy::onDrawOval(const SkRect& rect, const SkPaint& paint) {
+ mCanvas->drawOval(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, paint);
+}
+
+void SkiaCanvasProxy::onDrawRect(const SkRect& rect, const SkPaint& paint) {
+ mCanvas->drawRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, paint);
+}
+
+void SkiaCanvasProxy::onDrawRRect(const SkRRect& roundRect, const SkPaint& paint) {
+ if (!roundRect.isComplex()) {
+ const SkRect& rect = roundRect.rect();
+ SkVector radii = roundRect.getSimpleRadii();
+ mCanvas->drawRoundRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
+ radii.fX, radii.fY, paint);
+ } else {
+ SkPath path;
+ path.addRRect(roundRect);
+ mCanvas->drawPath(path, paint);
+ }
+}
+
+void SkiaCanvasProxy::onDrawPath(const SkPath& path, const SkPaint& paint) {
+ mCanvas->drawPath(path, paint);
+}
+
+void SkiaCanvasProxy::onDrawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
+ const SkPaint* paint) {
+ mCanvas->drawBitmap(bitmap, left, top, paint);
+}
+
+void SkiaCanvasProxy::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* srcPtr,
+ const SkRect& dst, const SkPaint* paint, DrawBitmapRectFlags) {
+ SkRect src = (srcPtr) ? *srcPtr : SkRect::MakeWH(bitmap.width(), bitmap.height());
+ mCanvas->drawBitmap(bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom,
+ dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, paint);
+}
+
+void SkiaCanvasProxy::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
+ const SkRect& dst, const SkPaint*) {
+ //TODO make nine-patch drawing a method on Canvas.h
+ SkDEBUGFAIL("SkiaCanvasProxy::onDrawBitmapNine is not yet supported");
+}
+
+void SkiaCanvasProxy::onDrawSprite(const SkBitmap& bitmap, int left, int top,
+ const SkPaint* paint) {
+ mCanvas->save(SkCanvas::kMatrixClip_SaveFlag);
+ mCanvas->setMatrix(SkMatrix::I());
+ mCanvas->drawBitmap(bitmap, left, top, paint);
+ mCanvas->restore();
+}
+
+void SkiaCanvasProxy::onDrawVertices(VertexMode mode, int vertexCount, const SkPoint vertices[],
+ const SkPoint texs[], const SkColor colors[], SkXfermode*, const uint16_t indices[],
+ int indexCount, const SkPaint& paint) {
+ // convert the SkPoints into floats
+ SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
+ const int floatCount = vertexCount << 1;
+ const float* vArray = &vertices[0].fX;
+ const float* tArray = (texs) ? &texs[0].fX : NULL;
+ const int* cArray = (colors) ? (int*)colors : NULL;
+ mCanvas->drawVertices(mode, floatCount, vArray, tArray, cArray, indices, indexCount, paint);
+}
+
+SkSurface* SkiaCanvasProxy::onNewSurface(const SkImageInfo&, const SkSurfaceProps&) {
+ SkDEBUGFAIL("SkiaCanvasProxy::onNewSurface is not supported");
+ return NULL;
+}
+
+void SkiaCanvasProxy::willSave() {
+ mCanvas->save(SkCanvas::kMatrixClip_SaveFlag);
+}
+
+SkCanvas::SaveLayerStrategy SkiaCanvasProxy::willSaveLayer(const SkRect* rectPtr,
+ const SkPaint* paint, SaveFlags flags) {
+ SkRect rect;
+ if (rectPtr) {
+ rect = *rectPtr;
+ } else if(!mCanvas->getClipBounds(&rect)) {
+ rect = SkRect::MakeEmpty();
+ }
+ mCanvas->saveLayer(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, paint, flags);
+ return SkCanvas::kNoLayer_SaveLayerStrategy;
+}
+
+void SkiaCanvasProxy::willRestore() {
+ mCanvas->restore();
+}
+
+void SkiaCanvasProxy::didConcat(const SkMatrix& matrix) {
+ mCanvas->concat(matrix);
+}
+
+void SkiaCanvasProxy::didSetMatrix(const SkMatrix& matrix) {
+ mCanvas->setMatrix(matrix);
+}
+
+void SkiaCanvasProxy::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
+ const SkPaint& paint) {
+ SkPath path;
+ path.addRRect(outer);
+ path.addRRect(inner);
+ path.setFillType(SkPath::kEvenOdd_FillType);
+ this->drawPath(path, paint);
+}
+
+/**
+ * Utility class that converts the incoming text & paint from the given encoding
+ * into glyphIDs.
+ */
+class GlyphIDConverter {
+public:
+ GlyphIDConverter(const void* text, size_t byteLength, const SkPaint& origPaint) {
+ paint = origPaint;
+ if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) {
+ glyphIDs = (uint16_t*)text;
+ count = byteLength >> 1;
+ } else {
+ storage.reset(byteLength); // ensures space for one glyph per ID given UTF8 encoding.
+ glyphIDs = storage.get();
+ count = paint.textToGlyphs(text, byteLength, storage.get());
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ }
+ }
+
+ SkPaint paint;
+ uint16_t* glyphIDs;
+ int count;
+private:
+ SkAutoSTMalloc<32, uint16_t> storage;
+};
+
+void SkiaCanvasProxy::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
+ const SkPaint& origPaint) {
+ // convert to glyphIDs if necessary
+ GlyphIDConverter glyphs(text, byteLength, origPaint);
+
+ // compute the glyph positions
+ SkAutoSTMalloc<32, SkPoint> pointStorage(glyphs.count);
+ SkAutoSTMalloc<32, SkScalar> glyphWidths(glyphs.count);
+ glyphs.paint.getTextWidths(glyphs.glyphIDs, glyphs.count << 1, glyphWidths.get());
+
+ // compute conservative bounds
+ // NOTE: We could call the faster paint.getFontBounds for a less accurate,
+ // but even more conservative bounds if this is too slow.
+ SkRect bounds;
+ glyphs.paint.measureText(glyphs.glyphIDs, glyphs.count << 1, &bounds);
+
+ // adjust for non-left alignment
+ if (glyphs.paint.getTextAlign() != SkPaint::kLeft_Align) {
+ SkScalar stop = 0;
+ for (int i = 0; i < glyphs.count; i++) {
+ stop += glyphWidths[i];
+ }
+ if (glyphs.paint.getTextAlign() == SkPaint::kCenter_Align) {
+ stop = SkScalarHalf(stop);
+ }
+ if (glyphs.paint.isVerticalText()) {
+ y -= stop;
+ } else {
+ x -= stop;
+ }
+ }
+
+ // setup the first glyph position and adjust bounds if needed
+ if (mCanvas->drawTextAbsolutePos()) {
+ bounds.offset(x,y);
+ pointStorage[0].set(x, y);
+ } else {
+ pointStorage[0].set(0, 0);
+ }
+
+ // setup the remaining glyph positions
+ if (glyphs.paint.isVerticalText()) {
+ for (int i = 1; i < glyphs.count; i++) {
+ pointStorage[i].set(x, glyphWidths[i-1] + pointStorage[i-1].fY);
+ }
+ } else {
+ for (int i = 1; i < glyphs.count; i++) {
+ pointStorage[i].set(glyphWidths[i-1] + pointStorage[i-1].fX, y);
+ }
+ }
+
+ SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
+ mCanvas->drawText(glyphs.glyphIDs, &pointStorage[0].fX, glyphs.count, glyphs.paint,
+ x, y, bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, 0);
+}
+
+void SkiaCanvasProxy::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
+ const SkPaint& origPaint) {
+ // convert to glyphIDs if necessary
+ GlyphIDConverter glyphs(text, byteLength, origPaint);
+
+ // convert to relative positions if necessary
+ int x, y;
+ const SkPoint* posArray;
+ SkAutoSTMalloc<32, SkPoint> pointStorage;
+ if (mCanvas->drawTextAbsolutePos()) {
+ x = 0;
+ y = 0;
+ posArray = pos;
+ } else {
+ x = pos[0].fX;
+ y = pos[0].fY;
+ posArray = pointStorage.reset(glyphs.count);
+ for (int i = 0; i < glyphs.count; i++) {
+ pointStorage[i].fX = pos[i].fX- x;
+ pointStorage[i].fY = pos[i].fY- y;
+ }
+ }
+
+ // compute conservative bounds
+ // NOTE: We could call the faster paint.getFontBounds for a less accurate,
+ // but even more conservative bounds if this is too slow.
+ SkRect bounds;
+ glyphs.paint.measureText(glyphs.glyphIDs, glyphs.count << 1, &bounds);
+
+ SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(float)*2, SkPoint_is_no_longer_2_floats);
+ mCanvas->drawText(glyphs.glyphIDs, &posArray[0].fX, glyphs.count, glyphs.paint, x, y,
+ bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, 0);
+}
+
+void SkiaCanvasProxy::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
+ SkScalar constY, const SkPaint& paint) {
+ const size_t pointCount = byteLength >> 1;
+ SkAutoSTMalloc<32, SkPoint> storage(pointCount);
+ SkPoint* pts = storage.get();
+ for (size_t i = 0; i < pointCount; i++) {
+ pts[i].set(xpos[i], constY);
+ }
+ this->onDrawPosText(text, byteLength, pts, paint);
+}
+
+void SkiaCanvasProxy::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
+ const SkMatrix* matrix, const SkPaint& origPaint) {
+ // convert to glyphIDs if necessary
+ GlyphIDConverter glyphs(text, byteLength, origPaint);
+ mCanvas->drawTextOnPath(glyphs.glyphIDs, glyphs.count, path, 0, 0, glyphs.paint);
+}
+
+void SkiaCanvasProxy::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
+ const SkPaint& paint) {
+ SkDEBUGFAIL("SkiaCanvasProxy::onDrawTextBlob is not supported");
+}
+
+void SkiaCanvasProxy::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
+ SkPatchUtils::VertexData data;
+
+ SkMatrix matrix;
+ mCanvas->getMatrix(&matrix);
+ SkISize lod = SkPatchUtils::GetLevelOfDetail(cubics, &matrix);
+
+ // It automatically adjusts lodX and lodY in case it exceeds the number of indices.
+ // If it fails to generate the vertices, then we do not draw.
+ if (SkPatchUtils::getVertexData(&data, cubics, colors, texCoords, lod.width(), lod.height())) {
+ this->drawVertices(SkCanvas::kTriangles_VertexMode, data.fVertexCount, data.fPoints,
+ data.fTexCoords, data.fColors, xmode, data.fIndices, data.fIndexCount,
+ paint);
+ }
+}
+
+void SkiaCanvasProxy::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle) {
+ mCanvas->clipRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, op);
+}
+
+void SkiaCanvasProxy::onClipRRect(const SkRRect& roundRect, SkRegion::Op op, ClipEdgeStyle) {
+ SkPath path;
+ path.addRRect(roundRect);
+ mCanvas->clipPath(&path, op);
+}
+
+void SkiaCanvasProxy::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle) {
+ mCanvas->clipPath(&path, op);
+}
+
+void SkiaCanvasProxy::onClipRegion(const SkRegion& region, SkRegion::Op op) {
+ mCanvas->clipRegion(&region, op);
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/SkiaCanvasProxy.h b/libs/hwui/SkiaCanvasProxy.h
new file mode 100644
index 0000000..4322fcf
--- /dev/null
+++ b/libs/hwui/SkiaCanvasProxy.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2015 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 SkiaCanvasProxy_DEFINED
+#define SkiaCanvasProxy_DEFINED
+
+#include <cutils/compiler.h>
+#include <SkCanvas.h>
+
+#include "Canvas.h"
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * This class serves as a proxy between Skia's SkCanvas and Android Framework's
+ * Canvas. The class does not maintain any state and will pass through any request
+ * directly to the Canvas provided in the constructor.
+ *
+ * Upon construction it is expected that the provided Canvas has already been
+ * prepared for recording and will continue to be in the recording state while
+ * this proxy class is being used.
+ */
+class ANDROID_API SkiaCanvasProxy : public SkCanvas {
+public:
+ SkiaCanvasProxy(Canvas* canvas);
+ virtual ~SkiaCanvasProxy() {}
+
+protected:
+
+ virtual SkSurface* onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override;
+
+ virtual void willSave() override;
+ virtual SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) override;
+ virtual void willRestore() override;
+
+ virtual void didConcat(const SkMatrix&) override;
+ virtual void didSetMatrix(const SkMatrix&) override;
+
+ virtual void onDrawPaint(const SkPaint& paint) override;
+ virtual void onDrawPoints(PointMode, size_t count, const SkPoint pts[],
+ const SkPaint&) override;
+ virtual void onDrawOval(const SkRect&, const SkPaint&) override;
+ virtual void onDrawRect(const SkRect&, const SkPaint&) override;
+ virtual void onDrawRRect(const SkRRect&, const SkPaint&) override;
+ virtual void onDrawPath(const SkPath& path, const SkPaint&) override;
+ virtual void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
+ const SkPaint*) override;
+ virtual void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst,
+ const SkPaint* paint, DrawBitmapRectFlags flags) override;
+ virtual void onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
+ const SkRect& dst, const SkPaint*) override;
+ virtual void onDrawSprite(const SkBitmap&, int left, int top,
+ const SkPaint*) override;
+ virtual void onDrawVertices(VertexMode, int vertexCount, const SkPoint vertices[],
+ const SkPoint texs[], const SkColor colors[], SkXfermode*,
+ const uint16_t indices[], int indexCount,
+ const SkPaint&) override;
+
+ virtual void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override;
+
+ virtual void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
+ const SkPaint&) override;
+ virtual void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
+ const SkPaint&) override;
+ virtual void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
+ SkScalar constY, const SkPaint&) override;
+ virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
+ const SkMatrix* matrix, const SkPaint&) override;
+ virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
+ const SkPaint& paint) override;
+
+ virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4], SkXfermode* xmode,
+ const SkPaint& paint) override;
+
+ virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override;
+ virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override;
+ virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) override;
+ virtual void onClipRegion(const SkRegion&, SkRegion::Op) override;
+
+private:
+ Canvas* mCanvas;
+
+ typedef SkCanvas INHERITED;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // SkiaCanvasProxy_DEFINED
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index c672bc4..9c929da 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -21,6 +21,7 @@
#include <SkMatrix.h>
#include "Caches.h"
+#include "Extensions.h"
#include "Layer.h"
#include "Matrix.h"
#include "SkiaShader.h"
@@ -56,7 +57,7 @@ static inline void bindUniformColor(int slot, uint32_t color) {
}
static inline void bindTexture(Caches* caches, Texture* texture, GLenum wrapS, GLenum wrapT) {
- caches->bindTexture(texture->id);
+ caches->textureState().bindTexture(texture->id);
texture->setWrapST(wrapS, wrapT);
}
@@ -86,7 +87,7 @@ static bool bitmapAndGradient(SkiaShaderType type1, SkiaShaderType type2) {
SkiaShaderType SkiaShader::getType(const SkShader& shader) {
// First check for a gradient shader.
- switch (shader.asAGradient(NULL)) {
+ switch (shader.asAGradient(nullptr)) {
case SkShader::kNone_GradientType:
// Not a gradient shader. Fall through to check for other types.
break;
@@ -100,7 +101,7 @@ SkiaShaderType SkiaShader::getType(const SkShader& shader) {
}
// The shader is not a gradient. Check for a bitmap shader.
- if (shader.asABitmap(NULL, NULL, NULL) == SkShader::kDefault_BitmapType) {
+ if (shader.asABitmap(nullptr, nullptr, nullptr) == SkShader::kDefault_BitmapType) {
return kBitmap_SkiaShaderType;
}
@@ -118,7 +119,7 @@ SkiaShaderType SkiaShader::getType(const SkShader& shader) {
return kCompose_SkiaShaderType;
}
- if (shader.asACustomShader(NULL)) {
+ if (shader.asACustomShader(nullptr)) {
return kLayer_SkiaShaderType;
}
@@ -175,7 +176,7 @@ void SkiaLayerShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
}
GLuint textureSlot = (*textureUnit)++;
- caches->activeTexture(textureSlot);
+ caches->textureState().activateTexture(textureSlot);
const float width = layer->getWidth();
const float height = layer->getHeight();
@@ -190,11 +191,11 @@ void SkiaLayerShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
layer->setWrap(GL_CLAMP_TO_EDGE);
layer->setFilter(GL_LINEAR);
- Program* program = caches->currentProgram;
- glUniform1i(program->getUniform("bitmapSampler"), textureSlot);
- glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
+ Program& program = caches->program();
+ glUniform1i(program.getUniform("bitmapSampler"), textureSlot);
+ glUniformMatrix4fv(program.getUniform("textureTransform"), 1,
GL_FALSE, &textureTransform.data[0]);
- glUniform2f(program->getUniform("textureDimension"), 1.0f / width, 1.0f / height);
+ glUniform2f(program.getUniform("textureDimension"), 1.0f / width, 1.0f / height);
}
///////////////////////////////////////////////////////////////////////////////
@@ -254,29 +255,29 @@ void SkiaBitmapShader::describe(Caches* caches, ProgramDescription& description,
const Extensions& extensions, const SkShader& shader) {
SkBitmap bitmap;
SkShader::TileMode xy[2];
- if (shader.asABitmap(&bitmap, NULL, xy) != SkShader::kDefault_BitmapType) {
+ if (shader.asABitmap(&bitmap, nullptr, xy) != SkShader::kDefault_BitmapType) {
LOG_ALWAYS_FATAL("SkiaBitmapShader::describe called with a different kind of shader!");
}
- bitmapShaderHelper(caches, &description, NULL, extensions, bitmap, xy);
+ bitmapShaderHelper(caches, &description, nullptr, extensions, bitmap, xy);
}
void SkiaBitmapShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) {
SkBitmap bitmap;
SkShader::TileMode xy[2];
- if (shader.asABitmap(&bitmap, NULL, xy) != SkShader::kDefault_BitmapType) {
+ if (shader.asABitmap(&bitmap, nullptr, xy) != SkShader::kDefault_BitmapType) {
LOG_ALWAYS_FATAL("SkiaBitmapShader::setupProgram called with a different kind of shader!");
}
GLuint textureSlot = (*textureUnit)++;
- Caches::getInstance().activeTexture(textureSlot);
+ Caches::getInstance().textureState().activateTexture(textureSlot);
BitmapShaderInfo shaderInfo;
- if (!bitmapShaderHelper(caches, NULL, &shaderInfo, extensions, bitmap, xy)) {
+ if (!bitmapShaderHelper(caches, nullptr, &shaderInfo, extensions, bitmap, xy)) {
return;
}
- Program* program = caches->currentProgram;
+ Program& program = caches->program();
Texture* texture = shaderInfo.texture;
const AutoTexture autoCleanup(texture);
@@ -289,10 +290,10 @@ void SkiaBitmapShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
bindTexture(caches, texture, shaderInfo.wrapS, shaderInfo.wrapT);
texture->setFilter(GL_LINEAR);
- glUniform1i(program->getUniform("bitmapSampler"), textureSlot);
- glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
+ glUniform1i(program.getUniform("bitmapSampler"), textureSlot);
+ glUniformMatrix4fv(program.getUniform("textureTransform"), 1,
GL_FALSE, &textureTransform.data[0]);
- glUniform2f(program->getUniform("textureDimension"), 1.0f / shaderInfo.width,
+ glUniform2f(program.getUniform("textureDimension"), 1.0f / shaderInfo.width,
1.0f / shaderInfo.height);
}
@@ -342,8 +343,8 @@ void SkiaGradientShader::describe(Caches*, ProgramDescription& description,
const Extensions& extensions, const SkShader& shader) {
SkShader::GradientInfo gradInfo;
gradInfo.fColorCount = 0;
- gradInfo.fColors = NULL;
- gradInfo.fColorOffsets = NULL;
+ gradInfo.fColors = nullptr;
+ gradInfo.fColorOffsets = nullptr;
switch (shader.asAGradient(&gradInfo)) {
case SkShader::kLinear_GradientType:
@@ -380,7 +381,7 @@ void SkiaGradientShader::setupProgram(Caches* caches, const mat4& modelViewMatri
SkShader::GradientType gradType = shader.asAGradient(&gradInfo);
- Program* program = caches->currentProgram;
+ Program& program = caches->program();
if (CC_UNLIKELY(!isSimpleGradient(gradInfo))) {
if (gradInfo.fColorCount > COLOR_COUNT) {
// There was not enough room in our arrays for all the colors and offsets. Try again,
@@ -391,7 +392,7 @@ void SkiaGradientShader::setupProgram(Caches* caches, const mat4& modelViewMatri
shader.asAGradient(&gradInfo);
}
GLuint textureSlot = (*textureUnit)++;
- caches->activeTexture(textureSlot);
+ caches->textureState().activateTexture(textureSlot);
#ifndef SK_SCALAR_IS_FLOAT
#error Need to convert gradInfo.fColorOffsets to float!
@@ -401,10 +402,10 @@ void SkiaGradientShader::setupProgram(Caches* caches, const mat4& modelViewMatri
// Uniforms
bindTexture(caches, texture, gTileModes[gradInfo.fTileMode], gTileModes[gradInfo.fTileMode]);
- glUniform1i(program->getUniform("gradientSampler"), textureSlot);
+ glUniform1i(program.getUniform("gradientSampler"), textureSlot);
} else {
- bindUniformColor(program->getUniform("startColor"), gradInfo.fColors[0]);
- bindUniformColor(program->getUniform("endColor"), gradInfo.fColors[1]);
+ bindUniformColor(program.getUniform("startColor"), gradInfo.fColors[0]);
+ bindUniformColor(program.getUniform("endColor"), gradInfo.fColors[1]);
}
caches->dither.setupProgram(program, textureUnit);
@@ -427,7 +428,7 @@ void SkiaGradientShader::setupProgram(Caches* caches, const mat4& modelViewMatri
mat4 screenSpace;
computeScreenSpaceMatrix(screenSpace, unitMatrix, shader.getLocalMatrix(), modelViewMatrix);
- glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
+ glUniformMatrix4fv(program.getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index 631305f..e110ca5 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -24,16 +24,15 @@
#include <cutils/compiler.h>
-#include "Extensions.h"
-#include "ProgramCache.h"
-#include "TextureCache.h"
-#include "GradientCache.h"
+#include "Matrix.h"
namespace android {
namespace uirenderer {
class Caches;
+class Extensions;
class Layer;
+struct ProgramDescription;
/**
* Type of Skia shader in use.
@@ -62,8 +61,7 @@ public:
// This shader is unsupported. Skip it.
}
static void setupProgram(Caches* caches, const mat4& modelViewMatrix,
- GLuint* textureUnit, const Extensions& extensions,
- const SkShader& shader) {
+ GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) {
// This shader is unsupported. Skip it.
}
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index cf8229f..597d95c 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -29,17 +29,16 @@ namespace uirenderer {
Snapshot::Snapshot()
: flags(0)
- , previous(NULL)
- , layer(NULL)
+ , previous(nullptr)
+ , layer(nullptr)
, fbo(0)
, invisible(false)
, empty(false)
, alpha(1.0f)
- , roundRectClipState(NULL) {
+ , roundRectClipState(nullptr)
+ , mClipArea(&mClipAreaRoot) {
transform = &mTransformRoot;
- clipRect = &mClipRectRoot;
- region = NULL;
- clipRegion = &mClipRegionRoot;
+ region = nullptr;
}
/**
@@ -55,6 +54,7 @@ Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags)
, empty(false)
, alpha(s->alpha)
, roundRectClipState(s->roundRectClipState)
+ , mClipArea(nullptr)
, mViewportData(s->mViewportData)
, mRelativeLightCenter(s->mRelativeLightCenter) {
if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
@@ -65,22 +65,17 @@ Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags)
}
if (saveFlags & SkCanvas::kClip_SaveFlag) {
- mClipRectRoot.set(*s->clipRect);
- clipRect = &mClipRectRoot;
- if (!s->clipRegion->isEmpty()) {
- mClipRegionRoot.op(*s->clipRegion, SkRegion::kUnion_Op);
- }
- clipRegion = &mClipRegionRoot;
+ mClipAreaRoot = s->getClipArea();
+ mClipArea = &mClipAreaRoot;
} else {
- clipRect = s->clipRect;
- clipRegion = s->clipRegion;
+ mClipArea = s->mClipArea;
}
if (s->flags & Snapshot::kFlagFboTarget) {
flags |= Snapshot::kFlagFboTarget;
region = s->region;
} else {
- region = NULL;
+ region = nullptr;
}
}
@@ -88,88 +83,23 @@ Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags)
// Clipping
///////////////////////////////////////////////////////////////////////////////
-void Snapshot::ensureClipRegion() {
- if (clipRegion->isEmpty()) {
- clipRegion->setRect(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
- }
-}
-
-void Snapshot::copyClipRectFromRegion() {
- if (!clipRegion->isEmpty()) {
- const SkIRect& bounds = clipRegion->getBounds();
- clipRect->set(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
-
- if (clipRegion->isRect()) {
- clipRegion->setEmpty();
- }
- } else {
- clipRect->setEmpty();
- }
-}
-
-bool Snapshot::clipRegionOp(float left, float top, float right, float bottom, SkRegion::Op op) {
- SkIRect tmp;
- tmp.set(left, top, right, bottom);
- clipRegion->op(tmp, op);
- copyClipRectFromRegion();
- return true;
-}
-
bool Snapshot::clipRegionTransformed(const SkRegion& region, SkRegion::Op op) {
- ensureClipRegion();
- clipRegion->op(region, op);
- copyClipRectFromRegion();
flags |= Snapshot::kFlagClipSet;
- return true;
+ return mClipArea->clipRegion(region, op);
}
bool Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
- Rect r(left, top, right, bottom);
- transform->mapRect(r);
- return clipTransformed(r, op);
+ flags |= Snapshot::kFlagClipSet;
+ return mClipArea->clipRectWithTransform(left, top, right, bottom, transform, op);
}
-bool Snapshot::clipTransformed(const Rect& r, SkRegion::Op op) {
- bool clipped = false;
-
- switch (op) {
- case SkRegion::kIntersect_Op: {
- if (CC_UNLIKELY(!clipRegion->isEmpty())) {
- ensureClipRegion();
- clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, SkRegion::kIntersect_Op);
- } else {
- clipped = clipRect->intersect(r);
- if (!clipped) {
- clipRect->setEmpty();
- clipped = true;
- }
- }
- break;
- }
- case SkRegion::kReplace_Op: {
- setClip(r.left, r.top, r.right, r.bottom);
- clipped = true;
- break;
- }
- default: {
- ensureClipRegion();
- clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, op);
- break;
- }
- }
-
- if (clipped) {
- flags |= Snapshot::kFlagClipSet;
- }
-
- return clipped;
+bool Snapshot::clipPath(const SkPath& path, SkRegion::Op op) {
+ flags |= Snapshot::kFlagClipSet;
+ return mClipArea->clipPathWithTransform(path, transform, op);
}
void Snapshot::setClip(float left, float top, float right, float bottom) {
- clipRect->set(left, top, right, bottom);
- if (!clipRegion->isEmpty()) {
- clipRegion->setEmpty();
- }
+ mClipArea->setClip(left, top, right, bottom);
flags |= Snapshot::kFlagClipSet;
}
@@ -181,7 +111,7 @@ const Rect& Snapshot::getLocalClip() {
mat4 inverse;
inverse.loadInverse(*transform);
- mLocalClip.set(*clipRect);
+ mLocalClip.set(mClipArea->getClipRect());
inverse.mapRect(mLocalClip);
return mLocalClip;
@@ -191,8 +121,7 @@ void Snapshot::resetClip(float left, float top, float right, float bottom) {
// TODO: This is incorrect, when we start rendering into a new layer,
// we may have to modify the previous snapshot's clip rect and clip
// region if the previous restore() call did not restore the clip
- clipRect = &mClipRectRoot;
- clipRegion = &mClipRegionRoot;
+ mClipArea = &mClipAreaRoot;
setClip(left, top, right, bottom);
}
@@ -219,7 +148,7 @@ void Snapshot::resetTransform(float x, float y, float z) {
void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds,
float radius, bool highPriority) {
if (bounds.isEmpty()) {
- clipRect->setEmpty();
+ mClipArea->setEmpty();
return;
}
@@ -272,9 +201,10 @@ bool Snapshot::isIgnored() const {
void Snapshot::dump() const {
ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d",
- this, flags, previous.get(), getViewportHeight(), isIgnored(), clipRegion && !clipRegion->isEmpty());
- ALOGD(" ClipRect (at %p) %.1f %.1f %.1f %.1f",
- clipRect, clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
+ this, flags, previous.get(), getViewportHeight(), isIgnored(), !mClipArea->isSimple());
+ const Rect& clipRect(mClipArea->getClipRect());
+ ALOGD(" ClipRect %.1f %.1f %.1f %.1f",
+ clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
ALOGD(" Transform (at %p):", transform);
transform->dump();
}
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 549de9b..4d704ab 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -26,6 +26,7 @@
#include <SkRegion.h>
+#include "ClipArea.h"
#include "Layer.h"
#include "Matrix.h"
#include "Outline.h"
@@ -129,6 +130,11 @@ public:
bool clipRegionTransformed(const SkRegion& region, SkRegion::Op op);
/**
+ * Modifies the current clip with the specified path and operation.
+ */
+ bool clipPath(const SkPath& path, SkRegion::Op op);
+
+ /**
* Sets the current clip.
*/
void setClip(float left, float top, float right, float bottom);
@@ -142,7 +148,16 @@ public:
/**
* Returns the current clip in render target coordinates.
*/
- const Rect& getRenderTargetClip() { return *clipRect; }
+ const Rect& getRenderTargetClip() { return mClipArea->getClipRect(); }
+
+ /*
+ * Accessor functions so that the clip area can stay private
+ */
+ bool clipIsEmpty() const { return mClipArea->isEmpty(); }
+ const Rect& getClipRect() const { return mClipArea->getClipRect(); }
+ const SkRegion& getClipRegion() const { return mClipArea->getClipRegion(); }
+ bool clipIsSimple() const { return mClipArea->isSimple(); }
+ const ClipArea& getClipArea() const { return *mClipArea; }
/**
* Resets the clip to the specified rect.
@@ -156,6 +171,7 @@ public:
void initializeViewport(int width, int height) {
mViewportData.initialize(width, height);
+ mClipAreaRoot.setViewportDimensions(width, height);
}
int getViewportWidth() const { return mViewportData.mWidth; }
@@ -175,7 +191,7 @@ public:
/**
* Indicates whether this snapshot should be ignored. A snapshot
- * is typicalled ignored if its layer is invisible or empty.
+ * is typically ignored if its layer is invisible or empty.
*/
bool isIgnored() const;
@@ -230,24 +246,6 @@ public:
mat4* transform;
/**
- * Current clip rect. The clip is stored in canvas-space coordinates,
- * (screen-space coordinates in the regular case.)
- *
- * This is a reference to a rect owned by this snapshot or another
- * snapshot. This pointer must not be freed. See ::mClipRectRoot.
- */
- Rect* clipRect;
-
- /**
- * Current clip region. The clip is stored in canvas-space coordinates,
- * (screen-space coordinates in the regular case.)
- *
- * This is a reference to a region owned by this snapshot or another
- * snapshot. This pointer must not be freed. See ::mClipRegionRoot.
- */
- SkRegion* clipRegion;
-
- /**
* The ancestor layer's dirty region.
*
* This is a reference to a region owned by a layer. This pointer must
@@ -260,7 +258,7 @@ public:
* 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
* operations. The value is inherited by child snapshots because the same value should
- * be applied to descendents of the current DisplayList (for example, a TextView contains
+ * be applied to descendants of the current DisplayList (for example, a TextView contains
* the base alpha value which should be applied to the child DisplayLists used for drawing
* the actual text).
*/
@@ -298,16 +296,12 @@ private:
mat4 mOrthoMatrix;
};
- void ensureClipRegion();
- void copyClipRectFromRegion();
-
- bool clipRegionOp(float left, float top, float right, float bottom, SkRegion::Op op);
-
mat4 mTransformRoot;
- Rect mClipRectRoot;
- Rect mLocalClip; // don't use directly, call getLocalClip() which initializes this
- SkRegion mClipRegionRoot;
+ ClipArea mClipAreaRoot;
+ ClipArea* mClipArea;
+ Rect mLocalClip;
+
ViewportData mViewportData;
Vector3 mRelativeLightCenter;
diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
index 3046fd5..b3b06d6 100644
--- a/libs/hwui/SpotShadow.cpp
+++ b/libs/hwui/SpotShadow.cpp
@@ -52,6 +52,7 @@
#include "ShadowTessellator.h"
#include "SpotShadow.h"
#include "Vertex.h"
+#include "VertexBuffer.h"
#include "utils/MathUtils.h"
// TODO: After we settle down the new algorithm, we can remove the old one and
@@ -331,7 +332,7 @@ bool SpotShadow::testPointInsidePolygon(const Vector2 testPoint,
* @param len the number of points of the polygon
*/
void SpotShadow::makeClockwise(Vector2* polygon, int len) {
- if (polygon == 0 || len == 0) {
+ if (polygon == nullptr || len == 0) {
return;
}
if (!ShadowTessellator::isClockwise(polygon, len)) {
@@ -1030,7 +1031,7 @@ void SpotShadow::generateTriangleStrip(bool isCasterOpaque, float shadowStrength
ShadowTessellator::checkOverflow(vertexBufferIndex, totalVertexCount, "Spot Vertex Buffer");
ShadowTessellator::checkOverflow(indexBufferIndex, totalIndexCount, "Spot Index Buffer");
- shadowTriangleStrip.setMode(VertexBuffer::kIndices);
+ shadowTriangleStrip.setMeshFeatureFlags(VertexBuffer::kAlpha | VertexBuffer::kIndices);
shadowTriangleStrip.computeBounds<AlphaVertex>();
}
diff --git a/libs/hwui/SpotShadow.h b/libs/hwui/SpotShadow.h
index e2d94f7..62a7e5d 100644
--- a/libs/hwui/SpotShadow.h
+++ b/libs/hwui/SpotShadow.h
@@ -19,11 +19,12 @@
#include "Debug.h"
#include "Vector.h"
-#include "VertexBuffer.h"
namespace android {
namespace uirenderer {
+class VertexBuffer;
+
class SpotShadow {
public:
static void createSpotShadow(bool isCasterOpaque, const Vector3& lightCenter,
diff --git a/libs/hwui/StatefulBaseRenderer.h b/libs/hwui/StatefulBaseRenderer.h
deleted file mode 100644
index fcd6060..0000000
--- a/libs/hwui/StatefulBaseRenderer.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2014 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_STATEFUL_BASE_RENDERER_H
-#define ANDROID_HWUI_STATEFUL_BASE_RENDERER_H
-
-#include <utils/RefBase.h>
-
-#include "Renderer.h"
-#include "Snapshot.h"
-
-namespace android {
-namespace uirenderer {
-
-/**
- * Abstract Renderer subclass, which implements Canvas state methods.
- *
- * Manages the Snapshot stack, implementing matrix, save/restore, and clipping methods in the
- * Renderer interface. Drawing and recording classes that extend StatefulBaseRenderer will have
- * different use cases:
- *
- * Drawing subclasses (i.e. OpenGLRenderer) can query attributes (such as transform) or hook into
- * changes (e.g. save/restore) with minimal surface area for manipulating the stack itself.
- *
- * Recording subclasses (i.e. DisplayListRenderer) can both record and pass through state operations
- * to StatefulBaseRenderer, so that not only will querying operations work (getClip/Matrix), but so
- * that quickRejection can also be used.
- */
-class StatefulBaseRenderer : public Renderer {
-public:
- StatefulBaseRenderer();
-
- virtual status_t prepare(bool opaque) {
- return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque);
- }
-
- /**
- * Initialize the first snapshot, computing the projection matrix, and stores the dimensions of
- * the render target.
- */
- virtual void setViewport(int width, int height);
- void initializeSaveStack(float clipLeft, float clipTop, float clipRight, float clipBottom,
- const Vector3& lightCenter);
-
- // getters
- bool hasRectToRectTransform() const {
- return CC_LIKELY(currentTransform()->rectToRect());
- }
-
- // Save (layer)
- virtual int getSaveCount() const { return mSaveCount; }
- virtual int save(int flags);
- virtual void restore();
- virtual void restoreToCount(int saveCount);
- //virtual int saveLayer(float left, float top, float right, float bottom,
- // int alpha, SkXfermode::Mode mode, int flags);
-
- // Matrix
- virtual void getMatrix(SkMatrix* outMatrix) const;
- virtual void translate(float dx, float dy, float dz = 0.0f);
- virtual void rotate(float degrees);
- virtual void scale(float sx, float sy);
- virtual void skew(float sx, float sy);
-
- virtual void setMatrix(const SkMatrix& matrix);
- void setMatrix(const Matrix4& matrix); // internal only convenience method
- virtual void concatMatrix(const SkMatrix& matrix);
- void concatMatrix(const Matrix4& matrix); // internal only convenience method
-
- // Clip
- virtual const Rect& getLocalClipBounds() const { return mSnapshot->getLocalClip(); }
-
- virtual bool quickRejectConservative(float left, float top, float right, float bottom) const;
-
- virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
- virtual bool clipPath(const SkPath* path, SkRegion::Op op);
- virtual 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);
-
- inline const mat4* currentTransform() const {
- return mSnapshot->transform;
- }
-
-protected:
- const Rect& getRenderTargetClipBounds() const { return mSnapshot->getRenderTargetClip(); }
-
- int getWidth() { return mWidth; }
- int getHeight() { return mHeight; }
-
- // Save
- int saveSnapshot(int flags);
- void restoreSnapshot();
-
- // allows subclasses to control what value is stored in snapshot's fbo field in
- // initializeSaveStack
- virtual GLuint getTargetFbo() const {
- return -1;
- }
-
- // Clip
- bool calculateQuickRejectForScissor(float left, float top, float right, float bottom,
- bool* clipRequired, bool* roundRectClipRequired, bool snapOut) const;
-
- /**
- * Called just after a restore has occurred. The 'removed' snapshot popped from the stack,
- * 'restored' snapshot has become the top/current.
- *
- * Subclasses can override this method to handle layer restoration
- */
- virtual void onSnapshotRestored(const Snapshot& removed,
- const Snapshot& restored) {};
-
- virtual void onViewportInitialized() {};
-
- inline const Rect* currentClipRect() const {
- return mSnapshot->clipRect;
- }
-
- inline const Snapshot* currentSnapshot() const {
- return mSnapshot != NULL ? mSnapshot.get() : mFirstSnapshot.get();
- }
-
- inline const Snapshot* firstSnapshot() const {
- return mFirstSnapshot.get();
- }
-
- // indicites that the clip has been changed since the last time it was consumed
- bool mDirtyClip;
-
-private:
- // Dimensions of the drawing surface
- int mWidth, mHeight;
-
- // Number of saved states
- int mSaveCount;
-
- // Base state
- sp<Snapshot> mFirstSnapshot;
-
-protected:
- // Current state
- // TODO: should become private, once hooks needed by OpenGLRenderer are added
- sp<Snapshot> mSnapshot;
-}; // class StatefulBaseRenderer
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_STATEFUL_BASE_RENDERER_H
diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp
index bc956be..66de333 100644
--- a/libs/hwui/TessellationCache.cpp
+++ b/libs/hwui/TessellationCache.cpp
@@ -76,7 +76,7 @@ void TessellationCache::Description::setupMatrixAndPaint(Matrix4* matrix, SkPain
}
TessellationCache::ShadowDescription::ShadowDescription()
- : nodeKey(NULL) {
+ : nodeKey(nullptr) {
memset(&matrixData, 0, 16 * sizeof(float));
}
@@ -114,7 +114,7 @@ public:
: TaskProcessor<VertexBuffer*>(&caches.tasks) {}
~TessellationProcessor() {}
- virtual void onProcess(const sp<Task<VertexBuffer*> >& task) {
+ virtual void onProcess(const sp<Task<VertexBuffer*> >& task) override {
TessellationTask* t = static_cast<TessellationTask*>(task.get());
ATRACE_NAME("shape tessellation");
VertexBuffer* buffer = t->tessellator(t->description);
@@ -126,7 +126,7 @@ class TessellationCache::Buffer {
public:
Buffer(const sp<Task<VertexBuffer*> >& task)
: mTask(task)
- , mBuffer(NULL) {
+ , mBuffer(nullptr) {
}
~Buffer() {
@@ -146,9 +146,9 @@ public:
private:
void blockOnPrecache() {
- if (mTask != NULL) {
+ if (mTask != nullptr) {
mBuffer = mTask->getResult();
- LOG_ALWAYS_FATAL_IF(mBuffer == NULL, "Failed to precache");
+ LOG_ALWAYS_FATAL_IF(mBuffer == nullptr, "Failed to precache");
mTask.clear();
}
}
@@ -278,7 +278,7 @@ public:
: TaskProcessor<TessellationCache::vertexBuffer_pair_t*>(&caches.tasks) {}
~ShadowProcessor() {}
- virtual void onProcess(const sp<Task<TessellationCache::vertexBuffer_pair_t*> >& task) {
+ virtual void onProcess(const sp<Task<TessellationCache::vertexBuffer_pair_t*> >& task) override {
ShadowTask* t = static_cast<ShadowTask*>(task.get());
ATRACE_NAME("shadow tessellation");
@@ -302,7 +302,7 @@ TessellationCache::TessellationCache()
, mCache(LruCache<Description, Buffer*>::kUnlimitedCapacity)
, mShadowCache(LruCache<ShadowDescription, Task<vertexBuffer_pair_t*>*>::kUnlimitedCapacity) {
char property[PROPERTY_VALUE_MAX];
- if (property_get(PROPERTY_VERTEX_CACHE_SIZE, property, NULL) > 0) {
+ if (property_get(PROPERTY_VERTEX_CACHE_SIZE, property, nullptr) > 0) {
INIT_LOGD(" Setting %s cache size to %sMB", name, property);
setMaxSize(MB(atof(property)));
} else {
@@ -382,14 +382,14 @@ void TessellationCache::precacheShadows(const Matrix4* drawTransform, const Rect
sp<ShadowTask> task = new ShadowTask(drawTransform, localClip, opaque,
casterPerimeter, transformXY, transformZ, lightCenter, lightRadius);
- if (mShadowProcessor == NULL) {
+ if (mShadowProcessor == nullptr) {
mShadowProcessor = new ShadowProcessor(Caches::getInstance());
}
if (!mShadowProcessor->add(task)) {
mShadowProcessor->process(task);
}
- task->incStrong(NULL); // not using sp<>s, so manually ref while in the cache
+ task->incStrong(nullptr); // not using sp<>s, so manually ref while in the cache
mShadowCache.put(key, task.get());
}
@@ -404,7 +404,7 @@ void TessellationCache::getShadowBuffers(const Matrix4* drawTransform, const Rec
transformXY, transformZ, lightCenter, lightRadius);
task = static_cast<ShadowTask*>(mShadowCache.get(key));
}
- LOG_ALWAYS_FATAL_IF(task == NULL, "shadow not precached");
+ LOG_ALWAYS_FATAL_IF(task == nullptr, "shadow not precached");
outBuffers = *(task->getResult());
}
@@ -420,7 +420,7 @@ TessellationCache::Buffer* TessellationCache::getOrCreateBuffer(
sp<TessellationTask> task = new TessellationTask(tessellator, entry);
buffer = new Buffer(task);
- if (mProcessor == NULL) {
+ if (mProcessor == nullptr) {
mProcessor = new TessellationProcessor(Caches::getInstance());
}
if (!mProcessor->add(task)) {
diff --git a/libs/hwui/TessellationCache.h b/libs/hwui/TessellationCache.h
index 7eca681..3efeaf6 100644
--- a/libs/hwui/TessellationCache.h
+++ b/libs/hwui/TessellationCache.h
@@ -24,7 +24,6 @@
#include "Debug.h"
#include "utils/Macros.h"
#include "utils/Pair.h"
-#include "VertexBuffer.h"
class SkBitmap;
class SkCanvas;
@@ -36,6 +35,7 @@ namespace android {
namespace uirenderer {
class Caches;
+class VertexBuffer;
///////////////////////////////////////////////////////////////////////////////
// Classes
@@ -166,7 +166,7 @@ private:
sp<TaskProcessor<VertexBuffer*> > mProcessor;
LruCache<Description, Buffer*> mCache;
class BufferRemovedListener : public OnEntryRemoved<Description, Buffer*> {
- void operator()(Description& description, Buffer*& buffer);
+ void operator()(Description& description, Buffer*& buffer) override;
};
BufferRemovedListener mBufferRemovedListener;
@@ -178,9 +178,8 @@ private:
// holds a pointer, and implicit strong ref to each shadow task of the frame
LruCache<ShadowDescription, Task<vertexBuffer_pair_t*>*> mShadowCache;
class BufferPairRemovedListener : public OnEntryRemoved<ShadowDescription, Task<vertexBuffer_pair_t*>*> {
- void operator()(ShadowDescription& description,
- Task<vertexBuffer_pair_t*>*& bufferPairTask) {
- bufferPairTask->decStrong(NULL);
+ void operator()(ShadowDescription& description, Task<vertexBuffer_pair_t*>*& bufferPairTask) override {
+ bufferPairTask->decStrong(nullptr);
}
};
BufferPairRemovedListener mBufferPairRemovedListener;
diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp
index 96c09e6..c2e88f3 100644
--- a/libs/hwui/TextDropShadowCache.cpp
+++ b/libs/hwui/TextDropShadowCache.cpp
@@ -20,6 +20,7 @@
#include "Caches.h"
#include "Debug.h"
+#include "FontRenderer.h"
#include "TextDropShadowCache.h"
#include "Properties.h"
@@ -99,7 +100,7 @@ TextDropShadowCache::TextDropShadowCache():
mCache(LruCache<ShadowText, ShadowTexture*>::kUnlimitedCapacity),
mSize(0), mMaxSize(MB(DEFAULT_DROP_SHADOW_CACHE_SIZE)) {
char property[PROPERTY_VALUE_MAX];
- if (property_get(PROPERTY_DROP_SHADOW_CACHE_SIZE, property, NULL) > 0) {
+ if (property_get(PROPERTY_DROP_SHADOW_CACHE_SIZE, property, nullptr) > 0) {
INIT_LOGD(" Setting drop shadow cache size to %sMB", property);
setMaxSize(MB(atof(property)));
} else {
@@ -181,7 +182,7 @@ ShadowTexture* TextDropShadowCache::get(const SkPaint* paint, const char* text,
len, numGlyphs, radius, positions);
if (!shadow.image) {
- return NULL;
+ return nullptr;
}
Caches& caches = Caches::getInstance();
@@ -206,7 +207,7 @@ ShadowTexture* TextDropShadowCache::get(const SkPaint* paint, const char* text,
glGenTextures(1, &texture->id);
- caches.bindTexture(texture->id);
+ caches.textureState().bindTexture(texture->id);
// Textures are Alpha8
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h
index 54b930b..caf089f 100644
--- a/libs/hwui/TextDropShadowCache.h
+++ b/libs/hwui/TextDropShadowCache.h
@@ -24,17 +24,18 @@
#include <utils/LruCache.h>
#include <utils/String16.h>
-#include "FontRenderer.h"
+#include "font/Font.h"
#include "Texture.h"
namespace android {
namespace uirenderer {
class Caches;
+class FontRenderer;
struct ShadowText {
- ShadowText(): len(0), radius(0.0f), textSize(0.0f), typeface(NULL),
- flags(0), italicStyle(0.0f), scaleX(0), text(NULL), positions(NULL) {
+ ShadowText(): len(0), radius(0.0f), textSize(0.0f), typeface(nullptr),
+ flags(0), italicStyle(0.0f), scaleX(0), text(nullptr), positions(nullptr) {
}
// len is the number of bytes in text
@@ -75,7 +76,7 @@ struct ShadowText {
uint32_t charCount = len / sizeof(char16_t);
str.setTo((const char16_t*) text, charCount);
text = str.string();
- if (positions != NULL) {
+ if (positions != nullptr) {
positionsCopy.clear();
positionsCopy.appendArray(positions, charCount * 2);
positions = positionsCopy.array();
@@ -133,7 +134,7 @@ public:
* Used as a callback when an entry is removed from the cache.
* Do not invoke directly.
*/
- void operator()(ShadowText& text, ShadowTexture*& texture);
+ void operator()(ShadowText& text, ShadowTexture*& texture) override;
ShadowTexture* get(const SkPaint* paint, const char* text, uint32_t len,
int numGlyphs, float radius, const float* positions);
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
index e783905..512f5cf 100644
--- a/libs/hwui/Texture.cpp
+++ b/libs/hwui/Texture.cpp
@@ -24,18 +24,44 @@
namespace android {
namespace uirenderer {
-Texture::Texture(): id(0), generation(0), blend(false), width(0), height(0),
- cleanup(false), bitmapSize(0), mipMap(false), uvMapper(NULL), isInUse(false),
- mWrapS(GL_CLAMP_TO_EDGE), mWrapT(GL_CLAMP_TO_EDGE),
- mMinFilter(GL_NEAREST), mMagFilter(GL_NEAREST),
- mFirstFilter(true), mFirstWrap(true), mCaches(Caches::getInstance()) {
+Texture::Texture()
+ : id(0)
+ , generation(0)
+ , blend(false)
+ , width(0)
+ , height(0)
+ , cleanup(false)
+ , bitmapSize(0)
+ , mipMap(false)
+ , uvMapper(nullptr)
+ , isInUse(false)
+ , mWrapS(GL_CLAMP_TO_EDGE)
+ , mWrapT(GL_CLAMP_TO_EDGE)
+ , mMinFilter(GL_NEAREST)
+ , mMagFilter(GL_NEAREST)
+ , mFirstFilter(true)
+ , mFirstWrap(true)
+ , mCaches(Caches::getInstance()) {
}
-Texture::Texture(Caches& caches): id(0), generation(0), blend(false), width(0), height(0),
- cleanup(false), bitmapSize(0), mipMap(false), uvMapper(NULL), isInUse(false),
- mWrapS(GL_CLAMP_TO_EDGE), mWrapT(GL_CLAMP_TO_EDGE),
- mMinFilter(GL_NEAREST), mMagFilter(GL_NEAREST),
- mFirstFilter(true), mFirstWrap(true), mCaches(caches) {
+Texture::Texture(Caches& caches)
+ : id(0)
+ , generation(0)
+ , blend(false)
+ , width(0)
+ , height(0)
+ , cleanup(false)
+ , bitmapSize(0)
+ , mipMap(false)
+ , uvMapper(nullptr)
+ , isInUse(false)
+ , mWrapS(GL_CLAMP_TO_EDGE)
+ , mWrapT(GL_CLAMP_TO_EDGE)
+ , mMinFilter(GL_NEAREST)
+ , mMagFilter(GL_NEAREST)
+ , mFirstFilter(true)
+ , mFirstWrap(true)
+ , mCaches(caches) {
}
void Texture::setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture, bool force,
@@ -48,7 +74,7 @@ void Texture::setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture, bool force
mWrapT = wrapT;
if (bindTexture) {
- mCaches.bindTexture(renderTarget, id);
+ mCaches.textureState().bindTexture(renderTarget, id);
}
glTexParameteri(renderTarget, GL_TEXTURE_WRAP_S, wrapS);
@@ -66,7 +92,7 @@ void Texture::setFilterMinMag(GLenum min, GLenum mag, bool bindTexture, bool for
mMagFilter = mag;
if (bindTexture) {
- mCaches.bindTexture(renderTarget, id);
+ mCaches.textureState().bindTexture(renderTarget, id);
}
if (mipMap && min == GL_LINEAR) min = GL_LINEAR_MIPMAP_LINEAR;
@@ -77,7 +103,7 @@ void Texture::setFilterMinMag(GLenum min, GLenum mag, bool bindTexture, bool for
}
void Texture::deleteTexture() const {
- mCaches.deleteTexture(id);
+ mCaches.textureState().deleteTexture(id);
}
}; // namespace uirenderer
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 63454d8..f4f8e44 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -26,6 +26,7 @@
#include "AssetAtlas.h"
#include "Caches.h"
+#include "Texture.h"
#include "TextureCache.h"
#include "Properties.h"
#include "utils/TraceUtils.h"
@@ -37,19 +38,21 @@ namespace uirenderer {
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
-TextureCache::TextureCache():
- mCache(LruCache<uint32_t, Texture*>::kUnlimitedCapacity),
- mSize(0), mMaxSize(MB(DEFAULT_TEXTURE_CACHE_SIZE)),
- mFlushRate(DEFAULT_TEXTURE_CACHE_FLUSH_RATE), mAssetAtlas(0) {
+TextureCache::TextureCache()
+ : mCache(LruCache<uint32_t, Texture*>::kUnlimitedCapacity)
+ , mSize(0)
+ , mMaxSize(MB(DEFAULT_TEXTURE_CACHE_SIZE))
+ , mFlushRate(DEFAULT_TEXTURE_CACHE_FLUSH_RATE)
+ , mAssetAtlas(nullptr) {
char property[PROPERTY_VALUE_MAX];
- if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, NULL) > 0) {
+ if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, nullptr) > 0) {
INIT_LOGD(" Setting texture cache size to %sMB", property);
setMaxSize(MB(atof(property)));
} else {
INIT_LOGD(" Using default texture cache size of %.2fMB", DEFAULT_TEXTURE_CACHE_SIZE);
}
- if (property_get(PROPERTY_TEXTURE_CACHE_FLUSH_RATE, property, NULL) > 0) {
+ if (property_get(PROPERTY_TEXTURE_CACHE_FLUSH_RATE, property, nullptr) > 0) {
float flushRate = atof(property);
INIT_LOGD(" Setting texture cache flush rate to %.2f%%", flushRate * 100.0f);
setFlushRate(flushRate);
@@ -58,20 +61,6 @@ TextureCache::TextureCache():
DEFAULT_TEXTURE_CACHE_FLUSH_RATE * 100.0f);
}
- init();
-}
-
-TextureCache::TextureCache(uint32_t maxByteSize):
- mCache(LruCache<uint32_t, Texture*>::kUnlimitedCapacity),
- mSize(0), mMaxSize(maxByteSize), mAssetAtlas(0) {
- init();
-}
-
-TextureCache::~TextureCache() {
- mCache.clear();
-}
-
-void TextureCache::init() {
mCache.setOnEntryRemovedListener(this);
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
@@ -80,6 +69,10 @@ void TextureCache::init() {
mDebugEnabled = readDebugLevel() & kDebugCaches;
}
+TextureCache::~TextureCache() {
+ mCache.clear();
+}
+
///////////////////////////////////////////////////////////////////////////////
// Size management
///////////////////////////////////////////////////////////////////////////////
@@ -159,7 +152,7 @@ Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap) {
if (!texture) {
if (!canMakeTextureFromBitmap(bitmap)) {
- return NULL;
+ return nullptr;
}
const uint32_t size = bitmap->rowBytes() * bitmap->height();
@@ -209,7 +202,7 @@ Texture* TextureCache::get(const SkBitmap* bitmap) {
if (!texture) {
if (!canMakeTextureFromBitmap(bitmap)) {
- return NULL;
+ return nullptr;
}
const uint32_t size = bitmap->rowBytes() * bitmap->height();
@@ -232,11 +225,9 @@ Texture* TextureCache::getTransient(const SkBitmap* bitmap) {
return texture;
}
-void TextureCache::releaseTexture(const SkBitmap* bitmap) {
- if (!bitmap || !bitmap->pixelRef()) return;
-
+void TextureCache::releaseTexture(uint32_t pixelRefStableID) {
Mutex::Autolock _l(mLock);
- mGarbage.push(bitmap->pixelRef()->getStableID());
+ mGarbage.push(pixelRefStableID);
}
void TextureCache::clearGarbage() {
@@ -281,7 +272,7 @@ void TextureCache::generateTexture(const SkBitmap* bitmap, Texture* texture, boo
// We could also enable mipmapping if both bitmap dimensions are powers
// of 2 but we'd have to deal with size changes. Let's keep this simple
- const bool canMipMap = Extensions::getInstance().hasNPot();
+ const bool canMipMap = Caches::getInstance().extensions().hasNPot();
// If the texture had mipmap enabled but not anymore,
// force a glTexImage2D to discard the mipmap levels
@@ -297,23 +288,20 @@ void TextureCache::generateTexture(const SkBitmap* bitmap, Texture* texture, boo
texture->width = bitmap->width();
texture->height = bitmap->height();
- Caches::getInstance().bindTexture(texture->id);
+ Caches::getInstance().textureState().bindTexture(texture->id);
switch (bitmap->colorType()) {
case kAlpha_8_SkColorType:
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(),
texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels());
texture->blend = true;
break;
case kRGB_565_SkColorType:
- glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
uploadToTexture(resize, GL_RGB, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(),
texture->width, texture->height, GL_UNSIGNED_SHORT_5_6_5, bitmap->getPixels());
texture->blend = false;
break;
case kN32_SkColorType:
- glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
uploadToTexture(resize, GL_RGBA, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(),
texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels());
// Do this after calling getPixels() to make sure Skia's deferred
@@ -322,7 +310,6 @@ void TextureCache::generateTexture(const SkBitmap* bitmap, Texture* texture, boo
break;
case kARGB_4444_SkColorType:
case kIndex_8_SkColorType:
- glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
uploadLoFiTexture(resize, bitmap, texture->width, texture->height);
texture->blend = !bitmap->isOpaque();
break;
@@ -351,7 +338,7 @@ void TextureCache::uploadLoFiTexture(bool resize, const SkBitmap* bitmap,
rgbaBitmap.eraseColor(0);
SkCanvas canvas(rgbaBitmap);
- canvas.drawBitmap(*bitmap, 0.0f, 0.0f, NULL);
+ canvas.drawBitmap(*bitmap, 0.0f, 0.0f, nullptr);
uploadToTexture(resize, GL_RGBA, rgbaBitmap.rowBytesAsPixels(), rgbaBitmap.bytesPerPixel(),
width, height, GL_UNSIGNED_BYTE, rgbaBitmap.getPixels());
@@ -359,7 +346,9 @@ void TextureCache::uploadLoFiTexture(bool resize, const SkBitmap* bitmap,
void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp,
GLsizei width, GLsizei height, GLenum type, const GLvoid * data) {
- const bool useStride = stride != width && Extensions::getInstance().hasUnpackRowLength();
+ glPixelStorei(GL_UNPACK_ALIGNMENT, bpp);
+ const bool useStride = stride != width
+ && Caches::getInstance().extensions().hasUnpackRowLength();
if ((stride == width) || useStride) {
if (useStride) {
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index cf8d134..a2c6380 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -24,11 +24,12 @@
#include <utils/Vector.h>
#include "Debug.h"
-#include "Texture.h"
namespace android {
namespace uirenderer {
+class Texture;
+
///////////////////////////////////////////////////////////////////////////////
// Defines
///////////////////////////////////////////////////////////////////////////////
@@ -51,17 +52,16 @@ class AssetAtlas;
* Any texture added to the cache causing the cache to grow beyond the maximum
* allowed size will also cause the oldest texture to be kicked out.
*/
-class TextureCache: public OnEntryRemoved<uint32_t, Texture*> {
+class TextureCache : public OnEntryRemoved<uint32_t, Texture*> {
public:
TextureCache();
- TextureCache(uint32_t maxByteSize);
~TextureCache();
/**
* Used as a callback when an entry is removed from the cache.
* Do not invoke directly.
*/
- void operator()(uint32_t&, Texture*& texture);
+ void operator()(uint32_t&, Texture*& texture) override;
/**
* Resets all Textures to not be marked as in use
@@ -87,10 +87,10 @@ public:
Texture* getTransient(const SkBitmap* bitmap);
/**
- * Removes the texture associated with the specified bitmap. This is meant
+ * Removes the texture associated with the specified pixelRef. This is meant
* to be called from threads that are not the EGL context thread.
*/
- void releaseTexture(const SkBitmap* bitmap);
+ ANDROID_API void releaseTexture(uint32_t pixelRefStableID);
/**
* Process deferred removals.
*/
@@ -145,8 +145,6 @@ private:
void uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp,
GLsizei width, GLsizei height, GLenum type, const GLvoid * data);
- void init();
-
LruCache<uint32_t, Texture*> mCache;
uint32_t mSize;
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index ae6ea94..0799c6c 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -20,7 +20,6 @@
#include <utils/Timers.h>
-#include "DamageAccumulator.h"
#include "utils/Macros.h"
namespace android {
@@ -30,6 +29,7 @@ namespace renderthread {
class CanvasContext;
}
+class DamageAccumulator;
class OpenGLRenderer;
class RenderState;
@@ -59,11 +59,11 @@ public:
: mode(mode)
, prepareTextures(mode == MODE_FULL)
, runAnimations(true)
- , damageAccumulator(NULL)
+ , damageAccumulator(nullptr)
, renderState(renderState)
- , renderer(NULL)
- , errorHandler(NULL)
- , canvasContext(NULL)
+ , renderer(nullptr)
+ , errorHandler(nullptr)
+ , canvasContext(nullptr)
{}
explicit TreeInfo(TraversalMode mode, const TreeInfo& clone)
diff --git a/libs/hwui/Vector.h b/libs/hwui/Vector.h
index aa6acc9..7c3f2fd 100644
--- a/libs/hwui/Vector.h
+++ b/libs/hwui/Vector.h
@@ -17,6 +17,9 @@
#ifndef ANDROID_HWUI_VECTOR_H
#define ANDROID_HWUI_VECTOR_H
+#include <math.h>
+#include <utils/Log.h>
+
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
index 4ff0b18..5b80bbd 100644
--- a/libs/hwui/Vertex.h
+++ b/libs/hwui/Vertex.h
@@ -19,6 +19,12 @@
#include "Vector.h"
+#include <type_traits>
+
+#define REQUIRE_COMPATIBLE_LAYOUT(TARGET_TYPE) \
+ static_assert(std::is_standard_layout<TARGET_TYPE>::value, \
+ #TARGET_TYPE " must have standard layout")
+
namespace android {
namespace uirenderer {
@@ -39,8 +45,8 @@ struct Vertex {
float x, y;
static inline void set(Vertex* vertex, float x, float y) {
- vertex[0].x = x;
- vertex[0].y = y;
+ vertex->x = x;
+ vertex->y = y;
}
static inline void set(Vertex* vertex, Vector2 val) {
@@ -53,6 +59,8 @@ struct Vertex {
}; // struct Vertex
+REQUIRE_COMPATIBLE_LAYOUT(Vertex);
+
/**
* Simple structure to describe a vertex with a position and texture UV.
*/
@@ -61,10 +69,7 @@ struct TextureVertex {
float u, v;
static inline void set(TextureVertex* vertex, float x, float y, float u, float v) {
- vertex[0].x = x;
- vertex[0].y = y;
- vertex[0].u = u;
- vertex[0].v = v;
+ *vertex = { x, y, u, v };
}
static inline void setUV(TextureVertex* vertex, float u, float v) {
@@ -73,39 +78,43 @@ struct TextureVertex {
}
}; // struct TextureVertex
+REQUIRE_COMPATIBLE_LAYOUT(TextureVertex);
+
/**
* Simple structure to describe a vertex with a position, texture UV and ARGB color.
*/
-struct ColorTextureVertex : TextureVertex {
+struct ColorTextureVertex {
+ float x, y;
+ float u, v;
float r, g, b, a;
static inline void set(ColorTextureVertex* vertex, float x, float y,
float u, float v, int color) {
- TextureVertex::set(vertex, x, y, u, v);
- const float a = ((color >> 24) & 0xff) / 255.0f;
- vertex[0].r = a * ((color >> 16) & 0xff) / 255.0f;
- vertex[0].g = a * ((color >> 8) & 0xff) / 255.0f;
- vertex[0].b = a * ((color ) & 0xff) / 255.0f;
- vertex[0].a = a;
+ float a = ((color >> 24) & 0xff) / 255.0f;
+ float r = a * ((color >> 16) & 0xff) / 255.0f;
+ float g = a * ((color >> 8) & 0xff) / 255.0f;
+ float b = a * ((color) & 0xff) / 255.0f;
+ *vertex = { x, y, u, v, r, g, b, a };
}
}; // struct ColorTextureVertex
+REQUIRE_COMPATIBLE_LAYOUT(ColorTextureVertex);
+
/**
* Simple structure to describe a vertex with a position and an alpha value.
*/
-struct AlphaVertex : Vertex {
+struct AlphaVertex {
+ float x, y;
float alpha;
static inline void set(AlphaVertex* vertex, float x, float y, float alpha) {
- Vertex::set(vertex, x, y);
- vertex[0].alpha = alpha;
+ *vertex = { x, y, alpha };
}
static inline void copyWithOffset(AlphaVertex* vertex, const AlphaVertex& src,
float x, float y) {
- Vertex::set(vertex, src.x + x, src.y + y);
- vertex[0].alpha = src.alpha;
+ AlphaVertex::set(vertex, src.x + x, src.y + y, src.alpha);
}
static inline void setColor(AlphaVertex* vertex, float alpha) {
@@ -113,6 +122,8 @@ struct AlphaVertex : Vertex {
}
}; // struct AlphaVertex
+REQUIRE_COMPATIBLE_LAYOUT(AlphaVertex);
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/VertexBuffer.h b/libs/hwui/VertexBuffer.h
index 8c3a272..9be4d84 100644
--- a/libs/hwui/VertexBuffer.h
+++ b/libs/hwui/VertexBuffer.h
@@ -24,25 +24,24 @@ namespace uirenderer {
class VertexBuffer {
public:
- enum Mode {
- kStandard = 0,
- kOnePolyRingShadow = 1,
- kTwoPolyRingShadow = 2,
- kIndices = 3
+ enum MeshFeatureFlags {
+ kNone = 0,
+ kAlpha = 1 << 0,
+ kIndices = 1 << 1,
};
VertexBuffer()
- : mBuffer(0)
- , mIndices(0)
+ : mBuffer(nullptr)
+ , mIndices(nullptr)
, mVertexCount(0)
, mIndexCount(0)
, mAllocatedVertexCount(0)
, mAllocatedIndexCount(0)
, mByteCount(0)
- , mMode(kStandard)
- , mReallocBuffer(0)
- , mCleanupMethod(NULL)
- , mCleanupIndexMethod(NULL)
+ , mMeshFeatureFlags(kNone)
+ , mReallocBuffer(nullptr)
+ , mCleanupMethod(nullptr)
+ , mCleanupIndexMethod(nullptr)
{}
~VertexBuffer() {
@@ -135,10 +134,12 @@ public:
void updateVertexCount(unsigned int newCount) {
mVertexCount = MathUtils::min(newCount, mAllocatedVertexCount);
}
- Mode getMode() const { return mMode; }
+ MeshFeatureFlags getMeshFeatureFlags() const { return mMeshFeatureFlags; }
+ void setMeshFeatureFlags(int flags) {
+ mMeshFeatureFlags = static_cast<MeshFeatureFlags>(flags);
+ }
void setBounds(Rect bounds) { mBounds = bounds; }
- void setMode(Mode mode) { mMode = mode; }
template <class TYPE>
void createDegenerateSeparators(int allocSize) {
@@ -166,7 +167,7 @@ private:
unsigned int mAllocatedIndexCount;
unsigned int mByteCount;
- Mode mMode;
+ MeshFeatureFlags mMeshFeatureFlags;
void* mReallocBuffer; // used for multi-allocation
diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
index 24ffb80..9314126 100644
--- a/libs/hwui/font/CacheTexture.cpp
+++ b/libs/hwui/font/CacheTexture.cpp
@@ -17,6 +17,7 @@
#include <SkGlyph.h>
#include "CacheTexture.h"
+#include "FontUtil.h"
#include "../Caches.h"
#include "../Debug.h"
#include "../Extensions.h"
@@ -42,7 +43,7 @@ CacheBlock* CacheBlock::insertBlock(CacheBlock* head, CacheBlock* newBlock) {
#endif
CacheBlock* currBlock = head;
- CacheBlock* prevBlock = NULL;
+ CacheBlock* prevBlock = nullptr;
while (currBlock && currBlock->mY != TEXTURE_BORDER_SIZE) {
if (newBlock->mWidth < currBlock->mWidth) {
@@ -109,9 +110,9 @@ CacheBlock* CacheBlock::removeBlock(CacheBlock* head, CacheBlock* blockToRemove)
///////////////////////////////////////////////////////////////////////////////
CacheTexture::CacheTexture(uint16_t width, uint16_t height, GLenum format, uint32_t maxQuadCount) :
- mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height), mFormat(format),
+ mTexture(nullptr), mTextureId(0), mWidth(width), mHeight(height), mFormat(format),
mLinearFiltering(false), mDirty(false), mNumGlyphs(0),
- mMesh(NULL), mCurrentQuad(0), mMaxQuadCount(maxQuadCount),
+ mMesh(nullptr), mCurrentQuad(0), mMaxQuadCount(maxQuadCount),
mCaches(Caches::getInstance()) {
mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE);
@@ -119,7 +120,7 @@ CacheTexture::CacheTexture(uint16_t width, uint16_t height, GLenum format, uint3
// OpenGL ES 3.0+ lets us specify the row length for unpack operations such
// as glTexSubImage2D(). This allows us to upload a sub-rectangle of a texture.
// With OpenGL ES 2.0 we have to upload entire stripes instead.
- mHasUnpackRowLength = Extensions::getInstance().hasUnpackRowLength();
+ mHasUnpackRowLength = mCaches.extensions().hasUnpackRowLength();
}
CacheTexture::~CacheTexture() {
@@ -130,7 +131,7 @@ CacheTexture::~CacheTexture() {
void CacheTexture::reset() {
// Delete existing cache blocks
- while (mCacheBlocks != NULL) {
+ while (mCacheBlocks != nullptr) {
CacheBlock* tmpBlock = mCacheBlocks;
mCacheBlocks = mCacheBlocks->mNext;
delete tmpBlock;
@@ -153,10 +154,10 @@ void CacheTexture::releaseMesh() {
void CacheTexture::releaseTexture() {
if (mTexture) {
delete mTexture;
- mTexture = NULL;
+ mTexture = nullptr;
}
if (mTextureId) {
- mCaches.deleteTexture(mTextureId);
+ mCaches.textureState().deleteTexture(mTextureId);
mTextureId = 0;
}
mDirty = false;
@@ -168,7 +169,7 @@ void CacheTexture::setLinearFiltering(bool linearFiltering, bool bind) {
mLinearFiltering = linearFiltering;
const GLenum filtering = linearFiltering ? GL_LINEAR : GL_NEAREST;
- if (bind) mCaches.bindTexture(getTextureId());
+ if (bind) mCaches.textureState().bindTexture(getTextureId());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
}
@@ -188,11 +189,11 @@ void CacheTexture::allocateTexture() {
if (!mTextureId) {
glGenTextures(1, &mTextureId);
- mCaches.bindTexture(mTextureId);
+ mCaches.textureState().bindTexture(mTextureId);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Initialize texture dimensions
glTexImage2D(GL_TEXTURE_2D, 0, mFormat, mWidth, mHeight, 0,
- mFormat, GL_UNSIGNED_BYTE, 0);
+ mFormat, GL_UNSIGNED_BYTE, nullptr);
const GLenum filtering = getLinearFiltering() ? GL_LINEAR : GL_NEAREST;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h
index 4cc4f22..5d3f959 100644
--- a/libs/hwui/font/CacheTexture.h
+++ b/libs/hwui/font/CacheTexture.h
@@ -23,7 +23,6 @@
#include <utils/Log.h>
-#include "FontUtil.h"
#include "../PixelBuffer.h"
#include "../Rect.h"
#include "../Vertex.h"
@@ -55,7 +54,7 @@ struct CacheBlock {
CacheBlock* mPrev;
CacheBlock(uint16_t x, uint16_t y, uint16_t width, uint16_t height):
- mX(x), mY(y), mWidth(width), mHeight(height), mNext(NULL), mPrev(NULL) {
+ mX(x), mY(y), mWidth(width), mHeight(height), mNext(nullptr), mPrev(nullptr) {
}
static CacheBlock* insertBlock(CacheBlock* head, CacheBlock* newBlock);
@@ -147,7 +146,7 @@ public:
}
uint16_t* indices() const {
- return (uint16_t*) 0;
+ return (uint16_t*) nullptr;
}
void resetMesh() {
diff --git a/libs/hwui/font/CachedGlyphInfo.h b/libs/hwui/font/CachedGlyphInfo.h
index 6680a00..0642d59 100644
--- a/libs/hwui/font/CachedGlyphInfo.h
+++ b/libs/hwui/font/CachedGlyphInfo.h
@@ -19,11 +19,11 @@
#include <SkFixed.h>
-#include "CacheTexture.h"
-
namespace android {
namespace uirenderer {
+class CacheTexture;
+
struct CachedGlyphInfo {
// Has the cache been invalidated?
bool mIsValid;
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index e1a38dd..b07a3c8 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -22,6 +22,7 @@
#include <utils/JenkinsHash.h>
#include <utils/Trace.h>
+#include <SkDeviceProperties.h>
#include <SkGlyph.h>
#include <SkGlyphCache.h>
#include <SkUtils.h>
@@ -41,9 +42,7 @@ namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
Font::Font(FontRenderer* state, const Font::FontDescription& desc) :
- mState(state), mDescription(desc) {
- mDeviceProperties = SkDeviceProperties::Make(SkDeviceProperties::Geometry::MakeDefault(), 1.0f);
-}
+ mState(state), mDescription(desc) { }
Font::FontDescription::FontDescription(const SkPaint* paint, const SkMatrix& rasterMatrix)
: mLookupTransform(rasterMatrix) {
@@ -139,8 +138,7 @@ void Font::invalidateTextureCache(CacheTexture* cacheTexture) {
}
void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y,
- uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds,
- const float* pos) {
+ uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
int width = (int) glyph->mBitmapWidth;
int height = (int) glyph->mBitmapHeight;
@@ -162,8 +160,7 @@ void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y,
}
void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
- uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds,
- const float* pos) {
+ uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
float width = (float) glyph->mBitmapWidth;
float height = (float) glyph->mBitmapHeight;
@@ -182,8 +179,7 @@ void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
}
void Font::drawCachedGlyphTransformed(CachedGlyphInfo* glyph, int x, int y,
- uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds,
- const float* pos) {
+ uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
float width = (float) glyph->mBitmapWidth;
float height = (float) glyph->mBitmapHeight;
@@ -213,8 +209,7 @@ void Font::drawCachedGlyphTransformed(CachedGlyphInfo* glyph, int x, int y,
}
void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y, uint8_t* bitmap,
- uint32_t bitmapWidth, uint32_t bitmapHeight, Rect* bounds,
- const float* pos) {
+ uint32_t bitmapWidth, uint32_t bitmapHeight, Rect* bounds, const float* pos) {
int dstX = x + glyph->mBitmapLeft;
int dstY = y + glyph->mBitmapTop;
@@ -289,7 +284,8 @@ CachedGlyphInfo* Font::getCachedGlyph(const SkPaint* paint, glyph_t textUnit, bo
if (cachedGlyph) {
// Is the glyph still in texture cache?
if (!cachedGlyph->mIsValid) {
- SkAutoGlyphCache autoCache(*paint, &mDeviceProperties, &mDescription.mLookupTransform);
+ SkDeviceProperties deviceProperties(kUnknown_SkPixelGeometry, 1.0f);
+ SkAutoGlyphCache autoCache(*paint, &deviceProperties, &mDescription.mLookupTransform);
const SkGlyph& skiaGlyph = GET_METRICS(autoCache.getCache(), textUnit);
updateGlyphCache(paint, skiaGlyph, autoCache.getCache(), cachedGlyph, precaching);
}
@@ -302,13 +298,13 @@ CachedGlyphInfo* Font::getCachedGlyph(const SkPaint* paint, glyph_t textUnit, bo
void Font::render(const SkPaint* paint, const char *text, uint32_t start, uint32_t len,
int numGlyphs, int x, int y, const float* positions) {
- render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, NULL,
- 0, 0, NULL, positions);
+ render(paint, text, start, len, numGlyphs, x, y, FRAMEBUFFER, nullptr,
+ 0, 0, nullptr, positions);
}
void Font::render(const SkPaint* paint, const char *text, uint32_t start, uint32_t len,
int numGlyphs, const SkPath* path, float hOffset, float vOffset) {
- if (numGlyphs == 0 || text == NULL || len == 0) {
+ if (numGlyphs == 0 || text == nullptr || len == 0) {
return;
}
@@ -358,18 +354,18 @@ void Font::render(const SkPaint* paint, const char *text, uint32_t start, uint32
void Font::measure(const SkPaint* paint, const char* text, uint32_t start, uint32_t len,
int numGlyphs, Rect *bounds, const float* positions) {
- if (bounds == NULL) {
+ if (bounds == nullptr) {
ALOGE("No return rectangle provided to measure text");
return;
}
bounds->set(1e6, -1e6, -1e6, 1e6);
- render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds, positions);
+ render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, nullptr, 0, 0, bounds, positions);
}
void Font::precache(const SkPaint* paint, const char* text, int numGlyphs) {
ATRACE_NAME("Precache Glyphs");
- if (numGlyphs == 0 || text == NULL) {
+ if (numGlyphs == 0 || text == nullptr) {
return;
}
@@ -390,7 +386,7 @@ void Font::precache(const SkPaint* paint, const char* text, int numGlyphs) {
void Font::render(const SkPaint* paint, const char* text, uint32_t start, uint32_t len,
int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* positions) {
- if (numGlyphs == 0 || text == NULL || len == 0) {
+ if (numGlyphs == 0 || text == nullptr || len == 0) {
return;
}
@@ -479,7 +475,8 @@ CachedGlyphInfo* Font::cacheGlyph(const SkPaint* paint, glyph_t glyph, bool prec
CachedGlyphInfo* newGlyph = new CachedGlyphInfo();
mCachedGlyphs.add(glyph, newGlyph);
- SkAutoGlyphCache autoCache(*paint, &mDeviceProperties, &mDescription.mLookupTransform);
+ SkDeviceProperties deviceProperties(kUnknown_SkPixelGeometry, 1.0f);
+ SkAutoGlyphCache autoCache(*paint, &deviceProperties, &mDescription.mLookupTransform);
const SkGlyph& skiaGlyph = GET_METRICS(autoCache.getCache(), glyph);
newGlyph->mIsValid = false;
newGlyph->mGlyphIndex = skiaGlyph.fID;
diff --git a/libs/hwui/font/Font.h b/libs/hwui/font/Font.h
index 0f10464..3119d73 100644
--- a/libs/hwui/font/Font.h
+++ b/libs/hwui/font/Font.h
@@ -22,13 +22,12 @@
#include <utils/KeyedVector.h>
#include <SkScalar.h>
-#include <SkDeviceProperties.h>
#include <SkGlyphCache.h>
#include <SkScalerContext.h>
#include <SkPaint.h>
#include <SkPathMeasure.h>
-#include "CachedGlyphInfo.h"
+#include "FontUtil.h"
#include "../Rect.h"
#include "../Matrix.h"
@@ -39,6 +38,8 @@ namespace uirenderer {
// Font
///////////////////////////////////////////////////////////////////////////////
+struct CachedGlyphInfo;
+class CacheTexture;
class FontRenderer;
/**
@@ -119,7 +120,7 @@ private:
void measure(const SkPaint* paint, const char* text, uint32_t start, uint32_t len,
int numGlyphs, Rect *bounds, const float* positions);
- void invalidateTextureCache(CacheTexture* cacheTexture = NULL);
+ void invalidateTextureCache(CacheTexture* cacheTexture = nullptr);
CachedGlyphInfo* cacheGlyph(const SkPaint* paint, glyph_t glyph, bool precaching);
void updateGlyphCache(const SkPaint* paint, const SkGlyph& skiaGlyph,
@@ -150,7 +151,6 @@ private:
DefaultKeyedVector<glyph_t, CachedGlyphInfo*> mCachedGlyphs;
bool mIdentityTransform;
- SkDeviceProperties mDeviceProperties;
};
inline int strictly_order_type(const Font::FontDescription& lhs,
diff --git a/libs/hwui/renderstate/Blend.cpp b/libs/hwui/renderstate/Blend.cpp
new file mode 100644
index 0000000..c751dba
--- /dev/null
+++ b/libs/hwui/renderstate/Blend.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2015 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 <renderstate/Blend.h>
+#include "Program.h"
+
+#include "ShadowTessellator.h"
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * Structure mapping Skia xfermodes to OpenGL blending factors.
+ */
+struct Blender {
+ SkXfermode::Mode mode;
+ GLenum src;
+ GLenum dst;
+};
+
+// In this array, the index of each Blender equals the value of the first
+// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
+const Blender kBlends[] = {
+ { SkXfermode::kClear_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kSrc_Mode, GL_ONE, GL_ZERO },
+ { SkXfermode::kDst_Mode, GL_ZERO, GL_ONE },
+ { SkXfermode::kSrcOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE },
+ { SkXfermode::kSrcIn_Mode, GL_DST_ALPHA, GL_ZERO },
+ { SkXfermode::kDstIn_Mode, GL_ZERO, GL_SRC_ALPHA },
+ { SkXfermode::kSrcOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
+ { SkXfermode::kDstOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kSrcATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kDstATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
+ { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kPlus_Mode, GL_ONE, GL_ONE },
+ { SkXfermode::kModulate_Mode, GL_ZERO, GL_SRC_COLOR },
+ { SkXfermode::kScreen_Mode, GL_ONE, GL_ONE_MINUS_SRC_COLOR }
+};
+
+// This array contains the swapped version of each SkXfermode. For instance
+// this array's SrcOver blending mode is actually DstOver. You can refer to
+// createLayer() for more information on the purpose of this array.
+const Blender kBlendsSwap[] = {
+ { SkXfermode::kClear_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
+ { SkXfermode::kSrc_Mode, GL_ZERO, GL_ONE },
+ { SkXfermode::kDst_Mode, GL_ONE, GL_ZERO },
+ { SkXfermode::kSrcOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE },
+ { SkXfermode::kDstOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kSrcIn_Mode, GL_ZERO, GL_SRC_ALPHA },
+ { SkXfermode::kDstIn_Mode, GL_DST_ALPHA, GL_ZERO },
+ { SkXfermode::kSrcOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kDstOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
+ { SkXfermode::kSrcATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
+ { SkXfermode::kDstATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
+ { SkXfermode::kPlus_Mode, GL_ONE, GL_ONE },
+ { SkXfermode::kModulate_Mode, GL_DST_COLOR, GL_ZERO },
+ { SkXfermode::kScreen_Mode, GL_ONE_MINUS_DST_COLOR, GL_ONE }
+};
+
+Blend::Blend()
+ : mEnabled(false)
+ , mSrcMode(GL_ZERO)
+ , mDstMode(GL_ZERO) {
+ // gl blending off by default
+}
+
+void Blend::enable(SkXfermode::Mode mode, bool swapSrcDst) {
+ GLenum srcMode;
+ GLenum dstMode;
+ getFactors(mode, swapSrcDst, &srcMode, &dstMode);
+ setFactors(srcMode, dstMode);
+}
+
+void Blend::disable() {
+ if (mEnabled) {
+ glDisable(GL_BLEND);
+ mEnabled = false;
+ }
+}
+
+void Blend::invalidate() {
+ syncEnabled();
+ mSrcMode = mDstMode = GL_ZERO;
+}
+
+void Blend::syncEnabled() {
+ if (mEnabled) {
+ glEnable(GL_BLEND);
+ } else {
+ glDisable(GL_BLEND);
+ }
+}
+
+void Blend::getFactors(SkXfermode::Mode mode, bool swapSrcDst, GLenum* outSrc, GLenum* outDst) {
+ *outSrc = swapSrcDst ? kBlendsSwap[mode].src : kBlends[mode].src;
+ *outDst = swapSrcDst ? kBlendsSwap[mode].dst : kBlends[mode].dst;
+}
+
+void Blend::setFactors(GLenum srcMode, GLenum dstMode) {
+ if (srcMode == GL_ZERO && dstMode == GL_ZERO) {
+ disable();
+ } else {
+ if (!mEnabled) {
+ glEnable(GL_BLEND);
+ mEnabled = true;
+ }
+
+ if (srcMode != mSrcMode || dstMode != mSrcMode) {
+ glBlendFunc(srcMode, dstMode);
+ mSrcMode = srcMode;
+ mDstMode = dstMode;
+ }
+ }
+}
+
+void Blend::dump() {
+ ALOGD("Blend: enabled %d, func src %d, dst %d", mEnabled, mSrcMode, mDstMode);
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
+
diff --git a/libs/hwui/renderstate/Blend.h b/libs/hwui/renderstate/Blend.h
new file mode 100644
index 0000000..6d0c115
--- /dev/null
+++ b/libs/hwui/renderstate/Blend.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015 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 RENDERSTATE_BLEND_H
+#define RENDERSTATE_BLEND_H
+
+#include "Vertex.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <SkXfermode.h>
+#include <memory>
+
+namespace android {
+namespace uirenderer {
+
+class Blend {
+ friend class RenderState;
+public:
+ void enable(SkXfermode::Mode mode, bool swapSrcDst);
+ void disable();
+ void syncEnabled();
+
+ static void getFactors(SkXfermode::Mode mode, bool swapSrcDst, GLenum* outSrc, GLenum* outDst);
+ void setFactors(GLenum src, GLenum dst);
+
+ void dump();
+private:
+ Blend();
+ void invalidate();
+ bool mEnabled;
+ GLenum mSrcMode;
+ GLenum mDstMode;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // RENDERSTATE_BLEND_H
diff --git a/libs/hwui/renderstate/MeshState.cpp b/libs/hwui/renderstate/MeshState.cpp
new file mode 100644
index 0000000..ce6030d
--- /dev/null
+++ b/libs/hwui/renderstate/MeshState.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2015 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 "renderstate/MeshState.h"
+
+#include "Program.h"
+
+#include "ShadowTessellator.h"
+
+namespace android {
+namespace uirenderer {
+
+MeshState::MeshState()
+ : mCurrentIndicesBuffer(0)
+ , mCurrentPixelBuffer(0)
+ , mCurrentPositionPointer(this)
+ , mCurrentPositionStride(0)
+ , mCurrentTexCoordsPointer(this)
+ , mCurrentTexCoordsStride(0)
+ , mTexCoordsArrayEnabled(false)
+ , mQuadListIndices(0) {
+
+ glGenBuffers(1, &mUnitQuadBuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, mUnitQuadBuffer);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(kUnitQuadVertices), kUnitQuadVertices, GL_STATIC_DRAW);
+
+ mCurrentBuffer = mUnitQuadBuffer;
+
+ // position attribute always enabled
+ glEnableVertexAttribArray(Program::kBindingPosition);
+}
+
+MeshState::~MeshState() {
+ glDeleteBuffers(1, &mUnitQuadBuffer);
+ mCurrentBuffer = 0;
+
+ glDeleteBuffers(1, &mQuadListIndices);
+ mQuadListIndices = 0;
+}
+
+void MeshState::dump() {
+ ALOGD("MeshState vertices: unitQuad %d, current %d", mUnitQuadBuffer, mCurrentBuffer);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Buffer Objects
+///////////////////////////////////////////////////////////////////////////////
+
+bool MeshState::bindMeshBuffer() {
+ return bindMeshBuffer(mUnitQuadBuffer);
+}
+
+bool MeshState::bindMeshBuffer(GLuint buffer) {
+ if (!buffer) buffer = mUnitQuadBuffer;
+ return bindMeshBufferInternal(buffer);
+}
+
+bool MeshState::unbindMeshBuffer() {
+ return bindMeshBufferInternal(0);
+}
+
+bool MeshState::bindMeshBufferInternal(GLuint buffer) {
+ if (mCurrentBuffer != buffer) {
+ glBindBuffer(GL_ARRAY_BUFFER, buffer);
+ mCurrentBuffer = buffer;
+ return true;
+ }
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Vertices
+///////////////////////////////////////////////////////////////////////////////
+
+void MeshState::bindPositionVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
+ if (force || vertices != mCurrentPositionPointer || stride != mCurrentPositionStride) {
+ glVertexAttribPointer(Program::kBindingPosition, 2, GL_FLOAT, GL_FALSE, stride, vertices);
+ mCurrentPositionPointer = vertices;
+ mCurrentPositionStride = stride;
+ }
+}
+
+void MeshState::bindTexCoordsVertexPointer(bool force, const GLvoid* vertices, GLsizei stride) {
+ if (force || vertices != mCurrentTexCoordsPointer || stride != mCurrentTexCoordsStride) {
+ glVertexAttribPointer(Program::kBindingTexCoords, 2, GL_FLOAT, GL_FALSE, stride, vertices);
+ mCurrentTexCoordsPointer = vertices;
+ mCurrentTexCoordsStride = stride;
+ }
+}
+
+void MeshState::resetVertexPointers() {
+ mCurrentPositionPointer = this;
+ mCurrentTexCoordsPointer = this;
+}
+
+void MeshState::resetTexCoordsVertexPointer() {
+ mCurrentTexCoordsPointer = this;
+}
+
+void MeshState::enableTexCoordsVertexArray() {
+ if (!mTexCoordsArrayEnabled) {
+ glEnableVertexAttribArray(Program::kBindingTexCoords);
+ mCurrentTexCoordsPointer = this;
+ mTexCoordsArrayEnabled = true;
+ }
+}
+
+void MeshState::disableTexCoordsVertexArray() {
+ if (mTexCoordsArrayEnabled) {
+ glDisableVertexAttribArray(Program::kBindingTexCoords);
+ mTexCoordsArrayEnabled = false;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Indices
+///////////////////////////////////////////////////////////////////////////////
+
+bool MeshState::bindIndicesBufferInternal(const GLuint buffer) {
+ if (mCurrentIndicesBuffer != buffer) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
+ mCurrentIndicesBuffer = buffer;
+ return true;
+ }
+ return false;
+}
+
+bool MeshState::bindQuadIndicesBuffer() {
+ if (!mQuadListIndices) {
+ std::unique_ptr<uint16_t[]> regionIndices(new uint16_t[kMaxNumberOfQuads * 6]);
+ for (uint32_t i = 0; i < kMaxNumberOfQuads; i++) {
+ uint16_t quad = i * 4;
+ int index = i * 6;
+ regionIndices[index ] = quad; // top-left
+ regionIndices[index + 1] = quad + 1; // top-right
+ regionIndices[index + 2] = quad + 2; // bottom-left
+ regionIndices[index + 3] = quad + 2; // bottom-left
+ regionIndices[index + 4] = quad + 1; // top-right
+ regionIndices[index + 5] = quad + 3; // bottom-right
+ }
+
+ glGenBuffers(1, &mQuadListIndices);
+ bool force = bindIndicesBufferInternal(mQuadListIndices);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, kMaxNumberOfQuads * 6 * sizeof(uint16_t),
+ regionIndices.get(), GL_STATIC_DRAW);
+ return force;
+ }
+
+ return bindIndicesBufferInternal(mQuadListIndices);
+}
+
+bool MeshState::unbindIndicesBuffer() {
+ if (mCurrentIndicesBuffer) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ mCurrentIndicesBuffer = 0;
+ return true;
+ }
+ return false;
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
+
diff --git a/libs/hwui/renderstate/MeshState.h b/libs/hwui/renderstate/MeshState.h
new file mode 100644
index 0000000..afc6267
--- /dev/null
+++ b/libs/hwui/renderstate/MeshState.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2015 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 RENDERSTATE_MESHSTATE_H
+#define RENDERSTATE_MESHSTATE_H
+
+#include "Vertex.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <memory>
+
+namespace android {
+namespace uirenderer {
+
+class Program;
+
+// Maximum number of quads that pre-allocated meshes can draw
+const uint32_t kMaxNumberOfQuads = 2048;
+
+// This array is never used directly but used as a memcpy source in the
+// OpenGLRenderer constructor
+const TextureVertex kUnitQuadVertices[] = {
+ { 0, 0, 0, 0 },
+ { 1, 0, 1, 0 },
+ { 0, 1, 0, 1 },
+ { 1, 1, 1, 1 },
+};
+
+const GLsizei kVertexStride = sizeof(Vertex);
+const GLsizei kAlphaVertexStride = sizeof(AlphaVertex);
+const GLsizei kTextureVertexStride = sizeof(TextureVertex);
+
+const GLsizei kMeshTextureOffset = 2 * sizeof(float);
+const GLsizei kVertexAlphaOffset = 2 * sizeof(float);
+const GLsizei kVertexAAWidthOffset = 2 * sizeof(float);
+const GLsizei kVertexAALengthOffset = 3 * sizeof(float);
+const GLsizei kUnitQuadCount = 4;
+
+class MeshState {
+private:
+ friend class RenderState;
+
+public:
+ ~MeshState();
+ void dump();
+ ///////////////////////////////////////////////////////////////////////////////
+ // Buffer objects
+ ///////////////////////////////////////////////////////////////////////////////
+ /**
+ * Binds the VBO used to render simple textured quads.
+ */
+ bool bindMeshBuffer();
+
+ /**
+ * Binds the specified VBO if needed. If buffer == 0, binds default simple textured quad.
+ */
+ bool bindMeshBuffer(GLuint buffer);
+
+ /**
+ * Unbinds the VBO used to render simple textured quads.
+ */
+ bool unbindMeshBuffer();
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // Vertices
+ ///////////////////////////////////////////////////////////////////////////////
+ /**
+ * Binds an attrib to the specified float vertex pointer.
+ * Assumes a stride of gTextureVertexStride and a size of 2.
+ */
+ void bindPositionVertexPointer(bool force, const GLvoid* vertices,
+ GLsizei stride = kTextureVertexStride);
+
+ /**
+ * Binds an attrib to the specified float vertex pointer.
+ * Assumes a stride of gTextureVertexStride and a size of 2.
+ */
+ void bindTexCoordsVertexPointer(bool force, const GLvoid* vertices,
+ GLsizei stride = kTextureVertexStride);
+
+ /**
+ * Resets the vertex pointers.
+ */
+ void resetVertexPointers();
+ void resetTexCoordsVertexPointer();
+
+ void enableTexCoordsVertexArray();
+ void disableTexCoordsVertexArray();
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // Indices
+ ///////////////////////////////////////////////////////////////////////////////
+ /**
+ * Binds a global indices buffer that can draw up to
+ * gMaxNumberOfQuads quads.
+ */
+ bool bindQuadIndicesBuffer();
+ bool unbindIndicesBuffer();
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // Getters - for use in Glop building
+ ///////////////////////////////////////////////////////////////////////////////
+ GLuint getUnitQuadVBO() { return mUnitQuadBuffer; }
+private:
+ MeshState();
+ bool bindMeshBufferInternal(const GLuint buffer);
+ bool bindIndicesBufferInternal(const GLuint buffer);
+
+ GLuint mUnitQuadBuffer;
+
+ GLuint mCurrentBuffer;
+ GLuint mCurrentIndicesBuffer;
+ GLuint mCurrentPixelBuffer;
+
+ const void* mCurrentPositionPointer;
+ GLsizei mCurrentPositionStride;
+ const void* mCurrentTexCoordsPointer;
+ GLsizei mCurrentTexCoordsStride;
+
+ bool mTexCoordsArrayEnabled;
+
+ // Global index buffer
+ GLuint mQuadListIndices;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // RENDERSTATE_MESHSTATE_H
diff --git a/libs/hwui/renderstate/PixelBufferState.cpp b/libs/hwui/renderstate/PixelBufferState.cpp
new file mode 100644
index 0000000..c23af52
--- /dev/null
+++ b/libs/hwui/renderstate/PixelBufferState.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015 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 "renderstate/PixelBufferState.h"
+
+namespace android {
+namespace uirenderer {
+
+PixelBufferState::PixelBufferState()
+ : mCurrentPixelBuffer(0) {
+}
+
+bool PixelBufferState::bind(GLuint buffer) {
+ if (mCurrentPixelBuffer != buffer) {
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer);
+ mCurrentPixelBuffer = buffer;
+ return true;
+ }
+ return false;
+}
+
+bool PixelBufferState::unbind() {
+ if (mCurrentPixelBuffer) {
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+ mCurrentPixelBuffer = 0;
+ return true;
+ }
+ return false;
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
+
diff --git a/libs/hwui/renderstate/PixelBufferState.h b/libs/hwui/renderstate/PixelBufferState.h
new file mode 100644
index 0000000..8dab21d
--- /dev/null
+++ b/libs/hwui/renderstate/PixelBufferState.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 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 RENDERSTATE_PIXELBUFFERSTATE_H
+#define RENDERSTATE_PIXELBUFFERSTATE_H
+
+#include <GLES3/gl3.h>
+
+namespace android {
+namespace uirenderer {
+
+class PixelBufferState {
+ friend class Caches; // TODO: move to RenderState
+public:
+ bool bind(GLuint buffer);
+ bool unbind();
+private:
+ PixelBufferState();
+ GLuint mCurrentPixelBuffer;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // RENDERSTATE_PIXELBUFFERSTATE_H
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
new file mode 100644
index 0000000..ba49833
--- /dev/null
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2014 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 "renderstate/RenderState.h"
+
+#include "renderthread/CanvasContext.h"
+#include "renderthread/EglManager.h"
+#include "utils/GLUtils.h"
+
+namespace android {
+namespace uirenderer {
+
+RenderState::RenderState(renderthread::RenderThread& thread)
+ : mRenderThread(thread)
+ , mViewportWidth(0)
+ , mViewportHeight(0)
+ , mFramebuffer(0) {
+ mThreadId = pthread_self();
+}
+
+RenderState::~RenderState() {
+ LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
+ "State object lifecycle not managed correctly");
+}
+
+void RenderState::onGLContextCreated() {
+ LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
+ "State object lifecycle not managed correctly");
+ mBlend = new Blend();
+ mMeshState = new MeshState();
+ mScissor = new Scissor();
+ mStencil = new Stencil();
+
+ // This is delayed because the first access of Caches makes GL calls
+ if (!mCaches) {
+ mCaches = &Caches::createInstance(*this);
+ }
+ mCaches->init();
+ mCaches->textureCache.setAssetAtlas(&mAssetAtlas);
+}
+
+static void layerLostGlContext(Layer* layer) {
+ layer->onGlContextLost();
+}
+
+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);
+ }
+*/
+
+ // TODO: reset all cached state in state objects
+ std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerLostGlContext);
+ mAssetAtlas.terminate();
+
+ mCaches->terminate();
+
+ delete mBlend;
+ mBlend = nullptr;
+ delete mMeshState;
+ mMeshState = nullptr;
+ delete mScissor;
+ mScissor = nullptr;
+ delete mStencil;
+ mStencil = nullptr;
+}
+
+void RenderState::setViewport(GLsizei width, GLsizei height) {
+ mViewportWidth = width;
+ mViewportHeight = height;
+ glViewport(0, 0, mViewportWidth, mViewportHeight);
+}
+
+
+void RenderState::getViewport(GLsizei* outWidth, GLsizei* outHeight) {
+ *outWidth = mViewportWidth;
+ *outHeight = mViewportHeight;
+}
+
+void RenderState::bindFramebuffer(GLuint fbo) {
+ if (mFramebuffer != fbo) {
+ mFramebuffer = fbo;
+ glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
+ }
+}
+
+void RenderState::invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlInfo* info) {
+ interruptForFunctorInvoke();
+ (*functor)(mode, info);
+ resumeFromFunctorInvoke();
+}
+
+void RenderState::interruptForFunctorInvoke() {
+ mCaches->setProgram(nullptr);
+ mCaches->textureState().resetActiveTexture();
+ meshState().unbindMeshBuffer();
+ meshState().unbindIndicesBuffer();
+ meshState().resetVertexPointers();
+ meshState().disableTexCoordsVertexArray();
+ debugOverdraw(false, false);
+}
+
+void RenderState::resumeFromFunctorInvoke() {
+ glViewport(0, 0, mViewportWidth, mViewportHeight);
+ glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
+ debugOverdraw(false, false);
+
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+ scissor().invalidate();
+ blend().invalidate();
+
+ mCaches->textureState().activateTexture(0);
+ mCaches->textureState().resetBoundTextures();
+}
+
+void RenderState::debugOverdraw(bool enable, bool clear) {
+ if (mCaches->debugOverdraw && mFramebuffer == 0) {
+ if (clear) {
+ scissor().setEnabled(false);
+ stencil().clear();
+ }
+ if (enable) {
+ stencil().enableDebugWrite();
+ } else {
+ stencil().disable();
+ }
+ }
+}
+
+void RenderState::requireGLContext() {
+ assertOnGLThread();
+ mRenderThread.eglManager().requireGlContext();
+}
+
+void RenderState::assertOnGLThread() {
+ pthread_t curr = pthread_self();
+ LOG_ALWAYS_FATAL_IF(!pthread_equal(mThreadId, curr), "Wrong thread!");
+}
+
+class DecStrongTask : public renderthread::RenderTask {
+public:
+ DecStrongTask(VirtualLightRefBase* object) : mObject(object) {}
+
+ virtual void run() override {
+ mObject->decStrong(nullptr);
+ mObject = nullptr;
+ delete this;
+ }
+
+private:
+ VirtualLightRefBase* mObject;
+};
+
+void RenderState::postDecStrong(VirtualLightRefBase* object) {
+ mRenderThread.queue(new DecStrongTask(object));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Render
+///////////////////////////////////////////////////////////////////////////////
+
+/*
+ * Not yet supported:
+ *
+ * Textures + coordinates
+ * SkiaShader
+ * ColorFilter
+ *
+ // TODO: texture coord
+ // TODO: texture support
+ // TODO: skiashader support
+ // TODO: color filter support
+ */
+
+void RenderState::render(const Glop& glop) {
+ const Glop::Mesh& mesh = glop.mesh;
+ const Glop::Fill& shader = glop.fill;
+
+ // --------------------------------------------
+ // ---------- Shader + uniform setup ----------
+ // --------------------------------------------
+ mCaches->setProgram(shader.program);
+
+ Glop::FloatColor color = shader.color;
+ shader.program->setColor(color.r, color.g, color.b, color.a);
+
+ shader.program->set(glop.transform.ortho,
+ glop.transform.modelView,
+ glop.transform.canvas,
+ glop.transform.fudgingOffset);
+
+ if (glop.fill.filterMode == ProgramDescription::kColorBlend) {
+ const Glop::FloatColor& color = glop.fill.filter.color;
+ glUniform4f(mCaches->program().getUniform("colorBlend"),
+ color.r, color.g, color.b, color.a);
+ } else if (glop.fill.filterMode == ProgramDescription::kColorMatrix) {
+ glUniformMatrix4fv(mCaches->program().getUniform("colorMatrix"), 1, GL_FALSE,
+ glop.fill.filter.matrix.matrix);
+ glUniform4fv(mCaches->program().getUniform("colorMatrixVector"), 1,
+ glop.fill.filter.matrix.vector);
+ }
+
+ // --------------------------------
+ // ---------- Mesh setup ----------
+ // --------------------------------
+ // vertices
+ bool force = meshState().bindMeshBufferInternal(mesh.vertexBufferObject)
+ || (mesh.vertices != nullptr);
+ meshState().bindPositionVertexPointer(force, mesh.vertices, mesh.stride);
+
+ // indices
+ meshState().bindIndicesBufferInternal(mesh.indexBufferObject);
+
+ if (glop.mesh.vertexFlags & kTextureCoord_Attrib) {
+ // TODO: support textures
+ LOG_ALWAYS_FATAL("textures not yet supported");
+ } else {
+ meshState().disableTexCoordsVertexArray();
+ }
+ if (glop.mesh.vertexFlags & kColor_Attrib) {
+ LOG_ALWAYS_FATAL("color vertex attribute not yet supported");
+ // TODO: enable color, disable when done
+ }
+ int alphaSlot = -1;
+ if (glop.mesh.vertexFlags & kAlpha_Attrib) {
+ const void* alphaCoords = ((const GLbyte*) glop.mesh.vertices) + kVertexAlphaOffset;
+ alphaSlot = shader.program->getAttrib("vtxAlpha");
+ glEnableVertexAttribArray(alphaSlot);
+ glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, kAlphaVertexStride, alphaCoords);
+ }
+
+ // ------------------------------------
+ // ---------- GL state setup ----------
+ // ------------------------------------
+ blend().setFactors(glop.blend.src, glop.blend.dst);
+
+ // ------------------------------------
+ // ---------- GL state setup ----------
+ // ------------------------------------
+ if (mesh.indexBufferObject || mesh.indices) {
+ glDrawElements(glop.mesh.primitiveMode, glop.mesh.vertexCount,
+ GL_UNSIGNED_SHORT, mesh.indices);
+ } else {
+ glDrawArrays(glop.mesh.primitiveMode, 0, glop.mesh.vertexCount);
+ }
+
+ if (glop.mesh.vertexFlags & kAlpha_Attrib) {
+ glDisableVertexAttribArray(alphaSlot);
+ }
+}
+
+void RenderState::dump() {
+ blend().dump();
+ meshState().dump();
+ scissor().dump();
+ stencil().dump();
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/RenderState.h b/libs/hwui/renderstate/RenderState.h
index 9ac9356..4fd792c 100644
--- a/libs/hwui/RenderState.h
+++ b/libs/hwui/renderstate/RenderState.h
@@ -20,16 +20,26 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <utils/Mutex.h>
-
+#include <utils/Functor.h>
+#include <utils/RefBase.h>
#include <private/hwui/DrawGlInfo.h>
+#include <renderstate/Blend.h>
#include "AssetAtlas.h"
#include "Caches.h"
+#include "Glop.h"
+#include "renderstate/MeshState.h"
+#include "renderstate/PixelBufferState.h"
+#include "renderstate/Scissor.h"
+#include "renderstate/Stencil.h"
#include "utils/Macros.h"
namespace android {
namespace uirenderer {
+class Caches;
+class Layer;
+
namespace renderthread {
class CanvasContext;
class RenderThread;
@@ -74,8 +84,15 @@ public:
// more thinking...
void postDecStrong(VirtualLightRefBase* object);
+ void render(const Glop& glop);
+
AssetAtlas& assetAtlas() { return mAssetAtlas; }
+ Blend& blend() { return *mBlend; }
+ MeshState& meshState() { return *mMeshState; }
+ Scissor& scissor() { return *mScissor; }
+ Stencil& stencil() { return *mStencil; }
+ void dump();
private:
friend class renderthread::RenderThread;
friend class Caches;
@@ -87,8 +104,15 @@ private:
RenderState(renderthread::RenderThread& thread);
~RenderState();
+
renderthread::RenderThread& mRenderThread;
- Caches* mCaches;
+ Caches* mCaches = nullptr;
+
+ Blend* mBlend = nullptr;
+ MeshState* mMeshState = nullptr;
+ Scissor* mScissor = nullptr;
+ Stencil* mStencil = nullptr;
+
AssetAtlas mAssetAtlas;
std::set<Layer*> mActiveLayers;
std::set<renderthread::CanvasContext*> mRegisteredContexts;
diff --git a/libs/hwui/renderstate/Scissor.cpp b/libs/hwui/renderstate/Scissor.cpp
new file mode 100644
index 0000000..95dcd18
--- /dev/null
+++ b/libs/hwui/renderstate/Scissor.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 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 "renderstate/Scissor.h"
+
+#include <utils/Log.h>
+
+namespace android {
+namespace uirenderer {
+
+Scissor::Scissor()
+ : mEnabled(false)
+ , mScissorX(0)
+ , mScissorY(0)
+ , mScissorWidth(0)
+ , mScissorHeight(0) {
+}
+
+bool Scissor::setEnabled(bool enabled) {
+ if (mEnabled != enabled) {
+ if (enabled) {
+ glEnable(GL_SCISSOR_TEST);
+ } else {
+ glDisable(GL_SCISSOR_TEST);
+ }
+ mEnabled = enabled;
+ return true;
+ }
+ return false;
+}
+
+bool Scissor::set(GLint x, GLint y, GLint width, GLint height) {
+ if (mEnabled && (x != mScissorX || y != mScissorY
+ || width != mScissorWidth || height != mScissorHeight)) {
+
+ if (x < 0) {
+ width += x;
+ x = 0;
+ }
+ if (y < 0) {
+ height += y;
+ y = 0;
+ }
+ if (width < 0) {
+ width = 0;
+ }
+ if (height < 0) {
+ height = 0;
+ }
+ glScissor(x, y, width, height);
+
+ mScissorX = x;
+ mScissorY = y;
+ mScissorWidth = width;
+ mScissorHeight = height;
+
+ return true;
+ }
+ return false;
+}
+
+void Scissor::reset() {
+ mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
+}
+
+void Scissor::invalidate() {
+ mEnabled = glIsEnabled(GL_SCISSOR_TEST);
+ setEnabled(true);
+ reset();
+}
+
+void Scissor::dump() {
+ ALOGD("Scissor: enabled %d, %d %d %d %d",
+ mEnabled, mScissorX, mScissorY, mScissorWidth, mScissorHeight);
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
+
diff --git a/libs/hwui/renderstate/Scissor.h b/libs/hwui/renderstate/Scissor.h
new file mode 100644
index 0000000..b37ec58
--- /dev/null
+++ b/libs/hwui/renderstate/Scissor.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 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 RENDERSTATE_SCISSOR_H
+#define RENDERSTATE_SCISSOR_H
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+namespace android {
+namespace uirenderer {
+
+class Scissor {
+ friend class RenderState;
+public:
+ bool setEnabled(bool enabled);
+ bool set(GLint x, GLint y, GLint width, GLint height);
+ void reset();
+ bool isEnabled() { return mEnabled; }
+ void dump();
+private:
+ Scissor();
+ void invalidate();
+ bool mEnabled;
+ GLint mScissorX;
+ GLint mScissorY;
+ GLint mScissorWidth;
+ GLint mScissorHeight;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // RENDERSTATE_SCISSOR_H
diff --git a/libs/hwui/Stencil.cpp b/libs/hwui/renderstate/Stencil.cpp
index 8ce57db..cedb233 100644
--- a/libs/hwui/Stencil.cpp
+++ b/libs/hwui/renderstate/Stencil.cpp
@@ -14,10 +14,12 @@
* limitations under the License.
*/
+#include "renderstate/Stencil.h"
+
+#include "Caches.h"
#include "Debug.h"
#include "Extensions.h"
#include "Properties.h"
-#include "Stencil.h"
#include <GLES2/gl2ext.h>
@@ -32,7 +34,8 @@ namespace uirenderer {
#define STENCIL_MASK_VALUE 0x1
#endif
-Stencil::Stencil(): mState(kDisabled) {
+Stencil::Stencil()
+ : mState(kDisabled) {
}
uint8_t Stencil::getStencilSize() {
@@ -41,7 +44,7 @@ uint8_t Stencil::getStencilSize() {
GLenum Stencil::getSmallestStencilFormat() {
#if !DEBUG_STENCIL
- const Extensions& extensions = Extensions::getInstance();
+ const Extensions& extensions = Caches::getInstance().extensions();
if (extensions.has1BitStencil()) {
return GL_STENCIL_INDEX1_OES;
} else if (extensions.has4BitStencil()) {
@@ -56,24 +59,36 @@ void Stencil::clear() {
glClear(GL_STENCIL_BUFFER_BIT);
}
-void Stencil::enableTest() {
+void Stencil::enableTest(int incrementThreshold) {
if (mState != kTest) {
enable();
- glStencilFunc(GL_EQUAL, STENCIL_WRITE_VALUE, STENCIL_MASK_VALUE);
+ if (incrementThreshold > 0) {
+ glStencilFunc(GL_EQUAL, incrementThreshold, 0xff);
+ } else {
+ glStencilFunc(GL_EQUAL, STENCIL_WRITE_VALUE, STENCIL_MASK_VALUE);
+ }
// We only want to test, let's keep everything
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glStencilMask(0);
mState = kTest;
}
}
-void Stencil::enableWrite() {
+void Stencil::enableWrite(int incrementThreshold) {
if (mState != kWrite) {
enable();
- glStencilFunc(GL_ALWAYS, STENCIL_WRITE_VALUE, STENCIL_MASK_VALUE);
- // The test always passes so the first two values are meaningless
- glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+ if (incrementThreshold > 0) {
+ glStencilFunc(GL_ALWAYS, 1, 0xff);
+ // The test always passes so the first two values are meaningless
+ glStencilOp(GL_INCR, GL_INCR, GL_INCR);
+ } else {
+ glStencilFunc(GL_ALWAYS, STENCIL_WRITE_VALUE, STENCIL_MASK_VALUE);
+ // The test always passes so the first two values are meaningless
+ glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+ }
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+ glStencilMask(0xff);
mState = kWrite;
}
}
@@ -110,5 +125,9 @@ void Stencil::disable() {
}
}
+void Stencil::dump() {
+ ALOGD("Stencil: state %d", mState);
+}
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/Stencil.h b/libs/hwui/renderstate/Stencil.h
index c5e5186..a88beae 100644
--- a/libs/hwui/Stencil.h
+++ b/libs/hwui/renderstate/Stencil.h
@@ -53,17 +53,21 @@ public:
void clear();
/**
- * Enables stencil test. When the stencil test is enabled the stencil
- * buffer is not written into.
+ * Enables stencil test. When the stencil test is enabled the stencil buffer is not written
+ * into. An increment threshold of zero causes the stencil to use a constant reference value
+ * and GL_EQUAL for the test. A non-zero increment threshold causes the stencil to use that
+ * value as the reference value and GL_EQUAL for the test.
*/
- void enableTest();
+ void enableTest(int incrementThreshold);
/**
* Enables stencil write. When stencil write is enabled, the stencil
* test always succeeds and the value 0x1 is written in the stencil
- * buffer for each fragment.
+ * buffer for each fragment. An increment threshold of zero causes the stencil to use a constant
+ * reference value and GL_EQUAL for the test. A non-zero increment threshold causes the stencil
+ * to use that value as the reference value and GL_EQUAL for the test.
*/
- void enableWrite();
+ void enableWrite(int incrementThreshold);
/**
* The test passes only when equal to the specified value.
@@ -94,6 +98,8 @@ public:
return mState == kTest;
}
+ void dump();
+
private:
void enable();
diff --git a/libs/hwui/renderstate/TextureState.cpp b/libs/hwui/renderstate/TextureState.cpp
new file mode 100644
index 0000000..1a638d2
--- /dev/null
+++ b/libs/hwui/renderstate/TextureState.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2015 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 <renderstate/TextureState.h>
+
+namespace android {
+namespace uirenderer {
+
+// Must define as many texture units as specified by kTextureUnitsCount
+const GLenum kTextureUnits[] = {
+ GL_TEXTURE0,
+ GL_TEXTURE1,
+ GL_TEXTURE2
+};
+
+TextureState::TextureState()
+ : mTextureUnit(0) {
+ glActiveTexture(kTextureUnits[0]);
+ resetBoundTextures();
+
+ GLint maxTextureUnits;
+ glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
+ LOG_ALWAYS_FATAL_IF(maxTextureUnits < kTextureUnitsCount,
+ "At least %d texture units are required!", kTextureUnitsCount);
+}
+
+void TextureState::activateTexture(GLuint textureUnit) {
+ if (mTextureUnit != textureUnit) {
+ glActiveTexture(kTextureUnits[textureUnit]);
+ mTextureUnit = textureUnit;
+ }
+}
+
+void TextureState::resetActiveTexture() {
+ mTextureUnit = -1;
+}
+
+void TextureState::bindTexture(GLuint texture) {
+ if (mBoundTextures[mTextureUnit] != texture) {
+ glBindTexture(GL_TEXTURE_2D, texture);
+ mBoundTextures[mTextureUnit] = texture;
+ }
+}
+
+void TextureState::bindTexture(GLenum target, GLuint texture) {
+ if (target == GL_TEXTURE_2D) {
+ bindTexture(texture);
+ } else {
+ // GLConsumer directly calls glBindTexture() with
+ // target=GL_TEXTURE_EXTERNAL_OES, don't cache this target
+ // since the cached state could be stale
+ glBindTexture(target, texture);
+ }
+}
+
+void TextureState::deleteTexture(GLuint texture) {
+ // When glDeleteTextures() is called on a currently bound texture,
+ // OpenGL ES specifies that the texture is then considered unbound
+ // Consider the following series of calls:
+ //
+ // glGenTextures -> creates texture name 2
+ // glBindTexture(2)
+ // glDeleteTextures(2) -> 2 is now unbound
+ // glGenTextures -> can return 2 again
+ //
+ // If we don't call glBindTexture(2) after the second glGenTextures
+ // call, any texture operation will be performed on the default
+ // texture (name=0)
+
+ unbindTexture(texture);
+
+ glDeleteTextures(1, &texture);
+}
+
+void TextureState::resetBoundTextures() {
+ for (int i = 0; i < kTextureUnitsCount; i++) {
+ mBoundTextures[i] = 0;
+ }
+}
+
+void TextureState::unbindTexture(GLuint texture) {
+ for (int i = 0; i < kTextureUnitsCount; i++) {
+ if (mBoundTextures[i] == texture) {
+ mBoundTextures[i] = 0;
+ }
+ }
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
+
diff --git a/libs/hwui/renderstate/TextureState.h b/libs/hwui/renderstate/TextureState.h
new file mode 100644
index 0000000..5a57b9f
--- /dev/null
+++ b/libs/hwui/renderstate/TextureState.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015 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 RENDERSTATE_TEXTURESTATE_H
+#define RENDERSTATE_TEXTURESTATE_H
+
+#include "Vertex.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <SkXfermode.h>
+#include <memory>
+
+namespace android {
+namespace uirenderer {
+
+class TextureState {
+ friend class Caches; // TODO: move to RenderState
+public:
+ /**
+ * Activate the specified texture unit. The texture unit must
+ * be specified using an integer number (0 for GL_TEXTURE0 etc.)
+ */
+ void activateTexture(GLuint textureUnit);
+
+ /**
+ * Invalidate the cached value of the active texture unit.
+ */
+ void resetActiveTexture();
+
+ /**
+ * Binds the specified texture as a GL_TEXTURE_2D texture.
+ * All texture bindings must be performed with this method or
+ * bindTexture(GLenum, GLuint).
+ */
+ void bindTexture(GLuint texture);
+
+ /**
+ * Binds the specified texture with the specified render target.
+ * All texture bindings must be performed with this method or
+ * bindTexture(GLuint).
+ */
+ void bindTexture(GLenum target, GLuint texture);
+
+ /**
+ * Deletes the specified texture and clears it from the cache
+ * of bound textures.
+ * All textures must be deleted using this method.
+ */
+ void deleteTexture(GLuint texture);
+
+ /**
+ * Signals that the cache of bound textures should be cleared.
+ * Other users of the context may have altered which textures are bound.
+ */
+ void resetBoundTextures();
+
+ /**
+ * Clear the cache of bound textures.
+ */
+ void unbindTexture(GLuint texture);
+private:
+ // total number of texture units available for use
+ static const int kTextureUnitsCount = 3;
+
+ TextureState();
+ GLuint mTextureUnit;
+
+ // Caches texture bindings for the GL_TEXTURE_2D target
+ GLuint mBoundTextures[kTextureUnitsCount];
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif // RENDERSTATE_BLEND_H
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index b7e1752..6346479 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -16,19 +16,19 @@
#include "CanvasContext.h"
-#include <algorithm>
-#include <private/hwui/DrawGlInfo.h>
-#include <strings.h>
-
#include "EglManager.h"
#include "RenderThread.h"
#include "../AnimationContext.h"
#include "../Caches.h"
#include "../DeferredLayerUpdater.h"
-#include "../RenderState.h"
+#include "../renderstate/RenderState.h"
+#include "../renderstate/Stencil.h"
#include "../LayerRenderer.h"
#include "../OpenGLRenderer.h"
-#include "../Stencil.h"
+
+#include <algorithm>
+#include <private/hwui/DrawGlInfo.h>
+#include <strings.h>
#define TRIM_MEMORY_COMPLETE 80
#define TRIM_MEMORY_UI_HIDDEN 20
@@ -45,28 +45,27 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent,
, mBufferPreserved(false)
, mSwapBehavior(kSwap_default)
, mOpaque(!translucent)
- , mCanvas(NULL)
+ , mCanvas(nullptr)
, mHaveNewSurface(false)
+ , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
, mRootRenderNode(rootRenderNode) {
- mAnimationContext = contextFactory->createAnimationContext(mRenderThread.timeLord());
mRenderThread.renderState().registerCanvasContext(this);
}
CanvasContext::~CanvasContext() {
destroy();
- delete mAnimationContext;
mRenderThread.renderState().unregisterCanvasContext(this);
}
void CanvasContext::destroy() {
stopDrawing();
- setSurface(NULL);
+ setSurface(nullptr);
freePrefetechedLayers();
destroyHardwareResources();
mAnimationContext->destroy();
if (mCanvas) {
delete mCanvas;
- mCanvas = 0;
+ mCanvas = nullptr;
}
}
@@ -96,7 +95,7 @@ void CanvasContext::setSurface(ANativeWindow* window) {
void CanvasContext::swapBuffers() {
if (CC_UNLIKELY(!mEglManager.swapBuffers(mEglSurface))) {
- setSurface(NULL);
+ setSurface(nullptr);
}
mHaveNewSurface = false;
}
@@ -128,8 +127,8 @@ bool CanvasContext::pauseSurface(ANativeWindow* window) {
}
// TODO: don't pass viewport size, it's automatic via EGL
-void CanvasContext::setup(int width, int height, const Vector3& lightCenter,
- float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
+void CanvasContext::setup(int width, int height, const Vector3& lightCenter, float lightRadius,
+ uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
if (!mCanvas) return;
mCanvas->initLight(lightCenter, lightRadius, ambientShadowAlpha, spotShadowAlpha);
}
@@ -224,24 +223,23 @@ void CanvasContext::draw() {
profiler().unionDirty(&dirty);
}
- status_t status;
if (!dirty.isEmpty()) {
- status = mCanvas->prepareDirty(dirty.fLeft, dirty.fTop,
+ mCanvas->prepareDirty(dirty.fLeft, dirty.fTop,
dirty.fRight, dirty.fBottom, mOpaque);
} else {
- status = mCanvas->prepare(mOpaque);
+ mCanvas->prepare(mOpaque);
}
Rect outBounds;
- status |= mCanvas->drawRenderNode(mRootRenderNode.get(), outBounds);
+ mCanvas->drawRenderNode(mRootRenderNode.get(), outBounds);
profiler().draw(mCanvas);
- mCanvas->finish();
+ bool drew = mCanvas->finish();
profiler().markPlaybackEnd();
- if (status & DrawGlInfo::kStatusDrew) {
+ if (drew) {
swapBuffers();
} else {
mEglManager.cancelFrame();
@@ -275,19 +273,19 @@ void CanvasContext::invokeFunctor(RenderThread& thread, Functor* functor) {
mode = DrawGlInfo::kModeProcess;
}
- thread.renderState().invokeFunctor(functor, mode, NULL);
+ thread.renderState().invokeFunctor(functor, mode, nullptr);
}
void CanvasContext::markLayerInUse(RenderNode* node) {
if (mPrefetechedLayers.erase(node)) {
- node->decStrong(0);
+ node->decStrong(nullptr);
}
}
static void destroyPrefetechedNode(RenderNode* node) {
ALOGW("Incorrectly called buildLayer on View: %s, destroying layer...", node->getName());
node->destroyHardwareResources();
- node->decStrong(0);
+ node->decStrong(nullptr);
}
void CanvasContext::freePrefetechedLayers() {
@@ -321,7 +319,7 @@ void CanvasContext::buildLayer(RenderNode* node) {
mCanvas->markLayersAsBuildLayers();
mCanvas->flushLayerUpdates();
- node->incStrong(0);
+ node->incStrong(nullptr);
mPrefetechedLayers.insert(node);
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 0cc2c7c..d3fbde8 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -80,7 +80,7 @@ public:
void destroy();
// IFrameCallback, Chroreographer-driven frame callback entry point
- virtual void doFrame();
+ virtual void doFrame() override;
void buildLayer(RenderNode* node);
bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
@@ -128,7 +128,7 @@ private:
OpenGLRenderer* mCanvas;
bool mHaveNewSurface;
DamageAccumulator mDamageAccumulator;
- AnimationContext* mAnimationContext;
+ std::unique_ptr<AnimationContext> mAnimationContext;
const sp<RenderNode> mRootRenderNode;
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 97b31a9..4d8a469 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -32,8 +32,8 @@ namespace uirenderer {
namespace renderthread {
DrawFrameTask::DrawFrameTask()
- : mRenderThread(NULL)
- , mContext(NULL)
+ : mRenderThread(nullptr)
+ , mContext(nullptr)
, mFrameTimeNanos(0)
, mRecordDurationNanos(0)
, mDensity(1.0f) // safe enough default
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index 28f6cb2..953f012 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -64,7 +64,7 @@ public:
void setDensity(float density) { mDensity = density; }
int drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos);
- virtual void run();
+ virtual void run() override;
private:
void postAndWait();
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 8fb1b10..3afca2f 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -16,15 +16,19 @@
#include "EglManager.h"
+#include "../Caches.h"
+#include "../renderstate/RenderState.h"
+#include "RenderThread.h"
+
#include <cutils/log.h>
#include <cutils/properties.h>
-
-#include "../RenderState.h"
-#include "RenderThread.h"
+#include <EGL/eglext.h>
#define PROPERTY_RENDER_DIRTY_REGIONS "debug.hwui.render_dirty_regions"
#define GLES_VERSION 2
+#define WAIT_FOR_GPU_COMPLETION 0
+
// Android-specific addition that is used to show when frames began in systrace
EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
@@ -67,12 +71,12 @@ static bool load_dirty_regions_property() {
EglManager::EglManager(RenderThread& thread)
: mRenderThread(thread)
, mEglDisplay(EGL_NO_DISPLAY)
- , mEglConfig(0)
+ , mEglConfig(nullptr)
, mEglContext(EGL_NO_CONTEXT)
, mPBufferSurface(EGL_NO_SURFACE)
, mAllowPreserveBuffer(load_dirty_regions_property())
, mCurrentSurface(EGL_NO_SURFACE)
- , mAtlasMap(NULL)
+ , mAtlasMap(nullptr)
, mAtlasMapSize(0)
, mInFrame(false) {
mCanSetPreserveBuffer = mAllowPreserveBuffer;
@@ -193,7 +197,7 @@ void EglManager::usePBufferSurface() {
EGLSurface EglManager::createSurface(EGLNativeWindowType window) {
initialize();
- EGLSurface surface = eglCreateWindowSurface(mEglDisplay, mEglConfig, window, NULL);
+ EGLSurface surface = eglCreateWindowSurface(mEglDisplay, mEglConfig, window, nullptr);
LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE,
"Failed to create EGLSurface for window %p, eglErr = %s",
(void*) window, egl_error_str());
@@ -213,9 +217,6 @@ void EglManager::destroy() {
if (mEglDisplay == EGL_NO_DISPLAY) return;
usePBufferSurface();
- if (Caches::hasInstance()) {
- Caches::getInstance().terminate();
- }
mRenderThread.renderState().onGLContextDestroyed();
eglDestroyContext(mEglDisplay, mEglContext);
@@ -262,6 +263,14 @@ void EglManager::beginFrame(EGLSurface surface, EGLint* width, EGLint* height) {
bool EglManager::swapBuffers(EGLSurface surface) {
mInFrame = false;
+
+#if WAIT_FOR_GPU_COMPLETION
+ {
+ ATRACE_NAME("Finishing GPU work");
+ fence();
+ }
+#endif
+
eglSwapBuffers(mEglDisplay, surface);
EGLint err = eglGetError();
if (CC_LIKELY(err == EGL_SUCCESS)) {
@@ -280,6 +289,13 @@ bool EglManager::swapBuffers(EGLSurface surface) {
return false;
}
+void EglManager::fence() {
+ EGLSyncKHR fence = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_FENCE_KHR, NULL);
+ eglClientWaitSyncKHR(mEglDisplay, fence,
+ EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR);
+ eglDestroySyncKHR(mEglDisplay, fence);
+}
+
void EglManager::cancelFrame() {
mInFrame = false;
}
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index e12db3a..b1a18a9 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -55,6 +55,8 @@ public:
void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize);
+ void fence();
+
private:
friend class RenderThread;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 36ba3a9..4dc4248 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -60,7 +60,7 @@ CREATE_BRIDGE4(createContext, RenderThread* thread, bool translucent,
RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory)
: mRenderThread(RenderThread::getInstance())
- , mContext(0) {
+ , mContext(nullptr) {
SETUP_TASK(createContext);
args->translucent = translucent;
args->rootRenderNode = rootRenderNode;
@@ -76,15 +76,15 @@ RenderProxy::~RenderProxy() {
CREATE_BRIDGE1(destroyContext, CanvasContext* context) {
delete args->context;
- return NULL;
+ return nullptr;
}
void RenderProxy::destroyContext() {
if (mContext) {
SETUP_TASK(destroyContext);
args->context = mContext;
- mContext = 0;
- mDrawFrameTask.setContext(NULL, NULL);
+ mContext = nullptr;
+ mDrawFrameTask.setContext(nullptr, nullptr);
// This is also a fence as we need to be certain that there are no
// outstanding mDrawFrame tasks posted before it is destroyed
postAndWait(task);
@@ -93,7 +93,7 @@ void RenderProxy::destroyContext() {
CREATE_BRIDGE2(setFrameInterval, RenderThread* thread, nsecs_t frameIntervalNanos) {
args->thread->timeLord().setFrameInterval(args->frameIntervalNanos);
- return NULL;
+ return nullptr;
}
void RenderProxy::setFrameInterval(nsecs_t frameIntervalNanos) {
@@ -105,7 +105,7 @@ void RenderProxy::setFrameInterval(nsecs_t frameIntervalNanos) {
CREATE_BRIDGE2(setSwapBehavior, CanvasContext* context, SwapBehavior swapBehavior) {
args->context->setSwapBehavior(args->swapBehavior);
- return NULL;
+ return nullptr;
}
void RenderProxy::setSwapBehavior(SwapBehavior swapBehavior) {
@@ -145,7 +145,7 @@ bool RenderProxy::initialize(const sp<ANativeWindow>& window) {
CREATE_BRIDGE2(updateSurface, CanvasContext* context, ANativeWindow* window) {
args->context->updateSurface(args->window);
- return NULL;
+ return nullptr;
}
void RenderProxy::updateSurface(const sp<ANativeWindow>& window) {
@@ -171,7 +171,7 @@ CREATE_BRIDGE7(setup, CanvasContext* context, int width, int height,
uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
args->context->setup(args->width, args->height, args->lightCenter, args->lightRadius,
args->ambientShadowAlpha, args->spotShadowAlpha);
- return NULL;
+ return nullptr;
}
void RenderProxy::setup(int width, int height, const Vector3& lightCenter, float lightRadius,
@@ -189,7 +189,7 @@ void RenderProxy::setup(int width, int height, const Vector3& lightCenter, float
CREATE_BRIDGE2(setOpaque, CanvasContext* context, bool opaque) {
args->context->setOpaque(args->opaque);
- return NULL;
+ return nullptr;
}
void RenderProxy::setOpaque(bool opaque) {
@@ -207,7 +207,7 @@ int RenderProxy::syncAndDrawFrame(nsecs_t frameTimeNanos, nsecs_t recordDuration
CREATE_BRIDGE1(destroy, CanvasContext* context) {
args->context->destroy();
- return NULL;
+ return nullptr;
}
void RenderProxy::destroy() {
@@ -221,7 +221,7 @@ void RenderProxy::destroy() {
CREATE_BRIDGE2(invokeFunctor, RenderThread* thread, Functor* functor) {
CanvasContext::invokeFunctor(*args->thread, args->functor);
- return NULL;
+ return nullptr;
}
void RenderProxy::invokeFunctor(Functor* functor, bool waitForCompletion) {
@@ -242,7 +242,7 @@ void RenderProxy::invokeFunctor(Functor* functor, bool waitForCompletion) {
CREATE_BRIDGE2(runWithGlContext, CanvasContext* context, RenderTask* task) {
args->context->runWithGlContext(args->task);
- return NULL;
+ return nullptr;
}
void RenderProxy::runWithGlContext(RenderTask* gltask) {
@@ -254,7 +254,7 @@ void RenderProxy::runWithGlContext(RenderTask* gltask) {
CREATE_BRIDGE2(createTextureLayer, RenderThread* thread, CanvasContext* context) {
Layer* layer = args->context->createTextureLayer();
- if (!layer) return 0;
+ if (!layer) return nullptr;
return new DeferredLayerUpdater(*args->thread, layer);
}
@@ -269,7 +269,7 @@ DeferredLayerUpdater* RenderProxy::createTextureLayer() {
CREATE_BRIDGE2(buildLayer, CanvasContext* context, RenderNode* node) {
args->context->buildLayer(args->node);
- return NULL;
+ return nullptr;
}
void RenderProxy::buildLayer(RenderNode* node) {
@@ -303,7 +303,7 @@ void RenderProxy::cancelLayerUpdate(DeferredLayerUpdater* layer) {
CREATE_BRIDGE1(detachSurfaceTexture, DeferredLayerUpdater* layer) {
args->layer->detachSurfaceTexture();
- return NULL;
+ return nullptr;
}
void RenderProxy::detachSurfaceTexture(DeferredLayerUpdater* layer) {
@@ -314,7 +314,7 @@ void RenderProxy::detachSurfaceTexture(DeferredLayerUpdater* layer) {
CREATE_BRIDGE1(destroyHardwareResources, CanvasContext* context) {
args->context->destroyHardwareResources();
- return NULL;
+ return nullptr;
}
void RenderProxy::destroyHardwareResources() {
@@ -325,7 +325,7 @@ void RenderProxy::destroyHardwareResources() {
CREATE_BRIDGE2(timMemory, RenderThread* thread, int level) {
CanvasContext::trimMemory(*args->thread, args->level);
- return NULL;
+ return nullptr;
}
void RenderProxy::trimMemory(int level) {
@@ -339,16 +339,14 @@ void RenderProxy::trimMemory(int level) {
}
}
-template <typename T>
-void UNUSED(T) {}
-
-
CREATE_BRIDGE0(fence) {
// Intentionally empty
- UNUSED(args);
- return NULL;
+ return nullptr;
}
+template <typename T>
+void UNUSED(T t) {}
+
void RenderProxy::fence() {
SETUP_TASK(fence);
UNUSED(args);
@@ -357,7 +355,7 @@ void RenderProxy::fence() {
CREATE_BRIDGE1(stopDrawing, CanvasContext* context) {
args->context->stopDrawing();
- return NULL;
+ return nullptr;
}
void RenderProxy::stopDrawing() {
@@ -368,7 +366,7 @@ void RenderProxy::stopDrawing() {
CREATE_BRIDGE1(notifyFramePending, CanvasContext* context) {
args->context->notifyFramePending();
- return NULL;
+ return nullptr;
}
void RenderProxy::notifyFramePending() {
@@ -379,7 +377,7 @@ void RenderProxy::notifyFramePending() {
CREATE_BRIDGE2(dumpProfileInfo, CanvasContext* context, int fd) {
args->context->profiler().dumpData(args->fd);
- return NULL;
+ return nullptr;
}
void RenderProxy::dumpProfileInfo(int fd) {
@@ -389,28 +387,36 @@ void RenderProxy::dumpProfileInfo(int fd) {
postAndWait(task);
}
-CREATE_BRIDGE1(outputLogBuffer, int fd) {
- RenderNode::outputLogBuffer(args->fd);
- return NULL;
+CREATE_BRIDGE1(dumpGraphicsMemory, int fd) {
+ FILE *file = fdopen(args->fd, "a");
+ if (Caches::hasInstance()) {
+ String8 cachesLog;
+ Caches::getInstance().dumpMemoryUsage(cachesLog);
+ fprintf(file, "\nCaches:\n%s\n", cachesLog.string());
+ } else {
+ fprintf(file, "\nNo caches instance.\n");
+ }
+ fflush(file);
+ return nullptr;
}
-void RenderProxy::outputLogBuffer(int fd) {
- SETUP_TASK(outputLogBuffer);
+void RenderProxy::dumpGraphicsMemory(int fd) {
+ SETUP_TASK(dumpGraphicsMemory);
args->fd = fd;
staticPostAndWait(task);
}
CREATE_BRIDGE4(setTextureAtlas, RenderThread* thread, GraphicBuffer* buffer, int64_t* map, size_t size) {
CanvasContext::setTextureAtlas(*args->thread, args->buffer, args->map, args->size);
- args->buffer->decStrong(0);
- return NULL;
+ args->buffer->decStrong(nullptr);
+ return nullptr;
}
void RenderProxy::setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size) {
SETUP_TASK(setTextureAtlas);
args->thread = &mRenderThread;
args->buffer = buffer.get();
- args->buffer->incStrong(0);
+ args->buffer->incStrong(nullptr);
args->map = map;
args->size = size;
post(task);
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index fd1fe05..d87e777 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -96,7 +96,7 @@ public:
ANDROID_API void notifyFramePending();
ANDROID_API void dumpProfileInfo(int fd);
- ANDROID_API static void outputLogBuffer(int fd);
+ ANDROID_API static void dumpGraphicsMemory(int fd);
ANDROID_API void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size);
diff --git a/libs/hwui/renderthread/RenderTask.cpp b/libs/hwui/renderthread/RenderTask.cpp
index 13970ba..b14f580 100644
--- a/libs/hwui/renderthread/RenderTask.cpp
+++ b/libs/hwui/renderthread/RenderTask.cpp
@@ -14,15 +14,8 @@
* limitations under the License.
*/
-// LOG_TAG is being provided by the Makefile, reset.
-#ifdef LOG_TAG
-#undef LOG_TAG
-#endif
-#define LOG_TAG "RenderTask"
-
#include "RenderTask.h"
-#include <utils/Log.h>
#include <utils/Condition.h>
#include <utils/Mutex.h>
diff --git a/libs/hwui/renderthread/RenderTask.h b/libs/hwui/renderthread/RenderTask.h
index 1554a16..89c3a7d 100644
--- a/libs/hwui/renderthread/RenderTask.h
+++ b/libs/hwui/renderthread/RenderTask.h
@@ -47,7 +47,7 @@ namespace renderthread {
class ANDROID_API RenderTask {
public:
- ANDROID_API RenderTask() : mNext(0), mRunAt(0) {}
+ ANDROID_API RenderTask() : mNext(nullptr), mRunAt(0) {}
ANDROID_API virtual ~RenderTask() {}
ANDROID_API virtual void run() = 0;
@@ -61,7 +61,7 @@ public:
// Takes ownership of task, caller owns lock and signal
SignalingRenderTask(RenderTask* task, Mutex* lock, Condition* signal)
: mTask(task), mLock(lock), mSignal(signal) {}
- virtual void run();
+ virtual void run() override;
private:
RenderTask* mTask;
@@ -74,12 +74,12 @@ typedef void* (*RunnableMethod)(void* data);
class MethodInvokeRenderTask : public RenderTask {
public:
MethodInvokeRenderTask(RunnableMethod method)
- : mMethod(method), mReturnPtr(0) {}
+ : mMethod(method), mReturnPtr(nullptr) {}
void* payload() { return mData; }
void setReturnPtr(void** retptr) { mReturnPtr = retptr; }
- virtual void run() {
+ virtual void run() override {
void* retval = mMethod(mData);
if (mReturnPtr) {
*mReturnPtr = retval;
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 37e11d8..9a0fbad 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -16,15 +16,15 @@
#include "RenderThread.h"
-#include <gui/DisplayEventReceiver.h>
-#include <sys/resource.h>
-#include <utils/Log.h>
-
-#include "../RenderState.h"
+#include "../renderstate/RenderState.h"
#include "CanvasContext.h"
#include "EglManager.h"
#include "RenderProxy.h"
+#include <gui/DisplayEventReceiver.h>
+#include <sys/resource.h>
+#include <utils/Log.h>
+
namespace android {
using namespace uirenderer::renderthread;
ANDROID_SINGLETON_STATIC_INSTANCE(RenderThread);
@@ -40,16 +40,16 @@ static const size_t EVENT_BUFFER_SIZE = 100;
// Slight delay to give the UI time to push us a new frame before we replay
static const nsecs_t DISPATCH_FRAME_CALLBACKS_DELAY = milliseconds_to_nanoseconds(4);
-TaskQueue::TaskQueue() : mHead(0), mTail(0) {}
+TaskQueue::TaskQueue() : mHead(nullptr), mTail(nullptr) {}
RenderTask* TaskQueue::next() {
RenderTask* ret = mHead;
if (ret) {
mHead = ret->mNext;
if (!mHead) {
- mTail = 0;
+ mTail = nullptr;
}
- ret->mNext = 0;
+ ret->mNext = nullptr;
}
return ret;
}
@@ -69,7 +69,7 @@ void TaskQueue::queue(RenderTask* task) {
mTail = task;
} else {
// Need to find the proper insertion point
- RenderTask* previous = 0;
+ RenderTask* previous = nullptr;
RenderTask* next = mHead;
while (next && next->mRunAt <= task->mRunAt) {
previous = next;
@@ -129,19 +129,19 @@ private:
public:
DispatchFrameCallbacks(RenderThread* rt) : mRenderThread(rt) {}
- virtual void run() {
+ virtual void run() override {
mRenderThread->dispatchFrameCallbacks();
}
};
RenderThread::RenderThread() : Thread(true), Singleton<RenderThread>()
, mNextWakeup(LLONG_MAX)
- , mDisplayEventReceiver(0)
+ , mDisplayEventReceiver(nullptr)
, mVsyncRequested(false)
, mFrameCallbackTaskPending(false)
- , mFrameCallbackTask(0)
- , mRenderState(NULL)
- , mEglManager(NULL) {
+ , mFrameCallbackTask(nullptr)
+ , mRenderState(nullptr)
+ , mEglManager(nullptr) {
mFrameCallbackTask = new DispatchFrameCallbacks(this);
mLooper = new Looper(false);
run("RenderThread");
@@ -346,7 +346,7 @@ RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) {
if (next->mRunAt <= 0 || next->mRunAt <= systemTime(SYSTEM_TIME_MONOTONIC)) {
next = mQueue.next();
} else {
- next = 0;
+ next = nullptr;
}
}
if (nextWakeup) {
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 99c2e15..8fc8ca5 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -90,7 +90,7 @@ public:
EglManager& eglManager() { return *mEglManager; }
protected:
- virtual bool threadLoop();
+ virtual bool threadLoop() override;
private:
friend class Singleton<RenderThread>;
diff --git a/libs/hwui/tests/Android.mk b/libs/hwui/tests/Android.mk
index 7bdce7f..a69f3fb 100644
--- a/libs/hwui/tests/Android.mk
+++ b/libs/hwui/tests/Android.mk
@@ -15,34 +15,9 @@
#
local_target_dir := $(TARGET_OUT_DATA)/local/tmp
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH:= $(call my-dir)/..
include $(CLEAR_VARS)
-LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES
-LOCAL_CFLAGS += -Wno-unused-parameter
-LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_VIEW -DLOG_TAG=\"OpenGLRenderer\"
-
-LOCAL_SRC_FILES:= \
- TestContext.cpp \
- main.cpp
-
-LOCAL_C_INCLUDES += \
- $(LOCAL_PATH)/.. \
- external/skia/src/core
-
-LOCAL_SHARED_LIBRARIES := \
- liblog \
- libcutils \
- libutils \
- libskia \
- libgui \
- libui \
- libhwui
-
-ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
- LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
-endif
-
LOCAL_MODULE_PATH := $(local_target_dir)
LOCAL_MODULE:= hwuitest
LOCAL_MODULE_TAGS := tests
@@ -50,7 +25,23 @@ LOCAL_MULTILIB := both
LOCAL_MODULE_STEM_32 := hwuitest
LOCAL_MODULE_STEM_64 := hwuitest64
-include external/stlport/libstlport.mk
+include $(LOCAL_PATH)/Android.common.mk
+
+LOCAL_SRC_FILES += \
+ tests/TestContext.cpp \
+ tests/main.cpp
+
include $(BUILD_EXECUTABLE)
-include $(call all-makefiles-under,$(LOCAL_PATH))
+include $(CLEAR_VARS)
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.common.mk
+LOCAL_MODULE := hwui_unit_tests
+LOCAL_MODULE_TAGS := tests
+
+include $(LOCAL_PATH)/Android.common.mk
+
+LOCAL_SRC_FILES += \
+ tests/ClipAreaTests.cpp \
+
+include $(BUILD_NATIVE_TEST)
diff --git a/libs/hwui/tests/ClipAreaTests.cpp b/libs/hwui/tests/ClipAreaTests.cpp
new file mode 100644
index 0000000..166d5b6
--- /dev/null
+++ b/libs/hwui/tests/ClipAreaTests.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2015 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 <gtest/gtest.h>
+#include <SkPath.h>
+#include <SkRegion.h>
+
+#include "ClipArea.h"
+
+#include "Matrix.h"
+#include "Rect.h"
+#include "utils/LinearAllocator.h"
+
+namespace android {
+namespace uirenderer {
+
+static Rect kViewportBounds(0, 0, 2048, 2048);
+
+static ClipArea createClipArea() {
+ ClipArea area;
+ area.setViewportDimensions(kViewportBounds.getWidth(), kViewportBounds.getHeight());
+ return area;
+}
+
+TEST(TransformedRectangle, basics) {
+ Rect r(0, 0, 100, 100);
+ Matrix4 minus90;
+ minus90.loadRotate(-90);
+ minus90.mapRect(r);
+ Rect r2(20, 40, 120, 60);
+
+ Matrix4 m90;
+ m90.loadRotate(90);
+ TransformedRectangle tr(r, m90);
+ EXPECT_TRUE(tr.canSimplyIntersectWith(tr));
+
+ Matrix4 m0;
+ TransformedRectangle tr0(r2, m0);
+ EXPECT_FALSE(tr.canSimplyIntersectWith(tr0));
+
+ Matrix4 m45;
+ m45.loadRotate(45);
+ TransformedRectangle tr2(r, m45);
+ EXPECT_FALSE(tr2.canSimplyIntersectWith(tr));
+}
+
+TEST(RectangleList, basics) {
+ RectangleList list;
+ EXPECT_TRUE(list.isEmpty());
+
+ Rect r(0, 0, 100, 100);
+ Matrix4 m45;
+ m45.loadRotate(45);
+ list.set(r, m45);
+ EXPECT_FALSE(list.isEmpty());
+
+ Rect r2(20, 20, 200, 200);
+ list.intersectWith(r2, m45);
+ EXPECT_FALSE(list.isEmpty());
+ EXPECT_EQ(1, list.getTransformedRectanglesCount());
+
+ Rect r3(20, 20, 200, 200);
+ Matrix4 m30;
+ m30.loadRotate(30);
+ list.intersectWith(r2, m30);
+ EXPECT_FALSE(list.isEmpty());
+ EXPECT_EQ(2, list.getTransformedRectanglesCount());
+
+ SkRegion clip;
+ clip.setRect(0, 0, 2000, 2000);
+ SkRegion rgn(list.convertToRegion(clip));
+ EXPECT_FALSE(rgn.isEmpty());
+}
+
+TEST(ClipArea, basics) {
+ ClipArea area(createClipArea());
+ EXPECT_FALSE(area.isEmpty());
+}
+
+TEST(ClipArea, paths) {
+ ClipArea area(createClipArea());
+ Matrix4 transform;
+ transform.loadIdentity();
+ SkPath path;
+ SkScalar r = 100;
+ path.addCircle(r, r, r);
+ area.clipPathWithTransform(path, &transform, SkRegion::kIntersect_Op);
+ EXPECT_FALSE(area.isEmpty());
+ EXPECT_FALSE(area.isSimple());
+ EXPECT_FALSE(area.isRectangleList());
+ Rect clipRect(area.getClipRect());
+ clipRect.dump("clipRect");
+ Rect expected(0, 0, r * 2, r * 2);
+ expected.dump("expected");
+ EXPECT_EQ(expected, clipRect);
+ SkRegion clipRegion(area.getClipRegion());
+ auto skRect(clipRegion.getBounds());
+ Rect regionBounds;
+ regionBounds.set(skRect);
+ EXPECT_EQ(expected, regionBounds);
+}
+}
+}
diff --git a/libs/hwui/tests/TestContext.cpp b/libs/hwui/tests/TestContext.cpp
index 35e402d..542bbae 100644
--- a/libs/hwui/tests/TestContext.cpp
+++ b/libs/hwui/tests/TestContext.cpp
@@ -16,30 +16,59 @@
#include "TestContext.h"
-#include <gui/ISurfaceComposer.h>
-#include <gui/SurfaceComposerClient.h>
+namespace android {
+namespace uirenderer {
+namespace test {
-using namespace android;
+static const int IDENT_DISPLAYEVENT = 1;
-DisplayInfo gDisplay;
-sp<SurfaceComposerClient> gSession;
-
-void createTestEnvironment() {
- gSession = new SurfaceComposerClient();
+static DisplayInfo getBuiltInDisplay() {
+ DisplayInfo display;
sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
- ISurfaceComposer::eDisplayIdMain));
- status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &gDisplay);
+ ISurfaceComposer::eDisplayIdMain));
+ status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &display);
LOG_ALWAYS_FATAL_IF(status, "Failed to get display info\n");
+ return display;
+}
+
+android::DisplayInfo gDisplay = getBuiltInDisplay();
+
+TestContext::TestContext() {
+ mLooper = new Looper(true);
+ mSurfaceComposerClient = new SurfaceComposerClient();
+ mLooper->addFd(mDisplayEventReceiver.getFd(), IDENT_DISPLAYEVENT,
+ Looper::EVENT_INPUT, nullptr, nullptr);
}
-sp<SurfaceControl> createWindow(int width, int height) {
- sp<SurfaceControl> control = gSession->createSurface(String8("HwuiTest"),
- width, height, PIXEL_FORMAT_RGBX_8888);
+TestContext::~TestContext() {}
+
+sp<Surface> TestContext::surface() {
+ if (!mSurfaceControl.get()) {
+ mSurfaceControl = mSurfaceComposerClient->createSurface(String8("HwuiTest"),
+ gDisplay.w, gDisplay.h, PIXEL_FORMAT_RGBX_8888);
- SurfaceComposerClient::openGlobalTransaction();
- control->setLayer(0x7FFFFFF);
- control->show();
- SurfaceComposerClient::closeGlobalTransaction();
+ SurfaceComposerClient::openGlobalTransaction();
+ mSurfaceControl->setLayer(0x7FFFFFF);
+ mSurfaceControl->show();
+ SurfaceComposerClient::closeGlobalTransaction();
+ }
- return control;
+ return mSurfaceControl->getSurface();
}
+
+void TestContext::waitForVsync() {
+ // Request vsync
+ mDisplayEventReceiver.requestNextVsync();
+
+ // Wait
+ mLooper->pollOnce(-1);
+
+ // Drain it
+ DisplayEventReceiver::Event buf[100];
+ while (mDisplayEventReceiver.getEvents(buf, 100) > 0) { }
+}
+
+} // namespace test
+} // namespace uirenderer
+} // namespace android
+
diff --git a/libs/hwui/tests/TestContext.h b/libs/hwui/tests/TestContext.h
index 8a5d530..7b30fc1 100644
--- a/libs/hwui/tests/TestContext.h
+++ b/libs/hwui/tests/TestContext.h
@@ -17,17 +17,39 @@
#ifndef TESTCONTEXT_H
#define TESTCONTEXT_H
-#include <ui/DisplayInfo.h>
+#include <gui/DisplayEventReceiver.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
#include <gui/SurfaceControl.h>
+#include <gui/Surface.h>
+#include <ui/DisplayInfo.h>
+#include <utils/Looper.h>
+
+namespace android {
+namespace uirenderer {
+namespace test {
+
+extern DisplayInfo gDisplay;
+#define dp(x) ((x) * android::uirenderer::test::gDisplay.density)
+
+class TestContext {
+public:
+ TestContext();
+ ~TestContext();
+
+ sp<Surface> surface();
-extern android::DisplayInfo gDisplay;
-#define dp(x) ((x) * gDisplay.density)
+ void waitForVsync();
-// Initializes all the static globals that are shared across all contexts
-// such as display info
-void createTestEnvironment();
+private:
+ sp<SurfaceComposerClient> mSurfaceComposerClient;
+ sp<SurfaceControl> mSurfaceControl;
+ DisplayEventReceiver mDisplayEventReceiver;
+ sp<Looper> mLooper;
+};
-// Defaults to fullscreen
-android::sp<android::SurfaceControl> createWindow(int width = -1, int height = -1);
+} // namespace test
+} // namespace uirenderer
+} // namespace android
#endif
diff --git a/libs/hwui/tests/main.cpp b/libs/hwui/tests/main.cpp
index d847d13..5f445f4 100644
--- a/libs/hwui/tests/main.cpp
+++ b/libs/hwui/tests/main.cpp
@@ -24,24 +24,27 @@
#include <DisplayListRenderer.h>
#include <RenderNode.h>
#include <renderthread/RenderProxy.h>
+#include <renderthread/RenderTask.h>
#include "TestContext.h"
using namespace android;
using namespace android::uirenderer;
using namespace android::uirenderer::renderthread;
+using namespace android::uirenderer::test;
class ContextFactory : public IContextFactory {
public:
- virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) {
+ virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) override {
return new AnimationContext(clock);
}
};
static DisplayListRenderer* startRecording(RenderNode* node) {
DisplayListRenderer* renderer = new DisplayListRenderer();
- renderer->setViewport(node->getWidth(), node->getHeight());
- renderer->prepare(false);
+ renderer->setViewport(node->stagingProperties().getWidth(),
+ node->stagingProperties().getHeight());
+ renderer->prepare();
return renderer;
}
@@ -51,81 +54,214 @@ static void endRecording(DisplayListRenderer* renderer, RenderNode* node) {
delete renderer;
}
-sp<RenderNode> createCard(int x, int y, int width, int height) {
- sp<RenderNode> node = new RenderNode();
- node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
- node->mutateStagingProperties().setElevation(dp(16));
- node->mutateStagingProperties().mutableOutline().setRoundRect(0, 0, width, height, dp(10), 1);
- node->mutateStagingProperties().mutableOutline().setShouldClip(true);
- node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::Z);
+class TreeContentAnimation {
+public:
+ virtual ~TreeContentAnimation() {}
+ virtual int getFrameCount() { return 150; }
+ virtual void createContent(int width, int height, DisplayListRenderer* renderer) = 0;
+ virtual void doFrame(int frameNr) = 0;
- DisplayListRenderer* renderer = startRecording(node.get());
- renderer->drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode);
- endRecording(renderer, node.get());
+ template <class T>
+ static void run() {
+ T animation;
- return node;
-}
+ TestContext testContext;
-int main() {
- createTestEnvironment();
+ // create the native surface
+ const int width = gDisplay.w;
+ const int height = gDisplay.h;
+ sp<Surface> surface = testContext.surface();
- // create the native surface
- const int width = gDisplay.w;
- const int height = gDisplay.h;
- sp<SurfaceControl> control = createWindow(width, height);
- sp<Surface> surface = control->getSurface();
+ RenderNode* rootNode = new RenderNode();
+ rootNode->incStrong(nullptr);
+ rootNode->mutateStagingProperties().setLeftTopRightBottom(0, 0, width, height);
+ rootNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+ rootNode->mutateStagingProperties().setClipToBounds(false);
+ rootNode->setPropertyFieldsDirty(RenderNode::GENERIC);
- RenderNode* rootNode = new RenderNode();
- rootNode->incStrong(0);
- rootNode->mutateStagingProperties().setLeftTopRightBottom(0, 0, width, height);
- rootNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
- rootNode->mutateStagingProperties().setClipToBounds(false);
- rootNode->setPropertyFieldsDirty(RenderNode::GENERIC);
+ ContextFactory factory;
+ std::unique_ptr<RenderProxy> proxy(new RenderProxy(false, rootNode, &factory));
+ proxy->loadSystemProperties();
+ proxy->initialize(surface);
+ float lightX = width / 2.0;
+ proxy->setup(width, height, (Vector3){lightX, dp(-200.0f), dp(800.0f)},
+ dp(800.0f), 255 * 0.075, 255 * 0.15);
- ContextFactory factory;
- RenderProxy* proxy = new RenderProxy(false, rootNode, &factory);
- proxy->loadSystemProperties();
- proxy->initialize(surface);
- float lightX = width / 2.0;
- proxy->setup(width, height, (Vector3){lightX, dp(-200.0f), dp(800.0f)},
- dp(800.0f), 255 * 0.075, 255 * 0.15);
+ android::uirenderer::Rect DUMMY;
- android::uirenderer::Rect DUMMY;
+ std::vector< sp<RenderNode> > cards;
- std::vector< sp<RenderNode> > cards;
+ DisplayListRenderer* renderer = startRecording(rootNode);
+ animation.createContent(width, height, renderer);
+ endRecording(renderer, rootNode);
- DisplayListRenderer* renderer = startRecording(rootNode);
- renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
- renderer->insertReorderBarrier(true);
+ for (int i = 0; i < 150; i++) {
+ testContext.waitForVsync();
- for (int x = dp(16); x < (width - dp(116)); x += dp(116)) {
- for (int y = dp(16); y < (height - dp(116)); y += dp(116)) {
- sp<RenderNode> card = createCard(x, y, dp(100), dp(100));
- renderer->drawRenderNode(card.get(), DUMMY, 0);
- cards.push_back(card);
+ ATRACE_NAME("UI-Draw Frame");
+ animation.doFrame(i);
+ nsecs_t frameTimeNs = systemTime(CLOCK_MONOTONIC);
+ proxy->syncAndDrawFrame(frameTimeNs, 0, gDisplay.density);
}
+
+ sleep(5);
+
+ rootNode->decStrong(nullptr);
}
+};
- renderer->insertReorderBarrier(false);
- endRecording(renderer, rootNode);
+class ShadowGridAnimation : public TreeContentAnimation {
+public:
+ std::vector< sp<RenderNode> > cards;
+ void createContent(int width, int height, DisplayListRenderer* renderer) override {
+ android::uirenderer::Rect DUMMY;
+
+ renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
+ renderer->insertReorderBarrier(true);
- for (int i = 0; i < 150; i++) {
- ATRACE_NAME("UI-Draw Frame");
+ for (int x = dp(16); x < (width - dp(116)); x += dp(116)) {
+ for (int y = dp(16); y < (height - dp(116)); y += dp(116)) {
+ sp<RenderNode> card = createCard(x, y, dp(100), dp(100));
+ renderer->drawRenderNode(card.get(), DUMMY, 0);
+ cards.push_back(card);
+ }
+ }
+
+ renderer->insertReorderBarrier(false);
+ }
+ void doFrame(int frameNr) override {
for (size_t ci = 0; ci < cards.size(); ci++) {
- cards[ci]->mutateStagingProperties().setTranslationX(i);
- cards[ci]->mutateStagingProperties().setTranslationY(i);
+ cards[ci]->mutateStagingProperties().setTranslationX(frameNr);
+ cards[ci]->mutateStagingProperties().setTranslationY(frameNr);
cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
}
- nsecs_t frameTimeNs = systemTime(CLOCK_MONOTONIC);
- proxy->syncAndDrawFrame(frameTimeNs, 0, gDisplay.density);
- usleep(12000);
}
+private:
+ sp<RenderNode> createCard(int x, int y, int width, int height) {
+ sp<RenderNode> node = new RenderNode();
+ node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
+ node->mutateStagingProperties().setElevation(dp(16));
+ node->mutateStagingProperties().mutableOutline().setRoundRect(0, 0, width, height, dp(10), 1);
+ node->mutateStagingProperties().mutableOutline().setShouldClip(true);
+ node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::Z);
- sleep(5);
+ DisplayListRenderer* renderer = startRecording(node.get());
+ renderer->drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode);
+ endRecording(renderer, node.get());
+ return node;
+ }
+};
+
+class RectGridAnimation : public TreeContentAnimation {
+public:
+ sp<RenderNode> card;
+ void createContent(int width, int height, DisplayListRenderer* renderer) override {
+ android::uirenderer::Rect DUMMY;
+
+ renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
+ renderer->insertReorderBarrier(true);
+
+ card = createCard(40, 40, 200, 200);
+ renderer->drawRenderNode(card.get(), DUMMY, 0);
+
+ renderer->insertReorderBarrier(false);
+ }
+ void doFrame(int frameNr) override {
+ card->mutateStagingProperties().setTranslationX(frameNr);
+ card->mutateStagingProperties().setTranslationY(frameNr);
+ card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+ }
+private:
+ sp<RenderNode> createCard(int x, int y, int width, int height) {
+ sp<RenderNode> node = new RenderNode();
+ node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
+ node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+
+ DisplayListRenderer* renderer = startRecording(node.get());
+ renderer->drawColor(0xFFFF00FF, SkXfermode::kSrcOver_Mode);
+
+ float rects[width * height];
+ int index = 0;
+ for (int xOffset = 0; xOffset < width; xOffset+=2) {
+ for (int yOffset = 0; yOffset < height; yOffset+=2) {
+ rects[index++] = xOffset;
+ rects[index++] = yOffset;
+ rects[index++] = xOffset + 1;
+ rects[index++] = yOffset + 1;
+ }
+ }
+ int count = width * height;
- delete proxy;
- rootNode->decStrong(0);
+ SkPaint paint;
+ paint.setColor(0xff00ffff);
+ renderer->drawRects(rects, count, &paint);
+ endRecording(renderer, node.get());
+ return node;
+ }
+};
+
+class OvalAnimation : public TreeContentAnimation {
+public:
+ sp<RenderNode> card;
+ void createContent(int width, int height, DisplayListRenderer* renderer) override {
+ android::uirenderer::Rect DUMMY;
+
+ renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
+ renderer->insertReorderBarrier(true);
+
+ card = createCard(40, 40, 200, 200);
+ renderer->drawRenderNode(card.get(), DUMMY, 0);
+
+ renderer->insertReorderBarrier(false);
+ }
+
+ void doFrame(int frameNr) override {
+ card->mutateStagingProperties().setTranslationX(frameNr);
+ card->mutateStagingProperties().setTranslationY(frameNr);
+ card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+ }
+private:
+ sp<RenderNode> createCard(int x, int y, int width, int height) {
+ sp<RenderNode> node = new RenderNode();
+ node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
+ node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+
+ DisplayListRenderer* renderer = startRecording(node.get());
+ renderer->drawColor(0xFFFF00FF, SkXfermode::kSrcOver_Mode);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(0xFF00FFFF);
+ renderer->drawOval(0, 0, width, height, paint);
+
+ endRecording(renderer, node.get());
+ return node;
+ }
+};
+
+struct cstr_cmp {
+ bool operator()(const char *a, const char *b) const {
+ return std::strcmp(a, b) < 0;
+ }
+};
+
+typedef void (*testProc)();
+
+std::map<const char*, testProc, cstr_cmp> gTestMap {
+ {"shadowgrid", TreeContentAnimation::run<ShadowGridAnimation>},
+ {"rectgrid", TreeContentAnimation::run<RectGridAnimation> },
+ {"oval", TreeContentAnimation::run<OvalAnimation> },
+};
+
+int main(int argc, char* argv[]) {
+ const char* testName = argc > 1 ? argv[1] : "shadowgrid";
+ testProc proc = gTestMap[testName];
+ if(!proc) {
+ printf("Error: couldn't find test %s\n", testName);
+ return 1;
+ }
+ proc();
printf("Success!\n");
return 0;
}
diff --git a/libs/hwui/thread/TaskManager.h b/libs/hwui/thread/TaskManager.h
index 5a933ab..10e8b9e 100644
--- a/libs/hwui/thread/TaskManager.h
+++ b/libs/hwui/thread/TaskManager.h
@@ -84,8 +84,8 @@ private:
void exit();
private:
- virtual status_t readyToRun();
- virtual bool threadLoop();
+ virtual status_t readyToRun() override;
+ virtual bool threadLoop() override;
// Lock for the list of tasks
mutable Mutex mLock;
diff --git a/libs/hwui/thread/TaskProcessor.h b/libs/hwui/thread/TaskProcessor.h
index 30b3719..ec6519c 100644
--- a/libs/hwui/thread/TaskProcessor.h
+++ b/libs/hwui/thread/TaskProcessor.h
@@ -41,7 +41,7 @@ public:
bool add(const sp<Task<T> >& task);
- virtual void process(const sp<TaskBase>& task) {
+ virtual void process(const sp<TaskBase>& task) override {
sp<Task<T> > realTask = static_cast<Task<T>* >(task.get());
// This is the right way to do it but sp<> doesn't play nice
// sp<Task<T> > realTask = static_cast<sp<Task<T> > >(task);
diff --git a/libs/hwui/utils/Macros.h b/libs/hwui/utils/Macros.h
index 5b7c87c..fe43fdb 100644
--- a/libs/hwui/utils/Macros.h
+++ b/libs/hwui/utils/Macros.h
@@ -18,8 +18,8 @@
#define PREVENT_COPY_AND_ASSIGN(Type) \
private: \
- Type(const Type&); \
- void operator=(const Type&)
+ Type(const Type&) = delete; \
+ void operator=(const Type&) = delete
#define DESCRIPTION_TYPE(Type) \
int compare(const Type& rhs) const { return memcmp(this, &rhs, sizeof(Type));} \
diff --git a/libs/hwui/utils/PaintUtils.h b/libs/hwui/utils/PaintUtils.h
new file mode 100644
index 0000000..679e2bf
--- /dev/null
+++ b/libs/hwui/utils/PaintUtils.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 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 PAINT_UTILS_H
+#define PAINT_UTILS_H
+
+#include <SkColorFilter.h>
+#include <SkXfermode.h>
+
+namespace android {
+namespace uirenderer {
+
+class PaintUtils {
+public:
+
+ /**
+ * Safely retrieves the mode from the specified xfermode. If the specified
+ * xfermode is null, the mode is assumed to be SkXfermode::kSrcOver_Mode.
+ */
+ static inline SkXfermode::Mode getXfermode(SkXfermode* mode) {
+ SkXfermode::Mode resultMode;
+ if (!SkXfermode::AsMode(mode, &resultMode)) {
+ resultMode = SkXfermode::kSrcOver_Mode;
+ }
+ return resultMode;
+ }
+
+ // TODO: move to a method on android:Paint? replace with SkPaint::nothingToDraw()?
+ static inline bool paintWillNotDraw(const SkPaint& paint) {
+ return paint.getAlpha() == 0
+ && !paint.getColorFilter()
+ && getXfermode(paint.getXfermode()) == SkXfermode::kSrcOver_Mode;
+ }
+
+ // TODO: move to a method on android:Paint? replace with SkPaint::nothingToDraw()?
+ static inline bool paintWillNotDrawText(const SkPaint& paint) {
+ return paint.getAlpha() == 0
+ && paint.getLooper() == nullptr
+ && !paint.getColorFilter()
+ && getXfermode(paint.getXfermode()) == SkXfermode::kSrcOver_Mode;
+ }
+
+ static bool isBlendedShader(const SkShader* shader) {
+ if (shader == nullptr) {
+ return false;
+ }
+ return !shader->isOpaque();
+ }
+
+ static bool isBlendedColorFilter(const SkColorFilter* filter) {
+ if (filter == nullptr) {
+ return false;
+ }
+ return (filter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag) == 0;
+ }
+
+}; // class PaintUtils
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* PAINT_UTILS_H */
diff --git a/libs/hwui/utils/Pair.h b/libs/hwui/utils/Pair.h
index 172606a..0db3aa3 100644
--- a/libs/hwui/utils/Pair.h
+++ b/libs/hwui/utils/Pair.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_HWUI_PAIR_H
#define ANDROID_HWUI_PAIR_H
+#include <utils/TypeHelpers.h>
+
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/utils/SortedList.h b/libs/hwui/utils/SortedList.h
index 2fa890a..a2c8c52 100644
--- a/libs/hwui/utils/SortedList.h
+++ b/libs/hwui/utils/SortedList.h
@@ -93,13 +93,13 @@ public:
}
protected:
- virtual void do_construct(void* storage, size_t num) const;
- virtual void do_destroy(void* storage, size_t num) const;
- virtual void do_copy(void* dest, const void* from, size_t num) const;
- virtual void do_splat(void* dest, const void* item, size_t num) const;
- virtual void do_move_forward(void* dest, const void* from, size_t num) const;
- virtual void do_move_backward(void* dest, const void* from, size_t num) const;
- virtual int do_compare(const void* lhs, const void* rhs) const;
+ virtual void do_construct(void* storage, size_t num) const override;
+ virtual void do_destroy(void* storage, size_t num) const override;
+ virtual void do_copy(void* dest, const void* from, size_t num) const override;
+ virtual void do_splat(void* dest, const void* item, size_t num) const override;
+ virtual void do_move_forward(void* dest, const void* from, size_t num) const override;
+ virtual void do_move_backward(void* dest, const void* from, size_t num) const override;
+ virtual int do_compare(const void* lhs, const void* rhs) const override;
}; // class SortedList
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/utils/SortedListImpl.h b/libs/hwui/utils/SortedListImpl.h
index dc385b5..b101826 100644
--- a/libs/hwui/utils/SortedListImpl.h
+++ b/libs/hwui/utils/SortedListImpl.h
@@ -41,7 +41,7 @@ protected:
virtual int do_compare(const void* lhs, const void* rhs) const = 0;
private:
- ssize_t _indexOrderOf(const void* item, size_t* order = 0) const;
+ ssize_t _indexOrderOf(const void* item, size_t* order = nullptr) const;
// these are made private, because they can't be used on a SortedVector
// (they don't have an implementation either)
diff --git a/libs/hwui/utils/Timing.h b/libs/hwui/utils/Timing.h
index eced987..dd8847a 100644
--- a/libs/hwui/utils/Timing.h
+++ b/libs/hwui/utils/Timing.h
@@ -24,12 +24,12 @@ class MethodTimer {
public:
MethodTimer(const char* name)
: mMethodName(name) {
- gettimeofday(&mStart, NULL);
+ gettimeofday(&mStart, nullptr);
}
~MethodTimer() {
struct timeval stop;
- gettimeofday(&stop, NULL);
+ gettimeofday(&stop, nullptr);
long long elapsed = (stop.tv_sec * 1000000) - (mStart.tv_sec * 1000000)
+ (stop.tv_usec - mStart.tv_usec);
ALOGD("%s took %.2fms", mMethodName, elapsed / 1000.0);