diff options
author | 2018-12-13 16:40:14 -0800 | |
---|---|---|
committer | 2018-12-14 14:07:18 -0800 | |
commit | 283bb46846ad161045efc4650d3cbc40abf5f24b (patch) | |
tree | 732e431c7f704282c3ae5a669f22999520f2507e | |
parent | 832c17330e2d0ce52f1471404ef539a63f120ca2 (diff) |
New WebViewFunctor API
Should function alongside existing functor API.
Bug: 120997728
Test: hwuiunit passes
Change-Id: I8f6143d0be1111431b55016f34de319f6b8c8910
48 files changed, 940 insertions, 315 deletions
diff --git a/core/jni/android_view_DisplayListCanvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp index e0fd1a634557..40a133b9383b 100644 --- a/core/jni/android_view_DisplayListCanvas.cpp +++ b/core/jni/android_view_DisplayListCanvas.cpp @@ -168,6 +168,11 @@ static void android_view_DisplayListCanvas_drawCircleProps(jlong canvasPtr, canvas->drawCircle(xProp, yProp, radiusProp, paintProp); } +static void android_view_DisplayListCanvas_drawWebViewFunctor(jlong canvasPtr, jint functor) { + Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr); + canvas->drawWebViewFunctor(functor); +} + // ---------------------------------------------------------------------------- // JNI Glue // ---------------------------------------------------------------------------- @@ -192,6 +197,7 @@ static JNINativeMethod gMethods[] = { { "nDrawTextureLayer", "(JJ)V", (void*) android_view_DisplayListCanvas_drawTextureLayer }, { "nDrawCircle", "(JJJJJ)V", (void*) android_view_DisplayListCanvas_drawCircleProps }, { "nDrawRoundRect", "(JJJJJJJJ)V",(void*) android_view_DisplayListCanvas_drawRoundRectProps }, + { "nDrawWebViewFunctor", "(JI)V", (void*) android_view_DisplayListCanvas_drawWebViewFunctor }, }; int register_android_view_DisplayListCanvas(JNIEnv* env) { diff --git a/graphics/java/android/graphics/RecordingCanvas.java b/graphics/java/android/graphics/RecordingCanvas.java index 67ad4045868e..515532ffda52 100644 --- a/graphics/java/android/graphics/RecordingCanvas.java +++ b/graphics/java/android/graphics/RecordingCanvas.java @@ -189,6 +189,14 @@ public final class RecordingCanvas extends DisplayListCanvas { nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunctor, releasedCallback); } + /** + * Calls the provided functor that was created via WebViewFunctor_create() + * @hide + */ + public void drawWebViewFunctor(int functor) { + nDrawWebViewFunctor(mNativeCanvasWrapper, functor); + } + /////////////////////////////////////////////////////////////////////////// // Display list /////////////////////////////////////////////////////////////////////////// @@ -303,4 +311,6 @@ public final class RecordingCanvas extends DisplayListCanvas { @CriticalNative private static native void nDrawRoundRect(long renderer, long propLeft, long propTop, long propRight, long propBottom, long propRx, long propRy, long propPaint); + @CriticalNative + private static native void nDrawWebViewFunctor(long canvas, int functor); } diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index d22eaf38cef6..b631b120f468 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -9,6 +9,8 @@ cc_defaults { "hwui_lto", ], + cpp_std: "experimental", + cflags: [ "-DEGL_EGLEXT_PROTOTYPES", "-DGL_GLEXT_PROTOTYPES", @@ -224,6 +226,7 @@ cc_defaults { "RenderProperties.cpp", "SkiaCanvas.cpp", "TreeInfo.cpp", + "WebViewFunctorManager.cpp", "VectorDrawable.cpp", "protos/graphicsstats.proto", ], @@ -328,6 +331,7 @@ cc_test { "tests/unit/TypefaceTests.cpp", "tests/unit/VectorDrawableTests.cpp", "tests/unit/VectorDrawableAtlasTests.cpp", + "tests/unit/WebViewFunctorManagerTests.cpp", ], } diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 00ce28ad196f..1ff7ffe6bf87 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -288,7 +288,10 @@ void RenderNode::syncDisplayList(TreeObserver& observer, TreeInfo* info) { mDisplayList = mStagingDisplayList; mStagingDisplayList = nullptr; if (mDisplayList) { - mDisplayList->syncContents(); + WebViewSyncData syncData { + .applyForceDark = info && !info->disableForceDark + }; + mDisplayList->syncContents(syncData); handleForceDark(info); } } diff --git a/libs/hwui/WebViewFunctorManager.cpp b/libs/hwui/WebViewFunctorManager.cpp new file mode 100644 index 000000000000..20e77b453706 --- /dev/null +++ b/libs/hwui/WebViewFunctorManager.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2018 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 "WebViewFunctorManager.h" + +#include <private/hwui/WebViewFunctor.h> +#include "Properties.h" + +#include <log/log.h> +#include <utils/Trace.h> +#include <atomic> + +namespace android::uirenderer { + +RenderMode WebViewFunctor_queryPlatformRenderMode() { + auto pipelineType = Properties::getRenderPipelineType(); + switch (pipelineType) { + case RenderPipelineType::SkiaGL: + return RenderMode::OpenGL_ES; + case RenderPipelineType::SkiaVulkan: + return RenderMode::Vulkan; + default: + LOG_ALWAYS_FATAL("Unknown render pipeline type: %d", (int)pipelineType); + } +} + +int WebViewFunctor_create(const WebViewFunctorCallbacks& prototype, RenderMode functorMode) { + if (functorMode != RenderMode::OpenGL_ES && functorMode != RenderMode::Vulkan) { + ALOGW("Unknown rendermode %d", (int)functorMode); + return -1; + } + if (functorMode == RenderMode::Vulkan && + WebViewFunctor_queryPlatformRenderMode() != RenderMode::Vulkan) { + ALOGW("Unable to map from GLES platform to a vulkan functor"); + return -1; + } + return WebViewFunctorManager::instance().createFunctor(prototype, functorMode); +} + +void WebViewFunctor_release(int functor) { + WebViewFunctorManager::instance().releaseFunctor(functor); +} + +static std::atomic_int sNextId{1}; + +WebViewFunctor::WebViewFunctor(const WebViewFunctorCallbacks& callbacks, RenderMode functorMode) { + mFunctor = sNextId++; + mCallbacks = callbacks; + mMode = functorMode; +} + +WebViewFunctor::~WebViewFunctor() { + destroyContext(); + + ATRACE_NAME("WebViewFunctor::onDestroy"); + mCallbacks.onDestroyed(mFunctor); +} + +void WebViewFunctor::sync(const WebViewSyncData& syncData) const { + ATRACE_NAME("WebViewFunctor::sync"); + mCallbacks.onSync(mFunctor, syncData); +} + +void WebViewFunctor::drawGl(const DrawGlInfo& drawInfo) { + ATRACE_NAME("WebViewFunctor::drawGl"); + if (!mHasContext) { + mHasContext = true; + } + mCallbacks.gles.draw(mFunctor, drawInfo); +} + +void WebViewFunctor::destroyContext() { + if (mHasContext) { + mHasContext = false; + ATRACE_NAME("WebViewFunctor::onContextDestroyed"); + mCallbacks.onContextDestroyed(mFunctor); + } +} + +WebViewFunctorManager& WebViewFunctorManager::instance() { + static WebViewFunctorManager sInstance; + return sInstance; +} + +int WebViewFunctorManager::createFunctor(const WebViewFunctorCallbacks& callbacks, + RenderMode functorMode) { + auto object = std::make_unique<WebViewFunctor>(callbacks, functorMode); + int id = object->id(); + auto handle = object->createHandle(); + { + std::lock_guard _lock{mLock}; + mActiveFunctors.push_back(std::move(handle)); + mFunctors.push_back(std::move(object)); + } + return id; +} + +void WebViewFunctorManager::releaseFunctor(int functor) { + sp<WebViewFunctor::Handle> toRelease; + { + std::lock_guard _lock{mLock}; + for (auto iter = mActiveFunctors.begin(); iter != mActiveFunctors.end(); iter++) { + if ((*iter)->id() == functor) { + toRelease = std::move(*iter); + mActiveFunctors.erase(iter); + break; + } + } + } +} + +void WebViewFunctorManager::onContextDestroyed() { + // WARNING: SKETCHY + // Because we know that we always remove from mFunctors on RenderThread, the same + // thread that always invokes onContextDestroyed, we know that the functor pointers + // will remain valid without the lock held. + // However, we won't block new functors from being added in the meantime. + mLock.lock(); + const size_t size = mFunctors.size(); + WebViewFunctor* toDestroyContext[size]; + for (size_t i = 0; i < size; i++) { + toDestroyContext[i] = mFunctors[i].get(); + } + mLock.unlock(); + for (size_t i = 0; i < size; i++) { + toDestroyContext[i]->destroyContext(); + } +} + +void WebViewFunctorManager::destroyFunctor(int functor) { + std::unique_ptr<WebViewFunctor> toRelease; + { + std::lock_guard _lock{mLock}; + for (auto iter = mFunctors.begin(); iter != mFunctors.end(); iter++) { + if ((*iter)->id() == functor) { + toRelease = std::move(*iter); + mFunctors.erase(iter); + break; + } + } + } +} + +sp<WebViewFunctor::Handle> WebViewFunctorManager::handleFor(int functor) { + std::lock_guard _lock{mLock}; + for (auto& iter : mActiveFunctors) { + if (iter->id() == functor) { + return iter; + } + } + return nullptr; +} + +} // namespace android::uirenderer
\ No newline at end of file diff --git a/libs/hwui/WebViewFunctorManager.h b/libs/hwui/WebViewFunctorManager.h new file mode 100644 index 000000000000..2a621dd411e3 --- /dev/null +++ b/libs/hwui/WebViewFunctorManager.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2018 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. + */ + +#pragma once + +#include <private/hwui/WebViewFunctor.h> +#include <renderthread/RenderProxy.h> + +#include <utils/LightRefBase.h> +#include <mutex> +#include <vector> + +namespace android::uirenderer { + +class WebViewFunctorManager; + +class WebViewFunctor { +public: + WebViewFunctor(const WebViewFunctorCallbacks& callbacks, RenderMode functorMode); + ~WebViewFunctor(); + + class Handle : public LightRefBase<Handle> { + public: + ~Handle() { renderthread::RenderProxy::destroyFunctor(id()); } + + int id() const { return mReference.id(); } + + void sync(const WebViewSyncData& syncData) const { mReference.sync(syncData); } + + void drawGl(const DrawGlInfo& drawInfo) const { mReference.drawGl(drawInfo); } + + private: + friend class WebViewFunctor; + + Handle(WebViewFunctor& ref) : mReference(ref) {} + + WebViewFunctor& mReference; + }; + + int id() const { return mFunctor; } + void sync(const WebViewSyncData& syncData) const; + void drawGl(const DrawGlInfo& drawInfo); + void destroyContext(); + + sp<Handle> createHandle() { + LOG_ALWAYS_FATAL_IF(mCreatedHandle); + mCreatedHandle = true; + return sp<Handle>{new Handle(*this)}; + } + +private: + WebViewFunctorCallbacks mCallbacks; + int mFunctor; + RenderMode mMode; + bool mHasContext = false; + bool mCreatedHandle = false; +}; + +class WebViewFunctorManager { +public: + static WebViewFunctorManager& instance(); + + int createFunctor(const WebViewFunctorCallbacks& callbacks, RenderMode functorMode); + void releaseFunctor(int functor); + void onContextDestroyed(); + void destroyFunctor(int functor); + + sp<WebViewFunctor::Handle> handleFor(int functor); + +private: + WebViewFunctorManager() = default; + ~WebViewFunctorManager() = default; + + std::mutex mLock; + std::vector<std::unique_ptr<WebViewFunctor>> mFunctors; + std::vector<sp<WebViewFunctor::Handle>> mActiveFunctors; +}; + +} // namespace android::uirenderer diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h index a5f21d8e6d73..71814c365c31 100644 --- a/libs/hwui/hwui/Canvas.h +++ b/libs/hwui/hwui/Canvas.h @@ -178,6 +178,9 @@ public: virtual void drawRenderNode(uirenderer::RenderNode* renderNode) = 0; virtual void callDrawGLFunction(Functor* functor, uirenderer::GlFunctorLifecycleListener* listener) = 0; + virtual void drawWebViewFunctor(int /*functor*/) { + LOG_ALWAYS_FATAL("Not supported"); + } // ---------------------------------------------------------------------------- // Canvas state operations diff --git a/libs/hwui/pipeline/skia/FunctorDrawable.h b/libs/hwui/pipeline/skia/FunctorDrawable.h index af3a056864a7..cf2f93b95e71 100644 --- a/libs/hwui/pipeline/skia/FunctorDrawable.h +++ b/libs/hwui/pipeline/skia/FunctorDrawable.h @@ -21,7 +21,9 @@ #include <SkCanvas.h> #include <SkDrawable.h> +#include <WebViewFunctorManager.h> #include <utils/Functor.h> +#include <variant> namespace android { namespace uirenderer { @@ -35,17 +37,43 @@ namespace skiapipeline { class FunctorDrawable : public SkDrawable { public: FunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas) - : mFunctor(functor), mListener(listener), mBounds(canvas->getLocalClipBounds()) {} + : mBounds(canvas->getLocalClipBounds()) + , mAnyFunctor(std::in_place_type<LegacyFunctor>, functor, listener) {} + + FunctorDrawable(int functor, SkCanvas* canvas) + : mBounds(canvas->getLocalClipBounds()) + , mAnyFunctor(std::in_place_type<NewFunctor>, functor) {} + virtual ~FunctorDrawable() {} - virtual void syncFunctor() const = 0; + virtual void syncFunctor(const WebViewSyncData& data) const { + if (mAnyFunctor.index() == 0) { + std::get<0>(mAnyFunctor).handle->sync(data); + } else { + (*(std::get<1>(mAnyFunctor).functor))(DrawGlInfo::kModeSync, nullptr); + } + } protected: virtual SkRect onGetBounds() override { return mBounds; } - Functor* mFunctor; - sp<GlFunctorLifecycleListener> mListener; const SkRect mBounds; + + struct LegacyFunctor { + explicit LegacyFunctor(Functor* functor, GlFunctorLifecycleListener* listener) + : functor(functor), listener(listener) {} + Functor* functor; + sp<GlFunctorLifecycleListener> listener; + }; + + struct NewFunctor { + explicit NewFunctor(int functor) { + handle = WebViewFunctorManager::instance().handleFor(functor); + } + sp<WebViewFunctor::Handle> handle; + }; + + std::variant<NewFunctor, LegacyFunctor> mAnyFunctor; }; } // namespace skiapipeline diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp index 4a87e7502c6f..240efb41285c 100644 --- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp +++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp @@ -17,29 +17,28 @@ #include "GLFunctorDrawable.h" #include <GrContext.h> #include <private/hwui/DrawGlInfo.h> +#include "FunctorDrawable.h" #include "GlFunctorLifecycleListener.h" +#include "GrBackendSurface.h" +#include "GrRenderTarget.h" +#include "GrRenderTargetContext.h" #include "RenderNode.h" #include "SkAndroidFrameworkUtils.h" #include "SkClipStack.h" #include "SkRect.h" -#include "GrBackendSurface.h" -#include "GrRenderTarget.h" -#include "GrRenderTargetContext.h" namespace android { namespace uirenderer { namespace skiapipeline { GLFunctorDrawable::~GLFunctorDrawable() { - if (mListener.get() != nullptr) { - mListener->onGlFunctorReleased(mFunctor); + if (auto lp = std::get_if<LegacyFunctor>(&mAnyFunctor)) { + if (lp->listener) { + lp->listener->onGlFunctorReleased(lp->functor); + } } } -void GLFunctorDrawable::syncFunctor() const { - (*mFunctor)(DrawGlInfo::kModeSync, nullptr); -} - static void setScissor(int viewportHeight, const SkIRect& clip) { SkASSERT(!clip.isEmpty()); // transform to Y-flipped GL space, and prevent negatives @@ -49,14 +48,14 @@ static void setScissor(int viewportHeight, const SkIRect& clip) { } static bool GetFboDetails(SkCanvas* canvas, GLuint* outFboID, SkISize* outFboSize) { - GrRenderTargetContext *renderTargetContext = + GrRenderTargetContext* renderTargetContext = canvas->internal_private_accessTopLayerRenderTargetContext(); if (!renderTargetContext) { ALOGW("Unable to extract renderTarget info from canvas; aborting GLFunctor draw"); return false; } - GrRenderTarget *renderTarget = renderTargetContext->accessRenderTarget(); + GrRenderTarget* renderTarget = renderTargetContext->accessRenderTarget(); if (!renderTarget) { ALOGW("Unable to extract renderTarget info from canvas; aborting GLFunctor draw"); return false; @@ -94,16 +93,16 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) { sk_sp<SkSurface> tmpSurface; // we are in a state where there is an unclipped saveLayer if (fboID != 0 && !surfaceBounds.contains(clipBounds)) { - // create an offscreen layer and clear it - SkImageInfo surfaceInfo = canvas->imageInfo().makeWH(clipBounds.width(), clipBounds.height()); - tmpSurface = SkSurface::MakeRenderTarget(canvas->getGrContext(), SkBudgeted::kYes, - surfaceInfo); + SkImageInfo surfaceInfo = + canvas->imageInfo().makeWH(clipBounds.width(), clipBounds.height()); + tmpSurface = + SkSurface::MakeRenderTarget(canvas->getGrContext(), SkBudgeted::kYes, surfaceInfo); tmpSurface->getCanvas()->clear(SK_ColorTRANSPARENT); GrGLFramebufferInfo fboInfo; if (!tmpSurface->getBackendRenderTarget(SkSurface::kFlushWrite_BackendHandleAccess) - .getGLFramebufferInfo(&fboInfo)) { + .getGLFramebufferInfo(&fboInfo)) { ALOGW("Unable to extract renderTarget info from offscreen canvas; aborting GLFunctor"); return; } @@ -144,7 +143,7 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) { bool clearStencilAfterFunctor = false; if (CC_UNLIKELY(clipRegion.isComplex())) { // clear the stencil - //TODO: move stencil clear and canvas flush to SkAndroidFrameworkUtils::clipWithStencil + // TODO: move stencil clear and canvas flush to SkAndroidFrameworkUtils::clipWithStencil glDisable(GL_SCISSOR_TEST); glStencilMask(0x1); glClearStencil(0); @@ -163,7 +162,7 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) { // GL ops get inserted here if previous flush is missing, which could dirty the stencil bool stencilWritten = SkAndroidFrameworkUtils::clipWithStencil(tmpCanvas); - tmpCanvas->flush(); //need this flush for the single op that draws into the stencil + tmpCanvas->flush(); // need this flush for the single op that draws into the stencil // ensure that the framebuffer that the webview will render into is bound before after we // draw into the stencil @@ -188,7 +187,11 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) { setScissor(info.height, clipRegion.getBounds()); } - (*mFunctor)(DrawGlInfo::kModeDraw, &info); + if (mAnyFunctor.index() == 0) { + std::get<0>(mAnyFunctor).handle->drawGl(info); + } else { + (*(std::get<1>(mAnyFunctor).functor))(DrawGlInfo::kModeDraw, &info); + } if (clearStencilAfterFunctor) { // clear stencil buffer as it may be used by Skia diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.h b/libs/hwui/pipeline/skia/GLFunctorDrawable.h index 215979cba2e3..2ea4f67428bc 100644 --- a/libs/hwui/pipeline/skia/GLFunctorDrawable.h +++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.h @@ -31,11 +31,9 @@ namespace skiapipeline { */ class GLFunctorDrawable : public FunctorDrawable { public: - GLFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas) - : FunctorDrawable(functor, listener, canvas) {} - virtual ~GLFunctorDrawable(); + using FunctorDrawable::FunctorDrawable; - void syncFunctor() const override; + virtual ~GLFunctorDrawable(); protected: void onDraw(SkCanvas* canvas) override; diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp index f08ac17e4082..eed19420a78a 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.cpp +++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp @@ -14,8 +14,8 @@ * limitations under the License. */ -#include <utils/MathUtils.h> #include "LayerDrawable.h" +#include <utils/MathUtils.h> #include "GrBackendSurface.h" #include "SkColorFilter.h" @@ -44,10 +44,9 @@ static bool shouldFilter(const SkMatrix& matrix) { if (!matrix.isScaleTranslate()) return true; // We only care about meaningful scale here - bool noScale = MathUtils::isOne(matrix.getScaleX()) - && MathUtils::isOne(matrix.getScaleY()); - bool pixelAligned = SkScalarIsInt(matrix.getTranslateX()) - && SkScalarIsInt(matrix.getTranslateY()); + bool noScale = MathUtils::isOne(matrix.getScaleX()) && MathUtils::isOne(matrix.getScaleY()); + bool pixelAligned = + SkScalarIsInt(matrix.getTranslateX()) && SkScalarIsInt(matrix.getTranslateY()); return !(noScale && pixelAligned); } @@ -120,11 +119,12 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer // Integer translation is defined as when src rect and dst rect align fractionally. // Skia TextureOp has the above logic build-in, but not NonAAFillRectOp. TextureOp works // only for SrcOver blending and without color filter (readback uses Src blending). - bool isIntegerTranslate = isBasicallyTranslate(totalMatrix) - && SkScalarFraction(skiaDestRect.fLeft + totalMatrix[SkMatrix::kMTransX]) - == SkScalarFraction(skiaSrcRect.fLeft) - && SkScalarFraction(skiaDestRect.fTop + totalMatrix[SkMatrix::kMTransY]) - == SkScalarFraction(skiaSrcRect.fTop); + bool isIntegerTranslate = + isBasicallyTranslate(totalMatrix) && + SkScalarFraction(skiaDestRect.fLeft + totalMatrix[SkMatrix::kMTransX]) == + SkScalarFraction(skiaSrcRect.fLeft) && + SkScalarFraction(skiaDestRect.fTop + totalMatrix[SkMatrix::kMTransY]) == + SkScalarFraction(skiaSrcRect.fTop); if (layer->getForceFilter() || !isIntegerTranslate) { paint.setFilterQuality(kLow_SkFilterQuality); } diff --git a/libs/hwui/pipeline/skia/LayerDrawable.h b/libs/hwui/pipeline/skia/LayerDrawable.h index 95dc6d0cf096..7cd515ae9fcb 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.h +++ b/libs/hwui/pipeline/skia/LayerDrawable.h @@ -32,8 +32,8 @@ class LayerDrawable : public SkDrawable { public: explicit LayerDrawable(DeferredLayerUpdater* layerUpdater) : mLayerUpdater(layerUpdater) {} - static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer, - const SkRect* srcRect, const SkRect* dstRect, bool useLayerTransform); + static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer, const SkRect* srcRect, + const SkRect* dstRect, bool useLayerTransform); protected: virtual SkRect onGetBounds() override { diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp index 4494cb05df10..df1537e2d824 100644 --- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp +++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp @@ -127,6 +127,7 @@ public: mNode.markDrawEnd(mCanvas); } } + private: SkCanvas& mCanvas; RenderNode& mNode; @@ -140,7 +141,7 @@ void RenderNodeDrawable::forceDraw(SkCanvas* canvas) { // ensures that we paint the layer even if it is not currently visible in the // event that the properties change and it becomes visible. if ((mProjectedDisplayList == nullptr && !renderNode->isRenderable()) || - (renderNode->nothingToDraw() && mComposeLayer)) { + (renderNode->nothingToDraw() && mComposeLayer)) { return; } @@ -234,8 +235,8 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const { // we need to restrict the portion of the surface drawn to the size of the renderNode. SkASSERT(renderNode->getLayerSurface()->width() >= bounds.width()); SkASSERT(renderNode->getLayerSurface()->height() >= bounds.height()); - canvas->drawImageRect(renderNode->getLayerSurface()->makeImageSnapshot().get(), - bounds, bounds, &paint); + canvas->drawImageRect(renderNode->getLayerSurface()->makeImageSnapshot().get(), bounds, + bounds, &paint); if (!renderNode->getSkiaLayer()->hasRenderedSinceRepaint) { renderNode->getSkiaLayer()->hasRenderedSinceRepaint = true; diff --git a/libs/hwui/pipeline/skia/ShaderCache.cpp b/libs/hwui/pipeline/skia/ShaderCache.cpp index 073b4814305e..562a3b225e36 100644 --- a/libs/hwui/pipeline/skia/ShaderCache.cpp +++ b/libs/hwui/pipeline/skia/ShaderCache.cpp @@ -15,11 +15,11 @@ */ #include "ShaderCache.h" -#include <algorithm> #include <log/log.h> -#include <thread> -#include <array> #include <openssl/sha.h> +#include <algorithm> +#include <array> +#include <thread> #include "FileBlobCache.h" #include "Properties.h" #include "utils/TraceUtils.h" @@ -44,8 +44,7 @@ ShaderCache& ShaderCache::get() { } bool ShaderCache::validateCache(const void* identity, ssize_t size) { - if (nullptr == identity && size == 0) - return true; + if (nullptr == identity && size == 0) return true; if (nullptr == identity || size < 0) { if (CC_UNLIKELY(Properties::debugLevel & kDebugCaches)) { @@ -66,8 +65,7 @@ bool ShaderCache::validateCache(const void* identity, ssize_t size) { auto key = sIDKey; auto loaded = mBlobCache->get(&key, sizeof(key), hash.data(), hash.size()); - if (loaded && std::equal(hash.begin(), hash.end(), mIDHash.begin())) - return true; + if (loaded && std::equal(hash.begin(), hash.end(), mIDHash.begin())) return true; if (CC_UNLIKELY(Properties::debugLevel & kDebugCaches)) { ALOGW("ShaderCache::validateCache cache validation fails"); @@ -119,7 +117,7 @@ sk_sp<SkData> ShaderCache::load(const SkData& key) { int maxTries = 3; while (valueSize > mObservedBlobValueSize && maxTries > 0) { mObservedBlobValueSize = std::min(valueSize, maxValueSize); - void *newValueBuffer = realloc(valueBuffer, mObservedBlobValueSize); + void* newValueBuffer = realloc(valueBuffer, mObservedBlobValueSize); if (!newValueBuffer) { free(valueBuffer); return nullptr; @@ -133,7 +131,7 @@ sk_sp<SkData> ShaderCache::load(const SkData& key) { return nullptr; } if (valueSize > mObservedBlobValueSize) { - ALOGE("ShaderCache::load value size is too big %d", (int) valueSize); + ALOGE("ShaderCache::load value size is too big %d", (int)valueSize); free(valueBuffer); return nullptr; } diff --git a/libs/hwui/pipeline/skia/ShaderCache.h b/libs/hwui/pipeline/skia/ShaderCache.h index 82804cf93785..d41aadb269dd 100644 --- a/libs/hwui/pipeline/skia/ShaderCache.h +++ b/libs/hwui/pipeline/skia/ShaderCache.h @@ -16,12 +16,12 @@ #pragma once +#include <GrContextOptions.h> #include <cutils/compiler.h> #include <memory> #include <mutex> #include <string> #include <vector> -#include <GrContextOptions.h> namespace android { @@ -52,7 +52,7 @@ public: * the initialized state the load and store methods will return without * performing any cache operations. */ - virtual void initShaderDiskCache(const void *identity, ssize_t size); + virtual void initShaderDiskCache(const void* identity, ssize_t size); virtual void initShaderDiskCache() { initShaderDiskCache(nullptr, 0); } @@ -153,7 +153,7 @@ private: /** * "mObservedBlobValueSize" is the maximum value size observed by the cache reading function. */ - size_t mObservedBlobValueSize = 20*1024; + size_t mObservedBlobValueSize = 20 * 1024; /** * The time in seconds to wait before saving newly inserted cache entries. @@ -176,7 +176,7 @@ private: */ static constexpr uint8_t sIDKey = 0; - friend class ShaderCacheTestUtils; //used for unit testing + friend class ShaderCacheTestUtils; // used for unit testing }; } /* namespace skiapipeline */ diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp index ac6f6a3f776d..230065c222a9 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp @@ -27,9 +27,9 @@ namespace android { namespace uirenderer { namespace skiapipeline { -void SkiaDisplayList::syncContents() { +void SkiaDisplayList::syncContents(const WebViewSyncData& data) { for (auto& functor : mChildFunctors) { - functor->syncFunctor(); + functor->syncFunctor(data); } for (auto& animatedImage : mAnimatedImages) { animatedImage->syncProperties(); diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h index d7879e722a29..309ec02a9435 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.h +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h @@ -16,11 +16,11 @@ #pragma once -#include "hwui/AnimatedImageDrawable.h" #include "FunctorDrawable.h" #include "RecordingCanvas.h" #include "RenderNodeDrawable.h" #include "TreeInfo.h" +#include "hwui/AnimatedImageDrawable.h" #include "utils/LinearAllocator.h" #include <deque> @@ -109,7 +109,7 @@ public: * NOTE: This function can be folded into RenderNode when we no longer need * to subclass from DisplayList */ - void syncContents(); + void syncContents(const WebViewSyncData& data); /** * ONLY to be called by RenderNode::prepareTree in order to prepare this diff --git a/libs/hwui/pipeline/skia/SkiaMemoryTracer.cpp b/libs/hwui/pipeline/skia/SkiaMemoryTracer.cpp index ea578cb3ec05..e48ecf490c56 100644 --- a/libs/hwui/pipeline/skia/SkiaMemoryTracer.cpp +++ b/libs/hwui/pipeline/skia/SkiaMemoryTracer.cpp @@ -21,16 +21,16 @@ namespace uirenderer { namespace skiapipeline { SkiaMemoryTracer::SkiaMemoryTracer(std::vector<ResourcePair> resourceMap, bool itemizeType) - : mResourceMap(resourceMap) - , mItemizeType(itemizeType) - , mTotalSize("bytes", 0) - , mPurgeableSize("bytes", 0) {} + : mResourceMap(resourceMap) + , mItemizeType(itemizeType) + , mTotalSize("bytes", 0) + , mPurgeableSize("bytes", 0) {} SkiaMemoryTracer::SkiaMemoryTracer(const char* categoryKey, bool itemizeType) - : mCategoryKey(categoryKey) - , mItemizeType(itemizeType) - , mTotalSize("bytes", 0) - , mPurgeableSize("bytes", 0) {} + : mCategoryKey(categoryKey) + , mItemizeType(itemizeType) + , mTotalSize("bytes", 0) + , mPurgeableSize("bytes", 0) {} const char* SkiaMemoryTracer::mapName(const char* resourceName) { for (auto& resource : mResourceMap) { @@ -42,7 +42,7 @@ const char* SkiaMemoryTracer::mapName(const char* resourceName) { } void SkiaMemoryTracer::processElement() { - if(!mCurrentElement.empty()) { + if (!mCurrentElement.empty()) { // Only count elements that contain "size", other values just provide metadata. auto sizeResult = mCurrentValues.find("size"); if (sizeResult != mCurrentValues.end()) { @@ -136,8 +136,8 @@ void SkiaMemoryTracer::logOutput(String8& log) { for (const auto& typedValue : namedItem.second) { TraceValue traceValue = convertUnits(typedValue.second); const char* entry = (traceValue.count > 1) ? "entries" : "entry"; - log.appendFormat(" %s: %.2f %s (%d %s)\n", typedValue.first, - traceValue.value, traceValue.units, traceValue.count, entry); + log.appendFormat(" %s: %.2f %s (%d %s)\n", typedValue.first, traceValue.value, + traceValue.units, traceValue.count, entry); } } else { auto result = namedItem.second.find("size"); diff --git a/libs/hwui/pipeline/skia/SkiaMemoryTracer.h b/libs/hwui/pipeline/skia/SkiaMemoryTracer.h index abf1f4b052ce..e9a7981ef028 100644 --- a/libs/hwui/pipeline/skia/SkiaMemoryTracer.h +++ b/libs/hwui/pipeline/skia/SkiaMemoryTracer.h @@ -50,8 +50,8 @@ public: } bool shouldDumpWrappedObjects() const override { return true; } - void setMemoryBacking(const char*, const char*, const char*) override { } - void setDiscardableMemoryBacking(const char*, const SkDiscardableMemory&) override { } + void setMemoryBacking(const char*, const char*, const char*) override {} + void setDiscardableMemoryBacking(const char*, const SkDiscardableMemory&) override {} private: struct TraceValue { diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index 7a255c15bf5f..bbc827d58dfe 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -183,15 +183,15 @@ bool SkiaPipeline::createOrUpdateLayer(RenderNode* node, const DamageAccumulator } else { String8 cachesOutput; mRenderThread.cacheManager().dumpMemoryUsage(cachesOutput, - &mRenderThread.renderState()); + &mRenderThread.renderState()); ALOGE("%s", cachesOutput.string()); if (errorHandler) { std::ostringstream err; err << "Unable to create layer for " << node->getName(); const int maxTextureSize = DeviceInfo::get()->maxTextureSize(); err << ", size " << info.width() << "x" << info.height() << " max size " - << maxTextureSize << " color type " << (int)info.colorType() - << " has context " << (int)(mRenderThread.getGrContext() != nullptr); + << maxTextureSize << " color type " << (int)info.colorType() << " has context " + << (int)(mRenderThread.getGrContext() != nullptr); errorHandler->onError(err.str()); } } @@ -300,8 +300,7 @@ void SkiaPipeline::endCapture(SkSurface* surface) { mSavePictureProcessor->savePicture(data, mCapturedFile); } else { mSavePictureProcessor->savePicture( - data, - mCapturedFile + "_" + std::to_string(mCaptureSequence)); + data, mCapturedFile + "_" + std::to_string(mCaptureSequence)); } mCaptureSequence--; } diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h index 42a411a6808c..c94b24a2cde7 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaPipeline.h @@ -97,8 +97,7 @@ public: return mLightCenter; } - static void updateLighting(const LightGeometry& lightGeometry, - const LightInfo& lightInfo) { + static void updateLighting(const LightGeometry& lightGeometry, const LightInfo& lightInfo) { mLightRadius = lightGeometry.radius; mAmbientShadowAlpha = lightInfo.ambientShadowAlpha; mSpotShadowAlpha = lightInfo.spotShadowAlpha; diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index b56c3ef94791..6eefed959913 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -24,8 +24,8 @@ #include "RenderNode.h" #include "pipeline/skia/AnimatedDrawables.h" #include "pipeline/skia/GLFunctorDrawable.h" -#include "pipeline/skia/VkInteropFunctorDrawable.h" #include "pipeline/skia/VkFunctorDrawable.h" +#include "pipeline/skia/VkInteropFunctorDrawable.h" namespace android { namespace uirenderer { @@ -95,8 +95,8 @@ void SkiaRecordingCanvas::insertReorderBarrier(bool enableReorder) { drawDrawable(drawable); } if (enableReorder) { - mCurrentBarrier = mDisplayList->allocateDrawable<StartReorderBarrierDrawable>( - mDisplayList.get()); + mCurrentBarrier = + mDisplayList->allocateDrawable<StartReorderBarrierDrawable>(mDisplayList.get()); drawDrawable(mCurrentBarrier); } } @@ -127,11 +127,25 @@ void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor, if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { // TODO(cblume) use VkFunctorDrawable instead of VkInteropFunctorDrawable here when the // interop is disabled/moved. - functorDrawable = mDisplayList->allocateDrawable<VkInteropFunctorDrawable>(functor, - listener, asSkCanvas()); + functorDrawable = mDisplayList->allocateDrawable<VkInteropFunctorDrawable>( + functor, listener, asSkCanvas()); + } else { + functorDrawable = + mDisplayList->allocateDrawable<GLFunctorDrawable>(functor, listener, asSkCanvas()); + } + mDisplayList->mChildFunctors.push_back(functorDrawable); + drawDrawable(functorDrawable); +} + +void SkiaRecordingCanvas::drawWebViewFunctor(int functor) { + FunctorDrawable* functorDrawable; + if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { + // TODO(cblume) use VkFunctorDrawable instead of VkInteropFunctorDrawable here when the + // interop is disabled. + functorDrawable = + mDisplayList->allocateDrawable<VkInteropFunctorDrawable>(functor, asSkCanvas()); } else { - functorDrawable = mDisplayList->allocateDrawable<GLFunctorDrawable>(functor, listener, - asSkCanvas()); + functorDrawable = mDisplayList->allocateDrawable<GLFunctorDrawable>(functor, asSkCanvas()); } mDisplayList->mChildFunctors.push_back(functorDrawable); drawDrawable(functorDrawable); @@ -167,7 +181,7 @@ SkiaCanvas::PaintCoW&& SkiaRecordingCanvas::filterBitmap(PaintCoW&& paint, if (colorSpaceFilter) { if (tmpPaint.getColorFilter()) { tmpPaint.setColorFilter(SkColorFilter::MakeComposeFilter( - tmpPaint.refColorFilter(), std::move(colorSpaceFilter))); + tmpPaint.refColorFilter(), std::move(colorSpaceFilter))); } else { tmpPaint.setColorFilter(std::move(colorSpaceFilter)); } @@ -248,8 +262,7 @@ void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& ch filteredPaint.writeable().setFilterQuality(kLow_SkFilterQuality); } sk_sp<SkImage> image = bitmap.makeImage(); - mRecorder.drawImageLattice(image, lattice, dst, - filterPaint(std::move(filteredPaint)), + mRecorder.drawImageLattice(image, lattice, dst, filterPaint(std::move(filteredPaint)), bitmap.palette()); if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) { mDisplayList->mMutableImages.push_back(image.get()); diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h index d6107a9d9969..afeccea3fb70 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h @@ -74,6 +74,7 @@ public: virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override; virtual void callDrawGLFunction(Functor* functor, uirenderer::GlFunctorLifecycleListener* listener) override; + void drawWebViewFunctor(int functor) override; private: RecordingCanvas mRecorder; diff --git a/libs/hwui/pipeline/skia/SkiaUtils.h b/libs/hwui/pipeline/skia/SkiaUtils.h index 834446905216..fa7f1fe2f746 100644 --- a/libs/hwui/pipeline/skia/SkiaUtils.h +++ b/libs/hwui/pipeline/skia/SkiaUtils.h @@ -22,7 +22,7 @@ namespace android { static inline SkRect SkRectMakeLargest() { const SkScalar v = SK_ScalarMax; - return { -v, -v, v, v }; + return {-v, -v, v, v}; }; } /* namespace android */ diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp index 437b5dc83f58..b64eb2426231 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -20,9 +20,9 @@ #include "Readback.h" #include "SkiaPipeline.h" #include "SkiaProfileRenderer.h" +#include "VkInteropFunctorDrawable.h" #include "renderstate/RenderState.h" #include "renderthread/Frame.h" -#include "VkInteropFunctorDrawable.h" #include <SkSurface.h> #include <SkTypes.h> diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp index 71ad5e17301a..156f74a611a7 100644 --- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp +++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp @@ -17,23 +17,21 @@ #include "VkFunctorDrawable.h" #include <private/hwui/DrawVkInfo.h> -#include "thread/ThreadBase.h" -#include "utils/TimeUtils.h" #include <GrBackendDrawableInfo.h> -#include <thread> +#include <SkImage.h> #include <utils/Color.h> #include <utils/Trace.h> #include <utils/TraceUtils.h> -#include <SkImage.h> #include <vk/GrVkTypes.h> +#include <thread> +#include "thread/ThreadBase.h" +#include "utils/TimeUtils.h" namespace android { namespace uirenderer { namespace skiapipeline { -VkFunctorDrawHandler::VkFunctorDrawHandler(Functor *functor) - : INHERITED() - , mFunctor(functor) {} +VkFunctorDrawHandler::VkFunctorDrawHandler(Functor* functor) : INHERITED(), mFunctor(functor) {} VkFunctorDrawHandler::~VkFunctorDrawHandler() { // TODO(cblume) Fill in the DrawVkInfo parameters. @@ -55,14 +53,12 @@ void VkFunctorDrawHandler::draw(const GrBackendDrawableInfo& info) { (*mFunctor)(DrawVkInfo::kModeComposite, &draw_vk_info); } -VkFunctorDrawable::VkFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, - SkCanvas* canvas) - : FunctorDrawable(functor, listener, canvas) {} - -VkFunctorDrawable::~VkFunctorDrawable() = default; - -void VkFunctorDrawable::syncFunctor() const { - (*mFunctor)(DrawVkInfo::kModeSync, nullptr); +VkFunctorDrawable::~VkFunctorDrawable() { + if (auto lp = std::get_if<LegacyFunctor>(&mAnyFunctor)) { + if (lp->listener) { + lp->listener->onGlFunctorReleased(lp->functor); + } + } } void VkFunctorDrawable::onDraw(SkCanvas* /*canvas*/) { @@ -71,12 +67,17 @@ void VkFunctorDrawable::onDraw(SkCanvas* /*canvas*/) { } std::unique_ptr<FunctorDrawable::GpuDrawHandler> VkFunctorDrawable::onSnapGpuDrawHandler( - GrBackendApi backendApi, const SkMatrix& matrix) { + GrBackendApi backendApi, const SkMatrix& matrix) { if (backendApi != GrBackendApi::kVulkan) { return nullptr; } - std::unique_ptr<VkFunctorDrawHandler> draw(new VkFunctorDrawHandler(mFunctor)); - return std::move(draw); + std::unique_ptr<VkFunctorDrawHandler> draw; + if (mAnyFunctor.index() == 0) { + LOG_ALWAYS_FATAL("Not implemented"); + return nullptr; + } else { + return std::make_unique<VkFunctorDrawHandler>(std::get<1>(mAnyFunctor).functor); + } } } // namespace skiapipeline diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.h b/libs/hwui/pipeline/skia/VkFunctorDrawable.h index 5cd131405d15..d6fefc1fca06 100644 --- a/libs/hwui/pipeline/skia/VkFunctorDrawable.h +++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.h @@ -18,9 +18,9 @@ #include "FunctorDrawable.h" -#include <utils/RefBase.h> -#include <ui/GraphicBuffer.h> #include <SkImageInfo.h> +#include <ui/GraphicBuffer.h> +#include <utils/RefBase.h> namespace android { namespace uirenderer { @@ -36,6 +36,7 @@ public: ~VkFunctorDrawHandler() override; void draw(const GrBackendDrawableInfo& info) override; + private: typedef GpuDrawHandler INHERITED; @@ -48,17 +49,15 @@ private: */ class VkFunctorDrawable : public FunctorDrawable { public: - VkFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, - SkCanvas* canvas); - ~VkFunctorDrawable() override; + using FunctorDrawable::FunctorDrawable; - void syncFunctor() const override; + ~VkFunctorDrawable() override; protected: // SkDrawable functions: void onDraw(SkCanvas* canvas) override; - std::unique_ptr<FunctorDrawable::GpuDrawHandler> onSnapGpuDrawHandler(GrBackendApi backendApi, - const SkMatrix& matrix) override; + std::unique_ptr<FunctorDrawable::GpuDrawHandler> onSnapGpuDrawHandler( + GrBackendApi backendApi, const SkMatrix& matrix) override; }; } // namespace skiapipeline diff --git a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp index 82285501cb63..a5faae7d5068 100644 --- a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp +++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp @@ -17,13 +17,13 @@ #include "VkInteropFunctorDrawable.h" #include <private/hwui/DrawGlInfo.h> -#include "renderthread/EglManager.h" -#include "thread/ThreadBase.h" -#include "utils/TimeUtils.h" -#include <thread> #include <utils/Color.h> #include <utils/Trace.h> #include <utils/TraceUtils.h> +#include <thread> +#include "renderthread/EglManager.h" +#include "thread/ThreadBase.h" +#include "utils/TimeUtils.h" #include <EGL/eglext.h> #include <GLES2/gl2.h> @@ -44,6 +44,7 @@ static renderthread::EglManager sEglManager; class ScopedDrawRequest { public: ScopedDrawRequest() { beginDraw(); } + private: void beginDraw() { std::lock_guard _lock{sLock}; @@ -57,9 +58,7 @@ private: } if (!sEglManager.hasEglContext()) { - sGLDrawThread->queue().runSync([]() { - sEglManager.initialize(); - }); + sGLDrawThread->queue().runSync([]() { sEglManager.initialize(); }); } } }; @@ -93,14 +92,14 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) { if (!mFrameBuffer.get() || mFBInfo != surfaceInfo) { // Buffer will be used as an OpenGL ES render target. mFrameBuffer = new GraphicBuffer( - //TODO: try to reduce the size of the buffer: possibly by using clip bounds. - static_cast<uint32_t>(surfaceInfo.width()), - static_cast<uint32_t>(surfaceInfo.height()), - ColorTypeToPixelFormat(surfaceInfo.colorType()), - GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER | - GraphicBuffer::USAGE_SW_READ_NEVER | GraphicBuffer::USAGE_HW_RENDER, - std::string("VkInteropFunctorDrawable::onDraw pid [") + std::to_string(getpid()) + - "]"); + // TODO: try to reduce the size of the buffer: possibly by using clip bounds. + static_cast<uint32_t>(surfaceInfo.width()), + static_cast<uint32_t>(surfaceInfo.height()), + ColorTypeToPixelFormat(surfaceInfo.colorType()), + GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER | + GraphicBuffer::USAGE_SW_READ_NEVER | GraphicBuffer::USAGE_HW_RENDER, + std::string("VkInteropFunctorDrawable::onDraw pid [") + std::to_string(getpid()) + + "]"); status_t error = mFrameBuffer->initCheck(); if (error < 0) { ALOGW("VkInteropFunctorDrawable::onDraw() failed in GraphicBuffer.create()"); @@ -110,16 +109,15 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) { mFBInfo = surfaceInfo; } - //TODO: Synchronization is needed on mFrameBuffer to guarantee that the previous Vulkan - //TODO: draw command has completed. - //TODO: A simple but inefficient way is to flush and issue a QueueWaitIdle call. See - //TODO: GrVkGpu::destroyResources() for example. + // TODO: Synchronization is needed on mFrameBuffer to guarantee that the previous Vulkan + // TODO: draw command has completed. + // TODO: A simple but inefficient way is to flush and issue a QueueWaitIdle call. See + // TODO: GrVkGpu::destroyResources() for example. bool success = sGLDrawThread->queue().runSync([&]() -> bool { ATRACE_FORMAT("WebViewDraw_%dx%d", mFBInfo.width(), mFBInfo.height()); EGLDisplay display = sEglManager.eglDisplay(); - LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, - "Failed to get EGL_DEFAULT_DISPLAY! err=%s", - uirenderer::renderthread::EglManager::eglErrorString()); + LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s", + uirenderer::renderthread::EglManager::eglErrorString()); // We use an EGLImage to access the content of the GraphicBuffer // The EGL image is later bound to a 2D texture EGLClientBuffer clientBuffer = (EGLClientBuffer)mFrameBuffer->getNativeBuffer(); @@ -154,10 +152,10 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) { AutoGLFramebuffer glFb; // Bind texture to the frame buffer. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - glTexture.mTexture, 0); + glTexture.mTexture, 0); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { ALOGE("Failed framebuffer check for created target buffer: %s", - GLUtils::getGLFramebufferError()); + GLUtils::getGLFramebufferError()); return false; } @@ -166,19 +164,22 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); - (*mFunctor)(DrawGlInfo::kModeDraw, &info); + if (mAnyFunctor.index() == 0) { + std::get<0>(mAnyFunctor).handle->drawGl(info); + } else { + (*(std::get<1>(mAnyFunctor).functor))(DrawGlInfo::kModeDraw, &info); + } EGLSyncKHR glDrawFinishedFence = eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL); LOG_ALWAYS_FATAL_IF(glDrawFinishedFence == EGL_NO_SYNC_KHR, - "Could not create sync fence %#x", eglGetError()); + "Could not create sync fence %#x", eglGetError()); glFlush(); // TODO: export EGLSyncKHR in file descr // TODO: import file desc in Vulkan Semaphore // TODO: instead block the GPU: probably by using external Vulkan semaphore. // Block the CPU until the glFlush finish. - EGLint waitStatus = eglClientWaitSyncKHR(display, glDrawFinishedFence, 0, - FENCE_TIMEOUT); + EGLint waitStatus = eglClientWaitSyncKHR(display, glDrawFinishedFence, 0, FENCE_TIMEOUT); LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR, "Failed to wait for the fence %#x", eglGetError()); eglDestroySyncKHR(display, glDrawFinishedFence); @@ -197,26 +198,25 @@ void VkInteropFunctorDrawable::onDraw(SkCanvas* canvas) { canvas->resetMatrix(); auto functorImage = SkImage::MakeFromAHardwareBuffer( - reinterpret_cast<AHardwareBuffer*>(mFrameBuffer.get()), kPremul_SkAlphaType, - nullptr, kBottomLeft_GrSurfaceOrigin); + reinterpret_cast<AHardwareBuffer*>(mFrameBuffer.get()), kPremul_SkAlphaType, nullptr, + kBottomLeft_GrSurfaceOrigin); canvas->drawImage(functorImage, 0, 0, &paint); canvas->restore(); } VkInteropFunctorDrawable::~VkInteropFunctorDrawable() { - if (mListener.get() != nullptr) { - ScopedDrawRequest _drawRequest{}; - sGLDrawThread->queue().runSync([&]() { - mListener->onGlFunctorReleased(mFunctor); - }); + if (auto lp = std::get_if<LegacyFunctor>(&mAnyFunctor)) { + if (lp->listener) { + ScopedDrawRequest _drawRequest{}; + sGLDrawThread->queue().runSync( + [&]() { lp->listener->onGlFunctorReleased(lp->functor); }); + } } } -void VkInteropFunctorDrawable::syncFunctor() const { +void VkInteropFunctorDrawable::syncFunctor(const WebViewSyncData& data) const { ScopedDrawRequest _drawRequest{}; - sGLDrawThread->queue().runSync([&]() { - (*mFunctor)(DrawGlInfo::kModeSync, nullptr); - }); + sGLDrawThread->queue().runSync([&]() { FunctorDrawable::syncFunctor(data); }); } } // namespace skiapipeline diff --git a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h index 8fe52c5ef700..c47ee114263f 100644 --- a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h +++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.h @@ -18,8 +18,8 @@ #include "FunctorDrawable.h" -#include <utils/RefBase.h> #include <ui/GraphicBuffer.h> +#include <utils/RefBase.h> namespace android { namespace uirenderer { @@ -32,20 +32,18 @@ namespace skiapipeline { */ class VkInteropFunctorDrawable : public FunctorDrawable { public: - VkInteropFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, - SkCanvas* canvas) - : FunctorDrawable(functor, listener, canvas) {} - virtual ~VkInteropFunctorDrawable(); + using FunctorDrawable::FunctorDrawable; - void syncFunctor() const override; + virtual ~VkInteropFunctorDrawable(); static void vkInvokeFunctor(Functor* functor); + void syncFunctor(const WebViewSyncData& data) const override; + protected: virtual void onDraw(SkCanvas* canvas) override; private: - // Variables below describe/store temporary offscreen buffer used for Vulkan pipeline. sp<GraphicBuffer> mFrameBuffer; SkImageInfo mFBInfo; diff --git a/libs/hwui/private/hwui/WebViewFunctor.h b/libs/hwui/private/hwui/WebViewFunctor.h new file mode 100644 index 000000000000..e5346aabaee3 --- /dev/null +++ b/libs/hwui/private/hwui/WebViewFunctor.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2018 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 FRAMEWORKS_BASE_WEBVIEWFUNCTOR_H +#define FRAMEWORKS_BASE_WEBVIEWFUNCTOR_H + +#include <private/hwui/DrawGlInfo.h> + +namespace android::uirenderer { + +enum class RenderMode { + OpenGL_ES, + Vulkan, +}; + +// Static for the lifetime of the process +RenderMode WebViewFunctor_queryPlatformRenderMode(); + +struct WebViewSyncData { + bool applyForceDark; +}; + +struct WebViewFunctorCallbacks { + // kModeSync, called on RenderThread + void (*onSync)(int functor, const WebViewSyncData& syncData); + + // Called when either the context is destroyed _or_ when the functor's last reference goes + // away. Will always be called with an active context and always on renderthread. + void (*onContextDestroyed)(int functor); + + // Called when the last reference to the handle goes away and the handle is considered + // irrevocably destroyed. Will always be proceeded by a call to onContextDestroyed if + // this functor had ever been drawn. + void (*onDestroyed)(int functor); + + union { + struct { + // Called on RenderThread. initialize is guaranteed to happen before this call + void (*draw)(int functor, const DrawGlInfo& params); + } gles; + // TODO: VK support. The current DrawVkInfo is monolithic and needs to be split up for + // what params are valid on what callbacks + struct { + // Called either the first time the functor is used or the first time it's used after + // a call to onContextDestroyed. + // void (*initialize)(int functor, const InitParams& params); + // void (*frameStart)(int functor, /* todo: what params are actually needed for this to + // be useful? Is this useful? */) + // void (*draw)(int functor, const CompositeParams& params /* todo: rename - composite + // almost always means something else, and we aren't compositing */); + // void (*frameEnd)(int functor, const PostCompositeParams& params /* todo: same as + // CompositeParams - rename */); + } vk; + }; +}; + +// Creates a new WebViewFunctor from the given prototype. The prototype is copied after +// this function returns. Caller retains full ownership of it. +// Returns -1 if the creation fails (such as an unsupported functorMode + platform mode combination) +int WebViewFunctor_create(const WebViewFunctorCallbacks& prototype, RenderMode functorMode); + +// May be called on any thread to signal that the functor should be destroyed. +// The functor will receive an onDestroyed when the last usage of it is released, +// and it should be considered alive & active until that point. +void WebViewFunctor_release(int functor); + +} // namespace android::uirenderer + +#endif // FRAMEWORKS_BASE_WEBVIEWFUNCTOR_H diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 4e4262c5c0a7..8e57a3a119e3 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -576,8 +576,7 @@ void CanvasContext::trimMemory(RenderThread& thread, int level) { ATRACE_CALL(); if (level >= TRIM_MEMORY_COMPLETE) { thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::Complete); - thread.destroyGlContext(); - thread.vulkanManager().destroy(); + thread.destroyRenderingContext(); } else if (level >= TRIM_MEMORY_UI_HIDDEN) { thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::UiHidden); } diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 085812a00f71..aa6af23d8ed3 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -30,6 +30,7 @@ #include "renderthread/RenderThread.h" #include "utils/Macros.h" #include "utils/TimeUtils.h" +#include "WebViewFunctorManager.h" #include <ui/GraphicBuffer.h> @@ -143,6 +144,14 @@ void RenderProxy::invokeFunctor(Functor* functor, bool waitForCompletion) { } } +void RenderProxy::destroyFunctor(int functor) { + ATRACE_CALL(); + RenderThread& thread = RenderThread::getInstance(); + thread.queue().post([=]() { + WebViewFunctorManager::instance().destroyFunctor(functor); + }); +} + DeferredLayerUpdater* RenderProxy::createTextureLayer() { return mRenderThread.queue().runSync([this]() -> auto { return mContext->createTextureLayer(); diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index d9b789f28f8d..9dc918121be6 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -82,6 +82,7 @@ public: ANDROID_API void destroy(); ANDROID_API static void invokeFunctor(Functor* functor, bool waitForCompletion); + static void destroyFunctor(int functor); ANDROID_API DeferredLayerUpdater* createTextureLayer(); ANDROID_API void buildLayer(RenderNode* node); diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index 207673c1c8dd..c06faddf7fa6 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -132,6 +132,7 @@ RenderThread::RenderThread() , mFrameCallbackTaskPending(false) , mRenderState(nullptr) , mEglManager(nullptr) + , mFunctorManager(WebViewFunctorManager::instance()) , mVkManager(nullptr) { Properties::load(); start("RenderThread"); @@ -197,11 +198,13 @@ void RenderThread::requireGlContext() { setGrContext(grContext); } -void RenderThread::destroyGlContext() { +void RenderThread::destroyRenderingContext() { + mFunctorManager.onContextDestroyed(); if (mEglManager->hasEglContext()) { setGrContext(nullptr); mEglManager->destroy(); } + vulkanManager().destroy(); } void RenderThread::dumpGraphicsMemory(int fd) { diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index 2384f9541ec0..12666b323d11 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -23,6 +23,7 @@ #include "CacheManager.h" #include "TimeLord.h" #include "thread/ThreadBase.h" +#include "WebViewFunctorManager.h" #include <GrContext.h> #include <SkBitmap.h> @@ -104,7 +105,7 @@ public: void dumpGraphicsMemory(int fd); void requireGlContext(); - void destroyGlContext(); + void destroyRenderingContext(); /** * isCurrent provides a way to query, if the caller is running on @@ -151,6 +152,7 @@ private: TimeLord mTimeLord; RenderState* mRenderState; EglManager* mEglManager; + WebViewFunctorManager& mFunctorManager; ProfileDataContainer mGlobalProfileData; Readback* mReadback = nullptr; diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp index f81202292a49..7aa9b82e3583 100644 --- a/libs/hwui/tests/common/TestUtils.cpp +++ b/libs/hwui/tests/common/TestUtils.cpp @@ -32,6 +32,8 @@ namespace android { namespace uirenderer { +std::unordered_map<int, TestUtils::CallCounts> TestUtils::sMockFunctorCounts{}; + SkColor TestUtils::interpolateColor(float fraction, SkColor start, SkColor end) { int startA = (start >> 24) & 0xff; int startR = (start >> 16) & 0xff; @@ -82,12 +84,10 @@ void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint uint32_t length = strlen(text); SkPaint glyphPaint(paint); glyphPaint.setTextEncoding(kGlyphID_SkTextEncoding); - canvas->drawText( - utf16.get(), length, // text buffer - 0, length, // draw range - 0, length, // context range - x, y, minikin::Bidi::LTR, - glyphPaint, nullptr, nullptr /* measured text */); + canvas->drawText(utf16.get(), length, // text buffer + 0, length, // draw range + 0, length, // context range + x, y, minikin::Bidi::LTR, glyphPaint, nullptr, nullptr /* measured text */); } void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint& paint, @@ -96,7 +96,7 @@ void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint SkPaint glyphPaint(paint); glyphPaint.setTextEncoding(kGlyphID_SkTextEncoding); canvas->drawTextOnPath(utf16.get(), strlen(text), minikin::Bidi::LTR, path, 0, 0, glyphPaint, - nullptr); + nullptr); } void TestUtils::TestTask::run() { @@ -110,11 +110,7 @@ void TestUtils::TestTask::run() { rtCallback(renderThread); - if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { - renderThread.vulkanManager().destroy(); - } else { - renderThread.destroyGlContext(); - } + renderThread.destroyRenderingContext(); } std::unique_ptr<uint16_t[]> TestUtils::asciiToUtf16(const char* str) { diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h index c5db861d4f48..5ff8993e6779 100644 --- a/libs/hwui/tests/common/TestUtils.h +++ b/libs/hwui/tests/common/TestUtils.h @@ -27,6 +27,7 @@ #include <renderstate/RenderState.h> #include <renderthread/RenderThread.h> +#include <gtest/gtest.h> #include <memory> namespace android { @@ -201,8 +202,7 @@ public: static void recordNode(RenderNode& node, std::function<void(Canvas&)> contentCallback) { std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas( - node.stagingProperties().getWidth(), node.stagingProperties().getHeight(), - &node)); + node.stagingProperties().getWidth(), node.stagingProperties().getHeight(), &node)); contentCallback(*canvas.get()); node.setStagingDisplayList(canvas->finishRecording()); } @@ -267,7 +267,14 @@ public: renderthread::RenderThread::getInstance().queue().runSync([&]() { task.run(); }); } + static void runOnRenderThreadUnmanaged(RtCallback rtCallback) { + auto& rt = renderthread::RenderThread::getInstance(); + rt.queue().runSync([&]() { rtCallback(rt); }); + } + + static bool isRenderThreadRunning() { return renderthread::RenderThread::hasInstance(); } + static pid_t getRenderThreadTid() { return renderthread::RenderThread::getInstance().getTid(); } static SkColor interpolateColor(float fraction, SkColor start, SkColor end); @@ -296,7 +303,52 @@ public: static SkRect getClipBounds(const SkCanvas* canvas); static SkRect getLocalClipBounds(const SkCanvas* canvas); + struct CallCounts { + int sync = 0; + int contextDestroyed = 0; + int destroyed = 0; + int glesDraw = 0; + }; + + static void expectOnRenderThread() { EXPECT_EQ(gettid(), TestUtils::getRenderThreadTid()); } + + static WebViewFunctorCallbacks createMockFunctor(RenderMode mode) { + auto callbacks = WebViewFunctorCallbacks{ + .onSync = + [](int functor, const WebViewSyncData& data) { + expectOnRenderThread(); + sMockFunctorCounts[functor].sync++; + }, + .onContextDestroyed = + [](int functor) { + expectOnRenderThread(); + sMockFunctorCounts[functor].contextDestroyed++; + }, + .onDestroyed = + [](int functor) { + expectOnRenderThread(); + sMockFunctorCounts[functor].destroyed++; + }, + }; + switch (mode) { + case RenderMode::OpenGL_ES: + callbacks.gles.draw = [](int functor, const DrawGlInfo& params) { + expectOnRenderThread(); + sMockFunctorCounts[functor].glesDraw++; + }; + break; + default: + ADD_FAILURE(); + return WebViewFunctorCallbacks{}; + } + return callbacks; + } + + static CallCounts& countsForFunctor(int functor) { return sMockFunctorCounts[functor]; } + private: + static std::unordered_map<int, CallCounts> sMockFunctorCounts; + static void syncHierarchyPropertiesAndDisplayListImpl(RenderNode* node) { MarkAndSweepRemoved observer(nullptr); node->syncProperties(); @@ -306,9 +358,9 @@ private: } auto displayList = node->getDisplayList(); if (displayList) { - for (auto&& childDr : static_cast<skiapipeline::SkiaDisplayList*>( - const_cast<DisplayList*>(displayList)) - ->mChildNodes) { + for (auto&& childDr : + static_cast<skiapipeline::SkiaDisplayList*>(const_cast<DisplayList*>(displayList)) + ->mChildNodes) { syncHierarchyPropertiesAndDisplayListImpl(childDr.getRenderNode()); } } diff --git a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp index a6869791a915..f4c3e13b0ea6 100644 --- a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp +++ b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp @@ -19,9 +19,9 @@ #include "tests/common/TestUtils.h" -#include <gtest/gtest.h> #include <SkBitmap.h> #include <SkImage.h> +#include <gtest/gtest.h> using namespace android; using namespace android::uirenderer; diff --git a/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp b/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp index 08b967964c59..dac888cd79ca 100644 --- a/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp +++ b/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp @@ -39,7 +39,7 @@ public: // current thread can spoof being a GPU thread static void destroyEglContext() { if (TestUtils::isRenderThreadRunning()) { - TestUtils::runOnRenderThread([](RenderThread& thread) { thread.destroyGlContext(); }); + TestUtils::runOnRenderThread([](RenderThread& thread) { thread.destroyRenderingContext(); }); } } diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp index 0331581799b7..c813cd945905 100644 --- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp +++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp @@ -355,9 +355,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, emptyReceiver) { class ProjectionTestCanvas : public SkCanvas { public: ProjectionTestCanvas(int width, int height) : SkCanvas(width, height) {} - void onDrawRect(const SkRect& rect, const SkPaint& paint) override { - mDrawCounter++; - } + void onDrawRect(const SkRect& rect, const SkPaint& paint) override { mDrawCounter++; } int getDrawCounter() { return mDrawCounter; } @@ -370,7 +368,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, emptyReceiver) { [](RenderProperties& properties, SkiaRecordingCanvas& canvas) { properties.setProjectionReceiver(true); }, - "B"); // a receiver with an empty display list + "B"); // a receiver with an empty display list auto projectingRipple = TestUtils::createSkiaNode( 0, 0, 100, 100, @@ -389,14 +387,14 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, emptyReceiver) { canvas.drawRenderNode(projectingRipple.get()); }, "C"); - auto parent = TestUtils::createSkiaNode( - 0, 0, 100, 100, - [&receiverBackground, &child](RenderProperties& properties, - SkiaRecordingCanvas& canvas) { - canvas.drawRenderNode(receiverBackground.get()); - canvas.drawRenderNode(child.get()); - }, - "A"); + auto parent = + TestUtils::createSkiaNode(0, 0, 100, 100, + [&receiverBackground, &child](RenderProperties& properties, + SkiaRecordingCanvas& canvas) { + canvas.drawRenderNode(receiverBackground.get()); + canvas.drawRenderNode(child.get()); + }, + "A"); ContextFactory contextFactory; std::unique_ptr<CanvasContext> canvasContext( CanvasContext::create(renderThread, false, parent.get(), &contextFactory)); @@ -1058,7 +1056,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, layerComposeQuality) { public: FrameTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {} void onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, - const SkPaint* paint, SrcRectConstraint constraint) override { + const SkPaint* paint, SrcRectConstraint constraint) override { mDrawCounter++; EXPECT_EQ(kLow_SkFilterQuality, paint->getFilterQuality()); } @@ -1076,7 +1074,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, layerComposeQuality) { FrameTestCanvas canvas; RenderNodeDrawable drawable(layerNode.get(), &canvas, true); canvas.drawDrawable(&drawable); - EXPECT_EQ(1, canvas.mDrawCounter); //make sure the layer was composed + EXPECT_EQ(1, canvas.mDrawCounter); // make sure the layer was composed // clean up layer pointer, so we can safely destruct RenderNode layerNode->setLayerSurface(nullptr); @@ -1129,15 +1127,14 @@ TEST(ReorderBarrierDrawable, testShadowMatrix) { getTotalMatrix()); } else { // Second invocation is preparing the matrix for an elevated RenderNodeDrawable. - EXPECT_EQ(SkMatrix::MakeTrans(TRANSLATE_X, TRANSLATE_Y), - matrix); - EXPECT_EQ(SkMatrix::MakeTrans(TRANSLATE_X, TRANSLATE_Y), - getTotalMatrix()); + EXPECT_EQ(SkMatrix::MakeTrans(TRANSLATE_X, TRANSLATE_Y), matrix); + EXPECT_EQ(SkMatrix::MakeTrans(TRANSLATE_X, TRANSLATE_Y), getTotalMatrix()); } } protected: int mDrawCounter = 0; + private: bool mFirstDidConcat = true; }; @@ -1174,14 +1171,14 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaRecordingCanvas, drawVectorDrawable) { public: VectorDrawableTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {} void onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, - const SkPaint* paint, SrcRectConstraint constraint) override { + const SkPaint* paint, SrcRectConstraint constraint) override { const int index = mDrawCounter++; switch (index) { case 0: EXPECT_EQ(dst, SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT)); break; case 1: - EXPECT_EQ(dst, SkRect::MakeWH(CANVAS_WIDTH/2, CANVAS_HEIGHT)); + EXPECT_EQ(dst, SkRect::MakeWH(CANVAS_WIDTH / 2, CANVAS_HEIGHT)); break; default: ADD_FAILURE(); @@ -1191,17 +1188,18 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaRecordingCanvas, drawVectorDrawable) { VectorDrawable::Group* group = new VectorDrawable::Group(); sp<VectorDrawableRoot> vectorDrawable(new VectorDrawableRoot(group)); - vectorDrawable->mutateStagingProperties()->setScaledSize(CANVAS_WIDTH/10, CANVAS_HEIGHT/10); + vectorDrawable->mutateStagingProperties()->setScaledSize(CANVAS_WIDTH / 10, CANVAS_HEIGHT / 10); - auto node = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, - [&](RenderProperties& props, SkiaRecordingCanvas& canvas) { - vectorDrawable->mutateStagingProperties()->setBounds(SkRect::MakeWH(CANVAS_WIDTH, - CANVAS_HEIGHT)); - canvas.drawVectorDrawable(vectorDrawable.get()); - vectorDrawable->mutateStagingProperties()->setBounds(SkRect::MakeWH(CANVAS_WIDTH/2, - CANVAS_HEIGHT)); - canvas.drawVectorDrawable(vectorDrawable.get()); - }); + auto node = + TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, + [&](RenderProperties& props, SkiaRecordingCanvas& canvas) { + vectorDrawable->mutateStagingProperties()->setBounds( + SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT)); + canvas.drawVectorDrawable(vectorDrawable.get()); + vectorDrawable->mutateStagingProperties()->setBounds( + SkRect::MakeWH(CANVAS_WIDTH / 2, CANVAS_HEIGHT)); + canvas.drawVectorDrawable(vectorDrawable.get()); + }); VectorDrawableTestCanvas canvas; RenderNodeDrawable drawable(node.get(), &canvas, true); diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp index a6073ebb5c74..3ebd0538ce87 100644 --- a/libs/hwui/tests/unit/RenderNodeTests.cpp +++ b/libs/hwui/tests/unit/RenderNodeTests.cpp @@ -295,7 +295,8 @@ RENDERTHREAD_TEST(RenderNode, prepareTree_nullableDisplayList) { canvasContext->destroy(); } -RENDERTHREAD_TEST(RenderNode, prepareTree_HwLayer_AVD_enqueueDamage) { +// TODO: Is this supposed to work in SkiaGL/SkiaVK? +RENDERTHREAD_TEST(DISABLED_RenderNode, prepareTree_HwLayer_AVD_enqueueDamage) { VectorDrawable::Group* group = new VectorDrawable::Group(); sp<VectorDrawableRoot> vectorDrawable(new VectorDrawableRoot(group)); diff --git a/libs/hwui/tests/unit/ShaderCacheTests.cpp b/libs/hwui/tests/unit/ShaderCacheTests.cpp index 1433aa0349f4..87981f115763 100644 --- a/libs/hwui/tests/unit/ShaderCacheTests.cpp +++ b/libs/hwui/tests/unit/ShaderCacheTests.cpp @@ -14,17 +14,17 @@ * limitations under the License. */ -#include <gtest/gtest.h> -#include <dirent.h> #include <cutils/properties.h> -#include <cstdint> +#include <dirent.h> #include <errno.h> +#include <gtest/gtest.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <utils/Log.h> -#include "pipeline/skia/ShaderCache.h" +#include <cstdint> #include "FileBlobCache.h" +#include "pipeline/skia/ShaderCache.h" using namespace android::uirenderer::skiapipeline; @@ -66,7 +66,6 @@ public: } /* namespace uirenderer */ } /* namespace android */ - namespace { std::string getExternalStorageFolder() { @@ -82,14 +81,12 @@ bool folderExist(const std::string& folderName) { return false; } -inline bool -checkShader(const sk_sp<SkData>& shader1, const sk_sp<SkData>& shader2) { - return nullptr != shader1 && nullptr != shader2 && shader1->size() == shader2->size() - && 0 == memcmp(shader1->data(), shader2->data(), shader1->size()); +inline bool checkShader(const sk_sp<SkData>& shader1, const sk_sp<SkData>& shader2) { + return nullptr != shader1 && nullptr != shader2 && shader1->size() == shader2->size() && + 0 == memcmp(shader1->data(), shader2->data(), shader1->size()); } -inline bool -checkShader(const sk_sp<SkData>& shader, const char* program) { +inline bool checkShader(const sk_sp<SkData>& shader, const char* program) { sk_sp<SkData> shader2 = SkData::MakeWithCString(program); return checkShader(shader, shader2); } @@ -116,32 +113,31 @@ void genRandomData(std::vector<T>& buffer) { } } - #define GrProgramDescTest(a) (*SkData::MakeWithCString(#a).get()) TEST(ShaderCacheTest, testWriteAndRead) { if (!folderExist(getExternalStorageFolder())) { - //don't run the test if external storage folder is not available + // don't run the test if external storage folder is not available return; } - std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1"; - std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2"; + std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1"; + std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2"; - //remove any test files from previous test run + // remove any test files from previous test run int deleteFile = remove(cacheFile1.c_str()); ASSERT_TRUE(0 == deleteFile || ENOENT == errno); std::srand(0); - //read the cache from a file that does not exist + // read the cache from a file that does not exist ShaderCache::get().setFilename(cacheFile1.c_str()); - ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); //disable deferred save + ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); // disable deferred save ShaderCache::get().initShaderDiskCache(); - //read a key - should not be found since the cache is empty + // read a key - should not be found since the cache is empty sk_sp<SkData> outVS; ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp<SkData>()); - //write to the in-memory cache without storing on disk and verify we read the same values + // write to the in-memory cache without storing on disk and verify we read the same values sk_sp<SkData> inVS; setShader(inVS, "sassas"); ShaderCache::get().store(GrProgramDescTest(100), *inVS.get()); @@ -152,23 +148,23 @@ TEST(ShaderCacheTest, testWriteAndRead) { ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>()); ASSERT_TRUE(checkShader(outVS, "someVS")); - //store content to disk and release in-memory cache + // store content to disk and release in-memory cache ShaderCacheTestUtils::terminate(ShaderCache::get(), true); - //change to a file that does not exist and verify load fails + // change to a file that does not exist and verify load fails ShaderCache::get().setFilename(cacheFile2.c_str()); ShaderCache::get().initShaderDiskCache(); ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp<SkData>()); ShaderCacheTestUtils::terminate(ShaderCache::get(), false); - //load again content from disk from an existing file and check the data is read correctly + // load again content from disk from an existing file and check the data is read correctly ShaderCache::get().setFilename(cacheFile1.c_str()); ShaderCache::get().initShaderDiskCache(); sk_sp<SkData> outVS2; ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>()); ASSERT_TRUE(checkShader(outVS2, "someVS")); - //change data, store to disk, read back again and verify data has been changed + // change data, store to disk, read back again and verify data has been changed setShader(inVS, "ewData1"); ShaderCache::get().store(GrProgramDescTest(432), *inVS.get()); ShaderCacheTestUtils::terminate(ShaderCache::get(), true); @@ -176,9 +172,8 @@ TEST(ShaderCacheTest, testWriteAndRead) { ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>()); ASSERT_TRUE(checkShader(outVS2, "ewData1")); - - //write and read big data chunk (50K) - size_t dataSize = 50*1024; + // write and read big data chunk (50K) + size_t dataSize = 50 * 1024; std::vector<uint8_t> dataBuffer(dataSize); genRandomData(dataBuffer); setShader(inVS, dataBuffer); @@ -194,31 +189,31 @@ TEST(ShaderCacheTest, testWriteAndRead) { TEST(ShaderCacheTest, testCacheValidation) { if (!folderExist(getExternalStorageFolder())) { - //don't run the test if external storage folder is not available + // don't run the test if external storage folder is not available return; } - std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1"; - std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2"; + std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1"; + std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2"; - //remove any test files from previous test run + // remove any test files from previous test run int deleteFile = remove(cacheFile1.c_str()); ASSERT_TRUE(0 == deleteFile || ENOENT == errno); std::srand(0); - //generate identity and read the cache from a file that does not exist + // generate identity and read the cache from a file that does not exist ShaderCache::get().setFilename(cacheFile1.c_str()); - ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); //disable deferred save + ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); // disable deferred save std::vector<uint8_t> identity(1024); genRandomData(identity); - ShaderCache::get().initShaderDiskCache(identity.data(), identity.size() * - sizeof(decltype(identity)::value_type)); + ShaderCache::get().initShaderDiskCache( + identity.data(), identity.size() * sizeof(decltype(identity)::value_type)); // generate random content in cache and store to disk constexpr size_t numBlob(10); constexpr size_t keySize(1024); constexpr size_t dataSize(50 * 1024); - std::vector< std::pair<sk_sp<SkData>, sk_sp<SkData>> > blobVec(numBlob); + std::vector<std::pair<sk_sp<SkData>, sk_sp<SkData>>> blobVec(numBlob); for (auto& blob : blobVec) { std::vector<uint8_t> keyBuffer(keySize); std::vector<uint8_t> dataBuffer(dataSize); @@ -237,47 +232,47 @@ TEST(ShaderCacheTest, testCacheValidation) { // change to a file that does not exist and verify validation fails ShaderCache::get().setFilename(cacheFile2.c_str()); ShaderCache::get().initShaderDiskCache(); - ASSERT_FALSE( ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity) ); + ASSERT_FALSE(ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity)); ShaderCacheTestUtils::terminate(ShaderCache::get(), false); // restore the original file and verify validation succeeds ShaderCache::get().setFilename(cacheFile1.c_str()); - ShaderCache::get().initShaderDiskCache(identity.data(), identity.size() * - sizeof(decltype(identity)::value_type)); - ASSERT_TRUE( ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity) ); + ShaderCache::get().initShaderDiskCache( + identity.data(), identity.size() * sizeof(decltype(identity)::value_type)); + ASSERT_TRUE(ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity)); for (const auto& blob : blobVec) { auto outVS = ShaderCache::get().load(*blob.first.get()); - ASSERT_TRUE( checkShader(outVS, blob.second) ); + ASSERT_TRUE(checkShader(outVS, blob.second)); } // generate error identity and verify load fails ShaderCache::get().initShaderDiskCache(identity.data(), -1); for (const auto& blob : blobVec) { - ASSERT_EQ( ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>() ); + ASSERT_EQ(ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>()); } - ShaderCache::get().initShaderDiskCache(nullptr, identity.size() * - sizeof(decltype(identity)::value_type)); + ShaderCache::get().initShaderDiskCache( + nullptr, identity.size() * sizeof(decltype(identity)::value_type)); for (const auto& blob : blobVec) { - ASSERT_EQ( ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>() ); + ASSERT_EQ(ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>()); } // verify the cache validation again after load fails - ShaderCache::get().initShaderDiskCache(identity.data(), identity.size() * - sizeof(decltype(identity)::value_type)); - ASSERT_TRUE( ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity) ); + ShaderCache::get().initShaderDiskCache( + identity.data(), identity.size() * sizeof(decltype(identity)::value_type)); + ASSERT_TRUE(ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity)); for (const auto& blob : blobVec) { auto outVS = ShaderCache::get().load(*blob.first.get()); - ASSERT_TRUE( checkShader(outVS, blob.second) ); + ASSERT_TRUE(checkShader(outVS, blob.second)); } // generate another identity and verify load fails for (auto& data : identity) { data += std::rand(); } - ShaderCache::get().initShaderDiskCache(identity.data(), identity.size() * - sizeof(decltype(identity)::value_type)); + ShaderCache::get().initShaderDiskCache( + identity.data(), identity.size() * sizeof(decltype(identity)::value_type)); for (const auto& blob : blobVec) { - ASSERT_EQ( ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>() ); + ASSERT_EQ(ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>()); } ShaderCacheTestUtils::terminate(ShaderCache::get(), false); diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp index 415f9e8517ff..53bf84f13fd6 100644 --- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp +++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp @@ -100,16 +100,35 @@ TEST(SkiaDisplayList, syncContexts) { GLFunctorDrawable functorDrawable(&functor, nullptr, &dummyCanvas); skiaDL.mChildFunctors.push_back(&functorDrawable); + int functor2 = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES), + RenderMode::OpenGL_ES); + auto& counts = TestUtils::countsForFunctor(functor2); + skiaDL.mChildFunctors.push_back( + skiaDL.allocateDrawable<GLFunctorDrawable>(functor2, &dummyCanvas)); + WebViewFunctor_release(functor2); + SkRect bounds = SkRect::MakeWH(200, 200); VectorDrawableRoot vectorDrawable(new VectorDrawable::Group()); vectorDrawable.mutateStagingProperties()->setBounds(bounds); skiaDL.mVectorDrawables.push_back(&vectorDrawable); // ensure that the functor and vectorDrawable are properly synced - skiaDL.syncContents(); - - ASSERT_EQ(functor.getLastMode(), DrawGlInfo::kModeSync); - ASSERT_EQ(vectorDrawable.mutateProperties()->getBounds(), bounds); + TestUtils::runOnRenderThread([&](auto&) { + skiaDL.syncContents(WebViewSyncData{ + .applyForceDark = false, + }); + }); + + EXPECT_EQ(functor.getLastMode(), DrawGlInfo::kModeSync); + EXPECT_EQ(counts.sync, 1); + EXPECT_EQ(counts.destroyed, 0); + EXPECT_EQ(vectorDrawable.mutateProperties()->getBounds(), bounds); + + skiaDL.reset(); + TestUtils::runOnRenderThread([](auto&) { + // Fence + }); + EXPECT_EQ(counts.destroyed, 1); } class ContextFactory : public IContextFactory { diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp index d16b8be89e20..3c06dab36fe4 100644 --- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp +++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp @@ -24,10 +24,10 @@ #include "DamageAccumulator.h" #include "IContextFactory.h" #include "SkiaCanvas.h" -#include "pipeline/skia/SkiaUtils.h" #include "pipeline/skia/SkiaDisplayList.h" #include "pipeline/skia/SkiaOpenGLPipeline.h" #include "pipeline/skia/SkiaRecordingCanvas.h" +#include "pipeline/skia/SkiaUtils.h" #include "renderthread/CanvasContext.h" #include "tests/common/TestUtils.h" @@ -51,8 +51,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrame) { auto surface = SkSurface::MakeRasterN32Premul(1, 1); surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, - surface); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED); } @@ -84,8 +83,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, testOnPrepareTree) { ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); // drawFrame will crash if "SkiaPipeline::onPrepareTree" did not clean invalid VD pointer - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, - surface); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED); } @@ -106,12 +104,10 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckOpaque) { auto surface = SkSurface::MakeRasterN32Premul(2, 2); surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, - surface); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, false, contentDrawBounds, - surface); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, false, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned int)SK_ColorTRANSPARENT); ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN); } @@ -130,8 +126,7 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckDirtyRect) { auto surface = SkSurface::MakeRasterN32Premul(2, 2); surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, - surface); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); ASSERT_EQ(TestUtils::getColor(surface, 1, 0), SK_ColorBLUE); ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorRED); @@ -203,38 +198,32 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderOverdraw) { ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); // Single draw, should be white. - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, - surface); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE); // 1 Overdraw, should be blue blended onto white. renderNodes.push_back(whiteNode); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, - surface); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffd0d0ff); // 2 Overdraw, should be green blended onto white renderNodes.push_back(whiteNode); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, - surface); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffd0ffd0); // 3 Overdraw, should be pink blended onto white. renderNodes.push_back(whiteNode); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, - surface); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffffc0c0); // 4 Overdraw, should be red blended onto white. renderNodes.push_back(whiteNode); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, - surface); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffff8080); // 5 Overdraw, should be red blended onto white. renderNodes.push_back(whiteNode); - pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, - surface); + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface); ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffff8080); } @@ -389,7 +378,6 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, context_lost) { EXPECT_FALSE(pipeline->isSurfaceReady()); EXPECT_TRUE(pipeline->setSurface((Surface*)0x01, SwapBehavior::kSwap_default, ColorMode::SRGB)); EXPECT_TRUE(pipeline->isSurfaceReady()); - renderThread.destroyGlContext(); + renderThread.destroyRenderingContext(); EXPECT_FALSE(pipeline->isSurfaceReady()); } - diff --git a/libs/hwui/tests/unit/TypefaceTests.cpp b/libs/hwui/tests/unit/TypefaceTests.cpp index b645aeb55074..1a09b1c52d8a 100644 --- a/libs/hwui/tests/unit/TypefaceTests.cpp +++ b/libs/hwui/tests/unit/TypefaceTests.cpp @@ -54,9 +54,9 @@ std::shared_ptr<minikin::FontFamily> buildFamily(const char* fileName) { sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault()); sk_sp<SkTypeface> typeface(fm->makeFromStream(std::move(fontData))); LOG_ALWAYS_FATAL_IF(typeface == nullptr, "Failed to make typeface from %s", fileName); - std::shared_ptr<minikin::MinikinFont> font = std::make_shared<MinikinFontSkia>( - std::move(typeface), data, st.st_size, fileName, 0, - std::vector<minikin::FontVariation>()); + std::shared_ptr<minikin::MinikinFont> font = + std::make_shared<MinikinFontSkia>(std::move(typeface), data, st.st_size, fileName, 0, + std::vector<minikin::FontVariation>()); std::vector<minikin::Font> fonts; fonts.push_back(minikin::Font::Builder(font).build()); return std::make_shared<minikin::FontFamily>(std::move(fonts)); diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp index ee6beba847a0..9e7f0964b2d2 100644 --- a/libs/hwui/tests/unit/VectorDrawableTests.cpp +++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp @@ -85,8 +85,10 @@ const static TestData sTestDataSet[] = { outPath->rCubicTo(8.0, 8.0, 8.0, 8.0, 8.0, 8.0); outPath->cubicTo(16.0, 16.0, 9.0, 9.0, 9.0, 9.0); outPath->rCubicTo(0.0, 0.0, 9.0, 9.0, 9.0, 9.0); - outPath->arcTo(10.0, 10.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCW_Direction, 10.0, 10.0); - outPath->arcTo(10.0, 10.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCW_Direction, 20.0, 20.0); + outPath->arcTo(10.0, 10.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCW_Direction, 10.0, + 10.0); + outPath->arcTo(10.0, 10.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCW_Direction, 20.0, + 20.0); }}, // Check box VectorDrawable path data @@ -157,7 +159,8 @@ const static TestData sTestDataSet[] = { }, [](SkPath* outPath) { outPath->moveTo(300.0, 70.0); - outPath->arcTo(230.0, 230.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCCW_Direction, 301.0, 70.0); + outPath->arcTo(230.0, 230.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCCW_Direction, + 301.0, 70.0); outPath->close(); outPath->moveTo(300.0, 70.0); }}, @@ -236,14 +239,14 @@ struct StringPath { }; const StringPath sStringPaths[] = { - {"3e...3", false}, // Not starting with a verb and ill-formatted float - {"L.M.F.A.O", false}, // No floats following verbs - {"m 1 1", true}, // Valid path data - {"\n \t z", true}, // Valid path data with leading spaces - {"1-2e34567", false}, // Not starting with a verb and ill-formatted float - {"f 4 5", false}, // Invalid verb - {"\r ", false}, // Empty string - {"L1,0 L1,1 L0,1 z M1000", false} // Not enough floats following verb M. + {"3e...3", false}, // Not starting with a verb and ill-formatted float + {"L.M.F.A.O", false}, // No floats following verbs + {"m 1 1", true}, // Valid path data + {"\n \t z", true}, // Valid path data with leading spaces + {"1-2e34567", false}, // Not starting with a verb and ill-formatted float + {"f 4 5", false}, // Invalid verb + {"\r ", false}, // Empty string + {"L1,0 L1,1 L0,1 z M1000", false} // Not enough floats following verb M. }; static bool hasSameVerbs(const PathData& from, const PathData& to) { diff --git a/libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp b/libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp new file mode 100644 index 000000000000..c8169aff1c5e --- /dev/null +++ b/libs/hwui/tests/unit/WebViewFunctorManagerTests.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2018 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 "WebViewFunctorManager.h" +#include "private/hwui/WebViewFunctor.h" +#include "renderthread/RenderProxy.h" +#include "tests/common/TestUtils.h" + +#include <unordered_map> + +using namespace android; +using namespace android::uirenderer; + +TEST(WebViewFunctor, createDestroyGLES) { + int functor = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES), + RenderMode::OpenGL_ES); + ASSERT_NE(-1, functor); + WebViewFunctor_release(functor); + TestUtils::runOnRenderThreadUnmanaged([](renderthread::RenderThread&) { + // Empty, don't care + }); + auto& counts = TestUtils::countsForFunctor(functor); + // We never initialized, so contextDestroyed == 0 + EXPECT_EQ(0, counts.contextDestroyed); + EXPECT_EQ(1, counts.destroyed); +} + +TEST(WebViewFunctor, createSyncHandleGLES) { + int functor = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES), + RenderMode::OpenGL_ES); + ASSERT_NE(-1, functor); + auto handle = WebViewFunctorManager::instance().handleFor(functor); + ASSERT_TRUE(handle); + WebViewFunctor_release(functor); + EXPECT_FALSE(WebViewFunctorManager::instance().handleFor(functor)); + TestUtils::runOnRenderThreadUnmanaged([](renderthread::RenderThread&) { + // fence + }); + auto& counts = TestUtils::countsForFunctor(functor); + EXPECT_EQ(0, counts.sync); + EXPECT_EQ(0, counts.contextDestroyed); + EXPECT_EQ(0, counts.destroyed); + + TestUtils::runOnRenderThreadUnmanaged([&](auto&) { + WebViewSyncData syncData; + handle->sync(syncData); + }); + + EXPECT_EQ(1, counts.sync); + + TestUtils::runOnRenderThreadUnmanaged([&](auto&) { + WebViewSyncData syncData; + handle->sync(syncData); + }); + + EXPECT_EQ(2, counts.sync); + + handle.clear(); + + TestUtils::runOnRenderThreadUnmanaged([](renderthread::RenderThread&) { + // fence + }); + + EXPECT_EQ(2, counts.sync); + EXPECT_EQ(0, counts.contextDestroyed); + EXPECT_EQ(1, counts.destroyed); +} + +TEST(WebViewFunctor, createSyncDrawGLES) { + int functor = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES), + RenderMode::OpenGL_ES); + ASSERT_NE(-1, functor); + auto handle = WebViewFunctorManager::instance().handleFor(functor); + ASSERT_TRUE(handle); + WebViewFunctor_release(functor); + auto& counts = TestUtils::countsForFunctor(functor); + for (int i = 0; i < 5; i++) { + TestUtils::runOnRenderThreadUnmanaged([&](auto&) { + WebViewSyncData syncData; + handle->sync(syncData); + DrawGlInfo drawInfo; + handle->drawGl(drawInfo); + handle->drawGl(drawInfo); + }); + } + handle.clear(); + TestUtils::runOnRenderThreadUnmanaged([](renderthread::RenderThread&) { + // fence + }); + EXPECT_EQ(5, counts.sync); + EXPECT_EQ(10, counts.glesDraw); + EXPECT_EQ(1, counts.contextDestroyed); + EXPECT_EQ(1, counts.destroyed); +} + +TEST(WebViewFunctor, contextDestroyed) { + int functor = WebViewFunctor_create(TestUtils::createMockFunctor(RenderMode::OpenGL_ES), + RenderMode::OpenGL_ES); + ASSERT_NE(-1, functor); + auto handle = WebViewFunctorManager::instance().handleFor(functor); + ASSERT_TRUE(handle); + WebViewFunctor_release(functor); + auto& counts = TestUtils::countsForFunctor(functor); + TestUtils::runOnRenderThreadUnmanaged([&](auto&) { + WebViewSyncData syncData; + handle->sync(syncData); + DrawGlInfo drawInfo; + handle->drawGl(drawInfo); + }); + EXPECT_EQ(1, counts.sync); + EXPECT_EQ(1, counts.glesDraw); + EXPECT_EQ(0, counts.contextDestroyed); + EXPECT_EQ(0, counts.destroyed); + TestUtils::runOnRenderThreadUnmanaged([](auto& rt) { + rt.destroyRenderingContext(); + }); + EXPECT_EQ(1, counts.sync); + EXPECT_EQ(1, counts.glesDraw); + EXPECT_EQ(1, counts.contextDestroyed); + EXPECT_EQ(0, counts.destroyed); + TestUtils::runOnRenderThreadUnmanaged([&](auto&) { + WebViewSyncData syncData; + handle->sync(syncData); + DrawGlInfo drawInfo; + handle->drawGl(drawInfo); + }); + EXPECT_EQ(2, counts.sync); + EXPECT_EQ(2, counts.glesDraw); + EXPECT_EQ(1, counts.contextDestroyed); + EXPECT_EQ(0, counts.destroyed); + handle.clear(); + TestUtils::runOnRenderThreadUnmanaged([](renderthread::RenderThread&) { + // fence + }); + EXPECT_EQ(2, counts.sync); + EXPECT_EQ(2, counts.glesDraw); + EXPECT_EQ(2, counts.contextDestroyed); + EXPECT_EQ(1, counts.destroyed); +}
\ No newline at end of file diff --git a/libs/hwui/tests/unit/main.cpp b/libs/hwui/tests/unit/main.cpp index aecceb3609f5..63d15403b607 100644 --- a/libs/hwui/tests/unit/main.cpp +++ b/libs/hwui/tests/unit/main.cpp @@ -17,14 +17,14 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "Properties.h" #include "debug/GlesDriver.h" #include "debug/NullGlesDriver.h" #include "hwui/Typeface.h" -#include "Properties.h" #include "tests/common/LeakChecker.h" -#include "thread/TaskProcessor.h" #include "thread/Task.h" #include "thread/TaskManager.h" +#include "thread/TaskProcessor.h" #include <signal.h> |