Loading graphics/composer/2.1/utils/vts/TestCommandReader.cpp +31 −1 Original line number Diff line number Diff line Loading @@ -26,23 +26,53 @@ namespace V2_1 { namespace vts { void TestCommandReader::parse() { mCompositionChanges.clear(); while (!isEmpty()) { IComposerClient::Command command; uint16_t length; ASSERT_TRUE(beginCommand(&command, &length)); switch (command) { case IComposerClient::Command::SELECT_DISPLAY: ASSERT_EQ(2, length); read64(); // display break; case IComposerClient::Command::SET_ERROR: { ASSERT_EQ(2, length); auto loc = read(); auto err = readSigned(); GTEST_FAIL() << "unexpected error " << err << " at location " << loc; } break; case IComposerClient::Command::SELECT_DISPLAY: case IComposerClient::Command::SET_CHANGED_COMPOSITION_TYPES: ASSERT_EQ(0, length % 3); for (uint16_t count = 0; count < length / 3; ++count) { uint64_t layerId = read64(); uint32_t composition = read(); std::pair<uint64_t, uint32_t> compositionChange(layerId, composition); mCompositionChanges.push_back(compositionChange); } break; case IComposerClient::Command::SET_DISPLAY_REQUESTS: ASSERT_EQ(1, length % 3); read(); // displayRequests, ignored for now for (uint16_t count = 0; count < (length - 1) / 3; ++count) { read64(); // layer // silently eat requests to clear the client target, since we won't be testing // client composition anyway ASSERT_EQ(1u, read()); } break; case IComposerClient::Command::SET_PRESENT_FENCE: ASSERT_EQ(1, length); close(readFence()); break; case IComposerClient::Command::SET_RELEASE_FENCES: ASSERT_EQ(0, length % 3); for (uint16_t count = 0; count < length / 3; ++count) { read64(); close(readFence()); } break; default: GTEST_FAIL() << "unexpected return command " << std::hex Loading graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h +2 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,8 @@ class TestCommandReader : public CommandReaderBase { // Parse all commands in the return command queue. Call GTEST_FAIL() for // unexpected errors or commands. void parse(); std::vector<std::pair<uint64_t, uint32_t>> mCompositionChanges; }; } // namespace vts Loading graphics/composer/2.2/utils/vts/ComposerVts.cpp +2 −3 Original line number Diff line number Diff line Loading @@ -138,12 +138,11 @@ void ComposerClient::getReadbackBufferAttributes(Display display, PixelFormat* o } void ComposerClient::getReadbackBufferFence(Display display, int32_t* outFence) { hidl_handle handle; mClient->getReadbackBufferFence(display, [&](const auto& tmpError, const auto& tmpHandle) { ASSERT_EQ(Error::NONE, tmpError) << "failed to get readback fence"; handle = tmpHandle; const native_handle_t* nativeFenceHandle = tmpHandle.getNativeHandle(); *outFence = dup(nativeFenceHandle->data[0]); }); *outFence = 0; } std::vector<ColorMode> ComposerClient::getColorModes(Display display) { Loading graphics/composer/2.2/vts/functional/Android.bp +5 −2 Original line number Diff line number Diff line Loading @@ -17,7 +17,10 @@ cc_test { name: "VtsHalGraphicsComposerV2_2TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalGraphicsComposerV2_2TargetTest.cpp"], srcs: [ "VtsHalGraphicsComposerV2_2ReadbackTest.cpp", "VtsHalGraphicsComposerV2_2TargetTest.cpp", ], // TODO(b/64437680): Assume these libs are always available on the device. shared_libs: [ Loading graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp 0 → 100644 +312 −0 Original line number Diff line number Diff line /* * Copyright 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "graphics_composer_hidl_hal_readback_tests@2.2" #include <VtsHalHidlTargetTestBase.h> #include <VtsHalHidlTargetTestEnvBase.h> #include <android-base/unique_fd.h> #include <android/hardware/graphics/composer/2.2/IComposerClient.h> #include <composer-command-buffer/2.2/ComposerCommandBuffer.h> #include <composer-vts/2.1/GraphicsComposerCallback.h> #include <composer-vts/2.1/TestCommandReader.h> #include <composer-vts/2.2/ComposerVts.h> #include <mapper-vts/2.1/MapperVts.h> namespace android { namespace hardware { namespace graphics { namespace composer { namespace V2_2 { namespace vts { namespace { using android::hardware::hidl_handle; using common::V1_1::BufferUsage; using common::V1_1::Dataspace; using common::V1_1::PixelFormat; using mapper::V2_1::IMapper; using mapper::V2_1::vts::Gralloc; using V2_1::Display; using V2_1::Layer; using V2_1::vts::TestCommandReader; // Test environment for graphics.composer class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { public: // get the test environment singleton static GraphicsComposerHidlEnvironment* Instance() { static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment; return instance; } virtual void registerTestServices() override { registerTestService<IComposer>(); } private: GraphicsComposerHidlEnvironment() {} GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment); }; class TestLayer { public: TestLayer(std::shared_ptr<ComposerClient> const client, Display display) : mLayer(client->createLayer(display, kBufferSlotCount)), mComposerClient(client), mDisplay(display) {} virtual ~TestLayer() { mComposerClient->destroyLayer(mDisplay, mLayer); } virtual void write(std::shared_ptr<CommandWriterBase> writer) { writer->selectLayer(mLayer); writer->setLayerDisplayFrame(mDisplayFrame); writer->setLayerZOrder(mZOrder); } void setDisplayFrame(IComposerClient::Rect frame) { mDisplayFrame = frame; } void setZOrder(uint32_t z) { mZOrder = z; } protected: Layer mLayer; IComposerClient::Rect mDisplayFrame = {0, 0, 0, 0}; uint32_t mZOrder = 0; private: std::shared_ptr<ComposerClient> const mComposerClient; const Display mDisplay; static constexpr uint32_t kBufferSlotCount = 64; }; class TestColorLayer : public TestLayer { public: TestColorLayer(std::shared_ptr<ComposerClient> const client, Display display) : TestLayer{client, display} {} void write(std::shared_ptr<CommandWriterBase> writer) override { TestLayer::write(writer); writer->setLayerCompositionType(IComposerClient::Composition::SOLID_COLOR); writer->setLayerColor(mColor); } void setColor(IComposerClient::Color color) { mColor = color; } private: IComposerClient::Color mColor = {0xff, 0xff, 0xff, 0xff}; }; class GraphicsComposerReadbackTest : public ::testing::VtsHalHidlTargetTestBase { protected: using PowerMode = V2_1::IComposerClient::PowerMode; void SetUp() override { ASSERT_NO_FATAL_FAILURE( mComposer = std::make_unique<Composer>( GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>())); ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient()); mComposerCallback = new V2_1::vts::GraphicsComposerCallback; mComposerClient->registerCallback(mComposerCallback); // assume the first display is primary and is never removed mPrimaryDisplay = waitForFirstDisplay(); Config activeConfig = mComposerClient->getActiveConfig(mPrimaryDisplay); width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, activeConfig, IComposerClient::Attribute::WIDTH); height = mComposerClient->getDisplayAttribute(mPrimaryDisplay, activeConfig, IComposerClient::Attribute::HEIGHT); // explicitly disable vsync mComposerClient->setVsyncEnabled(mPrimaryDisplay, false); mComposerCallback->setVsyncAllowed(false); // set up command writer/reader and gralloc mWriter = std::make_shared<CommandWriterBase>(1024); mReader = std::make_unique<TestCommandReader>(); mGralloc = std::make_unique<Gralloc>(); } ~GraphicsComposerReadbackTest() override { if (mComposerCallback != nullptr) { EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount()); EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount()); EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount()); } } void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); } void render(const std::vector<std::shared_ptr<TestLayer>>& layers) { for (auto layer : layers) { layer->write(mWriter); } execute(); mWriter->validateDisplay(); mWriter->presentDisplay(); execute(); } int32_t GetBytesPerPixel(PixelFormat format) { switch (format) { case PixelFormat::RGBA_8888: return 4; case PixelFormat::RGB_888: return 3; default: return -1; } } bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace, const Error& error) { if (error == Error::UNSUPPORTED) { return false; } // TODO: add support for RGBA_1010102 if (pixelFormat != PixelFormat::RGB_888 && pixelFormat != PixelFormat::RGBA_8888) { return false; } if (dataspace != Dataspace::V0_SRGB) { return false; } return true; } void getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat, Dataspace* outDataspace, Error* outError) { mComposerClient->getRaw()->getReadbackBufferAttributes( display, [&](const auto& tmpError, const auto& tmpOutPixelFormat, const auto& tmpOutDataspace) { *outError = tmpError; *outPixelFormat = tmpOutPixelFormat; *outDataspace = tmpOutDataspace; }); // Not all devices support readback. Pass test if this is the case if (!readbackSupported(*outPixelFormat, *outDataspace, *outError)) { GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; } } void checkReadbackBuffer(IMapper::BufferDescriptorInfo info, uint32_t stride, void* bufferData, std::vector<IComposerClient::Color> expectedColors) { int32_t bytesPerPixel = GetBytesPerPixel(info.format); ASSERT_NE(-1, bytesPerPixel) << "unexpected pixel format " << static_cast<int32_t>(info.format) << "(expected RGBA_8888 or RGB_888)"; for (int row = 0; row < height; row++) { for (int col = 0; col < width; col++) { int pixel = row * width + col; int offset = (row * stride + col) * bytesPerPixel; uint8_t* pixelColor = (uint8_t*)bufferData + offset; EXPECT_EQ(expectedColors[pixel].r, pixelColor[0]); EXPECT_EQ(expectedColors[pixel].g, pixelColor[1]); EXPECT_EQ(expectedColors[pixel].b, pixelColor[2]); } } } std::unique_ptr<Composer> mComposer; std::shared_ptr<ComposerClient> mComposerClient; sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback; // the first display and is assumed never to be removed Display mPrimaryDisplay; int32_t width; int32_t height; std::shared_ptr<CommandWriterBase> mWriter; std::unique_ptr<TestCommandReader> mReader; std::unique_ptr<Gralloc> mGralloc; private: Display waitForFirstDisplay() { while (true) { std::vector<Display> displays = mComposerCallback->getDisplays(); if (displays.empty()) { usleep(5 * 1000); continue; } return displays[0]; } } }; TEST_F(GraphicsComposerReadbackTest, SingleSolidColorLayer) { mWriter->selectDisplay(mPrimaryDisplay); mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON); mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB, RenderIntent::COLORIMETRIC); auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay); IComposerClient::Color color({0, 0, 0xff, 0xff}); IComposerClient::Rect coloredSquare({100, 100, 500, 500}); layer->setColor(color); layer->setDisplayFrame(coloredSquare); layer->setZOrder(10); std::vector<std::shared_ptr<TestLayer>> layers = {layer}; // expected color for each pixel std::vector<IComposerClient::Color> expectedColors(width * height); for (int row = 0; row < height; row++) { for (int col = 0; col < width; col++) { int pixel = row * width + col; if (row >= coloredSquare.top && row < coloredSquare.bottom && col >= coloredSquare.left && col < coloredSquare.right) { expectedColors[pixel] = color; } else { expectedColors[pixel] = {0, 0, 0, 0xff}; } } } PixelFormat pixelFormat; Dataspace dataspace; Error error; getReadbackBufferAttributes(mPrimaryDisplay, &pixelFormat, &dataspace, &error); IMapper::BufferDescriptorInfo info; info.width = width; info.height = height; info.layerCount = 1; info.format = pixelFormat; info.usage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::GPU_TEXTURE); uint32_t stride; const native_handle_t* buffer = mGralloc->allocate(info, /*import*/ true, &stride); mComposerClient->setReadbackBuffer(mPrimaryDisplay, buffer, -1); render(layers); int32_t fenceHandle; mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fenceHandle); base::unique_fd fence(fenceHandle); // lock buffer // Create Rect accessRegion to specify reading the entire buffer IMapper::Rect accessRegion; accessRegion.left = 0; accessRegion.top = 0; accessRegion.width = info.width; accessRegion.height = info.height; void* bufData = mGralloc->lock(buffer, info.usage, accessRegion, fence); checkReadbackBuffer(info, stride, bufData, expectedColors); } } // anonymous namespace } // namespace vts } // namespace V2_2 } // namespace composer } // namespace graphics } // namespace hardware } // namespace android Loading
graphics/composer/2.1/utils/vts/TestCommandReader.cpp +31 −1 Original line number Diff line number Diff line Loading @@ -26,23 +26,53 @@ namespace V2_1 { namespace vts { void TestCommandReader::parse() { mCompositionChanges.clear(); while (!isEmpty()) { IComposerClient::Command command; uint16_t length; ASSERT_TRUE(beginCommand(&command, &length)); switch (command) { case IComposerClient::Command::SELECT_DISPLAY: ASSERT_EQ(2, length); read64(); // display break; case IComposerClient::Command::SET_ERROR: { ASSERT_EQ(2, length); auto loc = read(); auto err = readSigned(); GTEST_FAIL() << "unexpected error " << err << " at location " << loc; } break; case IComposerClient::Command::SELECT_DISPLAY: case IComposerClient::Command::SET_CHANGED_COMPOSITION_TYPES: ASSERT_EQ(0, length % 3); for (uint16_t count = 0; count < length / 3; ++count) { uint64_t layerId = read64(); uint32_t composition = read(); std::pair<uint64_t, uint32_t> compositionChange(layerId, composition); mCompositionChanges.push_back(compositionChange); } break; case IComposerClient::Command::SET_DISPLAY_REQUESTS: ASSERT_EQ(1, length % 3); read(); // displayRequests, ignored for now for (uint16_t count = 0; count < (length - 1) / 3; ++count) { read64(); // layer // silently eat requests to clear the client target, since we won't be testing // client composition anyway ASSERT_EQ(1u, read()); } break; case IComposerClient::Command::SET_PRESENT_FENCE: ASSERT_EQ(1, length); close(readFence()); break; case IComposerClient::Command::SET_RELEASE_FENCES: ASSERT_EQ(0, length % 3); for (uint16_t count = 0; count < length / 3; ++count) { read64(); close(readFence()); } break; default: GTEST_FAIL() << "unexpected return command " << std::hex Loading
graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h +2 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,8 @@ class TestCommandReader : public CommandReaderBase { // Parse all commands in the return command queue. Call GTEST_FAIL() for // unexpected errors or commands. void parse(); std::vector<std::pair<uint64_t, uint32_t>> mCompositionChanges; }; } // namespace vts Loading
graphics/composer/2.2/utils/vts/ComposerVts.cpp +2 −3 Original line number Diff line number Diff line Loading @@ -138,12 +138,11 @@ void ComposerClient::getReadbackBufferAttributes(Display display, PixelFormat* o } void ComposerClient::getReadbackBufferFence(Display display, int32_t* outFence) { hidl_handle handle; mClient->getReadbackBufferFence(display, [&](const auto& tmpError, const auto& tmpHandle) { ASSERT_EQ(Error::NONE, tmpError) << "failed to get readback fence"; handle = tmpHandle; const native_handle_t* nativeFenceHandle = tmpHandle.getNativeHandle(); *outFence = dup(nativeFenceHandle->data[0]); }); *outFence = 0; } std::vector<ColorMode> ComposerClient::getColorModes(Display display) { Loading
graphics/composer/2.2/vts/functional/Android.bp +5 −2 Original line number Diff line number Diff line Loading @@ -17,7 +17,10 @@ cc_test { name: "VtsHalGraphicsComposerV2_2TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: ["VtsHalGraphicsComposerV2_2TargetTest.cpp"], srcs: [ "VtsHalGraphicsComposerV2_2ReadbackTest.cpp", "VtsHalGraphicsComposerV2_2TargetTest.cpp", ], // TODO(b/64437680): Assume these libs are always available on the device. shared_libs: [ Loading
graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp 0 → 100644 +312 −0 Original line number Diff line number Diff line /* * Copyright 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "graphics_composer_hidl_hal_readback_tests@2.2" #include <VtsHalHidlTargetTestBase.h> #include <VtsHalHidlTargetTestEnvBase.h> #include <android-base/unique_fd.h> #include <android/hardware/graphics/composer/2.2/IComposerClient.h> #include <composer-command-buffer/2.2/ComposerCommandBuffer.h> #include <composer-vts/2.1/GraphicsComposerCallback.h> #include <composer-vts/2.1/TestCommandReader.h> #include <composer-vts/2.2/ComposerVts.h> #include <mapper-vts/2.1/MapperVts.h> namespace android { namespace hardware { namespace graphics { namespace composer { namespace V2_2 { namespace vts { namespace { using android::hardware::hidl_handle; using common::V1_1::BufferUsage; using common::V1_1::Dataspace; using common::V1_1::PixelFormat; using mapper::V2_1::IMapper; using mapper::V2_1::vts::Gralloc; using V2_1::Display; using V2_1::Layer; using V2_1::vts::TestCommandReader; // Test environment for graphics.composer class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { public: // get the test environment singleton static GraphicsComposerHidlEnvironment* Instance() { static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment; return instance; } virtual void registerTestServices() override { registerTestService<IComposer>(); } private: GraphicsComposerHidlEnvironment() {} GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment); }; class TestLayer { public: TestLayer(std::shared_ptr<ComposerClient> const client, Display display) : mLayer(client->createLayer(display, kBufferSlotCount)), mComposerClient(client), mDisplay(display) {} virtual ~TestLayer() { mComposerClient->destroyLayer(mDisplay, mLayer); } virtual void write(std::shared_ptr<CommandWriterBase> writer) { writer->selectLayer(mLayer); writer->setLayerDisplayFrame(mDisplayFrame); writer->setLayerZOrder(mZOrder); } void setDisplayFrame(IComposerClient::Rect frame) { mDisplayFrame = frame; } void setZOrder(uint32_t z) { mZOrder = z; } protected: Layer mLayer; IComposerClient::Rect mDisplayFrame = {0, 0, 0, 0}; uint32_t mZOrder = 0; private: std::shared_ptr<ComposerClient> const mComposerClient; const Display mDisplay; static constexpr uint32_t kBufferSlotCount = 64; }; class TestColorLayer : public TestLayer { public: TestColorLayer(std::shared_ptr<ComposerClient> const client, Display display) : TestLayer{client, display} {} void write(std::shared_ptr<CommandWriterBase> writer) override { TestLayer::write(writer); writer->setLayerCompositionType(IComposerClient::Composition::SOLID_COLOR); writer->setLayerColor(mColor); } void setColor(IComposerClient::Color color) { mColor = color; } private: IComposerClient::Color mColor = {0xff, 0xff, 0xff, 0xff}; }; class GraphicsComposerReadbackTest : public ::testing::VtsHalHidlTargetTestBase { protected: using PowerMode = V2_1::IComposerClient::PowerMode; void SetUp() override { ASSERT_NO_FATAL_FAILURE( mComposer = std::make_unique<Composer>( GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>())); ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient()); mComposerCallback = new V2_1::vts::GraphicsComposerCallback; mComposerClient->registerCallback(mComposerCallback); // assume the first display is primary and is never removed mPrimaryDisplay = waitForFirstDisplay(); Config activeConfig = mComposerClient->getActiveConfig(mPrimaryDisplay); width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, activeConfig, IComposerClient::Attribute::WIDTH); height = mComposerClient->getDisplayAttribute(mPrimaryDisplay, activeConfig, IComposerClient::Attribute::HEIGHT); // explicitly disable vsync mComposerClient->setVsyncEnabled(mPrimaryDisplay, false); mComposerCallback->setVsyncAllowed(false); // set up command writer/reader and gralloc mWriter = std::make_shared<CommandWriterBase>(1024); mReader = std::make_unique<TestCommandReader>(); mGralloc = std::make_unique<Gralloc>(); } ~GraphicsComposerReadbackTest() override { if (mComposerCallback != nullptr) { EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount()); EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount()); EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount()); } } void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); } void render(const std::vector<std::shared_ptr<TestLayer>>& layers) { for (auto layer : layers) { layer->write(mWriter); } execute(); mWriter->validateDisplay(); mWriter->presentDisplay(); execute(); } int32_t GetBytesPerPixel(PixelFormat format) { switch (format) { case PixelFormat::RGBA_8888: return 4; case PixelFormat::RGB_888: return 3; default: return -1; } } bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace, const Error& error) { if (error == Error::UNSUPPORTED) { return false; } // TODO: add support for RGBA_1010102 if (pixelFormat != PixelFormat::RGB_888 && pixelFormat != PixelFormat::RGBA_8888) { return false; } if (dataspace != Dataspace::V0_SRGB) { return false; } return true; } void getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat, Dataspace* outDataspace, Error* outError) { mComposerClient->getRaw()->getReadbackBufferAttributes( display, [&](const auto& tmpError, const auto& tmpOutPixelFormat, const auto& tmpOutDataspace) { *outError = tmpError; *outPixelFormat = tmpOutPixelFormat; *outDataspace = tmpOutDataspace; }); // Not all devices support readback. Pass test if this is the case if (!readbackSupported(*outPixelFormat, *outDataspace, *outError)) { GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; } } void checkReadbackBuffer(IMapper::BufferDescriptorInfo info, uint32_t stride, void* bufferData, std::vector<IComposerClient::Color> expectedColors) { int32_t bytesPerPixel = GetBytesPerPixel(info.format); ASSERT_NE(-1, bytesPerPixel) << "unexpected pixel format " << static_cast<int32_t>(info.format) << "(expected RGBA_8888 or RGB_888)"; for (int row = 0; row < height; row++) { for (int col = 0; col < width; col++) { int pixel = row * width + col; int offset = (row * stride + col) * bytesPerPixel; uint8_t* pixelColor = (uint8_t*)bufferData + offset; EXPECT_EQ(expectedColors[pixel].r, pixelColor[0]); EXPECT_EQ(expectedColors[pixel].g, pixelColor[1]); EXPECT_EQ(expectedColors[pixel].b, pixelColor[2]); } } } std::unique_ptr<Composer> mComposer; std::shared_ptr<ComposerClient> mComposerClient; sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback; // the first display and is assumed never to be removed Display mPrimaryDisplay; int32_t width; int32_t height; std::shared_ptr<CommandWriterBase> mWriter; std::unique_ptr<TestCommandReader> mReader; std::unique_ptr<Gralloc> mGralloc; private: Display waitForFirstDisplay() { while (true) { std::vector<Display> displays = mComposerCallback->getDisplays(); if (displays.empty()) { usleep(5 * 1000); continue; } return displays[0]; } } }; TEST_F(GraphicsComposerReadbackTest, SingleSolidColorLayer) { mWriter->selectDisplay(mPrimaryDisplay); mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON); mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB, RenderIntent::COLORIMETRIC); auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay); IComposerClient::Color color({0, 0, 0xff, 0xff}); IComposerClient::Rect coloredSquare({100, 100, 500, 500}); layer->setColor(color); layer->setDisplayFrame(coloredSquare); layer->setZOrder(10); std::vector<std::shared_ptr<TestLayer>> layers = {layer}; // expected color for each pixel std::vector<IComposerClient::Color> expectedColors(width * height); for (int row = 0; row < height; row++) { for (int col = 0; col < width; col++) { int pixel = row * width + col; if (row >= coloredSquare.top && row < coloredSquare.bottom && col >= coloredSquare.left && col < coloredSquare.right) { expectedColors[pixel] = color; } else { expectedColors[pixel] = {0, 0, 0, 0xff}; } } } PixelFormat pixelFormat; Dataspace dataspace; Error error; getReadbackBufferAttributes(mPrimaryDisplay, &pixelFormat, &dataspace, &error); IMapper::BufferDescriptorInfo info; info.width = width; info.height = height; info.layerCount = 1; info.format = pixelFormat; info.usage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::GPU_TEXTURE); uint32_t stride; const native_handle_t* buffer = mGralloc->allocate(info, /*import*/ true, &stride); mComposerClient->setReadbackBuffer(mPrimaryDisplay, buffer, -1); render(layers); int32_t fenceHandle; mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fenceHandle); base::unique_fd fence(fenceHandle); // lock buffer // Create Rect accessRegion to specify reading the entire buffer IMapper::Rect accessRegion; accessRegion.left = 0; accessRegion.top = 0; accessRegion.width = info.width; accessRegion.height = info.height; void* bufData = mGralloc->lock(buffer, info.usage, accessRegion, fence); checkReadbackBuffer(info, stride, bufData, expectedColors); } } // anonymous namespace } // namespace vts } // namespace V2_2 } // namespace composer } // namespace graphics } // namespace hardware } // namespace android