From 5a240aaf0e3a1dd52be6a8d0811ec727369a210d Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Thu, 15 Dec 2016 12:34:06 -0800 Subject: [PATCH] test-hwc2: set layer buffer Test: Add "#define HAVE_NO_SURFACE_FLINGER" to frameworks/native/libs/gui/BufferQueueCore.cpp. Recompile and flash. Run "mm" in frameworks/native/services/surfaceflinger/tests/hwc2. Push test-hwc2 to device. Run "adb root && adb shell stop". Run test case. Ex: "./test-hwc2" Change-Id: Ie42d1fd4c2d0248c4a3ecf09a9b5871d501f6172 --- services/surfaceflinger/tests/hwc2/Android.mk | 22 +- services/surfaceflinger/tests/hwc2/Hwc2Test.cpp | 191 ++++++--- .../surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp | 452 +++++++++++++++++++++ .../surfaceflinger/tests/hwc2/Hwc2TestBuffer.h | 58 +++ .../surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp | 10 + services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h | 8 + .../tests/hwc2/Hwc2TestProperties.cpp | 17 + .../surfaceflinger/tests/hwc2/Hwc2TestProperties.h | 3 + 8 files changed, 711 insertions(+), 50 deletions(-) create mode 100644 services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp create mode 100644 services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h diff --git a/services/surfaceflinger/tests/hwc2/Android.mk b/services/surfaceflinger/tests/hwc2/Android.mk index 18437a9783..79c3e9271e 100644 --- a/services/surfaceflinger/tests/hwc2/Android.mk +++ b/services/surfaceflinger/tests/hwc2/Android.mk @@ -24,13 +24,27 @@ LOCAL_CFLAGS += \ -g \ -Wall -Wextra \ -Werror \ - -fno-builtin -LOCAL_SHARED_LIBRARIES := libcutils libutils libhardware liblog -LOCAL_STATIC_LIBRARIES := libbase libadf libadfhwc + -fno-builtin \ + -DEGL_EGLEXT_PROTOTYPES \ + -DGL_GLEXT_PROTOTYPES +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libutils \ + libhardware \ + libEGL \ + libGLESv2 \ + libui \ + libgui \ + liblog +LOCAL_STATIC_LIBRARIES := \ + libbase \ + libadf \ + libadfhwc LOCAL_SRC_FILES := \ Hwc2Test.cpp \ Hwc2TestProperties.cpp \ Hwc2TestLayer.cpp \ - Hwc2TestLayers.cpp + Hwc2TestLayers.cpp \ + Hwc2TestBuffer.cpp include $(BUILD_NATIVE_TEST) diff --git a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp index f441089f37..931cfc6c32 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp +++ b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #define HWC2_INCLUDE_STRINGIFICATION @@ -391,6 +392,23 @@ public: } } + void setLayerBuffer(hwc2_display_t display, hwc2_layer_t layer, + buffer_handle_t buffer, int32_t acquireFence, + hwc2_error_t* outErr = nullptr) + { + auto pfn = reinterpret_cast( + getFunction(HWC2_FUNCTION_SET_LAYER_BUFFER)); + ASSERT_TRUE(pfn) << "failed to get function"; + + auto err = static_cast(pfn(mHwc2Device, display, layer, + buffer, acquireFence)); + if (outErr) { + *outErr = err; + } else { + ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer buffer"; + } + } + void setLayerColor(hwc2_display_t display, hwc2_layer_t layer, hwc_color_t color, hwc2_error_t* outErr = nullptr) { @@ -665,19 +683,19 @@ protected: * Hwc2TestLayer to hwc2_layer_t on hwc2_display_t */ using TestLayerPropertyFunction = void (*)(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, - const Hwc2TestLayer& testLayer, hwc2_error_t* outErr); + Hwc2TestLayer* testLayer, hwc2_error_t* outErr); /* Calls a set property function from Hwc2Test to set property values from * Hwc2TestLayers to hwc2_layer_t on hwc2_display_t */ using TestLayerPropertiesFunction = void (*)(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, - const Hwc2TestLayers& testLayers); + Hwc2TestLayers* testLayers); /* Calls a set property function from Hwc2Test to set a bad property value * on hwc2_layer_t on hwc2_display_t */ using TestLayerPropertyBadLayerFunction = void (*)(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, - const Hwc2TestLayer& testLayer, hwc2_error_t* outErr); + Hwc2TestLayer* testLayer, hwc2_error_t* outErr); /* Calls a set property function from Hwc2Test to set a bad property value * on hwc2_layer_t on hwc2_display_t */ @@ -711,7 +729,7 @@ protected: ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer)); ASSERT_NO_FATAL_FAILURE(function(this, display, layer, - testLayer, nullptr)); + &testLayer, nullptr)); ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer)); } while (advance(&testLayer)); @@ -743,7 +761,7 @@ protected: do { ASSERT_NO_FATAL_FAILURE(function(this, display, layer, - testLayer, nullptr)); + &testLayer, nullptr)); } while (advance(&testLayer)); ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer)); @@ -776,7 +794,7 @@ protected: for (auto layer : layers) { EXPECT_NO_FATAL_FAILURE(function(this, display, layer, - testLayers)); + &testLayers)); } ASSERT_NO_FATAL_FAILURE(destroyLayers(display, std::move(layers))); @@ -810,19 +828,19 @@ protected: Hwc2TestLayer testLayer(coverage, displayArea); ASSERT_NO_FATAL_FAILURE(function(this, display, layer, - testLayer, &err)); + &testLayer, &err)); EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code"; ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer)); ASSERT_NO_FATAL_FAILURE(function(this, display, layer + 1, - testLayer, &err)); + &testLayer, &err)); EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code"; ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer)); ASSERT_NO_FATAL_FAILURE(function(this, display, layer, - testLayer, &err)); + &testLayer, &err)); EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code"; } } @@ -918,29 +936,50 @@ void hwc2TestVsyncCallback(hwc2_callback_data_t callbackData, } void setBlendMode(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, - const Hwc2TestLayer& testLayer, hwc2_error_t* outErr) + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) { EXPECT_NO_FATAL_FAILURE(test->setLayerBlendMode(display, layer, - testLayer.getBlendMode(), outErr)); + testLayer->getBlendMode(), outErr)); +} + +void setBuffer(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) +{ + buffer_handle_t handle; + android::base::unique_fd acquireFence; + hwc2_composition_t composition = testLayer->getComposition(); + + if (composition == HWC2_COMPOSITION_CLIENT + || composition == HWC2_COMPOSITION_SOLID_COLOR + || composition == HWC2_COMPOSITION_SIDEBAND) + return; + + if (testLayer->getBuffer(&handle, &acquireFence) < 0) + return; + + ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display, layer, + composition)); + EXPECT_NO_FATAL_FAILURE(test->setLayerBuffer(display, layer, + handle, acquireFence, outErr)); } void setColor(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, - const Hwc2TestLayer& testLayer, hwc2_error_t* outErr) + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) { ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display, layer, HWC2_COMPOSITION_SOLID_COLOR)); ASSERT_NO_FATAL_FAILURE(test->setLayerPlaneAlpha(display, - layer, testLayer.getPlaneAlpha())); + layer, testLayer->getPlaneAlpha())); ASSERT_NO_FATAL_FAILURE(test->setLayerBlendMode(display, - layer, testLayer.getBlendMode())); + layer, testLayer->getBlendMode())); EXPECT_NO_FATAL_FAILURE(test->setLayerColor(display, layer, - testLayer.getColor(), outErr)); + testLayer->getColor(), outErr)); } void setComposition(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, - const Hwc2TestLayer& testLayer, hwc2_error_t* outErr) + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) { - hwc2_composition_t composition = testLayer.getComposition(); + hwc2_composition_t composition = testLayer->getComposition(); hwc2_error_t err = HWC2_ERROR_NONE; ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display, layer, @@ -959,65 +998,65 @@ void setComposition(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, } void setCursorPosition(Hwc2Test* test, hwc2_display_t display, - hwc2_layer_t layer, const Hwc2TestLayer& testLayer, hwc2_error_t* outErr) + hwc2_layer_t layer, Hwc2TestLayer* testLayer, hwc2_error_t* outErr) { ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display, layer, HWC2_COMPOSITION_CURSOR)); - const hwc_rect_t cursorPosition = testLayer.getCursorPosition(); + const hwc_rect_t cursorPosition = testLayer->getCursorPosition(); EXPECT_NO_FATAL_FAILURE(test->setCursorPosition(display, layer, cursorPosition.left, cursorPosition.top, outErr)); } void setDataspace(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, - const Hwc2TestLayer& testLayer, hwc2_error_t* outErr) + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) { EXPECT_NO_FATAL_FAILURE(test->setLayerDataspace(display, layer, - testLayer.getDataspace(), outErr)); + testLayer->getDataspace(), outErr)); } void setDisplayFrame(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, - const Hwc2TestLayer& testLayer, hwc2_error_t* outErr) + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) { EXPECT_NO_FATAL_FAILURE(test->setLayerDisplayFrame(display, layer, - testLayer.getDisplayFrame(), outErr)); + testLayer->getDisplayFrame(), outErr)); } void setPlaneAlpha(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, - const Hwc2TestLayer& testLayer, hwc2_error_t *outErr) + Hwc2TestLayer* testLayer, hwc2_error_t *outErr) { ASSERT_NO_FATAL_FAILURE(test->setLayerBlendMode(display, layer, - testLayer.getBlendMode())); + testLayer->getBlendMode())); EXPECT_NO_FATAL_FAILURE(test->setLayerPlaneAlpha(display, layer, - testLayer.getPlaneAlpha(), outErr)); + testLayer->getPlaneAlpha(), outErr)); } void setSourceCrop(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, - const Hwc2TestLayer& testLayer, hwc2_error_t* outErr) + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) { EXPECT_NO_FATAL_FAILURE(test->setLayerSourceCrop(display, layer, - testLayer.getSourceCrop(), outErr)); + testLayer->getSourceCrop(), outErr)); } void setSurfaceDamage(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, - const Hwc2TestLayer& testLayer, hwc2_error_t* outErr) + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) { EXPECT_NO_FATAL_FAILURE(test->setLayerSurfaceDamage(display, layer, - testLayer.getSurfaceDamage(), outErr)); + testLayer->getSurfaceDamage(), outErr)); } void setTransform(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, - const Hwc2TestLayer& testLayer, hwc2_error_t* outErr) + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) { EXPECT_NO_FATAL_FAILURE(test->setLayerTransform(display, layer, - testLayer.getTransform(), outErr)); + testLayer->getTransform(), outErr)); } void setZOrder(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, - const Hwc2TestLayer& testLayer, hwc2_error_t* outErr) + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) { EXPECT_NO_FATAL_FAILURE(test->setLayerZOrder(display, layer, - testLayer.getZOrder(), outErr)); + testLayer->getZOrder(), outErr)); } bool advanceBlendMode(Hwc2TestLayer* testLayer) @@ -1025,6 +1064,13 @@ bool advanceBlendMode(Hwc2TestLayer* testLayer) return testLayer->advanceBlendMode(); } +bool advanceBuffer(Hwc2TestLayer* testLayer) +{ + if (testLayer->advanceComposition()) + return true; + return testLayer->advanceBufferArea(); +} + bool advanceColor(Hwc2TestLayer* testLayer) { /* Color depends on blend mode so advance blend mode last so color is not @@ -1948,9 +1994,9 @@ TEST_F(Hwc2Test, SET_CURSOR_POSITION_composition_type_unset) { ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete, [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, - const Hwc2TestLayer& testLayer, hwc2_error_t* outErr) { + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) { - const hwc_rect_t cursorPosition = testLayer.getCursorPosition(); + const hwc_rect_t cursorPosition = testLayer->getCursorPosition(); EXPECT_NO_FATAL_FAILURE(test->setCursorPosition(display, layer, cursorPosition.left, cursorPosition.top, outErr)); }, @@ -1978,9 +2024,9 @@ TEST_F(Hwc2Test, SET_CURSOR_POSITION_bad_layer) { ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default, [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t badLayer, - const Hwc2TestLayer& testLayer, hwc2_error_t* outErr) { + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) { - const hwc_rect_t cursorPosition = testLayer.getCursorPosition(); + const hwc_rect_t cursorPosition = testLayer->getCursorPosition(); EXPECT_NO_FATAL_FAILURE(test->setCursorPosition(display, badLayer, cursorPosition.left, cursorPosition.top, outErr)); @@ -2022,6 +2068,59 @@ TEST_F(Hwc2Test, SET_LAYER_BLEND_MODE_bad_parameter) )); } +/* TESTCASE: Tests that the HWC2 can set the buffer of a layer. */ +TEST_F(Hwc2Test, SET_LAYER_BUFFER) +{ + ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete, + setBuffer, advanceBuffer)); +} + +/* TESTCASE: Tests that the HWC2 can update the buffer of a layer. */ +TEST_F(Hwc2Test, SET_LAYER_BUFFER_update) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete, + setBuffer, advanceBuffer)); +} + +/* TESTCASE: Tests that the HWC2 cannot set the buffer of a bad layer. */ +TEST_F(Hwc2Test, SET_LAYER_BUFFER_bad_layer) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default, + [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t badLayer, + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) { + + buffer_handle_t handle = nullptr; + android::base::unique_fd acquireFence; + + /* If there is not available buffer for the given buffer + * properties, it should not fail this test case */ + if (testLayer->getBuffer(&handle, &acquireFence) == 0) { + *outErr = HWC2_ERROR_BAD_LAYER; + return; + } + + ASSERT_NO_FATAL_FAILURE(test->setLayerBuffer(display, badLayer, + handle, acquireFence, outErr)); + } + )); +} + +/* TESTCASE: Tests that the HWC2 can set an invalid buffer for a layer. */ +TEST_F(Hwc2Test, SET_LAYER_BUFFER_bad_parameter) +{ + ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadParameter( + [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, + hwc2_error_t* outErr) { + + buffer_handle_t handle = nullptr; + int32_t acquireFence = -1; + + ASSERT_NO_FATAL_FAILURE(test->setLayerBuffer(display, layer, + handle, acquireFence, outErr)); + } + )); +} + /* TESTCASE: Tests that the HWC2 can set the color of a layer. */ TEST_F(Hwc2Test, SET_LAYER_COLOR) { @@ -2042,10 +2141,10 @@ TEST_F(Hwc2Test, SET_LAYER_COLOR_composition_type_unset) { ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Basic, [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, - const Hwc2TestLayer& testLayer, hwc2_error_t* outErr) { + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) { EXPECT_NO_FATAL_FAILURE(test->setLayerColor(display, layer, - testLayer.getColor(), outErr)); + testLayer->getColor(), outErr)); }, advanceColor)); @@ -2056,10 +2155,10 @@ TEST_F(Hwc2Test, SET_LAYER_COLOR_bad_layer) { ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default, [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t badLayer, - const Hwc2TestLayer& testLayer, hwc2_error_t* outErr) { + Hwc2TestLayer* testLayer, hwc2_error_t* outErr) { EXPECT_NO_FATAL_FAILURE(test->setLayerColor(display, badLayer, - testLayer.getColor(), outErr)); + testLayer->getColor(), outErr)); } )); } @@ -2125,10 +2224,10 @@ TEST_F(Hwc2Test, SET_LAYER_PLANE_ALPHA_bad_layer) { ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default, [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t badLayer, - const Hwc2TestLayer& testLayer, hwc2_error_t *outErr) { + Hwc2TestLayer* testLayer, hwc2_error_t *outErr) { EXPECT_NO_FATAL_FAILURE(test->setLayerPlaneAlpha(display, - badLayer, testLayer.getPlaneAlpha(), outErr)); + badLayer, testLayer->getPlaneAlpha(), outErr)); } )); } @@ -2201,10 +2300,10 @@ TEST_F(Hwc2Test, SET_LAYER_Z_ORDER) { ASSERT_NO_FATAL_FAILURE(setLayerProperties(Hwc2TestCoverage::Complete, 10, [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer, - const Hwc2TestLayers& testLayers) { + Hwc2TestLayers* testLayers) { EXPECT_NO_FATAL_FAILURE(test->setLayerZOrder(display, layer, - testLayers.getZOrder(layer))); + testLayers->getZOrder(layer))); } )); } diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp new file mode 100644 index 0000000000..c9d8f4fdb7 --- /dev/null +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp @@ -0,0 +1,452 @@ +/* + * 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 +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include "Hwc2TestBuffer.h" +#include "Hwc2TestLayers.h" + +using namespace android; + +/* Returns a fence from egl */ +typedef void (*FenceCallback)(int32_t fence, void* callbackArgs); + +/* Returns fence to fence generator */ +static void setFence(int32_t fence, void* fenceGenerator); + + +/* Used to receive the surfaces and fences from egl. The egl buffers are thrown + * away. The fences are sent to the requester via a callback */ +class Hwc2TestSurfaceManager { +public: + /* Listens for a new frame, detaches the buffer and returns the fence + * through saved callback. */ + class BufferListener : public ConsumerBase::FrameAvailableListener { + public: + BufferListener(sp consumer, + FenceCallback callback, void* callbackArgs) + : mConsumer(consumer), + mCallback(callback), + mCallbackArgs(callbackArgs) { } + + void onFrameAvailable(const BufferItem& /*item*/) + { + BufferItem item; + + if (mConsumer->acquireBuffer(&item, 0)) + return; + if (mConsumer->detachBuffer(item.mSlot)) + return; + + mCallback(item.mFence->dup(), mCallbackArgs); + } + + private: + sp mConsumer; + FenceCallback mCallback; + void* mCallbackArgs; + }; + + /* Creates a buffer listener that waits on a new frame from the buffer + * queue. */ + void initialize(const Area& bufferArea, android_pixel_format_t format, + FenceCallback callback, void* callbackArgs) + { + sp producer; + sp consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + consumer->setDefaultBufferSize(bufferArea.width, bufferArea.height); + consumer->setDefaultBufferFormat(format); + + mBufferItemConsumer = new BufferItemConsumer(consumer, 0); + + mListener = new BufferListener(consumer, callback, callbackArgs); + mBufferItemConsumer->setFrameAvailableListener(mListener); + + mSurface = new Surface(producer, true); + } + + /* Used by Egl manager. The surface is never displayed. */ + sp getSurface() const + { + return mSurface; + } + +private: + sp mBufferItemConsumer; + sp mListener; + /* Used by Egl manager. The surface is never displayed */ + sp mSurface; +}; + + +/* Used to generate valid fences. It is not possible to create a dummy sync + * fence for testing. Egl can generate buffers along with a valid fence. + * The buffer cannot be guaranteed to be the same format across all devices so + * a CPU filled buffer is used instead. The Egl fence is used along with the + * CPU filled buffer. */ +class Hwc2TestEglManager { +public: + Hwc2TestEglManager() + : mEglDisplay(EGL_NO_DISPLAY), + mEglSurface(EGL_NO_SURFACE), + mEglContext(EGL_NO_CONTEXT) { } + + ~Hwc2TestEglManager() + { + cleanup(); + } + + int initialize(sp surface) + { + mSurface = surface; + + mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (mEglDisplay == EGL_NO_DISPLAY) return false; + + EGLint major; + EGLint minor; + if (!eglInitialize(mEglDisplay, &major, &minor)) { + ALOGW("Could not initialize EGL"); + return false; + } + + /* We're going to use a 1x1 pbuffer surface later on + * The configuration distance doesn't really matter for what we're + * trying to do */ + EGLint configAttrs[] = { + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 0, + EGL_DEPTH_SIZE, 24, + EGL_STENCIL_SIZE, 0, + EGL_NONE + }; + + EGLConfig configs[1]; + EGLint configCnt; + if (!eglChooseConfig(mEglDisplay, configAttrs, configs, 1, + &configCnt)) { + ALOGW("Could not select EGL configuration"); + eglReleaseThread(); + eglTerminate(mEglDisplay); + return false; + } + + if (configCnt <= 0) { + ALOGW("Could not find EGL configuration"); + eglReleaseThread(); + eglTerminate(mEglDisplay); + return false; + } + + /* These objects are initialized below but the default "null" values are + * used to cleanup properly at any point in the initialization sequence */ + EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; + mEglContext = eglCreateContext(mEglDisplay, configs[0], EGL_NO_CONTEXT, + attrs); + if (mEglContext == EGL_NO_CONTEXT) { + ALOGW("Could not create EGL context"); + cleanup(); + return false; + } + + EGLint surfaceAttrs[] = { EGL_NONE }; + mEglSurface = eglCreateWindowSurface(mEglDisplay, configs[0], + mSurface.get(), surfaceAttrs); + if (mEglSurface == EGL_NO_SURFACE) { + ALOGW("Could not create EGL surface"); + cleanup(); + return false; + } + + if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { + ALOGW("Could not change current EGL context"); + cleanup(); + return false; + } + + return true; + } + + void makeCurrent() const + { + eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext); + } + + void present() const + { + eglSwapBuffers(mEglDisplay, mEglSurface); + } + +private: + void cleanup() + { + if (mEglDisplay == EGL_NO_DISPLAY) + return; + if (mEglSurface != EGL_NO_SURFACE) + eglDestroySurface(mEglDisplay, mEglSurface); + if (mEglContext != EGL_NO_CONTEXT) + eglDestroyContext(mEglDisplay, mEglContext); + + eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT); + eglReleaseThread(); + eglTerminate(mEglDisplay); + } + + sp mSurface; + EGLDisplay mEglDisplay; + EGLSurface mEglSurface; + EGLContext mEglContext; +}; + + +static const std::array triangles = {{ + { 1.0f, 1.0f }, + { -1.0f, 1.0f }, + { 1.0f, -1.0f }, + { -1.0f, -1.0f }, +}}; + +class Hwc2TestFenceGenerator { +public: + + Hwc2TestFenceGenerator() + { + mSurfaceManager.initialize({1, 1}, HAL_PIXEL_FORMAT_RGBA_8888, + setFence, this); + + if (!mEglManager.initialize(mSurfaceManager.getSurface())) + return; + + mEglManager.makeCurrent(); + + glClearColor(0.0, 0.0, 0.0, 1.0); + glEnableVertexAttribArray(0); + } + + ~Hwc2TestFenceGenerator() + { + if (mFence >= 0) + close(mFence); + mFence = -1; + + mEglManager.makeCurrent(); + } + + /* It is not possible to simply generate a fence. The easiest way is to + * generate a buffer using egl and use the associated fence. The buffer + * cannot be guaranteed to be a certain format across all devices using this + * method. Instead the buffer is generated using the CPU */ + int32_t get() + { + if (mFence >= 0) { + return dup(mFence); + } + + std::unique_lock lock(mMutex); + + /* If the pending is still set to false and times out, we cannot recover. + * Set an error and return */ + while (mPending != false) { + if (mCv.wait_for(lock, std::chrono::seconds(2)) == std::cv_status::timeout) + return -ETIME; + } + + /* Generate a fence. The fence will be returned through the setFence + * callback */ + mEglManager.makeCurrent(); + + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, triangles.data()); + glClear(GL_COLOR_BUFFER_BIT); + + mEglManager.present(); + + /* Wait for the setFence callback */ + while (mPending != true) { + if (mCv.wait_for(lock, std::chrono::seconds(2)) == std::cv_status::timeout) + return -ETIME; + } + + mPending = false; + + return dup(mFence); + } + + /* Callback that sets the fence */ + void set(int32_t fence) + { + mFence = fence; + mPending = true; + + mCv.notify_all(); + } + +private: + + Hwc2TestSurfaceManager mSurfaceManager; + Hwc2TestEglManager mEglManager; + + std::mutex mMutex; + std::condition_variable mCv; + + int32_t mFence = -1; + bool mPending = false; +}; + + +static void setFence(int32_t fence, void* fenceGenerator) +{ + static_cast(fenceGenerator)->set(fence); +} + + +Hwc2TestBuffer::Hwc2TestBuffer() + : mFenceGenerator(new Hwc2TestFenceGenerator()) { } + +Hwc2TestBuffer::~Hwc2TestBuffer() = default; + +/* When the buffer changes sizes, save the new size and invalidate the current + * buffer */ +void Hwc2TestBuffer::updateBufferArea(const Area& bufferArea) +{ + if (mBufferArea.width == bufferArea.width + && mBufferArea.height == bufferArea.height) + return; + + mBufferArea.width = bufferArea.width; + mBufferArea.height = bufferArea.height; + + mValidBuffer = false; +} + +/* Returns a valid buffer handle and fence. The handle is filled using the CPU + * to ensure the correct format across all devices. The fence is created using + * egl. */ +int Hwc2TestBuffer::get(buffer_handle_t* outHandle, int32_t* outFence) +{ + if (mBufferArea.width == -1 || mBufferArea.height == -1) + return -EINVAL; + + /* If the current buffer is valid, the previous buffer can be reused. + * Otherwise, create new buffer */ + if (!mValidBuffer) { + int ret = generateBuffer(); + if (ret) + return ret; + } + + *outFence = mFenceGenerator->get(); + *outHandle = mHandle; + + mValidBuffer = true; + + return 0; +} + +/* CPU fills a buffer to guarantee the correct buffer format across all + * devices */ +int Hwc2TestBuffer::generateBuffer() +{ + int ret; + + /* Create new graphic buffer with correct dimensions */ + mGraphicBuffer = mGraphicBufferAlloc.createGraphicBuffer( + mBufferArea.width, mBufferArea.height, mFormat, + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER, + "hwc2_test_buffer", &ret); + if (ret) + return ret; + + /* Locks the buffer for writing */ + uint8_t* img; + mGraphicBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); + + uint32_t stride = mGraphicBuffer->getStride(); + + /* Iterate from the top row of the buffer to the bottom row */ + for (int32_t y = 0; y < mBufferArea.height; y++) { + + /* Will be used as R, G and B values for pixel colors */ + uint8_t max = 255; + uint8_t min = 0; + + /* Divide the rows into 3 sections. The first section will contain + * the lighest colors. The last section will contain the darkest + * colors. */ + if (y < mBufferArea.height * 1.0 / 3.0) { + min = 255 / 2; + } else if (y >= mBufferArea.height * 2.0 / 3.0) { + max = 255 / 2; + } + + /* Divide the columns into 3 sections. The first section is red, + * the second is green and the third is blue */ + int32_t x = 0; + for (; x < mBufferArea.width / 3; x++) { + setColor(x, y, mFormat, stride, img, max, min, min, 255); + } + + for (; x < mBufferArea.width * 2 / 3; x++) { + setColor(x, y, mFormat, stride, img, min, max, min, 255); + } + + for (; x < mBufferArea.width; x++) { + setColor(x, y, mFormat, stride, img, min, min, max, 255); + } + } + + /* Unlock the buffer for reading */ + mGraphicBuffer->unlock(); + + mHandle = mGraphicBuffer->handle; + + return 0; +} + +/* Sets the pixel of a buffer given the location, format, stride and color. + * Currently only supports RGBA_8888 */ +void Hwc2TestBuffer::setColor(int32_t x, int32_t y, + android_pixel_format_t format, uint32_t stride, uint8_t* img, uint8_t r, + uint8_t g, uint8_t b, uint8_t a) +{ + switch (format) { + case HAL_PIXEL_FORMAT_RGBA_8888: + img[(y * stride + x) * 4 + 0] = r; + img[(y * stride + x) * 4 + 1] = g; + img[(y * stride + x) * 4 + 2] = b; + img[(y * stride + x) * 4 + 3] = a; + break; + default: + break; + } +} diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h new file mode 100644 index 0000000000..721540fa42 --- /dev/null +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h @@ -0,0 +1,58 @@ +/* + * 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. + */ + +#ifndef _HWC2_TEST_BUFFER_H +#define _HWC2_TEST_BUFFER_H + +#include +#include + +#include +#include + +#include "Hwc2TestProperties.h" + +class Hwc2TestFenceGenerator; + +class Hwc2TestBuffer { +public: + Hwc2TestBuffer(); + ~Hwc2TestBuffer(); + + void updateBufferArea(const Area& bufferArea); + + int get(buffer_handle_t* outHandle, int32_t* outFence); + +protected: + int generateBuffer(); + + void setColor(int32_t x, int32_t y, android_pixel_format_t format, + uint32_t stride, uint8_t* img, uint8_t r, uint8_t g, uint8_t b, + uint8_t a); + + android::GraphicBufferAlloc mGraphicBufferAlloc; + android::sp mGraphicBuffer; + + std::unique_ptr mFenceGenerator; + + Area mBufferArea = {-1, -1}; + const android_pixel_format_t mFormat = HAL_PIXEL_FORMAT_RGBA_8888; + + bool mValidBuffer = false; + buffer_handle_t mHandle = nullptr; +}; + +#endif /* ifndef _HWC2_TEST_BUFFER_H */ diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp index 01d48c4c66..fcf5768ff0 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp @@ -32,6 +32,7 @@ Hwc2TestLayer::Hwc2TestLayer(Hwc2TestCoverage coverage, const Area& displayArea, mTransform(coverage), mZOrder(zOrder) { + mBufferArea.setDependent(&mBuffer); mBufferArea.setDependent(&mSourceCrop); mBufferArea.setDependent(&mSurfaceDamage); mBlendMode.setDependent(&mColor); @@ -52,6 +53,15 @@ std::string Hwc2TestLayer::dump() const return dmp.str(); } +int Hwc2TestLayer::getBuffer(buffer_handle_t* outHandle, + android::base::unique_fd* outAcquireFence) +{ + int32_t acquireFence; + int ret = mBuffer.get(outHandle, &acquireFence); + outAcquireFence->reset(acquireFence); + return ret; +} + void Hwc2TestLayer::reset() { for (auto property : mProperties) { diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h index f5b2c392a3..27885abefb 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h @@ -17,6 +17,9 @@ #ifndef _HWC2_TEST_LAYER_H #define _HWC2_TEST_LAYER_H +#include + +#include "Hwc2TestBuffer.h" #include "Hwc2TestProperties.h" #define HWC2_INCLUDE_STRINGIFICATION @@ -32,6 +35,9 @@ public: std::string dump() const; + int getBuffer(buffer_handle_t* outHandle, + android::base::unique_fd* outAcquireFence); + void reset(); hwc2_blend_mode_t getBlendMode() const; @@ -64,6 +70,8 @@ private: &mPlaneAlpha, &mSourceCrop, &mSurfaceDamage, &mTransform }}; + Hwc2TestBuffer mBuffer; + Hwc2TestBlendMode mBlendMode; Hwc2TestBufferArea mBufferArea; Hwc2TestColor mColor; diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp index 8ef3d59d9e..bfd076ffd1 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp @@ -17,6 +17,13 @@ #include #include +#define HWC2_INCLUDE_STRINGIFICATION +#define HWC2_USE_CPP11 +#include +#undef HWC2_INCLUDE_STRINGIFICATION +#undef HWC2_USE_CPP11 + +#include "Hwc2TestBuffer.h" #include "Hwc2TestProperties.h" Hwc2TestBufferArea::Hwc2TestBufferArea(Hwc2TestCoverage coverage, @@ -39,6 +46,14 @@ std::string Hwc2TestBufferArea::dump() const return dmp.str(); } +void Hwc2TestBufferArea::setDependent(Hwc2TestBuffer* buffer) +{ + mBuffer = buffer; + if (buffer) { + buffer->updateBufferArea(get()); + } +} + void Hwc2TestBufferArea::setDependent(Hwc2TestSourceCrop* sourceCrop) { mSourceCrop = sourceCrop; @@ -76,6 +91,8 @@ void Hwc2TestBufferArea::updateDependents() { const Area& curr = get(); + if (mBuffer) + mBuffer->updateBufferArea(curr); if (mSourceCrop) mSourceCrop->updateBufferArea(curr); if (mSurfaceDamage) diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h index 6f3bd0f438..048d6e95bc 100644 --- a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h +++ b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h @@ -96,6 +96,7 @@ protected: }; +class Hwc2TestBuffer; class Hwc2TestSourceCrop; class Hwc2TestSurfaceDamage; @@ -105,6 +106,7 @@ public: std::string dump() const override; + void setDependent(Hwc2TestBuffer* buffer); void setDependent(Hwc2TestSourceCrop* sourceCrop); void setDependent(Hwc2TestSurfaceDamage* surfaceDamage); @@ -119,6 +121,7 @@ protected: Area mDisplayArea; + Hwc2TestBuffer* mBuffer = nullptr; Hwc2TestSourceCrop* mSourceCrop = nullptr; Hwc2TestSurfaceDamage* mSurfaceDamage = nullptr; -- 2.11.0