diff options
author | John Reck <jreck@google.com> | 2018-04-09 16:56:34 -0700 |
---|---|---|
committer | John Reck <jreck@google.com> | 2018-04-11 13:39:19 -0700 |
commit | 18f442eb2d9c8cf9e7ce397ef1b2d526dd421ea6 (patch) | |
tree | 857ecc45a31aa4bca493ce548994d333efb95320 | |
parent | 076b631dd958819a640670714e27833998e6e29b (diff) |
Remove RenderPipelineType::OpenGL (1/many)
Just removes the define & all things referencing the define.
Test: hwui_unit passes
Change-Id: I3f98c271e23ef696c40addf260abdc0fb149a70d
24 files changed, 20 insertions, 5100 deletions
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 592a6e64a58b..be7f300918aa 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -345,33 +345,21 @@ cc_test { srcs: [ "tests/unit/main.cpp", - "tests/unit/BakedOpDispatcherTests.cpp", - "tests/unit/BakedOpRendererTests.cpp", - "tests/unit/BakedOpStateTests.cpp", "tests/unit/CacheManagerTests.cpp", "tests/unit/CanvasContextTests.cpp", "tests/unit/CanvasStateTests.cpp", "tests/unit/ClipAreaTests.cpp", "tests/unit/DamageAccumulatorTests.cpp", "tests/unit/DeferredLayerUpdaterTests.cpp", - "tests/unit/DeviceInfoTests.cpp", "tests/unit/FatVectorTests.cpp", - "tests/unit/FontRendererTests.cpp", - "tests/unit/FrameBuilderTests.cpp", - "tests/unit/GlopBuilderTests.cpp", "tests/unit/GpuMemoryTrackerTests.cpp", - "tests/unit/GradientCacheTests.cpp", "tests/unit/GraphicsStatsServiceTests.cpp", "tests/unit/LayerUpdateQueueTests.cpp", - "tests/unit/LeakCheckTests.cpp", "tests/unit/LinearAllocatorTests.cpp", "tests/unit/MatrixTests.cpp", - "tests/unit/MeshStateTests.cpp", - "tests/unit/OffscreenBufferPoolTests.cpp", "tests/unit/OpDumperTests.cpp", "tests/unit/PathInterpolatorTests.cpp", "tests/unit/RenderNodeDrawableTests.cpp", - "tests/unit/RecordingCanvasTests.cpp", "tests/unit/RenderNodeTests.cpp", "tests/unit/RenderPropertiesTests.cpp", "tests/unit/ShaderCacheTests.cpp", @@ -383,8 +371,6 @@ cc_test { "tests/unit/SnapshotTests.cpp", "tests/unit/StringUtilsTests.cpp", "tests/unit/TestUtilsTests.cpp", - "tests/unit/TextDropShadowCacheTests.cpp", - "tests/unit/TextureCacheTests.cpp", "tests/unit/ThreadBaseTests.cpp", "tests/unit/TypefaceTests.cpp", "tests/unit/VectorDrawableTests.cpp", diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index 7b143224f728..0d1257fc7b12 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -193,15 +193,12 @@ RenderPipelineType Properties::getRenderPipelineType() { } char prop[PROPERTY_VALUE_MAX]; property_get(PROPERTY_RENDERER, prop, "skiagl"); - if (!strcmp(prop, "skiagl")) { - ALOGD("Skia GL Pipeline"); - sRenderPipelineType = RenderPipelineType::SkiaGL; - } else if (!strcmp(prop, "skiavk")) { + if (!strcmp(prop, "skiavk")) { ALOGD("Skia Vulkan Pipeline"); sRenderPipelineType = RenderPipelineType::SkiaVulkan; - } else { //"opengl" - ALOGD("HWUI GL Pipeline"); - sRenderPipelineType = RenderPipelineType::OpenGL; + } else { //"skiagl" + ALOGD("Skia GL Pipeline"); + sRenderPipelineType = RenderPipelineType::SkiaGL; } return sRenderPipelineType; } diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 1a0bdfd4c237..03a3e36c4495 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -206,7 +206,7 @@ enum class OverdrawColorSet { Default = 0, Deuteranomaly }; enum class StencilClipDebug { Hide, ShowHighlight, ShowRegion }; -enum class RenderPipelineType { OpenGL = 0, SkiaGL, SkiaVulkan, NotInitialized = 128 }; +enum class RenderPipelineType { SkiaGL, SkiaVulkan, NotInitialized = 128 }; /** * Renderthread-only singleton which manages several static rendering properties. Most of these diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 609d26c53bfe..23023e7d422b 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -69,9 +69,6 @@ CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent, auto renderType = Properties::getRenderPipelineType(); switch (renderType) { - case RenderPipelineType::OpenGL: - return new CanvasContext(thread, translucent, rootRenderNode, contextFactory, - std::make_unique<OpenGLPipeline>(thread)); case RenderPipelineType::SkiaGL: return new CanvasContext(thread, translucent, rootRenderNode, contextFactory, std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread)); @@ -86,28 +83,13 @@ CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent, } void CanvasContext::destroyLayer(RenderNode* node) { - auto renderType = Properties::getRenderPipelineType(); - switch (renderType) { - case RenderPipelineType::OpenGL: - OpenGLPipeline::destroyLayer(node); - break; - case RenderPipelineType::SkiaGL: - case RenderPipelineType::SkiaVulkan: - skiapipeline::SkiaPipeline::destroyLayer(node); - break; - default: - LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType); - break; - } + skiapipeline::SkiaPipeline::destroyLayer(node); } void CanvasContext::invokeFunctor(const RenderThread& thread, Functor* functor) { ATRACE_CALL(); auto renderType = Properties::getRenderPipelineType(); switch (renderType) { - case RenderPipelineType::OpenGL: - OpenGLPipeline::invokeFunctor(thread, functor); - break; case RenderPipelineType::SkiaGL: skiapipeline::SkiaOpenGLPipeline::invokeFunctor(thread, functor); break; @@ -121,19 +103,7 @@ void CanvasContext::invokeFunctor(const RenderThread& thread, Functor* functor) } void CanvasContext::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) { - auto renderType = Properties::getRenderPipelineType(); - switch (renderType) { - case RenderPipelineType::OpenGL: - OpenGLPipeline::prepareToDraw(thread, bitmap); - break; - case RenderPipelineType::SkiaGL: - case RenderPipelineType::SkiaVulkan: - skiapipeline::SkiaPipeline::prepareToDraw(thread, bitmap); - break; - default: - LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType); - break; - } + skiapipeline::SkiaPipeline::prepareToDraw(thread, bitmap); } CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode, @@ -586,37 +556,15 @@ void CanvasContext::destroyHardwareResources() { } void CanvasContext::trimMemory(RenderThread& thread, int level) { - auto renderType = Properties::getRenderPipelineType(); - switch (renderType) { - case RenderPipelineType::OpenGL: { - // No context means nothing to free - if (!thread.eglManager().hasEglContext()) return; - ATRACE_CALL(); - if (level >= TRIM_MEMORY_COMPLETE) { - thread.renderState().flush(Caches::FlushMode::Full); - thread.eglManager().destroy(); - } else if (level >= TRIM_MEMORY_UI_HIDDEN) { - thread.renderState().flush(Caches::FlushMode::Moderate); - } - break; - } - case RenderPipelineType::SkiaGL: - case RenderPipelineType::SkiaVulkan: { - // No context means nothing to free - if (!thread.getGrContext()) return; - ATRACE_CALL(); - if (level >= TRIM_MEMORY_COMPLETE) { - thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::Complete); - thread.eglManager().destroy(); - thread.vulkanManager().destroy(); - } else if (level >= TRIM_MEMORY_UI_HIDDEN) { - thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::UiHidden); - } - break; - } - default: - LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType); - break; + ATRACE_CALL(); + if (!thread.getGrContext()) return; + ATRACE_CALL(); + if (level >= TRIM_MEMORY_COMPLETE) { + thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::Complete); + thread.eglManager().destroy(); + thread.vulkanManager().destroy(); + } else if (level >= TRIM_MEMORY_UI_HIDDEN) { + thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::UiHidden); } } diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index 4b154e6f560d..f4d230e7c76c 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -175,16 +175,6 @@ void RenderThread::dumpGraphicsMemory(int fd) { String8 pipeline; auto renderType = Properties::getRenderPipelineType(); switch (renderType) { - case RenderPipelineType::OpenGL: { - if (Caches::hasInstance()) { - cachesOutput.appendFormat("Caches:\n"); - Caches::getInstance().dumpMemoryUsage(cachesOutput); - } else { - cachesOutput.appendFormat("No caches instance."); - } - pipeline.appendFormat("FrameBuilder"); - break; - } case RenderPipelineType::SkiaGL: { mCacheManager->dumpMemoryUsage(cachesOutput, mRenderState); pipeline.appendFormat("Skia (OpenGL)"); @@ -208,9 +198,6 @@ Readback& RenderThread::readback() { if (!mReadback) { auto renderType = Properties::getRenderPipelineType(); switch (renderType) { - case RenderPipelineType::OpenGL: - mReadback = new OpenGLReadbackImpl(*this); - break; case RenderPipelineType::SkiaGL: mReadback = new skiapipeline::SkiaOpenGLReadback(*this); break; @@ -344,8 +331,6 @@ void RenderThread::pushBackFrameCallback(IFrameCallback* callback) { sk_sp<Bitmap> RenderThread::allocateHardwareBitmap(SkBitmap& skBitmap) { auto renderType = Properties::getRenderPipelineType(); switch (renderType) { - case RenderPipelineType::OpenGL: - return OpenGLPipeline::allocateHardwareBitmap(*this, skBitmap); case RenderPipelineType::SkiaGL: return skiapipeline::SkiaOpenGLPipeline::allocateHardwareBitmap(*this, skBitmap); case RenderPipelineType::SkiaVulkan: diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp index 03064985389e..f51e7cc04d8d 100644 --- a/libs/hwui/tests/common/TestUtils.cpp +++ b/libs/hwui/tests/common/TestUtils.cpp @@ -53,9 +53,7 @@ SkColor TestUtils::interpolateColor(float fraction, SkColor start, SkColor end) sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater( renderthread::RenderThread& renderThread) { android::uirenderer::renderthread::IRenderPipeline* pipeline; - if (Properties::getRenderPipelineType() == RenderPipelineType::OpenGL) { - pipeline = new renderthread::OpenGLPipeline(renderThread); - } else if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) { + if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) { pipeline = new skiapipeline::SkiaOpenGLPipeline(renderThread); } else { pipeline = new skiapipeline::SkiaVulkanPipeline(renderThread); diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h index 1bfa046eff63..707d61a47d0e 100644 --- a/libs/hwui/tests/common/TestUtils.h +++ b/libs/hwui/tests/common/TestUtils.h @@ -60,18 +60,6 @@ namespace uirenderer { Properties::overrideRenderPipelineType(oldType); \ }; -/** - * Like gtests' TEST, but only runs with the OpenGL RenderPipelineType - */ -#define OPENGL_PIPELINE_TEST(test_case_name, test_name) \ - class test_case_name##_##test_name##_HwuiTest { \ - public: \ - static void doTheThing(); \ - }; \ - INNER_PIPELINE_TEST(test_case_name, test_name, OpenGL, \ - test_case_name##_##test_name##_HwuiTest::doTheThing()) \ - void test_case_name##_##test_name##_HwuiTest::doTheThing() - #define INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, pipeline) \ INNER_PIPELINE_TEST(test_case_name, test_name, pipeline, \ TestUtils::runOnRenderThread( \ @@ -86,7 +74,6 @@ namespace uirenderer { public: \ static void doTheThing(renderthread::RenderThread& renderThread); \ }; \ - INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, OpenGL); \ INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaGL); \ /* Temporarily disabling Vulkan until we can figure out a way to stub out the driver */ \ /* INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaVulkan); */ \ @@ -94,18 +81,6 @@ namespace uirenderer { renderthread::RenderThread& renderThread) /** - * Like RENDERTHREAD_TEST, but only runs with the OpenGL RenderPipelineType - */ -#define RENDERTHREAD_OPENGL_PIPELINE_TEST(test_case_name, test_name) \ - class test_case_name##_##test_name##_RenderThreadTest { \ - public: \ - static void doTheThing(renderthread::RenderThread& renderThread); \ - }; \ - INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, OpenGL); \ - void test_case_name##_##test_name##_RenderThreadTest::doTheThing( \ - renderthread::RenderThread& renderThread) - -/** * Like RENDERTHREAD_TEST, but only runs with the Skia RenderPipelineTypes */ #define RENDERTHREAD_SKIA_PIPELINE_TEST(test_case_name, test_name) \ diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp index 4cb5cfdd729b..dc8e600df6b0 100644 --- a/libs/hwui/tests/macrobench/main.cpp +++ b/libs/hwui/tests/macrobench/main.cpp @@ -67,7 +67,7 @@ OPTIONS: --onscreen Render tests on device screen. By default tests are offscreen rendered --benchmark_format Set output format. Possible values are tabular, json, csv - --renderer=TYPE Sets the render pipeline to use. May be opengl, skiagl, or skiavk + --renderer=TYPE Sets the render pipeline to use. May be skiagl or skiavk --render-ahead=NUM Sets how far to render-ahead. Must be 0 (default), 1, or 2. )"); } @@ -148,9 +148,7 @@ static bool setBenchmarkFormat(const char* format) { } static bool setRenderer(const char* renderer) { - if (!strcmp(renderer, "opengl")) { - Properties::overrideRenderPipelineType(RenderPipelineType::OpenGL); - } else if (!strcmp(renderer, "skiagl")) { + if (!strcmp(renderer, "skiagl")) { Properties::overrideRenderPipelineType(RenderPipelineType::SkiaGL); } else if (!strcmp(renderer, "skiavk")) { Properties::overrideRenderPipelineType(RenderPipelineType::SkiaVulkan); diff --git a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp deleted file mode 100644 index 09f0b06ded39..000000000000 --- a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright (C) 2016 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 <BakedOpDispatcher.h> -#include <BakedOpRenderer.h> -#include <FrameBuilder.h> -#include <LayerUpdateQueue.h> -#include <RecordedOp.h> -#include <hwui/Paint.h> -#include <tests/common/TestUtils.h> -#include <utils/Color.h> - -#include <SkBlurDrawLooper.h> -#include <SkDashPathEffect.h> -#include <SkPath.h> - -using namespace android::uirenderer; - -static BakedOpRenderer::LightInfo sLightInfo; -const FrameBuilder::LightGeometry sLightGeometry = {{100, 100, 100}, 50}; - -class ValidatingBakedOpRenderer : public BakedOpRenderer { -public: - ValidatingBakedOpRenderer(RenderState& renderState, - std::function<void(const Glop& glop)> validator) - : BakedOpRenderer(Caches::getInstance(), renderState, true, false, sLightInfo) - , mValidator(validator) { - mGlopReceiver = ValidatingGlopReceiver; - } - -private: - static void ValidatingGlopReceiver(BakedOpRenderer& renderer, const Rect* dirtyBounds, - const ClipBase* clip, const Glop& glop) { - auto vbor = reinterpret_cast<ValidatingBakedOpRenderer*>(&renderer); - vbor->mValidator(glop); - } - std::function<void(const Glop& glop)> mValidator; -}; - -typedef void (*TestBakedOpReceiver)(BakedOpRenderer&, const BakedOpState&); - -static void testUnmergedGlopDispatch(renderthread::RenderThread& renderThread, RecordedOp* op, - std::function<void(const Glop& glop)> glopVerifier, - int expectedGlopCount = 1) { - // Create op, and wrap with basic state. - LinearAllocator allocator; - auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 100)); - auto state = BakedOpState::tryConstruct(allocator, *snapshot, *op); - ASSERT_NE(nullptr, state); - - int glopCount = 0; - auto glopReceiver = [&glopVerifier, &glopCount, &expectedGlopCount](const Glop& glop) { - ASSERT_LE(glopCount++, expectedGlopCount) << expectedGlopCount << "glop(s) expected"; - glopVerifier(glop); - }; - ValidatingBakedOpRenderer renderer(renderThread.renderState(), glopReceiver); - -// Dispatch based on op type created, similar to Frame/LayerBuilder dispatch behavior -#define X(Type) \ - [](BakedOpRenderer& renderer, const BakedOpState& state) { \ - BakedOpDispatcher::on##Type(renderer, static_cast<const Type&>(*(state.op)), state); \ - }, - static TestBakedOpReceiver unmergedReceivers[] = BUILD_RENDERABLE_OP_LUT(X); -#undef X - unmergedReceivers[op->opId](renderer, *state); - ASSERT_EQ(expectedGlopCount, glopCount) << "Exactly " << expectedGlopCount - << "Glop(s) expected"; -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, pathTexture_positionOvalArc) { - SkPaint strokePaint; - strokePaint.setStyle(SkPaint::kStroke_Style); - strokePaint.setStrokeWidth(4); - - float intervals[] = {1.0f, 1.0f}; - strokePaint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 0)); - - auto textureGlopVerifier = [](const Glop& glop) { - // validate glop produced by renderPathTexture (so texture, unit quad) - auto texture = glop.fill.texture.texture; - ASSERT_NE(nullptr, texture); - float expectedOffset = floor(4 * 1.5f + 0.5f); - EXPECT_EQ(expectedOffset, reinterpret_cast<PathTexture*>(texture)->offset) - << "Should see conservative offset from PathCache::computeBounds"; - Rect expectedBounds(10, 15, 20, 25); - expectedBounds.outset(expectedOffset); - - Matrix4 expectedModelView; - expectedModelView.loadTranslate(10 - expectedOffset, 15 - expectedOffset, 0); - expectedModelView.scale(10 + 2 * expectedOffset, 10 + 2 * expectedOffset, 1); - EXPECT_EQ(expectedModelView, glop.transform.modelView) - << "X and Y offsets, and scale both applied to model view"; - }; - - // Arc and Oval will render functionally the same glop, differing only in texture content - ArcOp arcOp(Rect(10, 15, 20, 25), Matrix4::identity(), nullptr, &strokePaint, 0, 270, true); - testUnmergedGlopDispatch(renderThread, &arcOp, textureGlopVerifier); - - OvalOp ovalOp(Rect(10, 15, 20, 25), Matrix4::identity(), nullptr, &strokePaint); - testUnmergedGlopDispatch(renderThread, &ovalOp, textureGlopVerifier); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, onLayerOp_bufferless) { - SkPaint layerPaint; - layerPaint.setAlpha(128); - OffscreenBuffer* buffer = nullptr; // no providing a buffer, should hit rect fallback case - LayerOp op(Rect(10, 10), Matrix4::identity(), nullptr, &layerPaint, &buffer); - testUnmergedGlopDispatch(renderThread, &op, - [](const Glop& glop) { ADD_FAILURE() << "Nothing should happen"; }, 0); -} - -static int getGlopTransformFlags(renderthread::RenderThread& renderThread, RecordedOp* op) { - int result = 0; - testUnmergedGlopDispatch(renderThread, op, [&result](const Glop& glop) { - result = glop.transform.transformFlags; - }); - return result; -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, offsetFlags) { - Rect bounds(10, 15, 20, 25); - SkPaint paint; - SkPaint aaPaint; - aaPaint.setAntiAlias(true); - - RoundRectOp roundRectOp(bounds, Matrix4::identity(), nullptr, &paint, 0, 270); - EXPECT_EQ(TransformFlags::None, getGlopTransformFlags(renderThread, &roundRectOp)) - << "Expect no offset for round rect op."; - - const float points[4] = {0.5, 0.5, 1.0, 1.0}; - PointsOp antiAliasedPointsOp(bounds, Matrix4::identity(), nullptr, &aaPaint, points, 4); - EXPECT_EQ(TransformFlags::None, getGlopTransformFlags(renderThread, &antiAliasedPointsOp)) - << "Expect no offset for AA points."; - PointsOp pointsOp(bounds, Matrix4::identity(), nullptr, &paint, points, 4); - EXPECT_EQ(TransformFlags::OffsetByFudgeFactor, getGlopTransformFlags(renderThread, &pointsOp)) - << "Expect an offset for non-AA points."; - - LinesOp antiAliasedLinesOp(bounds, Matrix4::identity(), nullptr, &aaPaint, points, 4); - EXPECT_EQ(TransformFlags::None, getGlopTransformFlags(renderThread, &antiAliasedLinesOp)) - << "Expect no offset for AA lines."; - LinesOp linesOp(bounds, Matrix4::identity(), nullptr, &paint, points, 4); - EXPECT_EQ(TransformFlags::OffsetByFudgeFactor, getGlopTransformFlags(renderThread, &linesOp)) - << "Expect an offset for non-AA lines."; -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, renderTextWithShadow) { - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) { - - android::Paint shadowPaint; - shadowPaint.setColor(SK_ColorRED); - - SkScalar sigma = Blur::convertRadiusToSigma(5); - shadowPaint.setLooper(SkBlurDrawLooper::Make(SK_ColorWHITE, sigma, 3, 3)); - - TestUtils::drawUtf8ToCanvas(&canvas, "A", shadowPaint, 25, 25); - TestUtils::drawUtf8ToCanvas(&canvas, "B", shadowPaint, 50, 50); - }); - - int glopCount = 0; - auto glopReceiver = [&glopCount](const Glop& glop) { - if (glopCount < 2) { - // two white shadows - EXPECT_EQ(FloatColor({1, 1, 1, 1}), glop.fill.color); - } else { - // two text draws merged into one, drawn after both shadows - EXPECT_EQ(FloatColor({1, 0, 0, 1}), glop.fill.color); - } - glopCount++; - }; - - ValidatingBakedOpRenderer renderer(renderThread.renderState(), glopReceiver); - - FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer); - ASSERT_EQ(3, glopCount) << "Exactly three glops expected"; -} - -static void validateLayerDraw(renderthread::RenderThread& renderThread, - std::function<void(const Glop& glop)> validator) { - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) { - props.mutateLayerProperties().setType(LayerType::RenderLayer); - - // provide different blend mode, so decoration draws contrast - props.mutateLayerProperties().setXferMode(SkBlendMode::kSrc); - canvas.drawColor(Color::Black, SkBlendMode::kSrcOver); - }); - OffscreenBuffer** layerHandle = node->getLayerHandle(); - - auto syncedNode = TestUtils::getSyncedNode(node); - - // create RenderNode's layer here in same way prepareTree would - OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100); - *layerHandle = &layer; - { - LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid - layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(0, 0, 100, 100)); - - ValidatingBakedOpRenderer renderer(renderThread.renderState(), validator); - FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferLayers(layerUpdateQueue); - frameBuilder.deferRenderNode(*syncedNode); - frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer); - } - - // clean up layer pointer, so we can safely destruct RenderNode - *layerHandle = nullptr; -} - -static FloatColor makeFloatColor(uint32_t color) { - FloatColor c; - c.set(color); - return c; -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, layerUpdateProperties) { - for (bool debugOverdraw : {false, true}) { - for (bool debugLayersUpdates : {false, true}) { - ScopedProperty<bool> ovdProp(Properties::debugOverdraw, debugOverdraw); - ScopedProperty<bool> lupProp(Properties::debugLayersUpdates, debugLayersUpdates); - - int glopCount = 0; - validateLayerDraw(renderThread, [&glopCount, &debugLayersUpdates](const Glop& glop) { - if (glopCount == 0) { - // 0 - Black layer fill - EXPECT_TRUE(glop.fill.colorEnabled); - EXPECT_EQ(makeFloatColor(Color::Black), glop.fill.color); - } else if (glopCount == 1) { - // 1 - Uncolored (textured) layer draw - EXPECT_FALSE(glop.fill.colorEnabled); - } else if (glopCount == 2) { - // 2 - layer overlay, if present - EXPECT_TRUE(glop.fill.colorEnabled); - // blend srcover, different from that of layer - EXPECT_EQ(GLenum(GL_ONE), glop.blend.src); - EXPECT_EQ(GLenum(GL_ONE_MINUS_SRC_ALPHA), glop.blend.dst); - EXPECT_EQ(makeFloatColor(debugLayersUpdates ? 0x7f00ff00 : 0), glop.fill.color) - << "Should be transparent green if debugLayersUpdates"; - } else if (glopCount < 7) { - // 3 - 6 - overdraw indicator overlays, if present - EXPECT_TRUE(glop.fill.colorEnabled); - uint32_t expectedColor = Caches::getInstance().getOverdrawColor(glopCount - 2); - ASSERT_EQ(makeFloatColor(expectedColor), glop.fill.color); - } else { - ADD_FAILURE() << "Too many glops observed"; - } - glopCount++; - }); - int expectedCount = 2; - if (debugLayersUpdates || debugOverdraw) expectedCount++; - if (debugOverdraw) expectedCount += 4; - EXPECT_EQ(expectedCount, glopCount); - } - } -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, pathTextureSnapping) { - Rect bounds(10, 15, 20, 25); - SkPaint paint; - SkPath path; - path.addRect(SkRect::MakeXYWH(1.5, 3.8, 100, 90)); - PathOp op(bounds, Matrix4::identity(), nullptr, &paint, &path); - testUnmergedGlopDispatch(renderThread, &op, [](const Glop& glop) { - auto texture = glop.fill.texture.texture; - ASSERT_NE(nullptr, texture); - EXPECT_EQ(1, reinterpret_cast<PathTexture*>(texture)->left); - EXPECT_EQ(3, reinterpret_cast<PathTexture*>(texture)->top); - }); -} diff --git a/libs/hwui/tests/unit/BakedOpRendererTests.cpp b/libs/hwui/tests/unit/BakedOpRendererTests.cpp deleted file mode 100644 index 1a3ec39a00d0..000000000000 --- a/libs/hwui/tests/unit/BakedOpRendererTests.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2016 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 <BakedOpRenderer.h> -#include <GlopBuilder.h> -#include <tests/common/TestUtils.h> - -using namespace android::uirenderer; - -const BakedOpRenderer::LightInfo sLightInfo = {128, 128}; - -RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpRenderer, startRepaintLayer_clear) { - BakedOpRenderer renderer(Caches::getInstance(), renderThread.renderState(), true, false, - sLightInfo); - OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 200u, 200u); - - layer.dirty(Rect(200, 200)); - { - renderer.startRepaintLayer(&layer, Rect(200, 200)); - EXPECT_TRUE(layer.region.isEmpty()) << "Repaint full layer should clear region"; - renderer.endLayer(); - } - - layer.dirty(Rect(200, 200)); - { - renderer.startRepaintLayer(&layer, Rect(100, 200)); // repainting left side - EXPECT_TRUE(layer.region.isRect()); - // ALOGD("bounds %d %d %d %d", RECT_ARGS(layer.region.getBounds())); - EXPECT_EQ(android::Rect(100, 0, 200, 200), layer.region.getBounds()) - << "Left side being repainted, so right side should be clear"; - renderer.endLayer(); - } - - // right side is now only dirty portion - { - renderer.startRepaintLayer(&layer, Rect(100, 0, 200, 200)); // repainting right side - EXPECT_TRUE(layer.region.isEmpty()) - << "Now right side being repainted, so region should be entirely clear"; - renderer.endLayer(); - } -} - -static void drawFirstOp(RenderState& renderState, int color, SkBlendMode mode) { - BakedOpRenderer renderer(Caches::getInstance(), renderState, true, false, sLightInfo); - - renderer.startFrame(100, 100, Rect(100, 100)); - SkPaint paint; - paint.setColor(color); - paint.setBlendMode(mode); - - Rect dest(0, 0, 100, 100); - Glop glop; - GlopBuilder(renderState, Caches::getInstance(), &glop) - .setRoundRectClipState(nullptr) - .setMeshUnitQuad() - .setFillPaint(paint, 1.0f) - .setTransform(Matrix4::identity(), TransformFlags::None) - .setModelViewMapUnitToRectSnap(dest) - .build(); - renderer.renderGlop(nullptr, nullptr, glop); - renderer.endFrame(Rect(100, 100)); -} - -static void verifyBlend(RenderState& renderState, GLenum expectedSrc, GLenum expectedDst) { - EXPECT_TRUE(renderState.blend().getEnabled()); - GLenum src; - GLenum dst; - renderState.blend().getFactors(&src, &dst); - EXPECT_EQ(expectedSrc, src); - EXPECT_EQ(expectedDst, dst); -} - -static void verifyBlendDisabled(RenderState& renderState) { - EXPECT_FALSE(renderState.blend().getEnabled()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpRenderer, firstDrawBlend_clear) { - // initialize blend state to nonsense value - renderThread.renderState().blend().setFactors(GL_ONE, GL_ONE); - - drawFirstOp(renderThread.renderState(), 0xfeff0000, SkBlendMode::kClear); - verifyBlend(renderThread.renderState(), GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpRenderer, firstDrawBlend_srcover) { - // initialize blend state to nonsense value - renderThread.renderState().blend().setFactors(GL_ONE, GL_ONE); - - drawFirstOp(renderThread.renderState(), 0xfeff0000, SkBlendMode::kSrcOver); - verifyBlendDisabled(renderThread.renderState()); -} diff --git a/libs/hwui/tests/unit/BakedOpStateTests.cpp b/libs/hwui/tests/unit/BakedOpStateTests.cpp deleted file mode 100644 index 6f8e24917767..000000000000 --- a/libs/hwui/tests/unit/BakedOpStateTests.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <gtest/gtest.h> - -#include <BakedOpState.h> -#include <ClipArea.h> -#include <RecordedOp.h> -#include <tests/common/TestUtils.h> - -namespace android { -namespace uirenderer { - -TEST(ResolvedRenderState, construct) { - LinearAllocator allocator; - Matrix4 translate10x20; - translate10x20.loadTranslate(10, 20, 0); - - SkPaint paint; - ClipRect clip(Rect(100, 200)); - RectOp recordedOp(Rect(30, 40, 100, 200), translate10x20, &clip, &paint); - { - // recorded with transform, no parent transform - auto parentSnapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200)); - ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false); - EXPECT_MATRIX_APPROX_EQ(state.transform, translate10x20); - EXPECT_EQ(Rect(100, 200), state.clipRect()); - EXPECT_EQ(Rect(40, 60, 100, 200), state.clippedBounds); // translated and also clipped - EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags); - } - { - // recorded with transform and parent transform - auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200)); - ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false); - - Matrix4 expectedTranslate; - expectedTranslate.loadTranslate(20, 40, 0); - EXPECT_MATRIX_APPROX_EQ(expectedTranslate, state.transform); - - // intersection of parent & transformed child clip - EXPECT_EQ(Rect(10, 20, 100, 200), state.clipRect()); - - // translated and also clipped - EXPECT_EQ(Rect(50, 80, 100, 200), state.clippedBounds); - EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags); - } -} - -TEST(ResolvedRenderState, computeLocalSpaceClip) { - LinearAllocator allocator; - Matrix4 translate10x20; - translate10x20.loadTranslate(10, 20, 0); - - SkPaint paint; - ClipRect clip(Rect(100, 200)); - RectOp recordedOp(Rect(1000, 1000), translate10x20, &clip, &paint); - { - // recorded with transform, no parent transform - auto parentSnapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200)); - ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false); - EXPECT_EQ(Rect(-10, -20, 90, 180), state.computeLocalSpaceClip()) - << "Local clip rect should be 100x200, offset by -10,-20"; - } - { - // recorded with transform + parent transform - auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200)); - ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false); - EXPECT_EQ(Rect(-10, -20, 80, 160), state.computeLocalSpaceClip()) - << "Local clip rect should be 90x190, offset by -10,-20"; - } -} - -const float HAIRLINE = 0.0f; - -// Note: bounds will be conservative, but not precise for non-hairline -// - use approx bounds checks for these -const float SEMI_HAIRLINE = 0.3f; - -struct StrokeTestCase { - float scale; - float strokeWidth; - const std::function<void(const ResolvedRenderState&)> validator; -}; - -const static StrokeTestCase sStrokeTestCases[] = { - {1, HAIRLINE, - [](const ResolvedRenderState& state) { - EXPECT_EQ(Rect(49.5f, 49.5f, 150.5f, 150.5f), state.clippedBounds); - }}, - {1, SEMI_HAIRLINE, - [](const ResolvedRenderState& state) { - EXPECT_TRUE(state.clippedBounds.contains(49.5f, 49.5f, 150.5f, 150.5f)); - EXPECT_TRUE(Rect(49, 49, 151, 151).contains(state.clippedBounds)); - }}, - {1, 20, - [](const ResolvedRenderState& state) { - EXPECT_EQ(Rect(40, 40, 160, 160), state.clippedBounds); - }}, - - // 3x3 scale: - {3, HAIRLINE, - [](const ResolvedRenderState& state) { - EXPECT_EQ(Rect(149.5f, 149.5f, 200, 200), state.clippedBounds); - EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags); - }}, - {3, SEMI_HAIRLINE, - [](const ResolvedRenderState& state) { - EXPECT_TRUE(state.clippedBounds.contains(149.5f, 149.5f, 200, 200)); - EXPECT_TRUE(Rect(149, 149, 200, 200).contains(state.clippedBounds)); - }}, - {3, 20, - [](const ResolvedRenderState& state) { - EXPECT_TRUE(state.clippedBounds.contains(120, 120, 200, 200)); - EXPECT_TRUE(Rect(119, 119, 200, 200).contains(state.clippedBounds)); - }}, - - // 0.5f x 0.5f scale - {0.5f, HAIRLINE, - [](const ResolvedRenderState& state) { - EXPECT_EQ(Rect(24.5f, 24.5f, 75.5f, 75.5f), state.clippedBounds); - }}, - {0.5f, SEMI_HAIRLINE, - [](const ResolvedRenderState& state) { - EXPECT_TRUE(state.clippedBounds.contains(24.5f, 24.5f, 75.5f, 75.5f)); - EXPECT_TRUE(Rect(24, 24, 76, 76).contains(state.clippedBounds)); - }}, - {0.5f, 20, [](const ResolvedRenderState& state) { - EXPECT_TRUE(state.clippedBounds.contains(19.5f, 19.5f, 80.5f, 80.5f)); - EXPECT_TRUE(Rect(19, 19, 81, 81).contains(state.clippedBounds)); - }}}; - -TEST(ResolvedRenderState, construct_expandForStroke) { - LinearAllocator allocator; - // Loop over table of test cases and verify different combinations of stroke width and transform - for (auto&& testCase : sStrokeTestCases) { - SkPaint strokedPaint; - strokedPaint.setAntiAlias(true); - strokedPaint.setStyle(SkPaint::kStroke_Style); - strokedPaint.setStrokeWidth(testCase.strokeWidth); - - ClipRect clip(Rect(200, 200)); - RectOp recordedOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &strokedPaint); - - Matrix4 snapshotMatrix; - snapshotMatrix.loadScale(testCase.scale, testCase.scale, 1); - auto parentSnapshot = TestUtils::makeSnapshot(snapshotMatrix, Rect(200, 200)); - - ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, true, false); - testCase.validator(state); - } -} - -TEST(BakedOpState, tryConstruct) { - Matrix4 translate100x0; - translate100x0.loadTranslate(100, 0, 0); - - SkPaint paint; - ClipRect clip(Rect(100, 200)); - - LinearAllocator allocator; - RectOp successOp(Rect(30, 40, 100, 200), Matrix4::identity(), &clip, &paint); - auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200)); - EXPECT_NE(nullptr, BakedOpState::tryConstruct(allocator, *snapshot, successOp)) - << "successOp NOT rejected by clip, so should be constructed"; - size_t successAllocSize = allocator.usedSize(); - EXPECT_LE(64u, successAllocSize) << "relatively large alloc for non-rejected op"; - - RectOp rejectOp(Rect(30, 40, 100, 200), translate100x0, &clip, &paint); - EXPECT_EQ(nullptr, BakedOpState::tryConstruct(allocator, *snapshot, rejectOp)) - << "rejectOp rejected by clip, so should not be constructed"; - - // NOTE: this relies on the clip having already been serialized by the op above - EXPECT_EQ(successAllocSize, allocator.usedSize()) << "no extra allocation used for rejected op"; -} - -TEST(BakedOpState, tryShadowOpConstruct) { - Matrix4 translate10x20; - translate10x20.loadTranslate(10, 20, 0); - - LinearAllocator allocator; - { - auto snapshot = TestUtils::makeSnapshot(translate10x20, Rect()); // Note: empty clip - BakedOpState* bakedState = - BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234); - - EXPECT_EQ(nullptr, bakedState) << "op should be rejected by clip, so not constructed"; - EXPECT_EQ(0u, allocator.usedSize()) << "no serialization, even for clip," - "since op is quick rejected based on snapshot clip"; - } - { - auto snapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200)); - BakedOpState* bakedState = - BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234); - - ASSERT_NE(nullptr, bakedState) << "NOT rejected by clip, so op should be constructed"; - EXPECT_LE(64u, allocator.usedSize()) << "relatively large alloc for non-rejected op"; - - EXPECT_MATRIX_APPROX_EQ(translate10x20, bakedState->computedState.transform); - EXPECT_EQ(Rect(100, 200), bakedState->computedState.clippedBounds); - } -} - -TEST(BakedOpState, tryStrokeableOpConstruct) { - LinearAllocator allocator; - { - // check regular rejection - SkPaint paint; - paint.setStyle(SkPaint::kStrokeAndFill_Style); - paint.setStrokeWidth(0.0f); - ClipRect clip(Rect(100, 200)); - RectOp rejectOp(Rect(100, 200), Matrix4::identity(), &clip, &paint); - auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip - auto bakedState = BakedOpState::tryStrokeableOpConstruct( - allocator, *snapshot, rejectOp, BakedOpState::StrokeBehavior::StyleDefined, false); - - EXPECT_EQ(nullptr, bakedState); - EXPECT_GT(8u, - allocator.usedSize()); // no significant allocation space used for rejected op - } - { - // check simple unscaled expansion - SkPaint paint; - paint.setStyle(SkPaint::kStrokeAndFill_Style); - paint.setStrokeWidth(10.0f); - ClipRect clip(Rect(200, 200)); - RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint); - auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200)); - auto bakedState = BakedOpState::tryStrokeableOpConstruct( - allocator, *snapshot, rejectOp, BakedOpState::StrokeBehavior::StyleDefined, false); - - ASSERT_NE(nullptr, bakedState); - EXPECT_EQ(Rect(45, 45, 155, 155), bakedState->computedState.clippedBounds); - EXPECT_EQ(0, bakedState->computedState.clipSideFlags); - } - { - // check simple unscaled expansion, and fill style with stroke forced - SkPaint paint; - paint.setStyle(SkPaint::kFill_Style); - paint.setStrokeWidth(10.0f); - ClipRect clip(Rect(200, 200)); - RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint); - auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200)); - auto bakedState = BakedOpState::tryStrokeableOpConstruct( - allocator, *snapshot, rejectOp, BakedOpState::StrokeBehavior::Forced, false); - - ASSERT_NE(nullptr, bakedState); - EXPECT_EQ(Rect(45, 45, 155, 155), bakedState->computedState.clippedBounds); - EXPECT_EQ(0, bakedState->computedState.clipSideFlags); - } -} - -} // namespace uirenderer -} // namespace android diff --git a/libs/hwui/tests/unit/DeviceInfoTests.cpp b/libs/hwui/tests/unit/DeviceInfoTests.cpp deleted file mode 100644 index af37938915e5..000000000000 --- a/libs/hwui/tests/unit/DeviceInfoTests.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <DeviceInfo.h> - -#include <gtest/gtest.h> -#include "tests/common/TestUtils.h" - -using namespace android; -using namespace android::uirenderer; - -OPENGL_PIPELINE_TEST(DeviceInfo, basic) { - // can't assert state before init - another test may have initialized the singleton - DeviceInfo::initialize(); - const DeviceInfo* di = DeviceInfo::get(); - ASSERT_NE(nullptr, di) << "DeviceInfo initialization failed"; - EXPECT_EQ(2048, di->maxTextureSize()) << "Max texture size didn't match"; -} diff --git a/libs/hwui/tests/unit/FontRendererTests.cpp b/libs/hwui/tests/unit/FontRendererTests.cpp deleted file mode 100644 index c78f131ce2ce..000000000000 --- a/libs/hwui/tests/unit/FontRendererTests.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2016 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 "GammaFontRenderer.h" -#include "tests/common/TestUtils.h" - -using namespace android::uirenderer; - -static bool isZero(uint8_t* data, int size) { - for (int i = 0; i < size; i++) { - if (data[i]) return false; - } - return true; -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FontRenderer, renderDropShadow) { - SkPaint paint; - paint.setTextSize(10); - paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - GammaFontRenderer gammaFontRenderer; - FontRenderer& fontRenderer = gammaFontRenderer.getFontRenderer(); - fontRenderer.setFont(&paint, SkMatrix::I()); - - std::vector<glyph_t> glyphs; - std::vector<float> positions; - float totalAdvance; - Rect bounds; - TestUtils::layoutTextUnscaled(paint, "This is a test", &glyphs, &positions, &totalAdvance, - &bounds); - - for (int radius : {28, 20, 2}) { - auto result = fontRenderer.renderDropShadow(&paint, glyphs.data(), glyphs.size(), radius, - positions.data()); - ASSERT_NE(nullptr, result.image); - EXPECT_FALSE(isZero(result.image, result.width * result.height)); - EXPECT_LE(bounds.getWidth() + radius * 2, (int)result.width); - EXPECT_LE(bounds.getHeight() + radius * 2, (int)result.height); - delete result.image; - } -} diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp deleted file mode 100644 index 4eb77514f4ae..000000000000 --- a/libs/hwui/tests/unit/FrameBuilderTests.cpp +++ /dev/null @@ -1,2705 +0,0 @@ -/* - * Copyright (C) 2016 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 <BakedOpState.h> -#include <DeferredLayerUpdater.h> -#include <FrameBuilder.h> -#include <GlLayer.h> -#include <LayerUpdateQueue.h> -#include <RecordedOp.h> -#include <RecordingCanvas.h> -#include <tests/common/TestUtils.h> - -#include <unordered_map> - -namespace android { -namespace uirenderer { - -const FrameBuilder::LightGeometry sLightGeometry = {{100, 100, 100}, 50}; - -/** - * Virtual class implemented by each test to redirect static operation / state transitions to - * virtual methods. - * - * Virtual dispatch allows for default behaviors to be specified (very common case in below tests), - * and allows Renderer vs Dispatching behavior to be merged. - * - * onXXXOp methods fail by default - tests should override ops they expect - * startRepaintLayer fails by default - tests should override if expected - * startFrame/endFrame do nothing by default - tests should override to intercept - */ -class TestRendererBase { -public: - virtual ~TestRendererBase() {} - virtual OffscreenBuffer* startTemporaryLayer(uint32_t, uint32_t) { - ADD_FAILURE() << "Temporary layers not expected in this test"; - return nullptr; - } - virtual void recycleTemporaryLayer(OffscreenBuffer*) { - ADD_FAILURE() << "Temporary layers not expected in this test"; - } - virtual void startRepaintLayer(OffscreenBuffer*, const Rect& repaintRect) { - ADD_FAILURE() << "Layer repaint not expected in this test"; - } - virtual void endLayer() { ADD_FAILURE() << "Layer updates not expected in this test"; } - virtual void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {} - virtual void endFrame(const Rect& repaintRect) {} - -// define virtual defaults for single draw methods -#define X(Type) \ - virtual void on##Type(const Type&, const BakedOpState&) { \ - ADD_FAILURE() << #Type " not expected in this test"; \ - } - MAP_RENDERABLE_OPS(X) -#undef X - -// define virtual defaults for merged draw methods -#define X(Type) \ - virtual void onMerged##Type##s(const MergedBakedOpList& opList) { \ - ADD_FAILURE() << "Merged " #Type "s not expected in this test"; \ - } - MAP_MERGEABLE_OPS(X) -#undef X - - int getIndex() { return mIndex; } - -protected: - int mIndex = 0; -}; - -/** - * Dispatches all static methods to similar formed methods on renderer, which fail by default but - * are overridden by subclasses per test. - */ -class TestDispatcher { -public: -// define single op methods, which redirect to TestRendererBase -#define X(Type) \ - static void on##Type(TestRendererBase& renderer, const Type& op, const BakedOpState& state) { \ - renderer.on##Type(op, state); \ - } - MAP_RENDERABLE_OPS(X); -#undef X - -// define merged op methods, which redirect to TestRendererBase -#define X(Type) \ - static void onMerged##Type##s(TestRendererBase& renderer, const MergedBakedOpList& opList) { \ - renderer.onMerged##Type##s(opList); \ - } - MAP_MERGEABLE_OPS(X); -#undef X -}; - -class FailRenderer : public TestRendererBase {}; - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simple) { - class SimpleTestRenderer : public TestRendererBase { - public: - void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override { - EXPECT_EQ(0, mIndex++); - EXPECT_EQ(100u, width); - EXPECT_EQ(200u, height); - } - void onRectOp(const RectOp& op, const BakedOpState& state) override { - EXPECT_EQ(1, mIndex++); - } - void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override { - EXPECT_EQ(2, mIndex++); - } - void endFrame(const Rect& repaintRect) override { EXPECT_EQ(3, mIndex++); } - }; - - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 200, [](RenderProperties& props, RecordingCanvas& canvas) { - sk_sp<Bitmap> bitmap(TestUtils::createBitmap(25, 25)); - canvas.drawRect(0, 0, 100, 200, SkPaint()); - canvas.drawBitmap(*bitmap, 10, 10, nullptr); - }); - FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - SimpleTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simpleStroke) { - class SimpleStrokeTestRenderer : public TestRendererBase { - public: - void onPointsOp(const PointsOp& op, const BakedOpState& state) override { - EXPECT_EQ(0, mIndex++); - // even though initial bounds are empty... - EXPECT_TRUE(op.unmappedBounds.isEmpty()) - << "initial bounds should be empty, since they're unstroked"; - EXPECT_EQ(Rect(45, 45, 55, 55), state.computedState.clippedBounds) - << "final bounds should account for stroke"; - } - }; - - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 200, [](RenderProperties& props, RecordingCanvas& canvas) { - SkPaint strokedPaint; - strokedPaint.setStrokeWidth(10); - canvas.drawPoint(50, 50, strokedPaint); - }); - FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - SimpleStrokeTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(1, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, arcStrokeClip) { - class ArcStrokeClipTestRenderer : public TestRendererBase { - public: - void onArcOp(const ArcOp& op, const BakedOpState& state) override { - EXPECT_EQ(0, mIndex++); - EXPECT_EQ(Rect(25, 25, 175, 175), op.unmappedBounds); - EXPECT_EQ(Rect(25, 25, 175, 175), state.computedState.clippedBounds); - EXPECT_EQ(OpClipSideFlags::Full, state.computedState.clipSideFlags) - << "Arc op clipped conservatively, since path texture may be expanded"; - } - }; - - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) { - canvas.clipRect(25, 25, 175, 175, SkClipOp::kIntersect); - SkPaint aaPaint; - aaPaint.setAntiAlias(true); - canvas.drawArc(25, 25, 175, 175, 40, 180, true, aaPaint); - }); - FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - ArcStrokeClipTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(1, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simpleRejection) { - auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200, [](RenderProperties& props, - RecordingCanvas& canvas) { - canvas.save(SaveFlags::MatrixClip); - canvas.clipRect(200, 200, 400, 400, SkClipOp::kIntersect); // intersection should be empty - canvas.drawRect(0, 0, 400, 400, SkPaint()); - canvas.restore(); - }); - FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - FailRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simpleBatching) { - const int LOOPS = 5; - class SimpleBatchingTestRenderer : public TestRendererBase { - public: - void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override { - EXPECT_TRUE(mIndex++ >= LOOPS) << "Bitmaps should be above all rects"; - } - void onRectOp(const RectOp& op, const BakedOpState& state) override { - EXPECT_TRUE(mIndex++ < LOOPS) << "Rects should be below all bitmaps"; - } - }; - - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) { - - sk_sp<Bitmap> bitmap(TestUtils::createBitmap( - 10, 10, - kAlpha_8_SkColorType)); // Disable merging by using alpha 8 bitmap - - // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects. - // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group. - canvas.save(SaveFlags::MatrixClip); - for (int i = 0; i < LOOPS; i++) { - canvas.translate(0, 10); - canvas.drawRect(0, 0, 10, 10, SkPaint()); - canvas.drawBitmap(*bitmap, 5, 0, nullptr); - } - canvas.restore(); - }); - FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - SimpleBatchingTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(2 * LOOPS, renderer.getIndex()) << "Expect number of ops = 2 * loop count"; -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, deferRenderNode_translateClip) { - class DeferRenderNodeTranslateClipTestRenderer : public TestRendererBase { - public: - void onRectOp(const RectOp& op, const BakedOpState& state) override { - EXPECT_EQ(0, mIndex++); - EXPECT_EQ(Rect(5, 10, 55, 60), state.computedState.clippedBounds); - EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, - state.computedState.clipSideFlags); - } - }; - - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) { - canvas.drawRect(0, 0, 100, 100, SkPaint()); - }); - - FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(5, 10, Rect(50, 50), // translate + clip node - *TestUtils::getSyncedNode(node)); - - DeferRenderNodeTranslateClipTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(1, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, deferRenderNodeScene) { - class DeferRenderNodeSceneTestRenderer : public TestRendererBase { - public: - void onRectOp(const RectOp& op, const BakedOpState& state) override { - const Rect& clippedBounds = state.computedState.clippedBounds; - Matrix4 expected; - switch (mIndex++) { - case 0: - // background - left side - EXPECT_EQ(Rect(600, 100, 700, 500), clippedBounds); - expected.loadTranslate(100, 100, 0); - break; - case 1: - // background - top side - EXPECT_EQ(Rect(100, 400, 600, 500), clippedBounds); - expected.loadTranslate(100, 100, 0); - break; - case 2: - // content - EXPECT_EQ(Rect(100, 100, 700, 500), clippedBounds); - expected.loadTranslate(-50, -50, 0); - break; - case 3: - // overlay - EXPECT_EQ(Rect(0, 0, 800, 200), clippedBounds); - break; - default: - ADD_FAILURE() << "Too many rects observed"; - } - EXPECT_EQ(expected, state.computedState.transform); - } - }; - - std::vector<sp<RenderNode>> nodes; - SkPaint transparentPaint; - transparentPaint.setAlpha(128); - - // backdrop - nodes.push_back(TestUtils::createNode<RecordingCanvas>( - 100, 100, 700, 500, // 600x400 - [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) { - canvas.drawRect(0, 0, 600, 400, transparentPaint); - })); - - // content - Rect contentDrawBounds(150, 150, 650, 450); // 500x300 - nodes.push_back(TestUtils::createNode<RecordingCanvas>( - 0, 0, 800, 600, [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) { - canvas.drawRect(0, 0, 800, 600, transparentPaint); - })); - - // overlay - nodes.push_back(TestUtils::createNode<RecordingCanvas>( - 0, 0, 800, 600, [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) { - canvas.drawRect(0, 0, 800, 200, transparentPaint); - })); - - for (auto& node : nodes) { - TestUtils::syncHierarchyPropertiesAndDisplayList(node); - } - - { - FrameBuilder frameBuilder(SkRect::MakeWH(800, 600), 800, 600, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNodeScene(nodes, contentDrawBounds); - - DeferRenderNodeSceneTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(4, renderer.getIndex()); - } - - for (auto& node : nodes) { - EXPECT_TRUE(node->isValid()); - EXPECT_FALSE(node->nothingToDraw()); - node->setStagingDisplayList(nullptr); - EXPECT_FALSE(node->isValid()); - EXPECT_FALSE(node->nothingToDraw()); - node->destroyHardwareResources(); - EXPECT_TRUE(node->nothingToDraw()); - EXPECT_FALSE(node->isValid()); - } - - { - // Validate no crashes if any nodes are missing DisplayLists - FrameBuilder frameBuilder(SkRect::MakeWH(800, 600), 800, 600, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNodeScene(nodes, contentDrawBounds); - - FailRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - } -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, empty_noFbo0) { - class EmptyNoFbo0TestRenderer : public TestRendererBase { - public: - void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override { - ADD_FAILURE() << "Primary frame draw not expected in this test"; - } - void endFrame(const Rect& repaintRect) override { - ADD_FAILURE() << "Primary frame draw not expected in this test"; - } - }; - - // Use layer update constructor, so no work is enqueued for Fbo0 - LayerUpdateQueue emptyLayerUpdateQueue; - FrameBuilder frameBuilder(emptyLayerUpdateQueue, sLightGeometry, Caches::getInstance()); - EmptyNoFbo0TestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, empty_withFbo0) { - class EmptyWithFbo0TestRenderer : public TestRendererBase { - public: - void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override { - EXPECT_EQ(0, mIndex++); - } - void endFrame(const Rect& repaintRect) override { EXPECT_EQ(1, mIndex++); } - }; - auto node = TestUtils::createNode<RecordingCanvas>( - 10, 10, 110, 110, [](RenderProperties& props, RecordingCanvas& canvas) { - // no drawn content - }); - - // Draw, but pass node without draw content, so no work is done for primary frame - FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - EmptyWithFbo0TestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(2, renderer.getIndex()) << "No drawing content produced," - " but fbo0 update lifecycle should still be observed"; -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, avoidOverdraw_rects) { - class AvoidOverdrawRectsTestRenderer : public TestRendererBase { - public: - void onRectOp(const RectOp& op, const BakedOpState& state) override { - EXPECT_EQ(mIndex++, 0) << "Should be one rect"; - EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds) - << "Last rect should occlude others."; - } - }; - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) { - canvas.drawRect(0, 0, 200, 200, SkPaint()); - canvas.drawRect(0, 0, 200, 200, SkPaint()); - canvas.drawRect(10, 10, 190, 190, SkPaint()); - }); - - // Damage (and therefore clip) is same as last draw, subset of renderable area. - // This means last op occludes other contents, and they'll be rejected to avoid overdraw. - FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 10, 190, 190), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - EXPECT_EQ(3u, node->getDisplayList()->getOps().size()) - << "Recording must not have rejected ops, in order for this test to be valid"; - - AvoidOverdrawRectsTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(1, renderer.getIndex()) << "Expect exactly one op"; -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, avoidOverdraw_bitmaps) { - static sk_sp<Bitmap> opaqueBitmap( - TestUtils::createBitmap(50, 50, SkColorType::kRGB_565_SkColorType)); - static sk_sp<Bitmap> transpBitmap( - TestUtils::createBitmap(50, 50, SkColorType::kAlpha_8_SkColorType)); - class AvoidOverdrawBitmapsTestRenderer : public TestRendererBase { - public: - void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override { - switch (mIndex++) { - case 0: - EXPECT_EQ(opaqueBitmap.get(), op.bitmap); - break; - case 1: - EXPECT_EQ(transpBitmap.get(), op.bitmap); - break; - default: - ADD_FAILURE() << "Only two ops expected."; - } - } - }; - - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 50, 50, [](RenderProperties& props, RecordingCanvas& canvas) { - canvas.drawRect(0, 0, 50, 50, SkPaint()); - canvas.drawRect(0, 0, 50, 50, SkPaint()); - canvas.drawBitmap(*transpBitmap, 0, 0, nullptr); - - // only the below draws should remain, since they're - canvas.drawBitmap(*opaqueBitmap, 0, 0, nullptr); - canvas.drawBitmap(*transpBitmap, 0, 0, nullptr); - }); - FrameBuilder frameBuilder(SkRect::MakeWH(50, 50), 50, 50, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - EXPECT_EQ(5u, node->getDisplayList()->getOps().size()) - << "Recording must not have rejected ops, in order for this test to be valid"; - - AvoidOverdrawBitmapsTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(2, renderer.getIndex()) << "Expect exactly two ops"; -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, clippedMerging) { - class ClippedMergingTestRenderer : public TestRendererBase { - public: - void onMergedBitmapOps(const MergedBakedOpList& opList) override { - EXPECT_EQ(0, mIndex); - mIndex += opList.count; - EXPECT_EQ(4u, opList.count); - EXPECT_EQ(Rect(10, 10, 90, 90), opList.clip); - EXPECT_EQ(OpClipSideFlags::Left | OpClipSideFlags::Top | OpClipSideFlags::Right, - opList.clipSideFlags); - } - }; - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) { - sk_sp<Bitmap> bitmap(TestUtils::createBitmap(20, 20)); - - // left side clipped (to inset left half) - canvas.clipRect(10, 0, 50, 100, SkClipOp::kReplace_deprecated); - canvas.drawBitmap(*bitmap, 0, 40, nullptr); - - // top side clipped (to inset top half) - canvas.clipRect(0, 10, 100, 50, SkClipOp::kReplace_deprecated); - canvas.drawBitmap(*bitmap, 40, 0, nullptr); - - // right side clipped (to inset right half) - canvas.clipRect(50, 0, 90, 100, SkClipOp::kReplace_deprecated); - canvas.drawBitmap(*bitmap, 80, 40, nullptr); - - // bottom not clipped, just abutting (inset bottom half) - canvas.clipRect(0, 50, 100, 90, SkClipOp::kReplace_deprecated); - canvas.drawBitmap(*bitmap, 40, 70, nullptr); - }); - - FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - ClippedMergingTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(4, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, regionClipStopsMerge) { - class RegionClipStopsMergeTestRenderer : public TestRendererBase { - public: - void onTextOp(const TextOp& op, const BakedOpState& state) override { mIndex++; } - }; - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 400, 400, [](RenderProperties& props, RecordingCanvas& canvas) { - SkPath path; - path.addCircle(200, 200, 200, SkPath::kCW_Direction); - canvas.save(SaveFlags::MatrixClip); - canvas.clipPath(&path, SkClipOp::kIntersect); - SkPaint paint; - paint.setAntiAlias(true); - paint.setTextSize(50); - TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100); - TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 200); - canvas.restore(); - }); - - FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - RegionClipStopsMergeTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(2, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textMerging) { - class TextMergingTestRenderer : public TestRendererBase { - public: - void onMergedTextOps(const MergedBakedOpList& opList) override { - EXPECT_EQ(0, mIndex); - mIndex += opList.count; - EXPECT_EQ(2u, opList.count); - EXPECT_EQ(OpClipSideFlags::Top, opList.clipSideFlags); - EXPECT_EQ(OpClipSideFlags::Top, opList.states[0]->computedState.clipSideFlags); - EXPECT_EQ(OpClipSideFlags::None, opList.states[1]->computedState.clipSideFlags); - } - }; - auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400, [](RenderProperties& props, - RecordingCanvas& canvas) { - SkPaint paint; - paint.setAntiAlias(true); - paint.setTextSize(50); - TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped - TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped - }); - FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - TextMergingTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(2, renderer.getIndex()) << "Expect 2 ops"; -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textStrikethrough) { - const int LOOPS = 5; - class TextStrikethroughTestRenderer : public TestRendererBase { - public: - void onRectOp(const RectOp& op, const BakedOpState& state) override { - EXPECT_TRUE(mIndex++ >= LOOPS) << "Strikethrough rects should be above all text"; - } - void onMergedTextOps(const MergedBakedOpList& opList) override { - EXPECT_EQ(0, mIndex); - mIndex += opList.count; - EXPECT_EQ(5u, opList.count); - } - }; - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 200, 2000, [](RenderProperties& props, RecordingCanvas& canvas) { - SkPaint textPaint; - textPaint.setAntiAlias(true); - textPaint.setTextSize(20); - textPaint.setFlags(textPaint.getFlags() | SkPaint::kStrikeThruText_ReserveFlag); - for (int i = 0; i < LOOPS; i++) { - TestUtils::drawUtf8ToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1)); - } - }); - - FrameBuilder frameBuilder(SkRect::MakeWH(200, 2000), 200, 2000, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - TextStrikethroughTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(2 * LOOPS, renderer.getIndex()) << "Expect number of ops = 2 * loop count"; -} - -static auto styles = {SkPaint::kFill_Style, SkPaint::kStroke_Style, SkPaint::kStrokeAndFill_Style}; - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textStyle) { - class TextStyleTestRenderer : public TestRendererBase { - public: - void onMergedTextOps(const MergedBakedOpList& opList) override { - ASSERT_EQ(0, mIndex); - ASSERT_EQ(3u, opList.count); - mIndex += opList.count; - - int index = 0; - for (auto style : styles) { - auto state = opList.states[index++]; - ASSERT_EQ(style, state->op->paint->getStyle()) - << "Remainder of validation relies upon stable merged order"; - ASSERT_EQ(0, state->computedState.clipSideFlags) - << "Clipped bounds validation requires unclipped ops"; - } - - Rect fill = opList.states[0]->computedState.clippedBounds; - Rect stroke = opList.states[1]->computedState.clippedBounds; - EXPECT_EQ(stroke, opList.states[2]->computedState.clippedBounds) - << "Stroke+Fill should be same as stroke"; - - EXPECT_TRUE(stroke.contains(fill)); - EXPECT_FALSE(fill.contains(stroke)); - - // outset by half the stroke width - Rect outsetFill(fill); - outsetFill.outset(5); - EXPECT_EQ(stroke, outsetFill); - } - }; - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 400, 400, [](RenderProperties& props, RecordingCanvas& canvas) { - SkPaint paint; - paint.setAntiAlias(true); - paint.setTextSize(50); - paint.setStrokeWidth(10); - - // draw 3 copies of the same text overlapping, each with a different style. - // They'll get merged, but with - for (auto style : styles) { - paint.setStyle(style); - TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100); - } - }); - FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - TextStyleTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(3, renderer.getIndex()) << "Expect 3 ops"; -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textureLayer_clipLocalMatrix) { - class TextureLayerClipLocalMatrixTestRenderer : public TestRendererBase { - public: - void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override { - EXPECT_EQ(0, mIndex++); - EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipRect()); - EXPECT_EQ(Rect(50, 50, 105, 105), state.computedState.clippedBounds); - - Matrix4 expected; - expected.loadTranslate(5, 5, 0); - EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform); - } - }; - - auto layerUpdater = - TestUtils::createTextureLayerUpdater(renderThread, 100, 100, SkMatrix::MakeTrans(5, 5)); - - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 200, 200, [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) { - canvas.save(SaveFlags::MatrixClip); - canvas.clipRect(50, 50, 150, 150, SkClipOp::kIntersect); - canvas.drawLayer(layerUpdater.get()); - canvas.restore(); - }); - - FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - TextureLayerClipLocalMatrixTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(1, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textureLayer_combineMatrices) { - class TextureLayerCombineMatricesTestRenderer : public TestRendererBase { - public: - void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override { - EXPECT_EQ(0, mIndex++); - - Matrix4 expected; - expected.loadTranslate(35, 45, 0); - EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform); - } - }; - - auto layerUpdater = - TestUtils::createTextureLayerUpdater(renderThread, 100, 100, SkMatrix::MakeTrans(5, 5)); - - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 200, 200, [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) { - canvas.save(SaveFlags::MatrixClip); - canvas.translate(30, 40); - canvas.drawLayer(layerUpdater.get()); - canvas.restore(); - }); - - FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - TextureLayerCombineMatricesTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(1, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textureLayer_reject) { - auto layerUpdater = - TestUtils::createTextureLayerUpdater(renderThread, 100, 100, SkMatrix::MakeTrans(5, 5)); - EXPECT_EQ(Layer::Api::OpenGL, layerUpdater->backingLayer()->getApi()); - - GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer()); - glLayer->setRenderTarget(GL_NONE); // Should be rejected - - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 200, 200, [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) { - canvas.drawLayer(layerUpdater.get()); - }); - - FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - FailRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, functor_reject) { - class FunctorTestRenderer : public TestRendererBase { - public: - void onFunctorOp(const FunctorOp& op, const BakedOpState& state) override { - EXPECT_EQ(0, mIndex++); - } - }; - Functor noopFunctor; - - // 1 million pixel tall view, scrolled down 80% - auto scrolledFunctorView = TestUtils::createNode<RecordingCanvas>( - 0, 0, 400, 1000000, [&noopFunctor](RenderProperties& props, RecordingCanvas& canvas) { - canvas.translate(0, -800000); - canvas.callDrawGLFunction(&noopFunctor, nullptr); - }); - - FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(scrolledFunctorView)); - - FunctorTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(1, renderer.getIndex()) << "Functor should not be rejected"; -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, deferColorOp_unbounded) { - class ColorTestRenderer : public TestRendererBase { - public: - void onColorOp(const ColorOp& op, const BakedOpState& state) override { - EXPECT_EQ(0, mIndex++); - EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds) - << "Color op should be expanded to bounds of surrounding"; - } - }; - - auto unclippedColorView = TestUtils::createNode<RecordingCanvas>( - 0, 0, 10, 10, [](RenderProperties& props, RecordingCanvas& canvas) { - props.setClipToBounds(false); - canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver); - }); - - FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(unclippedColorView)); - - ColorTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(1, renderer.getIndex()) << "ColorOp should not be rejected"; -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderNode) { - class RenderNodeTestRenderer : public TestRendererBase { - public: - void onRectOp(const RectOp& op, const BakedOpState& state) override { - switch (mIndex++) { - case 0: - EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds); - EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor()); - break; - case 1: - EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds); - EXPECT_EQ(SK_ColorWHITE, op.paint->getColor()); - break; - default: - ADD_FAILURE(); - } - } - }; - - auto child = TestUtils::createNode<RecordingCanvas>( - 10, 10, 110, 110, [](RenderProperties& props, RecordingCanvas& canvas) { - SkPaint paint; - paint.setColor(SK_ColorWHITE); - canvas.drawRect(0, 0, 100, 100, paint); - }); - - auto parent = TestUtils::createNode<RecordingCanvas>( - 0, 0, 200, 200, [&child](RenderProperties& props, RecordingCanvas& canvas) { - SkPaint paint; - paint.setColor(SK_ColorDKGRAY); - canvas.drawRect(0, 0, 200, 200, paint); - - canvas.save(SaveFlags::MatrixClip); - canvas.translate(40, 40); - canvas.drawRenderNode(child.get()); - canvas.restore(); - }); - - FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent)); - - RenderNodeTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(2, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, clipped) { - class ClippedTestRenderer : public TestRendererBase { - public: - void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override { - EXPECT_EQ(0, mIndex++); - EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds); - EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect()); - EXPECT_TRUE(state.computedState.transform.isIdentity()); - } - }; - - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) { - sk_sp<Bitmap> bitmap(TestUtils::createBitmap(200, 200)); - canvas.drawBitmap(*bitmap, 0, 0, nullptr); - }); - - // clip to small area, should see in receiver - FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 20, 30, 40), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - ClippedTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayer_simple) { - class SaveLayerSimpleTestRenderer : public TestRendererBase { - public: - OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override { - EXPECT_EQ(0, mIndex++); - EXPECT_EQ(180u, width); - EXPECT_EQ(180u, height); - return nullptr; - } - void endLayer() override { EXPECT_EQ(2, mIndex++); } - void onRectOp(const RectOp& op, const BakedOpState& state) override { - EXPECT_EQ(1, mIndex++); - EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds); - EXPECT_EQ(Rect(180, 180), state.computedState.clippedBounds); - EXPECT_EQ(Rect(180, 180), state.computedState.clipRect()); - - Matrix4 expectedTransform; - expectedTransform.loadTranslate(-10, -10, 0); - EXPECT_MATRIX_APPROX_EQ(expectedTransform, state.computedState.transform); - } - void onLayerOp(const LayerOp& op, const BakedOpState& state) override { - EXPECT_EQ(3, mIndex++); - EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds); - EXPECT_EQ(Rect(200, 200), state.computedState.clipRect()); - EXPECT_TRUE(state.computedState.transform.isIdentity()); - } - void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override { - EXPECT_EQ(4, mIndex++); - EXPECT_EQ(nullptr, offscreenBuffer); - } - }; - - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) { - canvas.saveLayerAlpha(10, 10, 190, 190, 128, SaveFlags::ClipToLayer); - canvas.drawRect(10, 10, 190, 190, SkPaint()); - canvas.restore(); - }); - - FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - SaveLayerSimpleTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(5, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayer_nested) { - /* saveLayer1 { rect1, saveLayer2 { rect2 } } will play back as: - * - startTemporaryLayer2, rect2 endLayer2 - * - startTemporaryLayer1, rect1, drawLayer2, endLayer1 - * - startFrame, layerOp1, endFrame - */ - class SaveLayerNestedTestRenderer : public TestRendererBase { - public: - OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override { - const int index = mIndex++; - if (index == 0) { - EXPECT_EQ(400u, width); - EXPECT_EQ(400u, height); - return (OffscreenBuffer*)0x400; - } else if (index == 3) { - EXPECT_EQ(800u, width); - EXPECT_EQ(800u, height); - return (OffscreenBuffer*)0x800; - } else { - ADD_FAILURE(); - } - return (OffscreenBuffer*)nullptr; - } - void endLayer() override { - int index = mIndex++; - EXPECT_TRUE(index == 2 || index == 6); - } - void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override { - EXPECT_EQ(7, mIndex++); - } - void endFrame(const Rect& repaintRect) override { EXPECT_EQ(9, mIndex++); } - void onRectOp(const RectOp& op, const BakedOpState& state) override { - const int index = mIndex++; - if (index == 1) { - EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner rect - } else if (index == 4) { - EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer rect - } else { - ADD_FAILURE(); - } - } - void onLayerOp(const LayerOp& op, const BakedOpState& state) override { - const int index = mIndex++; - if (index == 5) { - EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle); - EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner layer - } else if (index == 8) { - EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle); - EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer - } else { - ADD_FAILURE(); - } - } - void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override { - const int index = mIndex++; - // order isn't important, but we need to see both - if (index == 10) { - EXPECT_EQ((OffscreenBuffer*)0x400, offscreenBuffer); - } else if (index == 11) { - EXPECT_EQ((OffscreenBuffer*)0x800, offscreenBuffer); - } else { - ADD_FAILURE(); - } - } - }; - - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 800, 800, [](RenderProperties& props, RecordingCanvas& canvas) { - canvas.saveLayerAlpha(0, 0, 800, 800, 128, SaveFlags::ClipToLayer); - { - canvas.drawRect(0, 0, 800, 800, SkPaint()); - canvas.saveLayerAlpha(0, 0, 400, 400, 128, SaveFlags::ClipToLayer); - { canvas.drawRect(0, 0, 400, 400, SkPaint()); } - canvas.restore(); - } - canvas.restore(); - }); - - FrameBuilder frameBuilder(SkRect::MakeWH(800, 800), 800, 800, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - SaveLayerNestedTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(12, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayer_contentRejection) { - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) { - canvas.save(SaveFlags::MatrixClip); - canvas.clipRect(200, 200, 400, 400, SkClipOp::kIntersect); - canvas.saveLayerAlpha(200, 200, 400, 400, 128, SaveFlags::ClipToLayer); - - // draw within save layer may still be recorded, but shouldn't be drawn - canvas.drawRect(200, 200, 400, 400, SkPaint()); - - canvas.restore(); - canvas.restore(); - }); - - FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - FailRenderer renderer; - // should see no ops, even within the layer, since the layer should be rejected - frameBuilder.replayBakedOps<TestDispatcher>(renderer); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_simple) { - class SaveLayerUnclippedSimpleTestRenderer : public TestRendererBase { - public: - void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override { - EXPECT_EQ(0, mIndex++); - EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds); - EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState); - EXPECT_TRUE(state.computedState.transform.isIdentity()); - } - void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override { - EXPECT_EQ(1, mIndex++); - ASSERT_NE(nullptr, op.paint); - ASSERT_EQ(SkBlendMode::kClear, PaintUtils::getBlendModeDirect(op.paint)); - } - void onRectOp(const RectOp& op, const BakedOpState& state) override { - EXPECT_EQ(2, mIndex++); - EXPECT_EQ(Rect(200, 200), op.unmappedBounds); - EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds); - EXPECT_EQ(Rect(200, 200), state.computedState.clipRect()); - EXPECT_TRUE(state.computedState.transform.isIdentity()); - } - void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override { - EXPECT_EQ(3, mIndex++); - EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds); - EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState); - EXPECT_TRUE(state.computedState.transform.isIdentity()); - } - }; - - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) { - canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0)); - canvas.drawRect(0, 0, 200, 200, SkPaint()); - canvas.restore(); - }); - - FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - SaveLayerUnclippedSimpleTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(4, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_round) { - class SaveLayerUnclippedRoundTestRenderer : public TestRendererBase { - public: - void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override { - EXPECT_EQ(0, mIndex++); - EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds) - << "Bounds rect should round out"; - } - void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {} - void onRectOp(const RectOp& op, const BakedOpState& state) override {} - void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override { - EXPECT_EQ(1, mIndex++); - EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds) - << "Bounds rect should round out"; - } - }; - - auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200, [](RenderProperties& props, - RecordingCanvas& canvas) { - canvas.saveLayerAlpha(10.95f, 10.5f, 189.75f, 189.25f, // values should all round out - 128, (SaveFlags::Flags)(0)); - canvas.drawRect(0, 0, 200, 200, SkPaint()); - canvas.restore(); - }); - - FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - SaveLayerUnclippedRoundTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(2, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_mergedClears) { - class SaveLayerUnclippedMergedClearsTestRenderer : public TestRendererBase { - public: - void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override { - int index = mIndex++; - EXPECT_GT(4, index); - EXPECT_EQ(5, op.unmappedBounds.getWidth()); - EXPECT_EQ(5, op.unmappedBounds.getHeight()); - if (index == 0) { - EXPECT_EQ(Rect(10, 10), state.computedState.clippedBounds); - } else if (index == 1) { - EXPECT_EQ(Rect(190, 0, 200, 10), state.computedState.clippedBounds); - } else if (index == 2) { - EXPECT_EQ(Rect(0, 190, 10, 200), state.computedState.clippedBounds); - } else if (index == 3) { - EXPECT_EQ(Rect(190, 190, 200, 200), state.computedState.clippedBounds); - } - } - void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override { - EXPECT_EQ(4, mIndex++); - ASSERT_EQ(op.vertexCount, 16u); - for (size_t i = 0; i < op.vertexCount; i++) { - auto v = op.vertices[i]; - EXPECT_TRUE(v.x == 0 || v.x == 10 || v.x == 190 || v.x == 200); - EXPECT_TRUE(v.y == 0 || v.y == 10 || v.y == 190 || v.y == 200); - } - } - void onRectOp(const RectOp& op, const BakedOpState& state) override { - EXPECT_EQ(5, mIndex++); - } - void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override { - EXPECT_LT(5, mIndex++); - } - }; - - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) { - - int restoreTo = canvas.save(SaveFlags::MatrixClip); - canvas.scale(2, 2); - canvas.saveLayerAlpha(0, 0, 5, 5, 128, SaveFlags::MatrixClip); - canvas.saveLayerAlpha(95, 0, 100, 5, 128, SaveFlags::MatrixClip); - canvas.saveLayerAlpha(0, 95, 5, 100, 128, SaveFlags::MatrixClip); - canvas.saveLayerAlpha(95, 95, 100, 100, 128, SaveFlags::MatrixClip); - canvas.drawRect(0, 0, 100, 100, SkPaint()); - canvas.restoreToCount(restoreTo); - }); - - FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - SaveLayerUnclippedMergedClearsTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(10, renderer.getIndex()) - << "Expect 4 copyTos, 4 copyFroms, 1 clear SimpleRects, and 1 rect."; -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_clearClip) { - class SaveLayerUnclippedClearClipTestRenderer : public TestRendererBase { - public: - void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override { - EXPECT_EQ(0, mIndex++); - } - void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override { - EXPECT_EQ(1, mIndex++); - ASSERT_NE(nullptr, op.paint); - EXPECT_EQ(SkBlendMode::kClear, PaintUtils::getBlendModeDirect(op.paint)); - EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds) - << "Expect dirty rect as clip"; - ASSERT_NE(nullptr, state.computedState.clipState); - EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipState->rect); - EXPECT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode); - } - void onRectOp(const RectOp& op, const BakedOpState& state) override { - EXPECT_EQ(2, mIndex++); - } - void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override { - EXPECT_EQ(3, mIndex++); - } - }; - - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) { - // save smaller than clip, so we get unclipped behavior - canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0)); - canvas.drawRect(0, 0, 200, 200, SkPaint()); - canvas.restore(); - }); - - // draw with partial screen dirty, and assert we see that rect later - FrameBuilder frameBuilder(SkRect::MakeLTRB(50, 50, 150, 150), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - SaveLayerUnclippedClearClipTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(4, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_reject) { - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) { - // unclipped savelayer + rect both in area that won't intersect with dirty - canvas.saveLayerAlpha(100, 100, 200, 200, 128, (SaveFlags::Flags)(0)); - canvas.drawRect(100, 100, 200, 200, SkPaint()); - canvas.restore(); - }); - - // draw with partial screen dirty that doesn't intersect with savelayer - FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - FailRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); -} - -/* saveLayerUnclipped { saveLayer { saveLayerUnclipped { rect } } } will play back as: - * - startTemporaryLayer, onCopyToLayer, onSimpleRects, onRect, onCopyFromLayer, endLayer - * - startFrame, onCopyToLayer, onSimpleRects, drawLayer, onCopyFromLayer, endframe - */ -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_complex) { - class SaveLayerUnclippedComplexTestRenderer : public TestRendererBase { - public: - OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) { - EXPECT_EQ(0, mIndex++); // savelayer first - return (OffscreenBuffer*)0xabcd; - } - void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override { - int index = mIndex++; - EXPECT_TRUE(index == 1 || index == 7); - } - void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override { - int index = mIndex++; - EXPECT_TRUE(index == 2 || index == 8); - } - void onRectOp(const RectOp& op, const BakedOpState& state) override { - EXPECT_EQ(3, mIndex++); - Matrix4 expected; - expected.loadTranslate(-100, -100, 0); - EXPECT_EQ(Rect(100, 100, 200, 200), state.computedState.clippedBounds); - EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform); - } - void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override { - int index = mIndex++; - EXPECT_TRUE(index == 4 || index == 10); - } - void endLayer() override { EXPECT_EQ(5, mIndex++); } - void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override { - EXPECT_EQ(6, mIndex++); - } - void onLayerOp(const LayerOp& op, const BakedOpState& state) override { - EXPECT_EQ(9, mIndex++); - EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle); - } - void endFrame(const Rect& repaintRect) override { EXPECT_EQ(11, mIndex++); } - void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override { - EXPECT_EQ(12, mIndex++); - EXPECT_EQ((OffscreenBuffer*)0xabcd, offscreenBuffer); - } - }; - - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 600, 600, // 500x500 triggers clipping - [](RenderProperties& props, RecordingCanvas& canvas) { - canvas.saveLayerAlpha(0, 0, 500, 500, 128, (SaveFlags::Flags)0); // unclipped - canvas.saveLayerAlpha(100, 100, 400, 400, 128, SaveFlags::ClipToLayer); // clipped - canvas.saveLayerAlpha(200, 200, 300, 300, 128, (SaveFlags::Flags)0); // unclipped - canvas.drawRect(200, 200, 300, 300, SkPaint()); - canvas.restore(); - canvas.restore(); - canvas.restore(); - }); - - FrameBuilder frameBuilder(SkRect::MakeWH(600, 600), 600, 600, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - SaveLayerUnclippedComplexTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(13, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, hwLayer_simple) { - class HwLayerSimpleTestRenderer : public TestRendererBase { - public: - void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override { - EXPECT_EQ(0, mIndex++); - EXPECT_EQ(100u, offscreenBuffer->viewportWidth); - EXPECT_EQ(100u, offscreenBuffer->viewportHeight); - EXPECT_EQ(Rect(25, 25, 75, 75), repaintRect); - } - void onRectOp(const RectOp& op, const BakedOpState& state) override { - EXPECT_EQ(1, mIndex++); - - EXPECT_TRUE(state.computedState.transform.isIdentity()) - << "Transform should be reset within layer"; - - EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect()) - << "Damage rect should be used to clip layer content"; - } - void endLayer() override { EXPECT_EQ(2, mIndex++); } - void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override { - EXPECT_EQ(3, mIndex++); - } - void onLayerOp(const LayerOp& op, const BakedOpState& state) override { - EXPECT_EQ(4, mIndex++); - } - void endFrame(const Rect& repaintRect) override { EXPECT_EQ(5, mIndex++); } - }; - - auto node = TestUtils::createNode<RecordingCanvas>( - 10, 10, 110, 110, [](RenderProperties& props, RecordingCanvas& canvas) { - props.mutateLayerProperties().setType(LayerType::RenderLayer); - SkPaint paint; - paint.setColor(SK_ColorWHITE); - canvas.drawRect(0, 0, 100, 100, paint); - }); - OffscreenBuffer** layerHandle = node->getLayerHandle(); - - // create RenderNode's layer here in same way prepareTree would - OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100); - *layerHandle = &layer; - - auto syncedNode = TestUtils::getSyncedNode(node); - - // only enqueue partial damage - LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid - layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75)); - - FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferLayers(layerUpdateQueue); - frameBuilder.deferRenderNode(*syncedNode); - - HwLayerSimpleTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(6, renderer.getIndex()); - - // clean up layer pointer, so we can safely destruct RenderNode - *layerHandle = nullptr; -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, hwLayer_complex) { - /* parentLayer { greyRect, saveLayer { childLayer { whiteRect } } } will play back as: - * - startRepaintLayer(child), rect(grey), endLayer - * - startTemporaryLayer, drawLayer(child), endLayer - * - startRepaintLayer(parent), rect(white), drawLayer(saveLayer), endLayer - * - startFrame, drawLayer(parent), endLayerb - */ - class HwLayerComplexTestRenderer : public TestRendererBase { - public: - OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) { - EXPECT_EQ(3, mIndex++); // savelayer first - return (OffscreenBuffer*)0xabcd; - } - void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override { - int index = mIndex++; - if (index == 0) { - // starting inner layer - EXPECT_EQ(100u, offscreenBuffer->viewportWidth); - EXPECT_EQ(100u, offscreenBuffer->viewportHeight); - } else if (index == 6) { - // starting outer layer - EXPECT_EQ(200u, offscreenBuffer->viewportWidth); - EXPECT_EQ(200u, offscreenBuffer->viewportHeight); - } else { - ADD_FAILURE(); - } - } - void onRectOp(const RectOp& op, const BakedOpState& state) override { - int index = mIndex++; - if (index == 1) { - // inner layer's rect (white) - EXPECT_EQ(SK_ColorWHITE, op.paint->getColor()); - } else if (index == 7) { - // outer layer's rect (grey) - EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor()); - } else { - ADD_FAILURE(); - } - } - void endLayer() override { - int index = mIndex++; - EXPECT_TRUE(index == 2 || index == 5 || index == 9); - } - void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override { - EXPECT_EQ(10, mIndex++); - } - void onLayerOp(const LayerOp& op, const BakedOpState& state) override { - OffscreenBuffer* layer = *op.layerHandle; - int index = mIndex++; - if (index == 4) { - EXPECT_EQ(100u, layer->viewportWidth); - EXPECT_EQ(100u, layer->viewportHeight); - } else if (index == 8) { - EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle); - } else if (index == 11) { - EXPECT_EQ(200u, layer->viewportWidth); - EXPECT_EQ(200u, layer->viewportHeight); - } else { - ADD_FAILURE(); - } - } - void endFrame(const Rect& repaintRect) override { EXPECT_EQ(12, mIndex++); } - void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override { - EXPECT_EQ(13, mIndex++); - } - }; - - auto child = TestUtils::createNode<RecordingCanvas>( - 50, 50, 150, 150, [](RenderProperties& props, RecordingCanvas& canvas) { - props.mutateLayerProperties().setType(LayerType::RenderLayer); - SkPaint paint; - paint.setColor(SK_ColorWHITE); - canvas.drawRect(0, 0, 100, 100, paint); - }); - OffscreenBuffer childLayer(renderThread.renderState(), Caches::getInstance(), 100, 100); - *(child->getLayerHandle()) = &childLayer; - - RenderNode* childPtr = child.get(); - auto parent = TestUtils::createNode<RecordingCanvas>( - 0, 0, 200, 200, [childPtr](RenderProperties& props, RecordingCanvas& canvas) { - props.mutateLayerProperties().setType(LayerType::RenderLayer); - SkPaint paint; - paint.setColor(SK_ColorDKGRAY); - canvas.drawRect(0, 0, 200, 200, paint); - - canvas.saveLayerAlpha(50, 50, 150, 150, 128, SaveFlags::ClipToLayer); - canvas.drawRenderNode(childPtr); - canvas.restore(); - }); - OffscreenBuffer parentLayer(renderThread.renderState(), Caches::getInstance(), 200, 200); - *(parent->getLayerHandle()) = &parentLayer; - - auto syncedNode = TestUtils::getSyncedNode(parent); - - LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid - layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(100, 100)); - layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200)); - - FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferLayers(layerUpdateQueue); - frameBuilder.deferRenderNode(*syncedNode); - - HwLayerComplexTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(14, renderer.getIndex()); - - // clean up layer pointers, so we can safely destruct RenderNodes - *(child->getLayerHandle()) = nullptr; - *(parent->getLayerHandle()) = nullptr; -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, buildLayer) { - class BuildLayerTestRenderer : public TestRendererBase { - public: - void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override { - EXPECT_EQ(0, mIndex++); - EXPECT_EQ(100u, offscreenBuffer->viewportWidth); - EXPECT_EQ(100u, offscreenBuffer->viewportHeight); - EXPECT_EQ(Rect(25, 25, 75, 75), repaintRect); - } - void onColorOp(const ColorOp& op, const BakedOpState& state) override { - EXPECT_EQ(1, mIndex++); - - EXPECT_TRUE(state.computedState.transform.isIdentity()) - << "Transform should be reset within layer"; - - EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect()) - << "Damage rect should be used to clip layer content"; - } - void endLayer() override { EXPECT_EQ(2, mIndex++); } - void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override { - ADD_FAILURE() << "Primary frame draw not expected in this test"; - } - void endFrame(const Rect& repaintRect) override { - ADD_FAILURE() << "Primary frame draw not expected in this test"; - } - }; - - auto node = TestUtils::createNode<RecordingCanvas>( - 10, 10, 110, 110, [](RenderProperties& props, RecordingCanvas& canvas) { - props.mutateLayerProperties().setType(LayerType::RenderLayer); - canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver); - }); - OffscreenBuffer** layerHandle = node->getLayerHandle(); - - // create RenderNode's layer here in same way prepareTree would - OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100); - *layerHandle = &layer; - - TestUtils::syncHierarchyPropertiesAndDisplayList(node); - - // only enqueue partial damage - LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid - layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75)); - - // Draw, but pass empty node list, so no work is done for primary frame - FrameBuilder frameBuilder(layerUpdateQueue, sLightGeometry, Caches::getInstance()); - BuildLayerTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(3, renderer.getIndex()); - - // clean up layer pointer, so we can safely destruct RenderNode - *layerHandle = nullptr; -} - -namespace { - -static void drawOrderedRect(Canvas* canvas, uint8_t expectedDrawOrder) { - SkPaint paint; - // order put in blue channel, transparent so overlapped content doesn't get rejected - paint.setColor(SkColorSetARGB(1, 0, 0, expectedDrawOrder)); - canvas->drawRect(0, 0, 100, 100, paint); -} -static void drawOrderedNode(Canvas* canvas, uint8_t expectedDrawOrder, float z) { - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 100, [expectedDrawOrder](RenderProperties& props, RecordingCanvas& canvas) { - drawOrderedRect(&canvas, expectedDrawOrder); - }); - node->mutateStagingProperties().setTranslationZ(z); - node->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z); - canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership -} - -static void drawOrderedNode( - Canvas* canvas, uint8_t expectedDrawOrder, - std::function<void(RenderProperties& props, RecordingCanvas& canvas)> setup) { - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 100, - [expectedDrawOrder, setup](RenderProperties& props, RecordingCanvas& canvas) { - drawOrderedRect(&canvas, expectedDrawOrder); - if (setup) { - setup(props, canvas); - } - }); - canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership -} - -class ZReorderTestRenderer : public TestRendererBase { -public: - void onRectOp(const RectOp& op, const BakedOpState& state) override { - int expectedOrder = SkColorGetB(op.paint->getColor()); // extract order from blue channel - EXPECT_EQ(expectedOrder, mIndex++) << "An op was drawn out of order"; - } -}; - -} // end anonymous namespace - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, zReorder) { - auto parent = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) { - canvas.insertReorderBarrier(true); - canvas.insertReorderBarrier(false); - drawOrderedNode(&canvas, 0, - 10.0f); // in reorder=false at this point, so played inorder - drawOrderedRect(&canvas, 1); - canvas.insertReorderBarrier(true); - drawOrderedNode(&canvas, 6, 2.0f); - drawOrderedRect(&canvas, 3); - drawOrderedNode(&canvas, 4, 0.0f); - drawOrderedRect(&canvas, 5); - drawOrderedNode(&canvas, 2, -2.0f); - drawOrderedNode(&canvas, 7, 2.0f); - canvas.insertReorderBarrier(false); - drawOrderedRect(&canvas, 8); - drawOrderedNode(&canvas, 9, - -10.0f); // in reorder=false at this point, so played inorder - canvas.insertReorderBarrier(true); // reorder a node ahead of drawrect op - drawOrderedRect(&canvas, 11); - drawOrderedNode(&canvas, 10, -1.0f); - canvas.insertReorderBarrier(false); - canvas.insertReorderBarrier(true); // test with two empty reorder sections - canvas.insertReorderBarrier(true); - canvas.insertReorderBarrier(false); - drawOrderedRect(&canvas, 12); - }); - FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent)); - - ZReorderTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(13, renderer.getIndex()); -}; - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorder) { - static const int scrollX = 5; - static const int scrollY = 10; - class ProjectionReorderTestRenderer : public TestRendererBase { - public: - void onRectOp(const RectOp& op, const BakedOpState& state) override { - const int index = mIndex++; - - Matrix4 expectedMatrix; - switch (index) { - case 0: - EXPECT_EQ(Rect(100, 100), op.unmappedBounds); - EXPECT_EQ(SK_ColorWHITE, op.paint->getColor()); - expectedMatrix.loadIdentity(); - EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask); - break; - case 1: - EXPECT_EQ(Rect(-10, -10, 60, 60), op.unmappedBounds); - EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor()); - expectedMatrix.loadTranslate(50 - scrollX, 50 - scrollY, 0); - ASSERT_NE(nullptr, state.computedState.localProjectionPathMask); - EXPECT_EQ(Rect(-35, -30, 45, 50), - Rect(state.computedState.localProjectionPathMask->getBounds())); - break; - case 2: - EXPECT_EQ(Rect(100, 50), op.unmappedBounds); - EXPECT_EQ(SK_ColorBLUE, op.paint->getColor()); - expectedMatrix.loadTranslate(-scrollX, 50 - scrollY, 0); - EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask); - break; - default: - ADD_FAILURE(); - } - EXPECT_EQ(expectedMatrix, state.computedState.transform); - } - }; - - /** - * Construct a tree of nodes, where the root (A) has a receiver background (B), and a child (C) - * with a projecting child (P) of its own. P would normally draw between B and C's "background" - * draw, but because it is projected backwards, it's drawn in between B and C. - * - * The parent is scrolled by scrollX/scrollY, but this does not affect the background - * (which isn't affected by scroll). - */ - auto receiverBackground = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 100, [](RenderProperties& properties, RecordingCanvas& canvas) { - properties.setProjectionReceiver(true); - // scroll doesn't apply to background, so undone via translationX/Y - // NOTE: translationX/Y only! no other transform properties may be set for a proj - // receiver! - properties.setTranslationX(scrollX); - properties.setTranslationY(scrollY); - - SkPaint paint; - paint.setColor(SK_ColorWHITE); - canvas.drawRect(0, 0, 100, 100, paint); - }); - auto projectingRipple = TestUtils::createNode<RecordingCanvas>( - 50, 0, 100, 50, [](RenderProperties& properties, RecordingCanvas& canvas) { - properties.setProjectBackwards(true); - properties.setClipToBounds(false); - SkPaint paint; - paint.setColor(SK_ColorDKGRAY); - canvas.drawRect(-10, -10, 60, 60, paint); - }); - auto child = TestUtils::createNode<RecordingCanvas>( - 0, 50, 100, 100, - [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) { - SkPaint paint; - paint.setColor(SK_ColorBLUE); - canvas.drawRect(0, 0, 100, 50, paint); - canvas.drawRenderNode(projectingRipple.get()); - }); - auto parent = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 100, - [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) { - // Set a rect outline for the projecting ripple to be masked against. - properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f); - - canvas.save(SaveFlags::MatrixClip); - canvas.translate(-scrollX, - -scrollY); // Apply scroll (note: bg undoes this internally) - canvas.drawRenderNode(receiverBackground.get()); - canvas.drawRenderNode(child.get()); - canvas.restore(); - }); - - FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent)); - - ProjectionReorderTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(3, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionHwLayer) { - static const int scrollX = 5; - static const int scrollY = 10; - class ProjectionHwLayerTestRenderer : public TestRendererBase { - public: - void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override { - EXPECT_EQ(0, mIndex++); - } - void onArcOp(const ArcOp& op, const BakedOpState& state) override { - EXPECT_EQ(1, mIndex++); - ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask); - } - void endLayer() override { EXPECT_EQ(2, mIndex++); } - void onRectOp(const RectOp& op, const BakedOpState& state) override { - EXPECT_EQ(3, mIndex++); - ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask); - } - void onOvalOp(const OvalOp& op, const BakedOpState& state) override { - EXPECT_EQ(4, mIndex++); - ASSERT_NE(nullptr, state.computedState.localProjectionPathMask); - Matrix4 expected; - expected.loadTranslate(100 - scrollX, 100 - scrollY, 0); - EXPECT_EQ(expected, state.computedState.transform); - EXPECT_EQ(Rect(-85, -80, 295, 300), - Rect(state.computedState.localProjectionPathMask->getBounds())); - } - void onLayerOp(const LayerOp& op, const BakedOpState& state) override { - EXPECT_EQ(5, mIndex++); - ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask); - } - }; - auto receiverBackground = TestUtils::createNode<RecordingCanvas>( - 0, 0, 400, 400, [](RenderProperties& properties, RecordingCanvas& canvas) { - properties.setProjectionReceiver(true); - // scroll doesn't apply to background, so undone via translationX/Y - // NOTE: translationX/Y only! no other transform properties may be set for a proj - // receiver! - properties.setTranslationX(scrollX); - properties.setTranslationY(scrollY); - - canvas.drawRect(0, 0, 400, 400, SkPaint()); - }); - auto projectingRipple = TestUtils::createNode<RecordingCanvas>( - 0, 0, 200, 200, [](RenderProperties& properties, RecordingCanvas& canvas) { - properties.setProjectBackwards(true); - properties.setClipToBounds(false); - canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds - }); - auto child = TestUtils::createNode<RecordingCanvas>( - 100, 100, 300, 300, - [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) { - properties.mutateLayerProperties().setType(LayerType::RenderLayer); - canvas.drawRenderNode(projectingRipple.get()); - canvas.drawArc(0, 0, 200, 200, 0.0f, 280.0f, true, SkPaint()); - }); - auto parent = TestUtils::createNode<RecordingCanvas>( - 0, 0, 400, 400, - [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) { - // Set a rect outline for the projecting ripple to be masked against. - properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f); - canvas.translate(-scrollX, - -scrollY); // Apply scroll (note: bg undoes this internally) - canvas.drawRenderNode(receiverBackground.get()); - canvas.drawRenderNode(child.get()); - }); - - OffscreenBuffer** layerHandle = child->getLayerHandle(); - - // create RenderNode's layer here in same way prepareTree would, setting windowTransform - OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 200, 200); - Matrix4 windowTransform; - windowTransform.loadTranslate(100, 100, 0); // total transform of layer's origin - layer.setWindowTransform(windowTransform); - *layerHandle = &layer; - - auto syncedNode = TestUtils::getSyncedNode(parent); - - LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid - layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(200, 200)); - - FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferLayers(layerUpdateQueue); - frameBuilder.deferRenderNode(*syncedNode); - - ProjectionHwLayerTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(6, renderer.getIndex()); - - // clean up layer pointer, so we can safely destruct RenderNode - *layerHandle = nullptr; -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionChildScroll) { - static const int scrollX = 500000; - static const int scrollY = 0; - class ProjectionChildScrollTestRenderer : public TestRendererBase { - public: - void onRectOp(const RectOp& op, const BakedOpState& state) override { - EXPECT_EQ(0, mIndex++); - EXPECT_TRUE(state.computedState.transform.isIdentity()); - } - void onOvalOp(const OvalOp& op, const BakedOpState& state) override { - EXPECT_EQ(1, mIndex++); - ASSERT_NE(nullptr, state.computedState.clipState); - ASSERT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode); - ASSERT_EQ(Rect(400, 400), state.computedState.clipState->rect); - EXPECT_TRUE(state.computedState.transform.isIdentity()); - } - }; - auto receiverBackground = TestUtils::createNode<RecordingCanvas>( - 0, 0, 400, 400, [](RenderProperties& properties, RecordingCanvas& canvas) { - properties.setProjectionReceiver(true); - canvas.drawRect(0, 0, 400, 400, SkPaint()); - }); - auto projectingRipple = TestUtils::createNode<RecordingCanvas>( - 0, 0, 200, 200, [](RenderProperties& properties, RecordingCanvas& canvas) { - // scroll doesn't apply to background, so undone via translationX/Y - // NOTE: translationX/Y only! no other transform properties may be set for a proj - // receiver! - properties.setTranslationX(scrollX); - properties.setTranslationY(scrollY); - properties.setProjectBackwards(true); - properties.setClipToBounds(false); - canvas.drawOval(0, 0, 200, 200, SkPaint()); - }); - auto child = TestUtils::createNode<RecordingCanvas>( - 0, 0, 400, 400, - [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) { - // Record time clip will be ignored by projectee - canvas.clipRect(100, 100, 300, 300, SkClipOp::kIntersect); - - canvas.translate(-scrollX, - -scrollY); // Apply scroll (note: bg undoes this internally) - canvas.drawRenderNode(projectingRipple.get()); - }); - auto parent = TestUtils::createNode<RecordingCanvas>( - 0, 0, 400, 400, - [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) { - canvas.drawRenderNode(receiverBackground.get()); - canvas.drawRenderNode(child.get()); - }); - - FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent)); - - ProjectionChildScrollTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(2, renderer.getIndex()); -} - -// creates a 100x100 shadow casting node with provided translationZ -static sp<RenderNode> createWhiteRectShadowCaster(float translationZ) { - return TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 100, [translationZ](RenderProperties& properties, RecordingCanvas& canvas) { - properties.setTranslationZ(translationZ); - properties.mutableOutline().setRoundRect(0, 0, 100, 100, 0.0f, 1.0f); - SkPaint paint; - paint.setColor(SK_ColorWHITE); - canvas.drawRect(0, 0, 100, 100, paint); - }); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadow) { - class ShadowTestRenderer : public TestRendererBase { - public: - void onShadowOp(const ShadowOp& op, const BakedOpState& state) override { - EXPECT_EQ(0, mIndex++); - EXPECT_FLOAT_EQ(1.0f, op.casterAlpha); - EXPECT_TRUE(op.shadowTask->casterPerimeter.isRect(nullptr)); - EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.shadowTask->transformXY); - - Matrix4 expectedZ; - expectedZ.loadTranslate(0, 0, 5); - EXPECT_MATRIX_APPROX_EQ(expectedZ, op.shadowTask->transformZ); - } - void onRectOp(const RectOp& op, const BakedOpState& state) override { - EXPECT_EQ(1, mIndex++); - } - }; - - auto parent = TestUtils::createNode<RecordingCanvas>( - 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) { - canvas.insertReorderBarrier(true); - canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get()); - }); - - FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent)); - - ShadowTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(2, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadowSaveLayer) { - class ShadowSaveLayerTestRenderer : public TestRendererBase { - public: - OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override { - EXPECT_EQ(0, mIndex++); - return nullptr; - } - void onShadowOp(const ShadowOp& op, const BakedOpState& state) override { - EXPECT_EQ(1, mIndex++); - EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x); - EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y); - } - void onRectOp(const RectOp& op, const BakedOpState& state) override { - EXPECT_EQ(2, mIndex++); - } - void endLayer() override { EXPECT_EQ(3, mIndex++); } - void onLayerOp(const LayerOp& op, const BakedOpState& state) override { - EXPECT_EQ(4, mIndex++); - } - void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override { - EXPECT_EQ(5, mIndex++); - } - }; - - auto parent = TestUtils::createNode<RecordingCanvas>( - 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) { - // save/restore outside of reorderBarrier, so they don't get moved out of place - canvas.translate(20, 10); - int count = canvas.saveLayerAlpha(30, 50, 130, 150, 128, SaveFlags::ClipToLayer); - canvas.insertReorderBarrier(true); - canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get()); - canvas.insertReorderBarrier(false); - canvas.restoreToCount(count); - }); - - FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, - (FrameBuilder::LightGeometry){{100, 100, 100}, 50}, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent)); - - ShadowSaveLayerTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(6, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadowHwLayer) { - class ShadowHwLayerTestRenderer : public TestRendererBase { - public: - void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override { - EXPECT_EQ(0, mIndex++); - } - void onShadowOp(const ShadowOp& op, const BakedOpState& state) override { - EXPECT_EQ(1, mIndex++); - EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x); - EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y); - EXPECT_FLOAT_EQ(30, op.shadowTask->lightRadius); - } - void onRectOp(const RectOp& op, const BakedOpState& state) override { - EXPECT_EQ(2, mIndex++); - } - void endLayer() override { EXPECT_EQ(3, mIndex++); } - void onLayerOp(const LayerOp& op, const BakedOpState& state) override { - EXPECT_EQ(4, mIndex++); - } - }; - - auto parent = TestUtils::createNode<RecordingCanvas>( - 50, 60, 150, 160, [](RenderProperties& props, RecordingCanvas& canvas) { - props.mutateLayerProperties().setType(LayerType::RenderLayer); - canvas.insertReorderBarrier(true); - canvas.save(SaveFlags::MatrixClip); - canvas.translate(20, 10); - canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get()); - canvas.restore(); - }); - OffscreenBuffer** layerHandle = parent->getLayerHandle(); - - // create RenderNode's layer here in same way prepareTree would, setting windowTransform - OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100); - Matrix4 windowTransform; - windowTransform.loadTranslate(50, 60, 0); // total transform of layer's origin - layer.setWindowTransform(windowTransform); - *layerHandle = &layer; - - auto syncedNode = TestUtils::getSyncedNode(parent); - LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid - layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100)); - - FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, - (FrameBuilder::LightGeometry){{100, 100, 100}, 30}, - Caches::getInstance()); - frameBuilder.deferLayers(layerUpdateQueue); - frameBuilder.deferRenderNode(*syncedNode); - - ShadowHwLayerTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(5, renderer.getIndex()); - - // clean up layer pointer, so we can safely destruct RenderNode - *layerHandle = nullptr; -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadowLayering) { - class ShadowLayeringTestRenderer : public TestRendererBase { - public: - void onShadowOp(const ShadowOp& op, const BakedOpState& state) override { - int index = mIndex++; - EXPECT_TRUE(index == 0 || index == 1); - } - void onRectOp(const RectOp& op, const BakedOpState& state) override { - int index = mIndex++; - EXPECT_TRUE(index == 2 || index == 3); - } - }; - auto parent = TestUtils::createNode<RecordingCanvas>( - 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) { - canvas.insertReorderBarrier(true); - canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get()); - canvas.drawRenderNode(createWhiteRectShadowCaster(5.0001f).get()); - }); - FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, - (FrameBuilder::LightGeometry){{100, 100, 100}, 50}, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent)); - - ShadowLayeringTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(4, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadowClipping) { - class ShadowClippingTestRenderer : public TestRendererBase { - public: - void onShadowOp(const ShadowOp& op, const BakedOpState& state) override { - EXPECT_EQ(0, mIndex++); - EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipState->rect) - << "Shadow must respect pre-barrier canvas clip value."; - } - void onRectOp(const RectOp& op, const BakedOpState& state) override { - EXPECT_EQ(1, mIndex++); - } - }; - auto parent = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) { - // Apply a clip before the reorder barrier/shadow casting child is drawn. - // This clip must be applied to the shadow cast by the child. - canvas.clipRect(25, 25, 75, 75, SkClipOp::kIntersect); - canvas.insertReorderBarrier(true); - canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get()); - }); - - FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, - (FrameBuilder::LightGeometry){{100, 100, 100}, 50}, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent)); - - ShadowClippingTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(2, renderer.getIndex()); -} - -static void testProperty( - std::function<void(RenderProperties&)> propSetupCallback, - std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) { - class PropertyTestRenderer : public TestRendererBase { - public: - explicit PropertyTestRenderer( - std::function<void(const RectOp&, const BakedOpState&)> callback) - : mCallback(callback) {} - void onRectOp(const RectOp& op, const BakedOpState& state) override { - EXPECT_EQ(mIndex++, 0); - mCallback(op, state); - } - std::function<void(const RectOp&, const BakedOpState&)> mCallback; - }; - - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 100, [propSetupCallback](RenderProperties& props, RecordingCanvas& canvas) { - propSetupCallback(props); - SkPaint paint; - paint.setColor(SK_ColorWHITE); - canvas.drawRect(0, 0, 100, 100, paint); - }); - - FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - PropertyTestRenderer renderer(opValidateCallback); - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op"; -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropOverlappingRenderingAlpha) { - testProperty( - [](RenderProperties& properties) { - properties.setAlpha(0.5f); - properties.setHasOverlappingRendering(false); - }, - [](const RectOp& op, const BakedOpState& state) { - EXPECT_EQ(0.5f, state.alpha) << "Alpha should be applied directly to op"; - }); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropClipping) { - testProperty( - [](RenderProperties& properties) { - properties.setClipToBounds(true); - properties.setClipBounds(Rect(10, 20, 300, 400)); - }, - [](const RectOp& op, const BakedOpState& state) { - EXPECT_EQ(Rect(10, 20, 100, 100), state.computedState.clippedBounds) - << "Clip rect should be intersection of node bounds and clip bounds"; - }); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropRevealClip) { - testProperty( - [](RenderProperties& properties) { - properties.mutableRevealClip().set(true, 50, 50, 25); - }, - [](const RectOp& op, const BakedOpState& state) { - ASSERT_NE(nullptr, state.roundRectClipState); - EXPECT_TRUE(state.roundRectClipState->highPriority); - EXPECT_EQ(25, state.roundRectClipState->radius); - EXPECT_EQ(Rect(50, 50, 50, 50), state.roundRectClipState->innerRect); - }); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropOutlineClip) { - testProperty( - [](RenderProperties& properties) { - properties.mutableOutline().setShouldClip(true); - properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f); - }, - [](const RectOp& op, const BakedOpState& state) { - ASSERT_NE(nullptr, state.roundRectClipState); - EXPECT_FALSE(state.roundRectClipState->highPriority); - EXPECT_EQ(5, state.roundRectClipState->radius); - EXPECT_EQ(Rect(15, 25, 25, 35), state.roundRectClipState->innerRect); - }); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropTransform) { - testProperty( - [](RenderProperties& properties) { - properties.setLeftTopRightBottom(10, 10, 110, 110); - - SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f); - properties.setStaticMatrix(&staticMatrix); - - // ignored, since static overrides animation - SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15); - properties.setAnimationMatrix(&animationMatrix); - - properties.setTranslationX(10); - properties.setTranslationY(20); - properties.setScaleX(0.5f); - properties.setScaleY(0.7f); - }, - [](const RectOp& op, const BakedOpState& state) { - Matrix4 matrix; - matrix.loadTranslate(10, 10, 0); // left, top - matrix.scale(1.2f, 1.2f, 1); // static matrix - // ignore animation matrix, since static overrides it - - // translation xy - matrix.translate(10, 20); - - // scale xy (from default pivot - center) - matrix.translate(50, 50); - matrix.scale(0.5f, 0.7f, 1); - matrix.translate(-50, -50); - EXPECT_MATRIX_APPROX_EQ(matrix, state.computedState.transform) - << "Op draw matrix must match expected combination of transformation " - "properties"; - }); -} - -struct SaveLayerAlphaData { - uint32_t layerWidth = 0; - uint32_t layerHeight = 0; - Rect rectClippedBounds; - Matrix4 rectMatrix; - Matrix4 drawLayerMatrix; -}; -/** - * Constructs a view to hit the temporary layer alpha property implementation: - * a) 0 < alpha < 1 - * b) too big for layer (larger than maxTextureSize) - * c) overlapping rendering content - * returning observed data about layer size and content clip/transform. - * - * Used to validate clipping behavior of temporary layer, where requested layer size is reduced - * (for efficiency, and to fit in layer size constraints) based on parent clip. - */ -void testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData, - std::function<void(RenderProperties&)> propSetupCallback) { - class SaveLayerAlphaClipTestRenderer : public TestRendererBase { - public: - explicit SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData) : mOutData(outData) {} - - OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override { - EXPECT_EQ(0, mIndex++); - mOutData->layerWidth = width; - mOutData->layerHeight = height; - return nullptr; - } - void onRectOp(const RectOp& op, const BakedOpState& state) override { - EXPECT_EQ(1, mIndex++); - - mOutData->rectClippedBounds = state.computedState.clippedBounds; - mOutData->rectMatrix = state.computedState.transform; - } - void endLayer() override { EXPECT_EQ(2, mIndex++); } - void onLayerOp(const LayerOp& op, const BakedOpState& state) override { - EXPECT_EQ(3, mIndex++); - mOutData->drawLayerMatrix = state.computedState.transform; - } - void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override { - EXPECT_EQ(4, mIndex++); - } - - private: - SaveLayerAlphaData* mOutData; - }; - - ASSERT_GT(10000, DeviceInfo::get()->maxTextureSize()) - << "Node must be bigger than max texture size to exercise saveLayer codepath"; - auto node = TestUtils::createNode<RecordingCanvas>( - 0, 0, 10000, 10000, - [&propSetupCallback](RenderProperties& properties, RecordingCanvas& canvas) { - properties.setHasOverlappingRendering(true); - properties.setAlpha(0.5f); // force saveLayer, since too big for HW layer - // apply other properties - propSetupCallback(properties); - - SkPaint paint; - paint.setColor(SK_ColorWHITE); - canvas.drawRect(0, 0, 10000, 10000, paint); - }); - auto syncedNode = TestUtils::getSyncedNode(node); // sync before querying height - - FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*syncedNode); - - SaveLayerAlphaClipTestRenderer renderer(outObservedData); - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - - // assert, since output won't be valid if we haven't seen a save layer triggered - ASSERT_EQ(5, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior."; -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) { - SaveLayerAlphaData observedData; - testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) { - properties.setTranslationX(10); // offset rendering content - properties.setTranslationY(-2000); // offset rendering content - }); - EXPECT_EQ(190u, observedData.layerWidth); - EXPECT_EQ(200u, observedData.layerHeight); - EXPECT_EQ(Rect(190, 200), observedData.rectClippedBounds) - << "expect content to be clipped to screen area"; - Matrix4 expected; - expected.loadTranslate(0, -2000, 0); - EXPECT_MATRIX_APPROX_EQ(expected, observedData.rectMatrix) - << "expect content to be translated as part of being clipped"; - expected.loadTranslate(10, 0, 0); - EXPECT_MATRIX_APPROX_EQ(expected, observedData.drawLayerMatrix) - << "expect drawLayer to be translated as part of being clipped"; -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropSaveLayerAlphaRotate) { - SaveLayerAlphaData observedData; - testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) { - // Translate and rotate the view so that the only visible part is the top left corner of - // the view. It will form an isosceles right triangle with a long side length of 200 at the - // bottom of the viewport. - properties.setTranslationX(100); - properties.setTranslationY(100); - properties.setPivotX(0); - properties.setPivotY(0); - properties.setRotation(45); - }); - // ceil(sqrt(2) / 2 * 200) = 142 - EXPECT_EQ(142u, observedData.layerWidth); - EXPECT_EQ(142u, observedData.layerHeight); - EXPECT_EQ(Rect(142, 142), observedData.rectClippedBounds); - EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropSaveLayerAlphaScale) { - SaveLayerAlphaData observedData; - testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) { - properties.setPivotX(0); - properties.setPivotY(0); - properties.setScaleX(2); - properties.setScaleY(0.5f); - }); - EXPECT_EQ(100u, observedData.layerWidth); - EXPECT_EQ(400u, observedData.layerHeight); - EXPECT_EQ(Rect(100, 400), observedData.rectClippedBounds); - EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, clip_replace) { - class ClipReplaceTestRenderer : public TestRendererBase { - public: - void onColorOp(const ColorOp& op, const BakedOpState& state) override { - EXPECT_EQ(0, mIndex++); - EXPECT_TRUE(op.localClip->intersectWithRoot); - EXPECT_EQ(Rect(20, 10, 30, 40), state.computedState.clipState->rect) - << "Expect resolved clip to be intersection of viewport clip and clip op"; - } - }; - auto node = TestUtils::createNode<RecordingCanvas>( - 20, 20, 30, 30, [](RenderProperties& props, RecordingCanvas& canvas) { - canvas.clipRect(0, -20, 10, 30, SkClipOp::kReplace_deprecated); - canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver); - }); - - FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 10, 40, 40), 50, 50, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - - ClipReplaceTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(1, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectedInMiddle) { - /* R is backward projected on B - A - / \ - B C - | - R - */ - auto nodeA = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) { - drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) { - props.setProjectionReceiver(true); - }); // nodeB - drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) { - drawOrderedNode(&canvas, 1, - [](RenderProperties& props, RecordingCanvas& canvas) { - props.setProjectBackwards(true); - props.setClipToBounds(false); - }); // nodeR - }); // nodeC - }); // nodeA - - FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA)); - - ZReorderTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(3, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectLast) { - /* R is backward projected on E - A - / | \ - / | \ - B C E - | - R - */ - auto nodeA = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) { - drawOrderedNode(&canvas, 0, nullptr); // nodeB - drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) { - drawOrderedNode(&canvas, 3, [](RenderProperties& props, - RecordingCanvas& canvas) { // drawn as 2 - props.setProjectBackwards(true); - props.setClipToBounds(false); - }); // nodeR - }); // nodeC - drawOrderedNode(&canvas, 2, [](RenderProperties& props, - RecordingCanvas& canvas) { // drawn as 3 - props.setProjectionReceiver(true); - }); // nodeE - }); // nodeA - - FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA)); - - ZReorderTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(4, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderNoReceivable) { - /* R is backward projected without receiver - A - / \ - B C - | - R - */ - auto nodeA = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) { - drawOrderedNode(&canvas, 0, nullptr); // nodeB - drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) { - drawOrderedNode(&canvas, 255, - [](RenderProperties& props, RecordingCanvas& canvas) { - // not having a projection receiver is an undefined behavior - props.setProjectBackwards(true); - props.setClipToBounds(false); - }); // nodeR - }); // nodeC - }); // nodeA - - FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA)); - - ZReorderTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(2, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderParentReceivable) { - /* R is backward projected on C - A - / \ - B C - | - R - */ - auto nodeA = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) { - drawOrderedNode(&canvas, 0, nullptr); // nodeB - drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) { - props.setProjectionReceiver(true); - drawOrderedNode(&canvas, 2, - [](RenderProperties& props, RecordingCanvas& canvas) { - props.setProjectBackwards(true); - props.setClipToBounds(false); - }); // nodeR - }); // nodeC - }); // nodeA - - FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA)); - - ZReorderTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(3, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderSameNodeReceivable) { - auto nodeA = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) { - drawOrderedNode(&canvas, 0, nullptr); // nodeB - drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) { - drawOrderedNode(&canvas, 255, - [](RenderProperties& props, RecordingCanvas& canvas) { - // having a node that is projected on itself is an - // undefined/unexpected behavior - props.setProjectionReceiver(true); - props.setProjectBackwards(true); - props.setClipToBounds(false); - }); // nodeR - }); // nodeC - }); // nodeA - - FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA)); - - ZReorderTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(2, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectedSibling) { - // TODO: this test together with the next "projectionReorderProjectedSibling2" likely expose a - // bug in HWUI. First test draws R, while the second test does not draw R for a nearly identical - // tree setup. The correct behaviour is to not draw R, because the receiver cannot be a sibling - /* R is backward projected on B. R is not expected to be drawn (see Sibling2 outcome below), - but for some reason it is drawn. - A - /|\ - / | \ - B C R - */ - auto nodeA = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) { - drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) { - props.setProjectionReceiver(true); - }); // nodeB - drawOrderedNode(&canvas, 2, - [](RenderProperties& props, RecordingCanvas& canvas) {}); // nodeC - drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) { - props.setProjectBackwards(true); - props.setClipToBounds(false); - }); // nodeR - }); // nodeA - - FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA)); - - ZReorderTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(3, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectedSibling2) { - /* R is set to project on B, but R is not drawn because projecting on a sibling is not allowed. - A - | - G - /|\ - / | \ - B C R - */ - auto nodeA = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) { - drawOrderedNode(&canvas, 0, [](RenderProperties& props, - RecordingCanvas& canvas) { // G - drawOrderedNode(&canvas, 1, - [](RenderProperties& props, RecordingCanvas& canvas) { // B - props.setProjectionReceiver(true); - }); // nodeB - drawOrderedNode(&canvas, 2, - [](RenderProperties& props, RecordingCanvas& canvas) { // C - }); // nodeC - drawOrderedNode(&canvas, 255, - [](RenderProperties& props, RecordingCanvas& canvas) { // R - props.setProjectBackwards(true); - props.setClipToBounds(false); - }); // nodeR - }); // nodeG - }); // nodeA - - FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA)); - - ZReorderTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(3, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderGrandparentReceivable) { - /* R is backward projected on B - A - | - B - | - C - | - R - */ - auto nodeA = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) { - drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) { - props.setProjectionReceiver(true); - drawOrderedNode(&canvas, 1, - [](RenderProperties& props, RecordingCanvas& canvas) { - drawOrderedNode(&canvas, 2, [](RenderProperties& props, - RecordingCanvas& canvas) { - props.setProjectBackwards(true); - props.setClipToBounds(false); - }); // nodeR - }); // nodeC - }); // nodeB - }); // nodeA - - FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA)); - - ZReorderTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(3, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderTwoReceivables) { - /* B and G are receivables, R is backward projected - A - / \ - B C - / \ - G R - */ - auto nodeA = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) { - drawOrderedNode(&canvas, 0, - [](RenderProperties& props, RecordingCanvas& canvas) { // B - props.setProjectionReceiver(true); - }); // nodeB - drawOrderedNode(&canvas, 2, [](RenderProperties& props, - RecordingCanvas& canvas) { // C - drawOrderedNode(&canvas, 3, - [](RenderProperties& props, RecordingCanvas& canvas) { // G - props.setProjectionReceiver(true); - }); // nodeG - drawOrderedNode(&canvas, 1, - [](RenderProperties& props, RecordingCanvas& canvas) { // R - props.setProjectBackwards(true); - props.setClipToBounds(false); - }); // nodeR - }); // nodeC - }); // nodeA - - FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA)); - - ZReorderTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(4, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderTwoReceivablesLikelyScenario) { - /* B and G are receivables, G is backward projected - A - / \ - B C - / \ - G R - */ - auto nodeA = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) { - drawOrderedNode(&canvas, 0, - [](RenderProperties& props, RecordingCanvas& canvas) { // B - props.setProjectionReceiver(true); - }); // nodeB - drawOrderedNode(&canvas, 2, [](RenderProperties& props, - RecordingCanvas& canvas) { // C - drawOrderedNode(&canvas, 1, - [](RenderProperties& props, RecordingCanvas& canvas) { // G - props.setProjectionReceiver(true); - props.setProjectBackwards(true); - props.setClipToBounds(false); - }); // nodeG - drawOrderedNode(&canvas, 3, - [](RenderProperties& props, RecordingCanvas& canvas) { // R - }); // nodeR - }); // nodeC - }); // nodeA - - FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA)); - - ZReorderTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(4, renderer.getIndex()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderTwoReceivablesDeeper) { - /* B and G are receivables, R is backward projected - A - / \ - B C - / \ - G D - | - R - */ - auto nodeA = TestUtils::createNode<RecordingCanvas>( - 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) { - drawOrderedNode(&canvas, 0, - [](RenderProperties& props, RecordingCanvas& canvas) { // B - props.setProjectionReceiver(true); - }); // nodeB - drawOrderedNode(&canvas, 1, [](RenderProperties& props, - RecordingCanvas& canvas) { // C - drawOrderedNode(&canvas, 2, - [](RenderProperties& props, RecordingCanvas& canvas) { // G - props.setProjectionReceiver(true); - }); // nodeG - drawOrderedNode( - &canvas, 4, [](RenderProperties& props, RecordingCanvas& canvas) { // D - drawOrderedNode(&canvas, 3, [](RenderProperties& props, - RecordingCanvas& canvas) { // R - props.setProjectBackwards(true); - props.setClipToBounds(false); - }); // nodeR - }); // nodeD - }); // nodeC - }); // nodeA - - FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA)); - - ZReorderTestRenderer renderer; - frameBuilder.replayBakedOps<TestDispatcher>(renderer); - EXPECT_EQ(5, renderer.getIndex()); -} - -} // namespace uirenderer -} // namespace android diff --git a/libs/hwui/tests/unit/GlopBuilderTests.cpp b/libs/hwui/tests/unit/GlopBuilderTests.cpp deleted file mode 100644 index c8bfc99fac92..000000000000 --- a/libs/hwui/tests/unit/GlopBuilderTests.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2016 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 "Glop.h" -#include "GlopBuilder.h" -#include "Rect.h" -#include "tests/common/TestUtils.h" -#include "utils/Color.h" - -#include <SkPaint.h> - -using namespace android::uirenderer; - -static void expectFillEq(Glop::Fill& expectedFill, Glop::Fill& builtFill) { - EXPECT_EQ(expectedFill.colorEnabled, builtFill.colorEnabled); - if (expectedFill.colorEnabled) EXPECT_EQ(expectedFill.color, builtFill.color); - - EXPECT_EQ(expectedFill.filterMode, builtFill.filterMode); - if (expectedFill.filterMode == ProgramDescription::ColorFilterMode::Blend) { - EXPECT_EQ(expectedFill.filter.color, builtFill.filter.color); - } else if (expectedFill.filterMode == ProgramDescription::ColorFilterMode::Matrix) { - Glop::Fill::Filter::Matrix& expectedMatrix = expectedFill.filter.matrix; - Glop::Fill::Filter::Matrix& builtMatrix = expectedFill.filter.matrix; - EXPECT_TRUE(std::memcmp(expectedMatrix.matrix, builtMatrix.matrix, - sizeof(Glop::Fill::Filter::Matrix::matrix))); - EXPECT_TRUE(std::memcmp(expectedMatrix.vector, builtMatrix.vector, - sizeof(Glop::Fill::Filter::Matrix::vector))); - } - EXPECT_EQ(expectedFill.skiaShaderData.skiaShaderType, builtFill.skiaShaderData.skiaShaderType); - EXPECT_EQ(expectedFill.texture.clamp, builtFill.texture.clamp); - EXPECT_EQ(expectedFill.texture.filter, builtFill.texture.filter); - EXPECT_TRUE((expectedFill.texture.texture && builtFill.texture.texture) || - (!expectedFill.texture.texture && !builtFill.texture.texture)); - if (expectedFill.texture.texture) { - EXPECT_EQ(expectedFill.texture.texture->target(), builtFill.texture.texture->target()); - } - EXPECT_EQ(expectedFill.texture.textureTransform, builtFill.texture.textureTransform); -} - -static void expectBlendEq(Glop::Blend& expectedBlend, Glop::Blend& builtBlend) { - EXPECT_EQ(expectedBlend.src, builtBlend.src); - EXPECT_EQ(expectedBlend.dst, builtBlend.dst); -} - -static void expectMeshEq(Glop::Mesh& expectedMesh, Glop::Mesh& builtMesh) { - EXPECT_EQ(expectedMesh.elementCount, builtMesh.elementCount); - EXPECT_EQ(expectedMesh.primitiveMode, builtMesh.primitiveMode); - EXPECT_EQ(expectedMesh.indices.indices, builtMesh.indices.indices); - EXPECT_EQ(expectedMesh.indices.bufferObject, builtMesh.indices.bufferObject); - EXPECT_EQ(expectedMesh.vertices.attribFlags, builtMesh.vertices.attribFlags); - EXPECT_EQ(expectedMesh.vertices.bufferObject, builtMesh.vertices.bufferObject); - EXPECT_EQ(expectedMesh.vertices.color, builtMesh.vertices.color); - EXPECT_EQ(expectedMesh.vertices.position, builtMesh.vertices.position); - EXPECT_EQ(expectedMesh.vertices.stride, builtMesh.vertices.stride); - EXPECT_EQ(expectedMesh.vertices.texCoord, builtMesh.vertices.texCoord); - - if (builtMesh.vertices.position) { - for (int i = 0; i < 4; i++) { - TextureVertex& expectedVertex = expectedMesh.mappedVertices[i]; - TextureVertex& builtVertex = builtMesh.mappedVertices[i]; - EXPECT_EQ(expectedVertex.u, builtVertex.u); - EXPECT_EQ(expectedVertex.v, builtVertex.v); - EXPECT_EQ(expectedVertex.x, builtVertex.x); - EXPECT_EQ(expectedVertex.y, builtVertex.y); - } - } -} - -static void expectTransformEq(Glop::Transform& expectedTransform, Glop::Transform& builtTransform) { - EXPECT_EQ(expectedTransform.canvas, builtTransform.canvas); - EXPECT_EQ(expectedTransform.modelView, builtTransform.modelView); - EXPECT_EQ(expectedTransform.transformFlags, expectedTransform.transformFlags); -} - -static void expectGlopEq(Glop& expectedGlop, Glop& builtGlop) { - expectBlendEq(expectedGlop.blend, builtGlop.blend); - expectFillEq(expectedGlop.fill, builtGlop.fill); - expectMeshEq(expectedGlop.mesh, builtGlop.mesh); - expectTransformEq(expectedGlop.transform, builtGlop.transform); -} - -static std::unique_ptr<Glop> blackUnitQuadGlop(RenderState& renderState) { - std::unique_ptr<Glop> glop(new Glop()); - glop->blend = {GL_ZERO, GL_ZERO}; - glop->mesh.elementCount = 4; - glop->mesh.primitiveMode = GL_TRIANGLE_STRIP; - glop->mesh.indices.indices = nullptr; - glop->mesh.indices.bufferObject = GL_ZERO; - glop->mesh.vertices = {renderState.meshState().getUnitQuadVBO(), - VertexAttribFlags::None, - nullptr, - nullptr, - nullptr, - kTextureVertexStride}; - glop->transform.modelView.loadIdentity(); - glop->fill.colorEnabled = true; - glop->fill.color.set(Color::Black); - glop->fill.skiaShaderData.skiaShaderType = kNone_SkiaShaderType; - glop->fill.filterMode = ProgramDescription::ColorFilterMode::None; - glop->fill.texture = {nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr}; - return glop; -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(GlopBuilder, rectSnapTest) { - RenderState& renderState = renderThread.renderState(); - Caches& caches = Caches::getInstance(); - SkPaint paint; - Rect dest(1, 1, 100, 100); - Matrix4 simpleTranslate; - simpleTranslate.loadTranslate(0.7, 0.7, 0); - Glop glop; - GlopBuilder(renderState, caches, &glop) - .setRoundRectClipState(nullptr) - .setMeshUnitQuad() - .setFillPaint(paint, 1.0f) - .setTransform(simpleTranslate, TransformFlags::None) - .setModelViewMapUnitToRectSnap(dest) - .build(); - - std::unique_ptr<Glop> goldenGlop(blackUnitQuadGlop(renderState)); - // Rect(1,1,100,100) is the set destination, - // so unit quad should be translated by (1,1) and scaled by (99, 99) - // Tricky part: because translate (0.7, 0.7) and snapping were set in glopBuilder, - // unit quad also should be translate by additional (0.3, 0.3) to snap to exact pixels. - goldenGlop->transform.modelView.loadTranslate(1.3, 1.3, 0); - goldenGlop->transform.modelView.scale(99, 99, 1); - goldenGlop->transform.canvas = simpleTranslate; - goldenGlop->fill.texture.filter = GL_NEAREST; - expectGlopEq(*goldenGlop, glop); -} diff --git a/libs/hwui/tests/unit/GradientCacheTests.cpp b/libs/hwui/tests/unit/GradientCacheTests.cpp deleted file mode 100644 index 6710c71c386f..000000000000 --- a/libs/hwui/tests/unit/GradientCacheTests.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2016 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 "Extensions.h" -#include "GradientCache.h" -#include "tests/common/TestUtils.h" - -using namespace android; -using namespace android::uirenderer; - -RENDERTHREAD_OPENGL_PIPELINE_TEST(GradientCache, addRemove) { - Extensions extensions; - GradientCache cache(extensions); - ASSERT_LT(1000u, cache.getMaxSize()) << "Expect non-trivial size"; - - SkColor colors[] = {0xFF00FF00, 0xFFFF0000, 0xFF0000FF}; - float positions[] = {1, 2, 3}; - Texture* texture = cache.get(colors, positions, 3); - ASSERT_TRUE(texture); - ASSERT_FALSE(texture->cleanup); - ASSERT_EQ((uint32_t)texture->objectSize(), cache.getSize()); - ASSERT_TRUE(cache.getSize()); - cache.clear(); - ASSERT_EQ(cache.getSize(), 0u); -} diff --git a/libs/hwui/tests/unit/LeakCheckTests.cpp b/libs/hwui/tests/unit/LeakCheckTests.cpp deleted file mode 100644 index 20ec0848212f..000000000000 --- a/libs/hwui/tests/unit/LeakCheckTests.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2016 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 "BakedOpDispatcher.h" -#include "BakedOpRenderer.h" -#include "FrameBuilder.h" -#include "LayerUpdateQueue.h" -#include "RecordingCanvas.h" -#include "tests/common/TestUtils.h" - -#include <gtest/gtest.h> - -using namespace android; -using namespace android::uirenderer; - -const FrameBuilder::LightGeometry sLightGeometery = {{100, 100, 100}, 50}; -const BakedOpRenderer::LightInfo sLightInfo = {128, 128}; - -RENDERTHREAD_OPENGL_PIPELINE_TEST(LeakCheck, saveLayer_overdrawRejection) { - auto node = TestUtils::createNode(0, 0, 100, 100, [](RenderProperties& props, Canvas& canvas) { - canvas.saveLayerAlpha(0, 0, 100, 100, 128, SaveFlags::ClipToLayer); - canvas.drawRect(0, 0, 100, 100, SkPaint()); - canvas.restore(); - - // opaque draw, rejects saveLayer beneath - canvas.drawRect(0, 0, 100, 100, SkPaint()); - }); - RenderState& renderState = renderThread.renderState(); - Caches& caches = Caches::getInstance(); - - FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometery, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - BakedOpRenderer renderer(caches, renderState, true, false, sLightInfo); - frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(LeakCheck, saveLayerUnclipped_simple) { - auto node = TestUtils::createNode(0, 0, 200, 200, [](RenderProperties& props, Canvas& canvas) { - canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0)); - canvas.drawRect(0, 0, 200, 200, SkPaint()); - canvas.restore(); - }); - RenderState& renderState = renderThread.renderState(); - Caches& caches = Caches::getInstance(); - - FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometery, - Caches::getInstance()); - frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node)); - BakedOpRenderer renderer(caches, renderState, true, false, sLightInfo); - frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer); -} diff --git a/libs/hwui/tests/unit/MeshStateTests.cpp b/libs/hwui/tests/unit/MeshStateTests.cpp deleted file mode 100644 index 1573fd30d5cb..000000000000 --- a/libs/hwui/tests/unit/MeshStateTests.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2016 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 <debug/MockGlesDriver.h> -#include <debug/ScopedReplaceDriver.h> -#include <gmock/gmock.h> -#include <gtest/gtest.h> -#include <renderstate/MeshState.h> -#include <tests/common/TestUtils.h> - -using namespace android::uirenderer; -using namespace testing; - -RENDERTHREAD_OPENGL_PIPELINE_TEST(MeshState, genOrUpdate) { - debug::ScopedReplaceDriver<debug::MockGlesDriver> driverRef; - auto& mockGlDriver = driverRef.get(); - EXPECT_CALL(mockGlDriver, glGenBuffers_(_, _)).WillOnce(SetArgPointee<1>(35)); - EXPECT_CALL(mockGlDriver, glBindBuffer_(_, 35)); - EXPECT_CALL(mockGlDriver, glBufferData_(_, _, _, _)); - - GLuint buffer = 0; - renderThread.renderState().meshState().genOrUpdateMeshBuffer(&buffer, 10, nullptr, - GL_DYNAMIC_DRAW); -} diff --git a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp deleted file mode 100644 index 0d4736757629..000000000000 --- a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <Rect.h> -#include <gtest/gtest.h> -#include <renderstate/OffscreenBufferPool.h> - -#include <tests/common/TestUtils.h> - -using namespace android::uirenderer; - -TEST(OffscreenBuffer, computeIdealDimension) { - EXPECT_EQ(64u, OffscreenBuffer::computeIdealDimension(1)); - EXPECT_EQ(64u, OffscreenBuffer::computeIdealDimension(31)); - EXPECT_EQ(64u, OffscreenBuffer::computeIdealDimension(33)); - EXPECT_EQ(64u, OffscreenBuffer::computeIdealDimension(64)); - EXPECT_EQ(1024u, OffscreenBuffer::computeIdealDimension(1000)); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBuffer, construct) { - OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 49u, 149u); - EXPECT_EQ(49u, layer.viewportWidth); - EXPECT_EQ(149u, layer.viewportHeight); - - EXPECT_EQ(64u, layer.texture.width()); - EXPECT_EQ(192u, layer.texture.height()); - - EXPECT_EQ(64u * 192u * 4u, layer.getSizeInBytes()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBuffer, constructWideColorGamut) { - OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 49u, 149u, true); - EXPECT_EQ(49u, layer.viewportWidth); - EXPECT_EQ(149u, layer.viewportHeight); - - EXPECT_EQ(64u, layer.texture.width()); - EXPECT_EQ(192u, layer.texture.height()); - - EXPECT_TRUE(layer.wideColorGamut); - - EXPECT_EQ(64u * 192u * 8u, layer.getSizeInBytes()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBuffer, getTextureCoordinates) { - OffscreenBuffer layerAligned(renderThread.renderState(), Caches::getInstance(), 256u, 256u); - EXPECT_EQ(Rect(0, 1, 1, 0), layerAligned.getTextureCoordinates()); - - OffscreenBuffer layerUnaligned(renderThread.renderState(), Caches::getInstance(), 200u, 225u); - EXPECT_EQ(Rect(0, 225.0f / 256.0f, 200.0f / 256.0f, 0), layerUnaligned.getTextureCoordinates()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBuffer, dirty) { - OffscreenBuffer buffer(renderThread.renderState(), Caches::getInstance(), 256u, 256u); - buffer.dirty(Rect(-100, -100, 100, 100)); - EXPECT_EQ(android::Rect(100, 100), buffer.region.getBounds()); -} - -RENDERTHREAD_TEST(OffscreenBufferPool, construct) { - OffscreenBufferPool pool; - EXPECT_EQ(0u, pool.getCount()) << "pool must be created empty"; - EXPECT_EQ(0u, pool.getSize()) << "pool must be created empty"; - // TODO: Does this really make sense as a test? - EXPECT_EQ(DeviceInfo::multiplyByResolution(4 * 4), pool.getMaxSize()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, getPutClear) { - OffscreenBufferPool pool; - - auto layer = pool.get(renderThread.renderState(), 100u, 200u); - EXPECT_EQ(100u, layer->viewportWidth); - EXPECT_EQ(200u, layer->viewportHeight); - - ASSERT_LT(layer->getSizeInBytes(), pool.getMaxSize()); - - pool.putOrDelete(layer); - ASSERT_EQ(layer->getSizeInBytes(), pool.getSize()); - - auto layer2 = pool.get(renderThread.renderState(), 102u, 202u); - EXPECT_EQ(layer, layer2) << "layer should be recycled"; - ASSERT_EQ(0u, pool.getSize()) << "pool should have been emptied by removing only layer"; - - pool.putOrDelete(layer); - EXPECT_EQ(1u, pool.getCount()); - pool.clear(); - EXPECT_EQ(0u, pool.getSize()); - EXPECT_EQ(0u, pool.getCount()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, getPutClearWideColorGamut) { - OffscreenBufferPool pool; - - auto layer = pool.get(renderThread.renderState(), 100u, 200u, true); - EXPECT_EQ(100u, layer->viewportWidth); - EXPECT_EQ(200u, layer->viewportHeight); - EXPECT_TRUE(layer->wideColorGamut); - - ASSERT_LT(layer->getSizeInBytes(), pool.getMaxSize()); - - pool.putOrDelete(layer); - ASSERT_EQ(layer->getSizeInBytes(), pool.getSize()); - - auto layer2 = pool.get(renderThread.renderState(), 102u, 202u, true); - EXPECT_EQ(layer, layer2) << "layer should be recycled"; - ASSERT_EQ(0u, pool.getSize()) << "pool should have been emptied by removing only layer"; - - pool.putOrDelete(layer2); - EXPECT_EQ(1u, pool.getCount()); - pool.clear(); - EXPECT_EQ(0u, pool.getSize()); - EXPECT_EQ(0u, pool.getCount()); - - // add non wide gamut layer - auto layer3 = pool.get(renderThread.renderState(), 100u, 200u); - EXPECT_FALSE(layer3->wideColorGamut); - pool.putOrDelete(layer3); - EXPECT_EQ(1u, pool.getCount()); - - auto layer4 = pool.get(renderThread.renderState(), 100u, 200u, true); - EXPECT_TRUE(layer4->wideColorGamut); - EXPECT_EQ(1u, pool.getCount()); - ASSERT_NE(layer3, layer4); - - pool.putOrDelete(layer4); - - pool.clear(); - EXPECT_EQ(0u, pool.getSize()); - EXPECT_EQ(0u, pool.getCount()); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, resize) { - OffscreenBufferPool pool; - - auto layer = pool.get(renderThread.renderState(), 64u, 64u); - layer->dirty(Rect(64, 64)); - - // resize in place - ASSERT_EQ(layer, pool.resize(layer, 60u, 55u)); - EXPECT_TRUE(layer->region.isEmpty()) << "In place resize should clear usage region"; - EXPECT_EQ(60u, layer->viewportWidth); - EXPECT_EQ(55u, layer->viewportHeight); - EXPECT_EQ(64u, layer->texture.width()); - EXPECT_EQ(64u, layer->texture.height()); - - // resized to use different object in pool - auto layer2 = pool.get(renderThread.renderState(), 128u, 128u); - layer2->dirty(Rect(128, 128)); - EXPECT_FALSE(layer2->region.isEmpty()); - pool.putOrDelete(layer2); - ASSERT_EQ(1u, pool.getCount()); - - ASSERT_EQ(layer2, pool.resize(layer, 120u, 125u)); - EXPECT_TRUE(layer2->region.isEmpty()) << "Swap resize should clear usage region"; - EXPECT_EQ(120u, layer2->viewportWidth); - EXPECT_EQ(125u, layer2->viewportHeight); - EXPECT_EQ(128u, layer2->texture.width()); - EXPECT_EQ(128u, layer2->texture.height()); - - // original allocation now only thing in pool - EXPECT_EQ(1u, pool.getCount()); - EXPECT_EQ(layer->getSizeInBytes(), pool.getSize()); - - pool.putOrDelete(layer2); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, resizeWideColorGamut) { - OffscreenBufferPool pool; - - auto layer = pool.get(renderThread.renderState(), 64u, 64u, true); - - // resize in place - ASSERT_EQ(layer, pool.resize(layer, 60u, 55u)); - EXPECT_EQ(60u, layer->viewportWidth); - EXPECT_EQ(55u, layer->viewportHeight); - EXPECT_EQ(64u, layer->texture.width()); - EXPECT_EQ(64u, layer->texture.height()); - - EXPECT_TRUE(layer->wideColorGamut); - EXPECT_EQ(64u * 64u * 8u, layer->getSizeInBytes()); - - // resized to use different object in pool - auto layer2 = pool.get(renderThread.renderState(), 128u, 128u, true); - pool.putOrDelete(layer2); - ASSERT_EQ(1u, pool.getCount()); - - // add a non-wide gamut layer - auto layer3 = pool.get(renderThread.renderState(), 128u, 128u); - pool.putOrDelete(layer3); - ASSERT_EQ(2u, pool.getCount()); - - ASSERT_EQ(layer2, pool.resize(layer, 120u, 125u)); - EXPECT_EQ(120u, layer2->viewportWidth); - EXPECT_EQ(125u, layer2->viewportHeight); - EXPECT_EQ(128u, layer2->texture.width()); - EXPECT_EQ(128u, layer2->texture.height()); - - EXPECT_TRUE(layer2->wideColorGamut); - EXPECT_EQ(128u * 128u * 8u, layer2->getSizeInBytes()); - - pool.putOrDelete(layer2); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, putAndDestroy) { - OffscreenBufferPool pool; - // layer too big to return to the pool - // Note: this relies on the fact that the pool won't reject based on max texture size - auto hugeLayer = pool.get(renderThread.renderState(), pool.getMaxSize() / 64, 64); - EXPECT_GT(hugeLayer->getSizeInBytes(), pool.getMaxSize()); - pool.putOrDelete(hugeLayer); - EXPECT_EQ(0u, pool.getCount()); // failed to put (so was destroyed instead) -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, clear) { - EXPECT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::OffscreenBuffer)); - OffscreenBufferPool pool; - - // Create many buffers, with several at each size - std::vector<OffscreenBuffer*> buffers; - for (int size = 32; size <= 128; size += 32) { - for (int i = 0; i < 10; i++) { - buffers.push_back(pool.get(renderThread.renderState(), size, size)); - } - } - EXPECT_EQ(0u, pool.getCount()) << "Expect nothing inside"; - for (auto& buffer : buffers) pool.putOrDelete(buffer); - EXPECT_EQ(40u, pool.getCount()) << "Expect all items added"; - EXPECT_EQ(40, GpuMemoryTracker::getInstanceCount(GpuObjectType::OffscreenBuffer)); - pool.clear(); - EXPECT_EQ(0u, pool.getCount()) << "Expect all items cleared"; - - EXPECT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::OffscreenBuffer)); -} diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp deleted file mode 100644 index 8a9e34f81c6d..000000000000 --- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp +++ /dev/null @@ -1,847 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <gtest/gtest.h> - -#include <DeferredLayerUpdater.h> -#include <RecordedOp.h> -#include <RecordingCanvas.h> -#include <hwui/Paint.h> -#include <minikin/Layout.h> -#include <tests/common/TestUtils.h> -#include <utils/Color.h> - -#include <SkGradientShader.h> -#include <SkImagePriv.h> -#include <SkShader.h> - -namespace android { -namespace uirenderer { - -static void playbackOps(const DisplayList& displayList, - std::function<void(const RecordedOp&)> opReceiver) { - for (auto& chunk : displayList.getChunks()) { - for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) { - RecordedOp* op = displayList.getOps()[opIndex]; - opReceiver(*op); - } - } -} - -static void validateSingleOp(std::unique_ptr<DisplayList>& dl, - std::function<void(const RecordedOp& op)> opValidator) { - ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op"; - opValidator(*(dl->getOps()[0])); -} - -// The RecordingCanvas is only ever used by the OpenGL RenderPipeline and never when Skia is in use. -// Thus, even though many of these test are not directly dependent on the current RenderPipeline, we -// set them all to be OPENGL_PIPELINE_TESTs in case the underlying code in RecordingCanvas ever -// changes to require the use of the OPENGL_PIPELINE. Currently the textureLayer test is the only -// test that requires being an OPENGL_PIPELINE_TEST. - -OPENGL_PIPELINE_TEST(RecordingCanvas, emptyPlayback) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) { - canvas.save(SaveFlags::MatrixClip); - canvas.restore(); - }); - playbackOps(*dl, [](const RecordedOp& op) { ADD_FAILURE(); }); -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, clipRect) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [](RecordingCanvas& canvas) { - canvas.save(SaveFlags::MatrixClip); - canvas.clipRect(0, 0, 100, 100, SkClipOp::kIntersect); - canvas.drawRect(0, 0, 50, 50, SkPaint()); - canvas.drawRect(50, 50, 100, 100, SkPaint()); - canvas.restore(); - }); - - ASSERT_EQ(2u, dl->getOps().size()) << "Must be exactly two ops"; - EXPECT_CLIP_RECT(Rect(100, 100), dl->getOps()[0]->localClip); - EXPECT_CLIP_RECT(Rect(100, 100), dl->getOps()[1]->localClip); - EXPECT_EQ(dl->getOps()[0]->localClip, dl->getOps()[1]->localClip) - << "Clip should be serialized once"; -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, emptyClipRect) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { - canvas.save(SaveFlags::MatrixClip); - canvas.clipRect(0, 0, 100, 100, SkClipOp::kIntersect); - canvas.clipRect(100, 100, 200, 200, SkClipOp::kIntersect); - canvas.drawRect(0, 0, 50, 50, SkPaint()); // rejected at record time - canvas.restore(); - }); - ASSERT_EQ(0u, dl->getOps().size()) << "Must be zero ops. Rect should be rejected."; -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, emptyPaintRejection) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { - SkPaint emptyPaint; - emptyPaint.setColor(Color::Transparent); - - float points[] = {0, 0, 200, 200}; - canvas.drawPoints(points, 4, emptyPaint); - canvas.drawLines(points, 4, emptyPaint); - canvas.drawRect(0, 0, 200, 200, emptyPaint); - canvas.drawRegion(SkRegion(SkIRect::MakeWH(200, 200)), emptyPaint); - canvas.drawRoundRect(0, 0, 200, 200, 10, 10, emptyPaint); - canvas.drawCircle(100, 100, 100, emptyPaint); - canvas.drawOval(0, 0, 200, 200, emptyPaint); - canvas.drawArc(0, 0, 200, 200, 0, 360, true, emptyPaint); - SkPath path; - path.addRect(0, 0, 200, 200); - canvas.drawPath(path, emptyPaint); - }); - EXPECT_EQ(0u, dl->getOps().size()) << "Op should be rejected"; -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, drawArc) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { - canvas.drawArc(0, 0, 200, 200, 0, 180, true, SkPaint()); - canvas.drawArc(0, 0, 100, 100, 0, 360, true, SkPaint()); - }); - - auto&& ops = dl->getOps(); - ASSERT_EQ(2u, ops.size()) << "Must be exactly two ops"; - EXPECT_EQ(RecordedOpId::ArcOp, ops[0]->opId); - EXPECT_EQ(Rect(200, 200), ops[0]->unmappedBounds); - - EXPECT_EQ(RecordedOpId::OvalOp, ops[1]->opId) << "Circular arcs should be converted to ovals"; - EXPECT_EQ(Rect(100, 100), ops[1]->unmappedBounds); -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, drawLines) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) { - SkPaint paint; - paint.setStrokeWidth( - 20); // doesn't affect recorded bounds - would be resolved at bake time - float points[] = {0, 0, 20, 10, 30, 40, 90}; // NB: only 1 valid line - canvas.drawLines(&points[0], 7, paint); - }); - - ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op"; - auto op = dl->getOps()[0]; - ASSERT_EQ(RecordedOpId::LinesOp, op->opId); - EXPECT_EQ(4, ((LinesOp*)op)->floatCount) - << "float count must be rounded down to closest multiple of 4"; - EXPECT_EQ(Rect(20, 10), op->unmappedBounds) - << "unmapped bounds must be size of line, and not outset for stroke width"; -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, drawRect) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>( - 100, 200, [](RecordingCanvas& canvas) { canvas.drawRect(10, 20, 90, 180, SkPaint()); }); - - ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op"; - auto op = *(dl->getOps()[0]); - ASSERT_EQ(RecordedOpId::RectOp, op.opId); - EXPECT_EQ(nullptr, op.localClip); - EXPECT_EQ(Rect(10, 20, 90, 180), op.unmappedBounds); -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, drawRoundRect) { - // Round case - stays rounded - auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) { - canvas.drawRoundRect(0, 0, 100, 100, 10, 10, SkPaint()); - }); - ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op"; - ASSERT_EQ(RecordedOpId::RoundRectOp, dl->getOps()[0]->opId); - - // Non-rounded case - turned into drawRect - dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) { - canvas.drawRoundRect(0, 0, 100, 100, 0, -1, SkPaint()); - }); - ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op"; - ASSERT_EQ(RecordedOpId::RectOp, dl->getOps()[0]->opId) - << "Non-rounded rects should be converted"; -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, drawGlyphs) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { - SkPaint paint; - paint.setAntiAlias(true); - paint.setTextSize(20); - TestUtils::drawUtf8ToCanvas(&canvas, "test text", paint, 25, 25); - }); - - int count = 0; - playbackOps(*dl, [&count](const RecordedOp& op) { - count++; - ASSERT_EQ(RecordedOpId::TextOp, op.opId); - EXPECT_EQ(nullptr, op.localClip); - EXPECT_TRUE(op.localMatrix.isIdentity()); - EXPECT_TRUE(op.unmappedBounds.contains(25, 15, 50, 25)) - << "Op expected to be 25+ pixels wide, 10+ pixels tall"; - }); - ASSERT_EQ(1, count); -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, drawGlyphs_strikeThruAndUnderline) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { - SkPaint paint; - paint.setAntiAlias(true); - paint.setTextSize(20); - for (int i = 0; i < 2; i++) { - for (int j = 0; j < 2; j++) { - uint32_t flags = paint.getFlags(); - if (i != 0) { - flags |= SkPaint::kUnderlineText_ReserveFlag; - } else { - flags &= ~SkPaint::kUnderlineText_ReserveFlag; - } - if (j != 0) { - flags |= SkPaint::kStrikeThruText_ReserveFlag; - } else { - flags &= ~SkPaint::kStrikeThruText_ReserveFlag; - } - paint.setFlags(flags); - TestUtils::drawUtf8ToCanvas(&canvas, "test text", paint, 25, 25); - } - } - }); - - auto ops = dl->getOps(); - ASSERT_EQ(8u, ops.size()); - - int index = 0; - EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId); // no underline or strikethrough - - EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId); - EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // strikethrough only - - EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId); - EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // underline only - - EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId); - EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // underline - EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // strikethrough -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, drawGlyphs_forceAlignLeft) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { - SkPaint paint; - paint.setAntiAlias(true); - paint.setTextSize(20); - paint.setTextAlign(SkPaint::kLeft_Align); - TestUtils::drawUtf8ToCanvas(&canvas, "test text", paint, 25, 25); - paint.setTextAlign(SkPaint::kCenter_Align); - TestUtils::drawUtf8ToCanvas(&canvas, "test text", paint, 25, 25); - paint.setTextAlign(SkPaint::kRight_Align); - TestUtils::drawUtf8ToCanvas(&canvas, "test text", paint, 25, 25); - }); - - int count = 0; - float lastX = FLT_MAX; - playbackOps(*dl, [&count, &lastX](const RecordedOp& op) { - count++; - ASSERT_EQ(RecordedOpId::TextOp, op.opId); - EXPECT_EQ(SkPaint::kLeft_Align, op.paint->getTextAlign()) - << "recorded drawText commands must force kLeft_Align on their paint"; - - // verify TestUtils alignment offsetting (TODO: move asserts to Canvas base class) - EXPECT_GT(lastX, ((const TextOp&)op).x) - << "x coordinate should reduce across each of the draw commands, from alignment"; - lastX = ((const TextOp&)op).x; - }); - ASSERT_EQ(3, count); -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, drawColor) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { - canvas.drawColor(Color::Black, SkBlendMode::kSrcOver); - }); - - ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op"; - auto op = *(dl->getOps()[0]); - EXPECT_EQ(RecordedOpId::ColorOp, op.opId); - EXPECT_EQ(nullptr, op.localClip); - EXPECT_TRUE(op.unmappedBounds.isEmpty()) << "Expect undefined recorded bounds"; -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, backgroundAndImage) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) { - sk_sp<Bitmap> bitmap(TestUtils::createBitmap(25, 25)); - SkPaint paint; - paint.setColor(SK_ColorBLUE); - - canvas.save(SaveFlags::MatrixClip); - { - // a background! - canvas.save(SaveFlags::MatrixClip); - canvas.drawRect(0, 0, 100, 200, paint); - canvas.restore(); - } - { - // an image! - canvas.save(SaveFlags::MatrixClip); - canvas.translate(25, 25); - canvas.scale(2, 2); - canvas.drawBitmap(*bitmap, 0, 0, nullptr); - canvas.restore(); - } - canvas.restore(); - }); - - int count = 0; - playbackOps(*dl, [&count](const RecordedOp& op) { - if (count == 0) { - ASSERT_EQ(RecordedOpId::RectOp, op.opId); - ASSERT_NE(nullptr, op.paint); - EXPECT_EQ(SK_ColorBLUE, op.paint->getColor()); - EXPECT_EQ(Rect(100, 200), op.unmappedBounds); - EXPECT_EQ(nullptr, op.localClip); - - Matrix4 expectedMatrix; - expectedMatrix.loadIdentity(); - EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix); - } else { - ASSERT_EQ(RecordedOpId::BitmapOp, op.opId); - EXPECT_EQ(nullptr, op.paint); - EXPECT_EQ(Rect(25, 25), op.unmappedBounds); - EXPECT_EQ(nullptr, op.localClip); - - Matrix4 expectedMatrix; - expectedMatrix.loadTranslate(25, 25, 0); - expectedMatrix.scale(2, 2, 1); - EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix); - } - count++; - }); - ASSERT_EQ(2, count); -} - -RENDERTHREAD_OPENGL_PIPELINE_TEST(RecordingCanvas, textureLayer) { - auto layerUpdater = - TestUtils::createTextureLayerUpdater(renderThread, 100, 100, SkMatrix::MakeTrans(5, 5)); - - auto dl = TestUtils::createDisplayList<RecordingCanvas>( - 200, 200, - [&layerUpdater](RecordingCanvas& canvas) { canvas.drawLayer(layerUpdater.get()); }); - - validateSingleOp(dl, [](const RecordedOp& op) { - ASSERT_EQ(RecordedOpId::TextureLayerOp, op.opId); - ASSERT_TRUE(op.localMatrix.isIdentity()) << "Op must not apply matrix at record time."; - }); -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_simple) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { - canvas.saveLayerAlpha(10, 20, 190, 180, 128, SaveFlags::ClipToLayer); - canvas.drawRect(10, 20, 190, 180, SkPaint()); - canvas.restore(); - }); - int count = 0; - playbackOps(*dl, [&count](const RecordedOp& op) { - Matrix4 expectedMatrix; - switch (count++) { - case 0: - EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId); - EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds); - EXPECT_EQ(nullptr, op.localClip); - EXPECT_TRUE(op.localMatrix.isIdentity()); - break; - case 1: - EXPECT_EQ(RecordedOpId::RectOp, op.opId); - EXPECT_CLIP_RECT(Rect(180, 160), op.localClip); - EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds); - expectedMatrix.loadTranslate(-10, -20, 0); - EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix); - break; - case 2: - EXPECT_EQ(RecordedOpId::EndLayerOp, op.opId); - // Don't bother asserting recording state data - it's not used - break; - default: - ADD_FAILURE(); - } - }); - EXPECT_EQ(3, count); -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_rounding) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [](RecordingCanvas& canvas) { - canvas.saveLayerAlpha(10.25f, 10.75f, 89.25f, 89.75f, 128, SaveFlags::ClipToLayer); - canvas.drawRect(20, 20, 80, 80, SkPaint()); - canvas.restore(); - }); - int count = 0; - playbackOps(*dl, [&count](const RecordedOp& op) { - Matrix4 expectedMatrix; - switch (count++) { - case 0: - EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId); - EXPECT_EQ(Rect(10, 10, 90, 90), op.unmappedBounds) << "Expect bounds rounded out"; - break; - case 1: - EXPECT_EQ(RecordedOpId::RectOp, op.opId); - expectedMatrix.loadTranslate(-10, -10, 0); - EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix) << "Expect rounded offset"; - break; - case 2: - EXPECT_EQ(RecordedOpId::EndLayerOp, op.opId); - // Don't bother asserting recording state data - it's not used - break; - default: - ADD_FAILURE(); - } - }); - EXPECT_EQ(3, count); -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_missingRestore) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { - canvas.saveLayerAlpha(0, 0, 200, 200, 128, SaveFlags::ClipToLayer); - canvas.drawRect(0, 0, 200, 200, SkPaint()); - // Note: restore omitted, shouldn't result in unmatched save - }); - int count = 0; - playbackOps(*dl, [&count](const RecordedOp& op) { - if (count++ == 2) { - EXPECT_EQ(RecordedOpId::EndLayerOp, op.opId); - } - }); - EXPECT_EQ(3, count) << "Missing a restore shouldn't result in an unmatched saveLayer"; -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_simpleUnclipped) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { - canvas.saveLayerAlpha(10, 20, 190, 180, 128, (SaveFlags::Flags)0); // unclipped - canvas.drawRect(10, 20, 190, 180, SkPaint()); - canvas.restore(); - }); - int count = 0; - playbackOps(*dl, [&count](const RecordedOp& op) { - switch (count++) { - case 0: - EXPECT_EQ(RecordedOpId::BeginUnclippedLayerOp, op.opId); - EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds); - EXPECT_EQ(nullptr, op.localClip); - EXPECT_TRUE(op.localMatrix.isIdentity()); - break; - case 1: - EXPECT_EQ(RecordedOpId::RectOp, op.opId); - EXPECT_EQ(nullptr, op.localClip); - EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds); - EXPECT_TRUE(op.localMatrix.isIdentity()); - break; - case 2: - EXPECT_EQ(RecordedOpId::EndUnclippedLayerOp, op.opId); - // Don't bother asserting recording state data - it's not used - break; - default: - ADD_FAILURE(); - } - }); - EXPECT_EQ(3, count); -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_addClipFlag) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { - canvas.save(SaveFlags::MatrixClip); - canvas.clipRect(10, 20, 190, 180, SkClipOp::kIntersect); - canvas.saveLayerAlpha(10, 20, 190, 180, 128, (SaveFlags::Flags)0); // unclipped - canvas.drawRect(10, 20, 190, 180, SkPaint()); - canvas.restore(); - canvas.restore(); - }); - int count = 0; - playbackOps(*dl, [&count](const RecordedOp& op) { - if (count++ == 0) { - EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId) - << "Clip + unclipped saveLayer should result in a clipped layer"; - } - }); - EXPECT_EQ(3, count); -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_viewportCrop) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { - // shouldn't matter, since saveLayer will clip to its bounds - canvas.clipRect(-1000, -1000, 1000, 1000, SkClipOp::kReplace_deprecated); - - canvas.saveLayerAlpha(100, 100, 300, 300, 128, SaveFlags::ClipToLayer); - canvas.drawRect(0, 0, 400, 400, SkPaint()); - canvas.restore(); - }); - int count = 0; - playbackOps(*dl, [&count](const RecordedOp& op) { - if (count++ == 1) { - Matrix4 expectedMatrix; - EXPECT_EQ(RecordedOpId::RectOp, op.opId); - EXPECT_CLIP_RECT(Rect(100, 100), op.localClip) // Recorded clip rect should be - // intersection of viewport and saveLayer bounds, in layer space; - EXPECT_EQ(Rect(400, 400), op.unmappedBounds); - expectedMatrix.loadTranslate(-100, -100, 0); - EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix); - } - }); - EXPECT_EQ(3, count); -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_rotateUnclipped) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { - canvas.save(SaveFlags::MatrixClip); - canvas.translate(100, 100); - canvas.rotate(45); - canvas.translate(-50, -50); - - canvas.saveLayerAlpha(0, 0, 100, 100, 128, SaveFlags::ClipToLayer); - canvas.drawRect(0, 0, 100, 100, SkPaint()); - canvas.restore(); - - canvas.restore(); - }); - int count = 0; - playbackOps(*dl, [&count](const RecordedOp& op) { - if (count++ == 1) { - EXPECT_EQ(RecordedOpId::RectOp, op.opId); - EXPECT_CLIP_RECT(Rect(100, 100), op.localClip); - EXPECT_EQ(Rect(100, 100), op.unmappedBounds); - EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.localMatrix) - << "Recorded op shouldn't see any canvas transform before the saveLayer"; - } - }); - EXPECT_EQ(3, count); -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_rotateClipped) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { - canvas.save(SaveFlags::MatrixClip); - canvas.translate(100, 100); - canvas.rotate(45); - canvas.translate(-200, -200); - - // area of saveLayer will be clipped to parent viewport, so we ask for 400x400... - canvas.saveLayerAlpha(0, 0, 400, 400, 128, SaveFlags::ClipToLayer); - canvas.drawRect(0, 0, 400, 400, SkPaint()); - canvas.restore(); - - canvas.restore(); - }); - int count = 0; - playbackOps(*dl, [&count](const RecordedOp& op) { - if (count++ == 1) { - Matrix4 expectedMatrix; - EXPECT_EQ(RecordedOpId::RectOp, op.opId); - - // ...and get about 58.6, 58.6, 341.4 341.4, because the bounds are clipped by - // the parent 200x200 viewport, but prior to rotation - ASSERT_NE(nullptr, op.localClip); - ASSERT_EQ(ClipMode::Rectangle, op.localClip->mode); - // NOTE: this check relies on saveLayer altering the clip post-viewport init. This - // causes the clip to be recorded by contained draw commands, though it's not necessary - // since the same clip will be computed at draw time. If such a change is made, this - // check could be done at record time by querying the clip, or the clip could be altered - // slightly so that it is serialized. - EXPECT_EQ(Rect(59, 59, 341, 341), op.localClip->rect); - EXPECT_EQ(Rect(400, 400), op.unmappedBounds); - expectedMatrix.loadIdentity(); - EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix); - } - }); - EXPECT_EQ(3, count); -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_rejectBegin) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { - canvas.save(SaveFlags::MatrixClip); - canvas.translate(0, -20); // avoid identity case - // empty clip rect should force layer + contents to be rejected - canvas.clipRect(0, -20, 200, -20, SkClipOp::kIntersect); - canvas.saveLayerAlpha(0, 0, 200, 200, 128, SaveFlags::ClipToLayer); - canvas.drawRect(0, 0, 200, 200, SkPaint()); - canvas.restore(); - canvas.restore(); - }); - - ASSERT_EQ(0u, dl->getOps().size()) << "Begin/Rect/End should all be rejected."; -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, drawRenderNode_rejection) { - auto child = - TestUtils::createNode(50, 50, 150, 150, [](RenderProperties& props, Canvas& canvas) { - SkPaint paint; - paint.setColor(SK_ColorWHITE); - canvas.drawRect(0, 0, 100, 100, paint); - }); - - auto dl = TestUtils::createDisplayList<RecordingCanvas>( - 200, 200, [&child](RecordingCanvas& canvas) { - canvas.clipRect(0, 0, 0, 0, SkClipOp::kIntersect); // empty clip, reject node - canvas.drawRenderNode(child.get()); // shouldn't crash when rejecting node... - }); - ASSERT_TRUE(dl->isEmpty()); -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, drawRenderNode_projection) { - sp<RenderNode> background = - TestUtils::createNode(50, 50, 150, 150, [](RenderProperties& props, Canvas& canvas) { - SkPaint paint; - paint.setColor(SK_ColorWHITE); - canvas.drawRect(0, 0, 100, 100, paint); - }); - { - background->mutateStagingProperties().setProjectionReceiver(false); - - // NO RECEIVER PRESENT - auto dl = TestUtils::createDisplayList<RecordingCanvas>( - 200, 200, [&background](RecordingCanvas& canvas) { - canvas.drawRect(0, 0, 100, 100, SkPaint()); - canvas.drawRenderNode(background.get()); - canvas.drawRect(0, 0, 100, 100, SkPaint()); - }); - EXPECT_EQ(-1, dl->projectionReceiveIndex) - << "no projection receiver should have been observed"; - } - { - background->mutateStagingProperties().setProjectionReceiver(true); - - // RECEIVER PRESENT - auto dl = TestUtils::createDisplayList<RecordingCanvas>( - 200, 200, [&background](RecordingCanvas& canvas) { - canvas.drawRect(0, 0, 100, 100, SkPaint()); - canvas.drawRenderNode(background.get()); - canvas.drawRect(0, 0, 100, 100, SkPaint()); - }); - - ASSERT_EQ(3u, dl->getOps().size()) << "Must be three ops"; - auto op = dl->getOps()[1]; - EXPECT_EQ(RecordedOpId::RenderNodeOp, op->opId); - EXPECT_EQ(1, dl->projectionReceiveIndex) << "correct projection receiver not identified"; - - // verify the behavior works even though projection receiver hasn't been sync'd yet - EXPECT_TRUE(background->stagingProperties().isProjectionReceiver()); - EXPECT_FALSE(background->properties().isProjectionReceiver()); - } -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, firstClipWillReplace) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { - canvas.save(SaveFlags::MatrixClip); - // since no explicit clip set on canvas, this should be the one observed on op: - canvas.clipRect(-100, -100, 300, 300, SkClipOp::kIntersect); - - SkPaint paint; - paint.setColor(SK_ColorWHITE); - canvas.drawRect(0, 0, 100, 100, paint); - - canvas.restore(); - }); - ASSERT_EQ(1u, dl->getOps().size()) << "Must have one op"; - // first clip must be preserved, even if it extends beyond canvas bounds - EXPECT_CLIP_RECT(Rect(-100, -100, 300, 300), dl->getOps()[0]->localClip); -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, replaceClipIntersectWithRoot) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [](RecordingCanvas& canvas) { - canvas.save(SaveFlags::MatrixClip); - canvas.clipRect(-10, -10, 110, 110, SkClipOp::kReplace_deprecated); - canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver); - canvas.restore(); - }); - ASSERT_EQ(1u, dl->getOps().size()) << "Must have one op"; - // first clip must be preserved, even if it extends beyond canvas bounds - EXPECT_CLIP_RECT(Rect(-10, -10, 110, 110), dl->getOps()[0]->localClip); - EXPECT_TRUE(dl->getOps()[0]->localClip->intersectWithRoot); -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, insertReorderBarrier) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { - canvas.drawRect(0, 0, 400, 400, SkPaint()); - canvas.insertReorderBarrier(true); - canvas.insertReorderBarrier(false); - canvas.insertReorderBarrier(false); - canvas.insertReorderBarrier(true); - canvas.drawRect(0, 0, 400, 400, SkPaint()); - canvas.insertReorderBarrier(false); - }); - - auto chunks = dl->getChunks(); - EXPECT_EQ(0u, chunks[0].beginOpIndex); - EXPECT_EQ(1u, chunks[0].endOpIndex); - EXPECT_FALSE(chunks[0].reorderChildren); - - EXPECT_EQ(1u, chunks[1].beginOpIndex); - EXPECT_EQ(2u, chunks[1].endOpIndex); - EXPECT_TRUE(chunks[1].reorderChildren); -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, insertReorderBarrier_clip) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { - // first chunk: no recorded clip - canvas.insertReorderBarrier(true); - canvas.drawRect(0, 0, 400, 400, SkPaint()); - - // second chunk: no recorded clip, since inorder region - canvas.clipRect(0, 0, 200, 200, SkClipOp::kIntersect); - canvas.insertReorderBarrier(false); - canvas.drawRect(0, 0, 400, 400, SkPaint()); - - // third chunk: recorded clip - canvas.insertReorderBarrier(true); - canvas.drawRect(0, 0, 400, 400, SkPaint()); - }); - - auto chunks = dl->getChunks(); - ASSERT_EQ(3u, chunks.size()); - - EXPECT_TRUE(chunks[0].reorderChildren); - EXPECT_EQ(nullptr, chunks[0].reorderClip); - - EXPECT_FALSE(chunks[1].reorderChildren); - EXPECT_EQ(nullptr, chunks[1].reorderClip); - - EXPECT_TRUE(chunks[2].reorderChildren); - ASSERT_NE(nullptr, chunks[2].reorderClip); - EXPECT_EQ(Rect(200, 200), chunks[2].reorderClip->rect); -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, refPaint) { - SkPaint paint; - - auto dl = TestUtils::createDisplayList<RecordingCanvas>( - 200, 200, [&paint](RecordingCanvas& canvas) { - paint.setColor(SK_ColorBLUE); - // first two should use same paint - canvas.drawRect(0, 0, 200, 10, paint); - SkPaint paintCopy(paint); - canvas.drawRect(0, 10, 200, 20, paintCopy); - - // only here do we use different paint ptr - paint.setColor(SK_ColorRED); - canvas.drawRect(0, 20, 200, 30, paint); - }); - auto ops = dl->getOps(); - ASSERT_EQ(3u, ops.size()); - - // first two are the same - EXPECT_NE(nullptr, ops[0]->paint); - EXPECT_NE(&paint, ops[0]->paint); - EXPECT_EQ(ops[0]->paint, ops[1]->paint); - - // last is different, but still copied / non-null - EXPECT_NE(nullptr, ops[2]->paint); - EXPECT_NE(ops[0]->paint, ops[2]->paint); - EXPECT_NE(&paint, ops[2]->paint); -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, refBitmap) { - sk_sp<Bitmap> bitmap(TestUtils::createBitmap(100, 100)); - auto dl = TestUtils::createDisplayList<RecordingCanvas>( - 100, 100, - [&bitmap](RecordingCanvas& canvas) { canvas.drawBitmap(*bitmap, 0, 0, nullptr); }); - auto& bitmaps = dl->getBitmapResources(); - EXPECT_EQ(1u, bitmaps.size()); -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, refBitmapInShader_bitmapShader) { - sk_sp<Bitmap> bitmap = TestUtils::createBitmap(100, 100); - auto dl = TestUtils::createDisplayList<RecordingCanvas>( - 100, 100, [&bitmap](RecordingCanvas& canvas) { - SkPaint paint; - SkBitmap skBitmap; - bitmap->getSkBitmap(&skBitmap); - sk_sp<SkImage> image = - SkMakeImageFromRasterBitmap(skBitmap, kNever_SkCopyPixelsMode); - sk_sp<SkShader> shader = - image->makeShader(SkShader::TileMode::kClamp_TileMode, - SkShader::TileMode::kClamp_TileMode, nullptr); - paint.setShader(std::move(shader)); - canvas.drawRoundRect(0, 0, 100, 100, 20.0f, 20.0f, paint); - }); - auto& bitmaps = dl->getBitmapResources(); - EXPECT_EQ(1u, bitmaps.size()); -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, refBitmapInShader_composeShader) { - sk_sp<Bitmap> bitmap = TestUtils::createBitmap(100, 100); - auto dl = TestUtils::createDisplayList<RecordingCanvas>( - 100, 100, [&bitmap](RecordingCanvas& canvas) { - SkPaint paint; - SkBitmap skBitmap; - bitmap->getSkBitmap(&skBitmap); - sk_sp<SkImage> image = - SkMakeImageFromRasterBitmap(skBitmap, kNever_SkCopyPixelsMode); - sk_sp<SkShader> shader1 = - image->makeShader(SkShader::TileMode::kClamp_TileMode, - SkShader::TileMode::kClamp_TileMode, nullptr); - - SkPoint center; - center.set(50, 50); - SkColor colors[2]; - colors[0] = Color::Black; - colors[1] = Color::White; - sk_sp<SkShader> shader2 = SkGradientShader::MakeRadial( - center, 50, colors, nullptr, 2, SkShader::TileMode::kRepeat_TileMode); - - sk_sp<SkShader> composeShader = SkShader::MakeComposeShader( - std::move(shader1), std::move(shader2), SkBlendMode::kMultiply); - paint.setShader(std::move(composeShader)); - canvas.drawRoundRect(0, 0, 100, 100, 20.0f, 20.0f, paint); - }); - auto& bitmaps = dl->getBitmapResources(); - EXPECT_EQ(1u, bitmaps.size()); -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, drawText) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { - Paint paint; - paint.setAntiAlias(true); - paint.setTextSize(20); - TestUtils::drawUtf8ToCanvas(&canvas, "HELLO", paint, 25, 25); - }); - - int count = 0; - playbackOps(*dl, [&count](const RecordedOp& op) { - count++; - ASSERT_EQ(RecordedOpId::TextOp, op.opId); - EXPECT_EQ(nullptr, op.localClip); - EXPECT_TRUE(op.localMatrix.isIdentity()); - EXPECT_TRUE(op.unmappedBounds.getHeight() >= 10); - EXPECT_TRUE(op.unmappedBounds.getWidth() >= 25); - }); - ASSERT_EQ(1, count); -} - -OPENGL_PIPELINE_TEST(RecordingCanvas, drawTextInHighContrast) { - Properties::enableHighContrastText = true; - auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { - Paint paint; - paint.setColor(SK_ColorWHITE); - paint.setAntiAlias(true); - paint.setTextSize(20); - TestUtils::drawUtf8ToCanvas(&canvas, "HELLO", paint, 25, 25); - }); - Properties::enableHighContrastText = false; - - int count = 0; - playbackOps(*dl, [&count](const RecordedOp& op) { - ASSERT_EQ(RecordedOpId::TextOp, op.opId); - if (count++ == 0) { - EXPECT_EQ(SK_ColorBLACK, op.paint->getColor()); - EXPECT_EQ(SkPaint::kStrokeAndFill_Style, op.paint->getStyle()); - } else { - EXPECT_EQ(SK_ColorWHITE, op.paint->getColor()); - EXPECT_EQ(SkPaint::kFill_Style, op.paint->getStyle()); - } - - }); - ASSERT_EQ(2, count); -} - -} // namespace uirenderer -} // namespace android diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp index 1d7dc3d06ee4..2e4de0bac755 100644 --- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp +++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp @@ -26,41 +26,6 @@ using namespace android; using namespace android::uirenderer; -/** - * Verify that we get the same culling bounds for text for (1) drawing glyphs - * directly to a Canvas or (2) going through a SkPicture as an intermediate step. - */ -OPENGL_PIPELINE_TEST(SkiaCanvasProxy, drawGlyphsViaPicture) { - auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { - // setup test variables - SkPaint paint; - paint.setAntiAlias(true); - paint.setTextSize(20); - static const char* text = "testing text bounds"; - - // draw text directly into Recording canvas - TestUtils::drawUtf8ToCanvas(&canvas, text, paint, 25, 25); - - // record the same text draw into a SkPicture and replay it into a Recording canvas - SkPictureRecorder recorder; - SkCanvas* skCanvas = recorder.beginRecording(200, 200, NULL, 0); - std::unique_ptr<Canvas> pictCanvas(Canvas::create_canvas(skCanvas)); - TestUtils::drawUtf8ToCanvas(pictCanvas.get(), text, paint, 25, 25); - sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture(); - - canvas.asSkCanvas()->drawPicture(picture); - }); - - // verify that the text bounds and matrices match - ASSERT_EQ(2U, dl->getOps().size()); - auto directOp = dl->getOps()[0]; - auto pictureOp = dl->getOps()[1]; - ASSERT_EQ(RecordedOpId::TextOp, directOp->opId); - EXPECT_EQ(directOp->opId, pictureOp->opId); - EXPECT_EQ(directOp->unmappedBounds, pictureOp->unmappedBounds); - EXPECT_EQ(directOp->localMatrix, pictureOp->localMatrix); -} - TEST(SkiaCanvas, drawShadowLayer) { auto surface = SkSurface::MakeRasterN32Premul(10, 10); SkiaCanvas canvas(surface->getCanvas()); diff --git a/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp b/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp deleted file mode 100644 index 92d05e44c6ca..000000000000 --- a/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2016 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 "GammaFontRenderer.h" -#include "TextDropShadowCache.h" -#include "tests/common/TestUtils.h" -#include "utils/Blur.h" - -#include <SkPaint.h> - -using namespace android; -using namespace android::uirenderer; - -RENDERTHREAD_OPENGL_PIPELINE_TEST(TextDropShadowCache, addRemove) { - SkPaint paint; - paint.setTextSize(20); - paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - - GammaFontRenderer gammaFontRenderer; - FontRenderer& fontRenderer = gammaFontRenderer.getFontRenderer(); - fontRenderer.setFont(&paint, SkMatrix::I()); - TextDropShadowCache cache(MB(5)); - cache.setFontRenderer(fontRenderer); - - std::vector<glyph_t> glyphs; - std::vector<float> positions; - float totalAdvance; - uirenderer::Rect bounds; - TestUtils::layoutTextUnscaled(paint, "This is a test", &glyphs, &positions, &totalAdvance, - &bounds); - EXPECT_TRUE(bounds.contains(5, -10, 100, 0)) << "Expect input to be nontrivially sized"; - - ShadowTexture* texture = cache.get(&paint, glyphs.data(), glyphs.size(), 10, positions.data()); - - ASSERT_TRUE(texture); - ASSERT_FALSE(texture->cleanup); - ASSERT_EQ((uint32_t)texture->objectSize(), cache.getSize()); - ASSERT_TRUE(cache.getSize()); - cache.clear(); - ASSERT_EQ(cache.getSize(), 0u); -} diff --git a/libs/hwui/tests/unit/TextureCacheTests.cpp b/libs/hwui/tests/unit/TextureCacheTests.cpp deleted file mode 100644 index ab740dd8330e..000000000000 --- a/libs/hwui/tests/unit/TextureCacheTests.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2017 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 "Extensions.h" -#include "TextureCache.h" -#include "tests/common/TestUtils.h" - -using namespace android; -using namespace android::uirenderer; - -RENDERTHREAD_OPENGL_PIPELINE_TEST(TextureCache, clear) { - TextureCache cache; - ASSERT_EQ(cache.getSize(), 0u); - // it is not 0, because FontRenderer allocates one texture - int initialCount = GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture); - SkBitmap skBitmap; - SkImageInfo info = SkImageInfo::Make(100, 100, kN32_SkColorType, kPremul_SkAlphaType); - skBitmap.setInfo(info); - sk_sp<Bitmap> hwBitmap(renderThread.allocateHardwareBitmap(skBitmap)); - cache.get(hwBitmap.get()); - ASSERT_EQ(GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture), initialCount + 1); - cache.clear(); - ASSERT_EQ(GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture), initialCount); -} diff --git a/native/webview/plat_support/draw_gl_functor.cpp b/native/webview/plat_support/draw_gl_functor.cpp index d54f558b9866..7cb49da483de 100644 --- a/native/webview/plat_support/draw_gl_functor.cpp +++ b/native/webview/plat_support/draw_gl_functor.cpp @@ -21,7 +21,6 @@ #include "draw_gl.h" -#include <Properties.h> #include <errno.h> #include <jni.h> #include <private/hwui/DrawGlInfo.h> @@ -54,13 +53,7 @@ class DrawGLFunctor : public Functor { } AwDrawGLInfo aw_info; - // TODO(boliu): Remove property check once OpenGL fallback is removed. - auto render_pipeline_type = - android::uirenderer::Properties::getRenderPipelineType(); - aw_info.version = (render_pipeline_type == - android::uirenderer::RenderPipelineType::OpenGL) - ? 2 - : kAwDrawGLInfoVersion; + aw_info.version = kAwDrawGLInfoVersion; switch (what) { case DrawGlInfo::kModeDraw: { aw_info.mode = AwDrawGLInfo::kModeDraw; |