Loading services/surfaceflinger/tests/hwc2/Android.mk +5 −2 Original line number Diff line number Diff line Loading @@ -36,7 +36,9 @@ LOCAL_SHARED_LIBRARIES := \ libui \ libgui \ liblog \ libsync libsync \ libskia \ android.hardware.graphics.common@1.0 LOCAL_STATIC_LIBRARIES := \ libbase \ libadf \ Loading @@ -49,6 +51,7 @@ LOCAL_SRC_FILES := \ Hwc2TestLayers.cpp \ Hwc2TestBuffer.cpp \ Hwc2TestClientTarget.cpp \ Hwc2TestVirtualDisplay.cpp Hwc2TestVirtualDisplay.cpp \ Hwc2TestPixelComparator.cpp include $(BUILD_NATIVE_TEST) services/surfaceflinger/tests/hwc2/Hwc2Test.cpp +213 −3 Original line number Diff line number Diff line Loading @@ -1775,6 +1775,145 @@ protected: } } void createAndPresentVirtualDisplay(size_t layerCnt, Hwc2TestCoverage coverage, const std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>& coverageExceptions) { Hwc2TestVirtualDisplay testVirtualDisplay(coverage); hwc2_display_t display; android_pixel_format_t desiredFormat = HAL_PIXEL_FORMAT_RGBA_8888; do { // Items dependent on the display dimensions hwc2_error_t err = HWC2_ERROR_NONE; const UnsignedArea& dimension = testVirtualDisplay.getDisplayDimension(); ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(dimension.width, dimension.height, &desiredFormat, &display, &err)); ASSERT_TRUE(err == HWC2_ERROR_NONE) << "Cannot allocate virtual display"; ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON)); ASSERT_NO_FATAL_FAILURE(enableVsync(display)); std::vector<hwc2_config_t> configs; ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs)); for (auto config : configs) { ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config)); Area displayArea; ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display, &displayArea)); std::vector<hwc2_layer_t> layers; ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt)); Hwc2TestLayers testLayers(layers, coverage, displayArea, coverageExceptions); /* * Layouts that do not cover an entire virtual display will * cause undefined behavior. * Enable optimizeLayouts to avoid this. */ testLayers.optimizeLayouts(); do { // Items dependent on the testLayers properties std::set<hwc2_layer_t> clientLayers; std::set<hwc2_layer_t> clearLayers; uint32_t numTypes, numRequests; bool hasChanges, skip; bool flipClientTarget; int32_t presentFence; Hwc2TestClientTarget testClientTarget; buffer_handle_t outputBufferHandle; android::base::unique_fd outputBufferReleaseFence; ASSERT_NO_FATAL_FAILURE(setLayerProperties(display, layers, &testLayers, &skip)); if (skip) continue; ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes, &numRequests, &hasChanges)); if (hasChanges) EXPECT_LE(numTypes, static_cast<uint32_t>(layers.size())) << "wrong number of requests"; ASSERT_NO_FATAL_FAILURE(handleCompositionChanges(display, testLayers, layers, numTypes, &clientLayers)); ASSERT_NO_FATAL_FAILURE(handleRequests(display, layers, numRequests, &clearLayers, &flipClientTarget)); ASSERT_NO_FATAL_FAILURE(setClientTarget(display, &testClientTarget, testLayers, clientLayers, clearLayers, flipClientTarget, displayArea)); ASSERT_NO_FATAL_FAILURE(acceptDisplayChanges(display)); ASSERT_EQ(testVirtualDisplay.getOutputBuffer( &outputBufferHandle, &outputBufferReleaseFence), 0); ASSERT_NO_FATAL_FAILURE(setOutputBuffer(display, outputBufferHandle, outputBufferReleaseFence)); EXPECT_NO_FATAL_FAILURE(presentDisplay(display, &presentFence)); ASSERT_NO_FATAL_FAILURE(closeFences(display, presentFence)); ASSERT_EQ(testVirtualDisplay.verifyOutputBuffer(&testLayers, &layers, &clearLayers), 0); /* * Upscaling the image causes minor pixel differences. * Work around this by using some threshold. * * Fail test if we are off by more than 1% of our * pixels. */ ComparatorResult& comparatorResult = ComparatorResult::get(); int threshold = (dimension.width * dimension.height) / 100; double diffPercent = (comparatorResult.getDifferentPixelCount() * 100.0) / (dimension.width * dimension.height); if (comparatorResult.getDifferentPixelCount() != 0) EXPECT_TRUE(false) << comparatorResult.getDifferentPixelCount() << " pixels (" << diffPercent << "%) are different."; if (comparatorResult.getDifferentPixelCount() > threshold) { EXPECT_TRUE(false) << "Mismatched pixel count exceeds threshold. " << "Writing buffers to file."; const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance() ->current_test_info(); EXPECT_EQ(testVirtualDisplay.writeBuffersToFile( test_info->name()), 0) << "Failed to write buffers."; } ASSERT_LE(comparatorResult.getDifferentPixelCount(), threshold) << comparatorResult.getDifferentPixelCount() << " pixels (" << diffPercent << "%) are different. " << "Exceeds 1% threshold, terminating test. " << "Test case: " << testLayers.dump(); } while (testLayers.advance()); ASSERT_NO_FATAL_FAILURE(destroyLayers(display, std::move(layers))); } ASSERT_NO_FATAL_FAILURE(disableVsync(display)); ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF)); ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display)); } while (testVirtualDisplay.advance()); } hwc2_device_t* mHwc2Device = nullptr; enum class Hwc2TestHotplugStatus { Loading Loading @@ -4479,7 +4618,7 @@ TEST_F(Hwc2Test, SET_OUTPUT_BUFFER) buffer_handle_t handle; android::base::unique_fd acquireFence; if (testVirtualDisplay->getBuffer(&handle, &acquireFence) >= 0) if (testVirtualDisplay->getOutputBuffer(&handle, &acquireFence) >= 0) EXPECT_NO_FATAL_FAILURE(test->setOutputBuffer(display, handle, acquireFence)); })); Loading @@ -4499,7 +4638,7 @@ TEST_F(Hwc2Test, SET_OUTPUT_BUFFER_bad_display) ASSERT_NO_FATAL_FAILURE(test->getBadDisplay(&badDisplay)); if (testVirtualDisplay->getBuffer(&handle, &acquireFence) < 0) if (testVirtualDisplay->getOutputBuffer(&handle, &acquireFence) < 0) return; ASSERT_NO_FATAL_FAILURE(test->setOutputBuffer(badDisplay, Loading Loading @@ -4539,7 +4678,7 @@ TEST_F(Hwc2Test, SET_OUTPUT_BUFFER_unsupported) android::base::unique_fd acquireFence; hwc2_error_t err = HWC2_ERROR_NONE; if (testVirtualDisplay.getBuffer(&handle, &acquireFence) < 0) if (testVirtualDisplay.getOutputBuffer(&handle, &acquireFence) < 0) continue; ASSERT_NO_FATAL_FAILURE(setOutputBuffer(display, handle, Loading @@ -4557,3 +4696,74 @@ TEST_F(Hwc2Test, DUMP) ASSERT_NO_FATAL_FAILURE(dump(&buffer)); } /* * TODO(b/64724708): Hwc2TestPropertyName::BufferArea MUST be default for all * virtual display tests as we don't handle this case correctly. * * Only default dataspace is supported in our drawing code. */ const std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> virtualDisplayExceptions = {{Hwc2TestPropertyName::BufferArea, Hwc2TestCoverage::Default}, {Hwc2TestPropertyName::Dataspace, Hwc2TestCoverage::Default}}; /* TESTCASE: Tests that the HWC2 can present 1 layer with default coverage on a * virtual display. */ TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_1) { Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; const size_t layerCnt = 1; ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage, virtualDisplayExceptions)); } /* TESTCASE: Tests that the HWC2 can present 1 layer with basic coverage on a * virtual display. */ TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_basic_1) { Hwc2TestCoverage coverage = Hwc2TestCoverage::Basic; const size_t layerCnt = 1; ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage, virtualDisplayExceptions)); } /* TESTCASE: Tests that the HWC2 can present 2 layers with default coverage on a * virtual display. */ TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_2) { Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; const size_t layerCnt = 2; ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage, virtualDisplayExceptions)); } /* TESTCASE: Tests that the HWC2 can present 3 layers with default coverage on a * virtual display. */ TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_3) { Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; const size_t layerCnt = 3; ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage, virtualDisplayExceptions)); } /* TESTCASE: Tests that the HWC2 can present 4 layers with default coverage on a * virtual display. */ TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_4) { Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; const size_t layerCnt = 4; ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage, virtualDisplayExceptions)); } /* TESTCASE: Tests that the HWC2 can present 5 layers with default coverage on a * virtual display. */ TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_5) { Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; const size_t layerCnt = 5; ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage, virtualDisplayExceptions)); } services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp +116 −26 Original line number Diff line number Diff line Loading @@ -27,7 +27,8 @@ #include <math/vec4.h> #include <GLES3/gl3.h> #include <SkImageEncoder.h> #include <SkStream.h> #include "Hwc2TestBuffer.h" #include "Hwc2TestLayers.h" Loading Loading @@ -462,33 +463,22 @@ Hwc2TestClientTargetBuffer::Hwc2TestClientTargetBuffer() Hwc2TestClientTargetBuffer::~Hwc2TestClientTargetBuffer() { } /* Generates a client target buffer using the layers assigned for client * composition. Takes into account the individual layer properties such as /* Generates a buffer from layersToDraw. * Takes into account the individual layer properties such as * transform, blend mode, source crop, etc. */ int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle, int32_t* outFence, const Area& bufferArea, static void compositeBufferFromLayers( const android::sp<android::GraphicBuffer>& graphicBuffer, android_pixel_format_t format, const Area& bufferArea, const Hwc2TestLayers* testLayers, const std::set<hwc2_layer_t>* clientLayers, const std::set<hwc2_layer_t>* layersToDraw, const std::set<hwc2_layer_t>* clearLayers) { /* Create new graphic buffer with correct dimensions */ mGraphicBuffer = new GraphicBuffer(bufferArea.width, bufferArea.height, mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer"); int ret = mGraphicBuffer->initCheck(); if (ret) { return ret; } if (!mGraphicBuffer->handle) { return -EINVAL; } /* Locks the buffer for writing */ uint8_t* img; mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN), graphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN), (void**)(&img)); uint32_t stride = mGraphicBuffer->getStride(); uint32_t stride = graphicBuffer->getStride(); float bWDiv3 = bufferArea.width / 3; float bW2Div3 = bufferArea.width * 2 / 3; Loading @@ -503,10 +493,10 @@ int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle, uint8_t r = 0, g = 0, b = 0; float a = 0.0f; /* Cycle through each client layer from back to front and /* Cycle through each layer from back to front and * update the pixel color. */ for (auto layer = clientLayers->rbegin(); layer != clientLayers->rend(); ++layer) { for (auto layer = layersToDraw->rbegin(); layer != layersToDraw->rend(); ++layer) { const hwc_rect_t df = testLayers->getDisplayFrame(*layer); Loading Loading @@ -688,14 +678,114 @@ int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle, } /* Set the pixel color */ setColor(x, y, mFormat, stride, img, r, g, b, a * 255); setColor(x, y, format, stride, img, r, g, b, a * 255); } } mGraphicBuffer->unlock(); graphicBuffer->unlock(); } /* Generates a client target buffer using the layers assigned for client * composition. Takes into account the individual layer properties such as * transform, blend mode, source crop, etc. */ int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle, int32_t* outFence, const Area& bufferArea, const Hwc2TestLayers* testLayers, const std::set<hwc2_layer_t>* clientLayers, const std::set<hwc2_layer_t>* clearLayers) { /* Create new graphic buffer with correct dimensions */ mGraphicBuffer = new GraphicBuffer(bufferArea.width, bufferArea.height, mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer"); int ret = mGraphicBuffer->initCheck(); if (ret) return ret; if (!mGraphicBuffer->handle) return -EINVAL; compositeBufferFromLayers(mGraphicBuffer, mFormat, bufferArea, testLayers, clientLayers, clearLayers); *outFence = mFenceGenerator->get(); *outHandle = mGraphicBuffer->handle; return 0; } void Hwc2TestVirtualBuffer::updateBufferArea(const Area& bufferArea) { mBufferArea.width = bufferArea.width; mBufferArea.height = bufferArea.height; } bool Hwc2TestVirtualBuffer::writeBufferToFile(std::string path) { SkFILEWStream file(path.c_str()); const SkImageInfo info = SkImageInfo::Make(mBufferArea.width, mBufferArea.height, SkColorType::kRGBA_8888_SkColorType, SkAlphaType::kPremul_SkAlphaType); uint8_t* img; mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN), (void**)(&img)); SkPixmap pixmap(info, img, mGraphicBuffer->getStride()); bool result = file.isValid() && SkEncodeImage(&file, pixmap, SkEncodedImageFormat::kPNG, 100); mGraphicBuffer->unlock(); return result; } /* Generates a buffer that holds the expected result of compositing all of our * layers */ int Hwc2TestExpectedBuffer::generateExpectedBuffer( const Hwc2TestLayers* testLayers, const std::vector<hwc2_layer_t>* allLayers, const std::set<hwc2_layer_t>* clearLayers) { mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height, mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN, "hwc2_test_buffer"); int ret = mGraphicBuffer->initCheck(); if (ret) return ret; if (!mGraphicBuffer->handle) return -EINVAL; const std::set<hwc2_layer_t> allLayerSet(allLayers->begin(), allLayers->end()); compositeBufferFromLayers(mGraphicBuffer, mFormat, mBufferArea, testLayers, &allLayerSet, clearLayers); return 0; } int Hwc2TestOutputBuffer::getOutputBuffer(buffer_handle_t* outHandle, int32_t* outFence) { if (mBufferArea.width == -1 || mBufferArea.height == -1) return -EINVAL; mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height, mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::GPU_RENDER_TARGET, "hwc2_test_buffer"); int ret = mGraphicBuffer->initCheck(); if (ret) return ret; if (!mGraphicBuffer->handle) return -EINVAL; *outFence = -1; *outHandle = mGraphicBuffer->handle; return 0; } services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h +34 −0 Original line number Diff line number Diff line Loading @@ -71,4 +71,38 @@ protected: const android_pixel_format_t mFormat = HAL_PIXEL_FORMAT_RGBA_8888; }; class Hwc2TestVirtualBuffer { public: void updateBufferArea(const Area& bufferArea); bool writeBufferToFile(std::string path); android::sp<android::GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; } protected: android::sp<android::GraphicBuffer> mGraphicBuffer; Area mBufferArea = {-1, -1}; const android_pixel_format_t mFormat = HAL_PIXEL_FORMAT_RGBA_8888; }; class Hwc2TestExpectedBuffer : public Hwc2TestVirtualBuffer { public: int generateExpectedBuffer(const Hwc2TestLayers* testLayers, const std::vector<hwc2_layer_t>* allLayers, const std::set<hwc2_layer_t>* clearLayers); }; class Hwc2TestOutputBuffer : public Hwc2TestVirtualBuffer { public: int getOutputBuffer(buffer_handle_t* outHandle, int32_t* outFence); }; #endif /* ifndef _HWC2_TEST_BUFFER_H */ services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp 0 → 100644 +113 −0 Original line number Diff line number Diff line /* * 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 <sstream> #include <android/hardware/graphics/common/1.0/types.h> #include "Hwc2TestPixelComparator.h" using android::hardware::graphics::common::V1_0::BufferUsage; uint32_t ComparatorResult::getPixel(int32_t x, int32_t y, uint32_t stride, uint8_t* img) const { uint32_t r = img[(y * stride + x) * 4 + 0]; uint32_t g = img[(y * stride + x) * 4 + 1]; uint32_t b = img[(y * stride + x) * 4 + 2]; uint32_t a = img[(y * stride + x) * 4 + 3]; uint32_t pixel = 0; pixel |= r; pixel |= g << 8; pixel |= b << 16; pixel |= a << 24; return pixel; } void ComparatorResult::CompareBuffers( android::sp<android::GraphicBuffer>& resultBuffer, android::sp<android::GraphicBuffer>& expectedBuffer) { uint8_t* resultBufferImg; uint8_t* expectedBufferImg; resultBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_READ_OFTEN), (void**)(&resultBufferImg)); expectedBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_READ_OFTEN), (void**)(&expectedBufferImg)); mComparisons.clear(); int32_t mDifferentPixelCount = 0; int32_t mBlankPixelCount = 0; for (uint32_t y = 0; y < resultBuffer->getHeight(); y++) { for (uint32_t x = 0; x < resultBuffer->getWidth(); x++) { uint32_t result = getPixel(x, y, resultBuffer->getStride(), resultBufferImg); uint32_t expected = getPixel(x, y, expectedBuffer->getStride(), expectedBufferImg); if (result == 0) mBlankPixelCount++; if (result != expected) mDifferentPixelCount++; mComparisons.emplace_back(std::make_tuple(x, y, result, expected)); } } resultBuffer->unlock(); expectedBuffer->unlock(); } std::string ComparatorResult::pixelDiff(uint32_t x, uint32_t y, uint32_t resultPixel, uint32_t expectedPixel) const { uint32_t resultAlpha = (resultPixel >> 24) & 0xFF; uint32_t resultBlue = (resultPixel >> 16) & 0xFF; uint32_t resultGreen = (resultPixel >> 8) & 0xFF; uint32_t resultRed = resultPixel & 0xFF; uint32_t expectedAlpha = (expectedPixel >> 24) & 0xFF; uint32_t expectedBlue = (expectedPixel >> 16) & 0xFF; uint32_t expectedGreen = (expectedPixel >> 8) & 0xFF; uint32_t expectedRed = expectedPixel & 0xFF; std::ostringstream stream; stream << "x: " << x << " y: " << y << std::endl; stream << std::hex; stream << "Result pixel: " << resultRed << "|" << resultGreen << "|" << resultBlue << "|" << resultAlpha << std::endl; stream << "Expected pixel: " << expectedRed << "|" << expectedGreen << "|" << expectedBlue << "|" << expectedAlpha << std::endl; return stream.str(); } std::string ComparatorResult::dumpComparison() const { std::ostringstream stream; stream << "Number of different pixels: " << mDifferentPixelCount; for (const auto& comparison : mComparisons) { if (std::get<2>(comparison) != std::get<3>(comparison)) stream << pixelDiff(std::get<0>(comparison), std::get<1>(comparison), std::get<2>(comparison), std::get<3>(comparison)); } return stream.str(); } Loading
services/surfaceflinger/tests/hwc2/Android.mk +5 −2 Original line number Diff line number Diff line Loading @@ -36,7 +36,9 @@ LOCAL_SHARED_LIBRARIES := \ libui \ libgui \ liblog \ libsync libsync \ libskia \ android.hardware.graphics.common@1.0 LOCAL_STATIC_LIBRARIES := \ libbase \ libadf \ Loading @@ -49,6 +51,7 @@ LOCAL_SRC_FILES := \ Hwc2TestLayers.cpp \ Hwc2TestBuffer.cpp \ Hwc2TestClientTarget.cpp \ Hwc2TestVirtualDisplay.cpp Hwc2TestVirtualDisplay.cpp \ Hwc2TestPixelComparator.cpp include $(BUILD_NATIVE_TEST)
services/surfaceflinger/tests/hwc2/Hwc2Test.cpp +213 −3 Original line number Diff line number Diff line Loading @@ -1775,6 +1775,145 @@ protected: } } void createAndPresentVirtualDisplay(size_t layerCnt, Hwc2TestCoverage coverage, const std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>& coverageExceptions) { Hwc2TestVirtualDisplay testVirtualDisplay(coverage); hwc2_display_t display; android_pixel_format_t desiredFormat = HAL_PIXEL_FORMAT_RGBA_8888; do { // Items dependent on the display dimensions hwc2_error_t err = HWC2_ERROR_NONE; const UnsignedArea& dimension = testVirtualDisplay.getDisplayDimension(); ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(dimension.width, dimension.height, &desiredFormat, &display, &err)); ASSERT_TRUE(err == HWC2_ERROR_NONE) << "Cannot allocate virtual display"; ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON)); ASSERT_NO_FATAL_FAILURE(enableVsync(display)); std::vector<hwc2_config_t> configs; ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs)); for (auto config : configs) { ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config)); Area displayArea; ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display, &displayArea)); std::vector<hwc2_layer_t> layers; ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt)); Hwc2TestLayers testLayers(layers, coverage, displayArea, coverageExceptions); /* * Layouts that do not cover an entire virtual display will * cause undefined behavior. * Enable optimizeLayouts to avoid this. */ testLayers.optimizeLayouts(); do { // Items dependent on the testLayers properties std::set<hwc2_layer_t> clientLayers; std::set<hwc2_layer_t> clearLayers; uint32_t numTypes, numRequests; bool hasChanges, skip; bool flipClientTarget; int32_t presentFence; Hwc2TestClientTarget testClientTarget; buffer_handle_t outputBufferHandle; android::base::unique_fd outputBufferReleaseFence; ASSERT_NO_FATAL_FAILURE(setLayerProperties(display, layers, &testLayers, &skip)); if (skip) continue; ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes, &numRequests, &hasChanges)); if (hasChanges) EXPECT_LE(numTypes, static_cast<uint32_t>(layers.size())) << "wrong number of requests"; ASSERT_NO_FATAL_FAILURE(handleCompositionChanges(display, testLayers, layers, numTypes, &clientLayers)); ASSERT_NO_FATAL_FAILURE(handleRequests(display, layers, numRequests, &clearLayers, &flipClientTarget)); ASSERT_NO_FATAL_FAILURE(setClientTarget(display, &testClientTarget, testLayers, clientLayers, clearLayers, flipClientTarget, displayArea)); ASSERT_NO_FATAL_FAILURE(acceptDisplayChanges(display)); ASSERT_EQ(testVirtualDisplay.getOutputBuffer( &outputBufferHandle, &outputBufferReleaseFence), 0); ASSERT_NO_FATAL_FAILURE(setOutputBuffer(display, outputBufferHandle, outputBufferReleaseFence)); EXPECT_NO_FATAL_FAILURE(presentDisplay(display, &presentFence)); ASSERT_NO_FATAL_FAILURE(closeFences(display, presentFence)); ASSERT_EQ(testVirtualDisplay.verifyOutputBuffer(&testLayers, &layers, &clearLayers), 0); /* * Upscaling the image causes minor pixel differences. * Work around this by using some threshold. * * Fail test if we are off by more than 1% of our * pixels. */ ComparatorResult& comparatorResult = ComparatorResult::get(); int threshold = (dimension.width * dimension.height) / 100; double diffPercent = (comparatorResult.getDifferentPixelCount() * 100.0) / (dimension.width * dimension.height); if (comparatorResult.getDifferentPixelCount() != 0) EXPECT_TRUE(false) << comparatorResult.getDifferentPixelCount() << " pixels (" << diffPercent << "%) are different."; if (comparatorResult.getDifferentPixelCount() > threshold) { EXPECT_TRUE(false) << "Mismatched pixel count exceeds threshold. " << "Writing buffers to file."; const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance() ->current_test_info(); EXPECT_EQ(testVirtualDisplay.writeBuffersToFile( test_info->name()), 0) << "Failed to write buffers."; } ASSERT_LE(comparatorResult.getDifferentPixelCount(), threshold) << comparatorResult.getDifferentPixelCount() << " pixels (" << diffPercent << "%) are different. " << "Exceeds 1% threshold, terminating test. " << "Test case: " << testLayers.dump(); } while (testLayers.advance()); ASSERT_NO_FATAL_FAILURE(destroyLayers(display, std::move(layers))); } ASSERT_NO_FATAL_FAILURE(disableVsync(display)); ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF)); ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display)); } while (testVirtualDisplay.advance()); } hwc2_device_t* mHwc2Device = nullptr; enum class Hwc2TestHotplugStatus { Loading Loading @@ -4479,7 +4618,7 @@ TEST_F(Hwc2Test, SET_OUTPUT_BUFFER) buffer_handle_t handle; android::base::unique_fd acquireFence; if (testVirtualDisplay->getBuffer(&handle, &acquireFence) >= 0) if (testVirtualDisplay->getOutputBuffer(&handle, &acquireFence) >= 0) EXPECT_NO_FATAL_FAILURE(test->setOutputBuffer(display, handle, acquireFence)); })); Loading @@ -4499,7 +4638,7 @@ TEST_F(Hwc2Test, SET_OUTPUT_BUFFER_bad_display) ASSERT_NO_FATAL_FAILURE(test->getBadDisplay(&badDisplay)); if (testVirtualDisplay->getBuffer(&handle, &acquireFence) < 0) if (testVirtualDisplay->getOutputBuffer(&handle, &acquireFence) < 0) return; ASSERT_NO_FATAL_FAILURE(test->setOutputBuffer(badDisplay, Loading Loading @@ -4539,7 +4678,7 @@ TEST_F(Hwc2Test, SET_OUTPUT_BUFFER_unsupported) android::base::unique_fd acquireFence; hwc2_error_t err = HWC2_ERROR_NONE; if (testVirtualDisplay.getBuffer(&handle, &acquireFence) < 0) if (testVirtualDisplay.getOutputBuffer(&handle, &acquireFence) < 0) continue; ASSERT_NO_FATAL_FAILURE(setOutputBuffer(display, handle, Loading @@ -4557,3 +4696,74 @@ TEST_F(Hwc2Test, DUMP) ASSERT_NO_FATAL_FAILURE(dump(&buffer)); } /* * TODO(b/64724708): Hwc2TestPropertyName::BufferArea MUST be default for all * virtual display tests as we don't handle this case correctly. * * Only default dataspace is supported in our drawing code. */ const std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> virtualDisplayExceptions = {{Hwc2TestPropertyName::BufferArea, Hwc2TestCoverage::Default}, {Hwc2TestPropertyName::Dataspace, Hwc2TestCoverage::Default}}; /* TESTCASE: Tests that the HWC2 can present 1 layer with default coverage on a * virtual display. */ TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_1) { Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; const size_t layerCnt = 1; ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage, virtualDisplayExceptions)); } /* TESTCASE: Tests that the HWC2 can present 1 layer with basic coverage on a * virtual display. */ TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_basic_1) { Hwc2TestCoverage coverage = Hwc2TestCoverage::Basic; const size_t layerCnt = 1; ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage, virtualDisplayExceptions)); } /* TESTCASE: Tests that the HWC2 can present 2 layers with default coverage on a * virtual display. */ TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_2) { Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; const size_t layerCnt = 2; ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage, virtualDisplayExceptions)); } /* TESTCASE: Tests that the HWC2 can present 3 layers with default coverage on a * virtual display. */ TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_3) { Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; const size_t layerCnt = 3; ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage, virtualDisplayExceptions)); } /* TESTCASE: Tests that the HWC2 can present 4 layers with default coverage on a * virtual display. */ TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_4) { Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; const size_t layerCnt = 4; ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage, virtualDisplayExceptions)); } /* TESTCASE: Tests that the HWC2 can present 5 layers with default coverage on a * virtual display. */ TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_5) { Hwc2TestCoverage coverage = Hwc2TestCoverage::Default; const size_t layerCnt = 5; ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage, virtualDisplayExceptions)); }
services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp +116 −26 Original line number Diff line number Diff line Loading @@ -27,7 +27,8 @@ #include <math/vec4.h> #include <GLES3/gl3.h> #include <SkImageEncoder.h> #include <SkStream.h> #include "Hwc2TestBuffer.h" #include "Hwc2TestLayers.h" Loading Loading @@ -462,33 +463,22 @@ Hwc2TestClientTargetBuffer::Hwc2TestClientTargetBuffer() Hwc2TestClientTargetBuffer::~Hwc2TestClientTargetBuffer() { } /* Generates a client target buffer using the layers assigned for client * composition. Takes into account the individual layer properties such as /* Generates a buffer from layersToDraw. * Takes into account the individual layer properties such as * transform, blend mode, source crop, etc. */ int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle, int32_t* outFence, const Area& bufferArea, static void compositeBufferFromLayers( const android::sp<android::GraphicBuffer>& graphicBuffer, android_pixel_format_t format, const Area& bufferArea, const Hwc2TestLayers* testLayers, const std::set<hwc2_layer_t>* clientLayers, const std::set<hwc2_layer_t>* layersToDraw, const std::set<hwc2_layer_t>* clearLayers) { /* Create new graphic buffer with correct dimensions */ mGraphicBuffer = new GraphicBuffer(bufferArea.width, bufferArea.height, mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer"); int ret = mGraphicBuffer->initCheck(); if (ret) { return ret; } if (!mGraphicBuffer->handle) { return -EINVAL; } /* Locks the buffer for writing */ uint8_t* img; mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN), graphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN), (void**)(&img)); uint32_t stride = mGraphicBuffer->getStride(); uint32_t stride = graphicBuffer->getStride(); float bWDiv3 = bufferArea.width / 3; float bW2Div3 = bufferArea.width * 2 / 3; Loading @@ -503,10 +493,10 @@ int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle, uint8_t r = 0, g = 0, b = 0; float a = 0.0f; /* Cycle through each client layer from back to front and /* Cycle through each layer from back to front and * update the pixel color. */ for (auto layer = clientLayers->rbegin(); layer != clientLayers->rend(); ++layer) { for (auto layer = layersToDraw->rbegin(); layer != layersToDraw->rend(); ++layer) { const hwc_rect_t df = testLayers->getDisplayFrame(*layer); Loading Loading @@ -688,14 +678,114 @@ int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle, } /* Set the pixel color */ setColor(x, y, mFormat, stride, img, r, g, b, a * 255); setColor(x, y, format, stride, img, r, g, b, a * 255); } } mGraphicBuffer->unlock(); graphicBuffer->unlock(); } /* Generates a client target buffer using the layers assigned for client * composition. Takes into account the individual layer properties such as * transform, blend mode, source crop, etc. */ int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle, int32_t* outFence, const Area& bufferArea, const Hwc2TestLayers* testLayers, const std::set<hwc2_layer_t>* clientLayers, const std::set<hwc2_layer_t>* clearLayers) { /* Create new graphic buffer with correct dimensions */ mGraphicBuffer = new GraphicBuffer(bufferArea.width, bufferArea.height, mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer"); int ret = mGraphicBuffer->initCheck(); if (ret) return ret; if (!mGraphicBuffer->handle) return -EINVAL; compositeBufferFromLayers(mGraphicBuffer, mFormat, bufferArea, testLayers, clientLayers, clearLayers); *outFence = mFenceGenerator->get(); *outHandle = mGraphicBuffer->handle; return 0; } void Hwc2TestVirtualBuffer::updateBufferArea(const Area& bufferArea) { mBufferArea.width = bufferArea.width; mBufferArea.height = bufferArea.height; } bool Hwc2TestVirtualBuffer::writeBufferToFile(std::string path) { SkFILEWStream file(path.c_str()); const SkImageInfo info = SkImageInfo::Make(mBufferArea.width, mBufferArea.height, SkColorType::kRGBA_8888_SkColorType, SkAlphaType::kPremul_SkAlphaType); uint8_t* img; mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN), (void**)(&img)); SkPixmap pixmap(info, img, mGraphicBuffer->getStride()); bool result = file.isValid() && SkEncodeImage(&file, pixmap, SkEncodedImageFormat::kPNG, 100); mGraphicBuffer->unlock(); return result; } /* Generates a buffer that holds the expected result of compositing all of our * layers */ int Hwc2TestExpectedBuffer::generateExpectedBuffer( const Hwc2TestLayers* testLayers, const std::vector<hwc2_layer_t>* allLayers, const std::set<hwc2_layer_t>* clearLayers) { mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height, mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN, "hwc2_test_buffer"); int ret = mGraphicBuffer->initCheck(); if (ret) return ret; if (!mGraphicBuffer->handle) return -EINVAL; const std::set<hwc2_layer_t> allLayerSet(allLayers->begin(), allLayers->end()); compositeBufferFromLayers(mGraphicBuffer, mFormat, mBufferArea, testLayers, &allLayerSet, clearLayers); return 0; } int Hwc2TestOutputBuffer::getOutputBuffer(buffer_handle_t* outHandle, int32_t* outFence) { if (mBufferArea.width == -1 || mBufferArea.height == -1) return -EINVAL; mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height, mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::GPU_RENDER_TARGET, "hwc2_test_buffer"); int ret = mGraphicBuffer->initCheck(); if (ret) return ret; if (!mGraphicBuffer->handle) return -EINVAL; *outFence = -1; *outHandle = mGraphicBuffer->handle; return 0; }
services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h +34 −0 Original line number Diff line number Diff line Loading @@ -71,4 +71,38 @@ protected: const android_pixel_format_t mFormat = HAL_PIXEL_FORMAT_RGBA_8888; }; class Hwc2TestVirtualBuffer { public: void updateBufferArea(const Area& bufferArea); bool writeBufferToFile(std::string path); android::sp<android::GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; } protected: android::sp<android::GraphicBuffer> mGraphicBuffer; Area mBufferArea = {-1, -1}; const android_pixel_format_t mFormat = HAL_PIXEL_FORMAT_RGBA_8888; }; class Hwc2TestExpectedBuffer : public Hwc2TestVirtualBuffer { public: int generateExpectedBuffer(const Hwc2TestLayers* testLayers, const std::vector<hwc2_layer_t>* allLayers, const std::set<hwc2_layer_t>* clearLayers); }; class Hwc2TestOutputBuffer : public Hwc2TestVirtualBuffer { public: int getOutputBuffer(buffer_handle_t* outHandle, int32_t* outFence); }; #endif /* ifndef _HWC2_TEST_BUFFER_H */
services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp 0 → 100644 +113 −0 Original line number Diff line number Diff line /* * 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 <sstream> #include <android/hardware/graphics/common/1.0/types.h> #include "Hwc2TestPixelComparator.h" using android::hardware::graphics::common::V1_0::BufferUsage; uint32_t ComparatorResult::getPixel(int32_t x, int32_t y, uint32_t stride, uint8_t* img) const { uint32_t r = img[(y * stride + x) * 4 + 0]; uint32_t g = img[(y * stride + x) * 4 + 1]; uint32_t b = img[(y * stride + x) * 4 + 2]; uint32_t a = img[(y * stride + x) * 4 + 3]; uint32_t pixel = 0; pixel |= r; pixel |= g << 8; pixel |= b << 16; pixel |= a << 24; return pixel; } void ComparatorResult::CompareBuffers( android::sp<android::GraphicBuffer>& resultBuffer, android::sp<android::GraphicBuffer>& expectedBuffer) { uint8_t* resultBufferImg; uint8_t* expectedBufferImg; resultBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_READ_OFTEN), (void**)(&resultBufferImg)); expectedBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_READ_OFTEN), (void**)(&expectedBufferImg)); mComparisons.clear(); int32_t mDifferentPixelCount = 0; int32_t mBlankPixelCount = 0; for (uint32_t y = 0; y < resultBuffer->getHeight(); y++) { for (uint32_t x = 0; x < resultBuffer->getWidth(); x++) { uint32_t result = getPixel(x, y, resultBuffer->getStride(), resultBufferImg); uint32_t expected = getPixel(x, y, expectedBuffer->getStride(), expectedBufferImg); if (result == 0) mBlankPixelCount++; if (result != expected) mDifferentPixelCount++; mComparisons.emplace_back(std::make_tuple(x, y, result, expected)); } } resultBuffer->unlock(); expectedBuffer->unlock(); } std::string ComparatorResult::pixelDiff(uint32_t x, uint32_t y, uint32_t resultPixel, uint32_t expectedPixel) const { uint32_t resultAlpha = (resultPixel >> 24) & 0xFF; uint32_t resultBlue = (resultPixel >> 16) & 0xFF; uint32_t resultGreen = (resultPixel >> 8) & 0xFF; uint32_t resultRed = resultPixel & 0xFF; uint32_t expectedAlpha = (expectedPixel >> 24) & 0xFF; uint32_t expectedBlue = (expectedPixel >> 16) & 0xFF; uint32_t expectedGreen = (expectedPixel >> 8) & 0xFF; uint32_t expectedRed = expectedPixel & 0xFF; std::ostringstream stream; stream << "x: " << x << " y: " << y << std::endl; stream << std::hex; stream << "Result pixel: " << resultRed << "|" << resultGreen << "|" << resultBlue << "|" << resultAlpha << std::endl; stream << "Expected pixel: " << expectedRed << "|" << expectedGreen << "|" << expectedBlue << "|" << expectedAlpha << std::endl; return stream.str(); } std::string ComparatorResult::dumpComparison() const { std::ostringstream stream; stream << "Number of different pixels: " << mDifferentPixelCount; for (const auto& comparison : mComparisons) { if (std::get<2>(comparison) != std::get<3>(comparison)) stream << pixelDiff(std::get<0>(comparison), std::get<1>(comparison), std::get<2>(comparison), std::get<3>(comparison)); } return stream.str(); }