diff options
Diffstat (limited to 'libs')
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(®ion, 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); |