| // TODO(b/129481165): remove the #pragma below and fix conversion issues |
| #pragma clang diagnostic push |
| #pragma clang diagnostic ignored "-Wconversion" |
| |
| #include <aidl/Gtest.h> |
| #include <aidl/Vintf.h> |
| #include <aidl/android/hardware/graphics/common/BlendMode.h> |
| #include <aidl/android/hardware/graphics/common/BufferUsage.h> |
| #include <aidl/android/hardware/graphics/common/FRect.h> |
| #include <aidl/android/hardware/graphics/common/Rect.h> |
| #include <aidl/android/hardware/graphics/composer3/Composition.h> |
| #include <aidl/android/hardware/graphics/composer3/IComposer.h> |
| #include <android-base/properties.h> |
| #include <android/binder_manager.h> |
| #include <android/binder_process.h> |
| #include <android/hardware/graphics/composer3/command-buffer.h> |
| #include <binder/ProcessState.h> |
| #include <gtest/gtest.h> |
| #include <ui/GraphicBuffer.h> |
| #include <ui/PixelFormat.h> |
| #include <algorithm> |
| #include <numeric> |
| #include <regex> |
| #include <string> |
| #include <thread> |
| #include <unordered_map> |
| #include <unordered_set> |
| #include <utility> |
| #include "composer-vts/include/GraphicsComposerCallback.h" |
| |
| // TODO(b/129481165): remove the #pragma below and fix conversion issues |
| #pragma clang diagnostic pop // ignored "-Wconversion |
| |
| #undef LOG_TAG |
| #define LOG_TAG "VtsHalGraphicsComposer3_TargetTest" |
| |
| namespace aidl::android::hardware::graphics::composer3::vts { |
| namespace { |
| |
| using namespace std::chrono_literals; |
| |
| using ::android::GraphicBuffer; |
| using ::android::sp; |
| |
| class VtsDisplay { |
| public: |
| VtsDisplay(int64_t displayId, int32_t displayWidth, int32_t displayHeight) |
| : mDisplayId(displayId), mDisplayWidth(displayWidth), mDisplayHeight(displayHeight) {} |
| |
| int64_t get() const { return mDisplayId; } |
| |
| FRect getCrop() const { |
| return {0, 0, static_cast<float>(mDisplayWidth), static_cast<float>(mDisplayHeight)}; |
| } |
| |
| Rect getFrameRect() const { return {0, 0, mDisplayWidth, mDisplayHeight}; } |
| |
| void setDimensions(int32_t displayWidth, int32_t displayHeight) { |
| mDisplayWidth = displayWidth; |
| mDisplayHeight = displayHeight; |
| } |
| |
| private: |
| const int64_t mDisplayId; |
| int32_t mDisplayWidth; |
| int32_t mDisplayHeight; |
| }; |
| |
| class GraphicsComposerAidlTest : public ::testing::TestWithParam<std::string> { |
| protected: |
| void SetUp() override { |
| std::string name = GetParam(); |
| ndk::SpAIBinder binder(AServiceManager_waitForService(name.c_str())); |
| ASSERT_NE(binder, nullptr); |
| ASSERT_NO_FATAL_FAILURE(mComposer = IComposer::fromBinder(binder)); |
| ASSERT_NE(mComposer, nullptr); |
| ASSERT_NO_FATAL_FAILURE(mComposer->createClient(&mComposerClient)); |
| |
| mComposerCallback = ::ndk::SharedRefBase::make<GraphicsComposerCallback>(); |
| EXPECT_TRUE(mComposerClient->registerCallback(mComposerCallback).isOk()); |
| |
| // assume the first displays are built-in and are never removed |
| mDisplays = waitForDisplays(); |
| mPrimaryDisplay = mDisplays[0].get(); |
| ASSERT_NO_FATAL_FAILURE(mInvalidDisplayId = GetInvalidDisplayId()); |
| |
| int32_t activeConfig; |
| EXPECT_TRUE(mComposerClient->getActiveConfig(mPrimaryDisplay, &activeConfig).isOk()); |
| EXPECT_TRUE(mComposerClient |
| ->getDisplayAttribute(mPrimaryDisplay, activeConfig, |
| DisplayAttribute::WIDTH, &mDisplayWidth) |
| .isOk()); |
| EXPECT_TRUE(mComposerClient |
| ->getDisplayAttribute(mPrimaryDisplay, activeConfig, |
| DisplayAttribute::HEIGHT, &mDisplayHeight) |
| .isOk()); |
| |
| // explicitly disable vsync |
| for (const auto& display : mDisplays) { |
| EXPECT_TRUE(mComposerClient->setVsyncEnabled(display.get(), false).isOk()); |
| } |
| mComposerCallback->setVsyncAllowed(false); |
| } |
| |
| void TearDown() override { |
| destroyAllLayers(); |
| if (mComposerCallback != nullptr) { |
| EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount()); |
| EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount()); |
| EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount()); |
| EXPECT_EQ(0, mComposerCallback->getInvalidVsyncPeriodChangeCount()); |
| EXPECT_EQ(0, mComposerCallback->getInvalidSeamlessPossibleCount()); |
| } |
| } |
| |
| void Test_setContentTypeForDisplay(const int64_t& display, |
| const std::vector<ContentType>& capabilities, |
| const ContentType& contentType, const char* contentTypeStr) { |
| const bool contentTypeSupport = std::find(capabilities.begin(), capabilities.end(), |
| contentType) != capabilities.end(); |
| |
| if (!contentTypeSupport) { |
| EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, |
| mComposerClient->setContentType(display, contentType) |
| .getServiceSpecificError()); |
| GTEST_SUCCEED() << contentTypeStr << " content type is not supported on display " |
| << std::to_string(display) << ", skipping test"; |
| return; |
| } |
| |
| EXPECT_TRUE(mComposerClient->setContentType(display, contentType).isOk()); |
| EXPECT_TRUE(mComposerClient->setContentType(display, ContentType::NONE).isOk()); |
| } |
| |
| void Test_setContentType(const ContentType& contentType, const char* contentTypeStr) { |
| for (const auto& display : mDisplays) { |
| std::vector<ContentType> supportedContentTypes; |
| const auto error = mComposerClient->getSupportedContentTypes(display.get(), |
| &supportedContentTypes); |
| EXPECT_TRUE(error.isOk()); |
| |
| Test_setContentTypeForDisplay(display.get(), supportedContentTypes, contentType, |
| contentTypeStr); |
| } |
| } |
| |
| int64_t createLayer(const VtsDisplay& display) { |
| int64_t layer; |
| EXPECT_TRUE(mComposerClient->createLayer(display.get(), kBufferSlotCount, &layer).isOk()); |
| |
| auto resourceIt = mDisplayResources.find(display.get()); |
| if (resourceIt == mDisplayResources.end()) { |
| resourceIt = mDisplayResources.insert({display.get(), DisplayResource(false)}).first; |
| } |
| |
| EXPECT_TRUE(resourceIt->second.layers.insert(layer).second) |
| << "duplicated layer id " << layer; |
| |
| return layer; |
| } |
| |
| void destroyAllLayers() { |
| for (const auto& it : mDisplayResources) { |
| auto display = it.first; |
| const DisplayResource& resource = it.second; |
| |
| for (auto layer : resource.layers) { |
| const auto error = mComposerClient->destroyLayer(display, layer); |
| EXPECT_TRUE(error.isOk()); |
| } |
| |
| if (resource.isVirtual) { |
| const auto error = mComposerClient->destroyVirtualDisplay(display); |
| EXPECT_TRUE(error.isOk()); |
| } |
| } |
| mDisplayResources.clear(); |
| } |
| |
| void destroyLayer(const VtsDisplay& display, int64_t layer) { |
| auto const error = mComposerClient->destroyLayer(display.get(), layer); |
| ASSERT_TRUE(error.isOk()) << "failed to destroy layer " << layer; |
| |
| auto resourceIt = mDisplayResources.find(display.get()); |
| ASSERT_NE(mDisplayResources.end(), resourceIt); |
| resourceIt->second.layers.erase(layer); |
| } |
| |
| // returns an invalid display id (one that has not been registered to a |
| // display. Currently assuming that a device will never have close to |
| // std::numeric_limit<uint64_t>::max() displays registered while running tests |
| int64_t GetInvalidDisplayId() { |
| int64_t id = std::numeric_limits<int64_t>::max(); |
| while (id > 0) { |
| if (std::none_of(mDisplays.begin(), mDisplays.end(), |
| [&](const VtsDisplay& display) { return id == display.get(); })) { |
| return id; |
| } |
| id--; |
| } |
| |
| // Although 0 could be an invalid display, a return value of 0 |
| // from GetInvalidDisplayId means all other ids are in use, a condition which |
| // we are assuming a device will never have |
| EXPECT_NE(0, id); |
| return id; |
| } |
| |
| std::vector<VtsDisplay> waitForDisplays() { |
| while (true) { |
| // Sleep for a small period of time to allow all built-in displays |
| // to post hotplug events |
| std::this_thread::sleep_for(5ms); |
| std::vector<int64_t> displays = mComposerCallback->getDisplays(); |
| if (displays.empty()) { |
| continue; |
| } |
| |
| std::vector<VtsDisplay> vtsDisplays; |
| vtsDisplays.reserve(displays.size()); |
| for (int64_t display : displays) { |
| int32_t activeConfig; |
| EXPECT_TRUE(mComposerClient->getActiveConfig(display, &activeConfig).isOk()); |
| int32_t displayWidth; |
| EXPECT_TRUE(mComposerClient |
| ->getDisplayAttribute(display, activeConfig, |
| DisplayAttribute::WIDTH, &displayWidth) |
| .isOk()); |
| int32_t displayHeight; |
| EXPECT_TRUE(mComposerClient |
| ->getDisplayAttribute(display, activeConfig, |
| DisplayAttribute::HEIGHT, &displayHeight) |
| .isOk()); |
| vtsDisplays.emplace_back(VtsDisplay{display, displayWidth, displayHeight}); |
| } |
| |
| return vtsDisplays; |
| } |
| } |
| |
| // returns an invalid config id which is std::numeric_limit<int32_t>::max() |
| int32_t GetInvalidConfigId() { return IComposerClient::INVALID_CONFIGURATION; } |
| |
| ndk::ScopedAStatus setActiveConfigWithConstraints( |
| VtsDisplay& display, int32_t config, const VsyncPeriodChangeConstraints& constraints, |
| VsyncPeriodChangeTimeline* timeline) { |
| auto error = mComposerClient->setActiveConfigWithConstraints(display.get(), config, |
| constraints, timeline); |
| if (error.isOk()) { |
| int32_t displayWidth; |
| EXPECT_TRUE(mComposerClient |
| ->getDisplayAttribute(display.get(), config, |
| DisplayAttribute::WIDTH, &displayWidth) |
| .isOk()); |
| int32_t displayHeight; |
| EXPECT_TRUE(mComposerClient |
| ->getDisplayAttribute(display.get(), config, |
| DisplayAttribute::HEIGHT, &displayHeight) |
| .isOk()); |
| display.setDimensions(displayWidth, displayHeight); |
| } |
| return error; |
| } |
| |
| struct TestParameters { |
| nsecs_t delayForChange; |
| bool refreshMiss; |
| }; |
| |
| // Keep track of all virtual displays and layers. When a test fails with |
| // ASSERT_*, the destructor will clean up the resources for the test. |
| struct DisplayResource { |
| DisplayResource(bool isVirtual_) : isVirtual(isVirtual_) {} |
| |
| bool isVirtual; |
| std::unordered_set<int64_t> layers; |
| }; |
| |
| std::shared_ptr<IComposer> mComposer; |
| std::shared_ptr<IComposerClient> mComposerClient; |
| int64_t mInvalidDisplayId; |
| int64_t mPrimaryDisplay; |
| std::vector<VtsDisplay> mDisplays; |
| std::shared_ptr<GraphicsComposerCallback> mComposerCallback; |
| // use the slot count usually set by SF |
| static constexpr uint32_t kBufferSlotCount = 64; |
| std::unordered_map<int64_t, DisplayResource> mDisplayResources; |
| int32_t mDisplayWidth; |
| int32_t mDisplayHeight; |
| }; |
| |
| TEST_P(GraphicsComposerAidlTest, getDisplayCapabilitiesBadDisplay) { |
| std::vector<DisplayCapability> capabilities; |
| const auto error = mComposerClient->getDisplayCapabilities(mInvalidDisplayId, &capabilities); |
| |
| EXPECT_FALSE(error.isOk()); |
| EXPECT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, getDisplayCapabilities) { |
| for (const auto& display : mDisplays) { |
| std::vector<DisplayCapability> capabilities; |
| |
| EXPECT_TRUE(mComposerClient->getDisplayCapabilities(display.get(), &capabilities).isOk()); |
| } |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, DumpDebugInfo) { |
| std::string debugInfo; |
| EXPECT_TRUE(mComposer->dumpDebugInfo(&debugInfo).isOk()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, CreateClientSingleton) { |
| std::shared_ptr<IComposerClient> composerClient; |
| const auto error = mComposer->createClient(&composerClient); |
| |
| EXPECT_FALSE(error.isOk()); |
| EXPECT_EQ(IComposerClient::EX_NO_RESOURCES, error.getServiceSpecificError()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, GetDisplayIdentificationData) { |
| DisplayIdentification displayIdentification0; |
| |
| const auto error = |
| mComposerClient->getDisplayIdentificationData(mPrimaryDisplay, &displayIdentification0); |
| if (error.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED) { |
| return; |
| } |
| ASSERT_TRUE(error.isOk()) << "failed to get display identification data"; |
| ASSERT_FALSE(displayIdentification0.data.empty()); |
| |
| constexpr size_t kEdidBlockSize = 128; |
| ASSERT_TRUE(displayIdentification0.data.size() % kEdidBlockSize == 0) |
| << "EDID blob length is not a multiple of " << kEdidBlockSize; |
| |
| const uint8_t kEdidHeader[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; |
| ASSERT_TRUE(std::equal(std::begin(kEdidHeader), std::end(kEdidHeader), |
| displayIdentification0.data.begin())) |
| << "EDID blob doesn't start with the fixed EDID header"; |
| ASSERT_EQ(0, std::accumulate(displayIdentification0.data.begin(), |
| displayIdentification0.data.begin() + kEdidBlockSize, |
| static_cast<uint8_t>(0))) |
| << "EDID base block doesn't checksum"; |
| |
| DisplayIdentification displayIdentification1; |
| ASSERT_TRUE( |
| mComposerClient->getDisplayIdentificationData(mPrimaryDisplay, &displayIdentification1) |
| .isOk()); |
| |
| ASSERT_EQ(displayIdentification0.port, displayIdentification1.port) << "ports are not stable"; |
| ASSERT_TRUE(displayIdentification0.data.size() == displayIdentification1.data.size() && |
| std::equal(displayIdentification0.data.begin(), displayIdentification0.data.end(), |
| displayIdentification1.data.begin())) |
| << "data is not stable"; |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, GetHdrCapabilities) { |
| HdrCapabilities hdrCapabilities; |
| const auto error = mComposerClient->getHdrCapabilities(mPrimaryDisplay, &hdrCapabilities); |
| |
| ASSERT_TRUE(error.isOk()); |
| ASSERT_TRUE(hdrCapabilities.maxLuminance >= hdrCapabilities.minLuminance); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, GetPerFrameMetadataKeys) { |
| std::vector<PerFrameMetadataKey> keys; |
| const auto error = mComposerClient->getPerFrameMetadataKeys(mPrimaryDisplay, &keys); |
| |
| if (error.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED) { |
| GTEST_SUCCEED() << "getPerFrameMetadataKeys is not supported"; |
| return; |
| } |
| EXPECT_TRUE(error.isOk()); |
| ASSERT_TRUE(keys.size() >= 0); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, GetReadbackBufferAttributes) { |
| ReadbackBufferAttributes readBackBufferAttributes; |
| const auto error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, |
| &readBackBufferAttributes); |
| |
| if (error.isOk()) { |
| EXPECT_EQ(EX_NONE, error.getServiceSpecificError()); |
| } |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, GetRenderIntents) { |
| std::vector<ColorMode> modes; |
| EXPECT_TRUE(mComposerClient->getColorModes(mPrimaryDisplay, &modes).isOk()); |
| for (auto mode : modes) { |
| std::vector<RenderIntent> intents; |
| EXPECT_TRUE(mComposerClient->getRenderIntents(mPrimaryDisplay, mode, &intents).isOk()); |
| |
| bool isHdr; |
| switch (mode) { |
| case ColorMode::BT2100_PQ: |
| case ColorMode::BT2100_HLG: |
| isHdr = true; |
| break; |
| default: |
| isHdr = false; |
| break; |
| } |
| RenderIntent requiredIntent = |
| isHdr ? RenderIntent::TONE_MAP_COLORIMETRIC : RenderIntent::COLORIMETRIC; |
| |
| auto iter = std::find(intents.cbegin(), intents.cend(), requiredIntent); |
| EXPECT_NE(intents.cend(), iter); |
| } |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, GetRenderIntentsBadDisplay) { |
| std::vector<ColorMode> modes; |
| EXPECT_TRUE(mComposerClient->getColorModes(mPrimaryDisplay, &modes).isOk()); |
| for (auto mode : modes) { |
| std::vector<RenderIntent> renderIntents; |
| const auto error = |
| mComposerClient->getRenderIntents(mInvalidDisplayId, mode, &renderIntents); |
| EXPECT_FALSE(error.isOk()); |
| EXPECT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError()); |
| } |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, GetRenderIntentsBadParameter) { |
| std::vector<RenderIntent> renderIntents; |
| const auto error = mComposerClient->getRenderIntents( |
| mPrimaryDisplay, static_cast<ColorMode>(-1), &renderIntents); |
| EXPECT_FALSE(error.isOk()); |
| EXPECT_EQ(IComposerClient::EX_BAD_PARAMETER, error.getServiceSpecificError()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, GetColorModes) { |
| std::vector<ColorMode> colorModes; |
| EXPECT_TRUE(mComposerClient->getColorModes(mPrimaryDisplay, &colorModes).isOk()); |
| |
| auto native = std::find(colorModes.cbegin(), colorModes.cend(), ColorMode::NATIVE); |
| ASSERT_NE(colorModes.cend(), native); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, GetColorModeBadDisplay) { |
| std::vector<ColorMode> colorModes; |
| const auto error = mComposerClient->getColorModes(mInvalidDisplayId, &colorModes); |
| |
| EXPECT_FALSE(error.isOk()); |
| EXPECT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, SetColorMode) { |
| std::vector<ColorMode> colorModes; |
| EXPECT_TRUE(mComposerClient->getColorModes(mPrimaryDisplay, &colorModes).isOk()); |
| for (auto mode : colorModes) { |
| std::vector<RenderIntent> intents; |
| EXPECT_TRUE(mComposerClient->getRenderIntents(mPrimaryDisplay, mode, &intents).isOk()) |
| << "failed to get render intents"; |
| for (auto intent : intents) { |
| const auto error = mComposerClient->setColorMode(mPrimaryDisplay, mode, intent); |
| EXPECT_TRUE(error.isOk() || |
| IComposerClient::EX_UNSUPPORTED == error.getServiceSpecificError()) |
| << "failed to set color mode"; |
| } |
| } |
| |
| const auto error = mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::NATIVE, |
| RenderIntent::COLORIMETRIC); |
| EXPECT_TRUE(error.isOk() || IComposerClient::EX_UNSUPPORTED == error.getServiceSpecificError()) |
| << "failed to set color mode"; |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, SetColorModeBadDisplay) { |
| std::vector<ColorMode> colorModes; |
| EXPECT_TRUE(mComposerClient->getColorModes(mPrimaryDisplay, &colorModes).isOk()); |
| for (auto mode : colorModes) { |
| std::vector<RenderIntent> intents; |
| EXPECT_TRUE(mComposerClient->getRenderIntents(mPrimaryDisplay, mode, &intents).isOk()) |
| << "failed to get render intents"; |
| for (auto intent : intents) { |
| auto const error = mComposerClient->setColorMode(mInvalidDisplayId, mode, intent); |
| |
| EXPECT_FALSE(error.isOk()); |
| ASSERT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError()); |
| } |
| } |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, SetColorModeBadParameter) { |
| const auto colorModeError = mComposerClient->setColorMode( |
| mPrimaryDisplay, static_cast<ColorMode>(-1), RenderIntent::COLORIMETRIC); |
| |
| EXPECT_FALSE(colorModeError.isOk()); |
| EXPECT_EQ(IComposerClient::EX_BAD_PARAMETER, colorModeError.getServiceSpecificError()); |
| |
| const auto renderIntentError = mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::NATIVE, |
| static_cast<RenderIntent>(-1)); |
| |
| EXPECT_FALSE(renderIntentError.isOk()); |
| EXPECT_EQ(IComposerClient::EX_BAD_PARAMETER, renderIntentError.getServiceSpecificError()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, GetDisplayedContentSamplingAttributes) { |
| int constexpr invalid = -1; |
| |
| DisplayContentSamplingAttributes format; |
| auto error = mComposerClient->getDisplayedContentSamplingAttributes(mPrimaryDisplay, &format); |
| |
| if (error.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED) { |
| SUCCEED() << "Device does not support optional extension. Test skipped"; |
| return; |
| } |
| |
| EXPECT_TRUE(error.isOk()); |
| EXPECT_NE(format.format, static_cast<common::PixelFormat>(invalid)); |
| EXPECT_NE(format.dataspace, static_cast<common::Dataspace>(invalid)); |
| EXPECT_NE(format.componentMask, static_cast<FormatColorComponent>(invalid)); |
| }; |
| |
| TEST_P(GraphicsComposerAidlTest, SetDisplayedContentSamplingEnabled) { |
| auto const maxFrames = 10; |
| FormatColorComponent enableAllComponents = FormatColorComponent::FORMAT_COMPONENT_0; |
| auto error = mComposerClient->setDisplayedContentSamplingEnabled( |
| mPrimaryDisplay, true, enableAllComponents, maxFrames); |
| if (error.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED) { |
| SUCCEED() << "Device does not support optional extension. Test skipped"; |
| return; |
| } |
| EXPECT_TRUE(error.isOk()); |
| |
| error = mComposerClient->setDisplayedContentSamplingEnabled(mPrimaryDisplay, false, |
| enableAllComponents, maxFrames); |
| EXPECT_TRUE(error.isOk()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, GetDisplayedContentSample) { |
| DisplayContentSamplingAttributes displayContentSamplingAttributes; |
| int constexpr invalid = -1; |
| displayContentSamplingAttributes.format = static_cast<common::PixelFormat>(invalid); |
| displayContentSamplingAttributes.dataspace = static_cast<common::Dataspace>(invalid); |
| displayContentSamplingAttributes.componentMask = static_cast<FormatColorComponent>(invalid); |
| auto error = mComposerClient->getDisplayedContentSamplingAttributes( |
| mPrimaryDisplay, &displayContentSamplingAttributes); |
| if (error.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED) { |
| SUCCEED() << "Sampling attributes aren't supported on this device, test skipped"; |
| return; |
| } |
| |
| int64_t maxFrames = 10; |
| int64_t timestamp = 0; |
| int64_t frameCount = 0; |
| DisplayContentSample displayContentSample; |
| error = mComposerClient->getDisplayedContentSample(mPrimaryDisplay, maxFrames, timestamp, |
| &displayContentSample); |
| if (error.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED) { |
| SUCCEED() << "Device does not support optional extension. Test skipped"; |
| return; |
| } |
| |
| EXPECT_TRUE(error.isOk()); |
| EXPECT_LE(frameCount, maxFrames); |
| std::vector<std::vector<int64_t>> histogram = { |
| displayContentSample.sampleComponent0, displayContentSample.sampleComponent1, |
| displayContentSample.sampleComponent2, displayContentSample.sampleComponent3}; |
| |
| for (size_t i = 0; i < histogram.size(); i++) { |
| const bool shouldHaveHistogram = |
| static_cast<int>(displayContentSamplingAttributes.componentMask) & (1 << i); |
| EXPECT_EQ(shouldHaveHistogram, !histogram[i].empty()); |
| } |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, getDisplayCapabilitiesBasic) { |
| std::vector<DisplayCapability> capabilities; |
| const auto error = mComposerClient->getDisplayCapabilities(mPrimaryDisplay, &capabilities); |
| ASSERT_TRUE(error.isOk()); |
| const bool hasDozeSupport = std::find(capabilities.begin(), capabilities.end(), |
| DisplayCapability::DOZE) != capabilities.end(); |
| bool isDozeSupported = false; |
| EXPECT_TRUE(mComposerClient->getDozeSupport(mPrimaryDisplay, &isDozeSupported).isOk()); |
| EXPECT_EQ(hasDozeSupport, isDozeSupported); |
| |
| bool hasBrightnessSupport = std::find(capabilities.begin(), capabilities.end(), |
| DisplayCapability::BRIGHTNESS) != capabilities.end(); |
| bool isBrightnessSupported = false; |
| EXPECT_TRUE( |
| mComposerClient->getDisplayBrightnessSupport(mPrimaryDisplay, &isBrightnessSupported) |
| .isOk()); |
| EXPECT_EQ(isBrightnessSupported, hasBrightnessSupport); |
| } |
| |
| /* |
| * Test that if brightness operations are supported, setDisplayBrightness works as expected. |
| */ |
| TEST_P(GraphicsComposerAidlTest, setDisplayBrightness) { |
| std::vector<DisplayCapability> capabilities; |
| auto error = mComposerClient->getDisplayCapabilities(mPrimaryDisplay, &capabilities); |
| ASSERT_TRUE(error.isOk()); |
| bool brightnessSupport = std::find(capabilities.begin(), capabilities.end(), |
| DisplayCapability::BRIGHTNESS) != capabilities.end(); |
| if (!brightnessSupport) { |
| EXPECT_EQ(mComposerClient->setDisplayBrightness(mPrimaryDisplay, 0.5f) |
| .getServiceSpecificError(), |
| IComposerClient::EX_UNSUPPORTED); |
| GTEST_SUCCEED() << "Brightness operations are not supported"; |
| return; |
| } |
| |
| EXPECT_TRUE(mComposerClient->setDisplayBrightness(mPrimaryDisplay, 0.0f).isOk()); |
| EXPECT_TRUE(mComposerClient->setDisplayBrightness(mPrimaryDisplay, 0.5f).isOk()); |
| EXPECT_TRUE(mComposerClient->setDisplayBrightness(mPrimaryDisplay, 1.0f).isOk()); |
| EXPECT_TRUE(mComposerClient->setDisplayBrightness(mPrimaryDisplay, -1.0f).isOk()); |
| |
| error = mComposerClient->setDisplayBrightness(mPrimaryDisplay, +2.0f); |
| EXPECT_FALSE(error.isOk()); |
| EXPECT_EQ(error.getServiceSpecificError(), IComposerClient::EX_BAD_PARAMETER); |
| |
| error = mComposerClient->setDisplayBrightness(mPrimaryDisplay, -2.0f); |
| EXPECT_FALSE(error.isOk()); |
| EXPECT_EQ(error.getServiceSpecificError(), IComposerClient::EX_BAD_PARAMETER); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, getDisplayConnectionType) { |
| DisplayConnectionType type; |
| EXPECT_FALSE(mComposerClient->getDisplayConnectionType(mInvalidDisplayId, &type).isOk()); |
| for (const auto& display : mDisplays) { |
| EXPECT_TRUE(mComposerClient->getDisplayConnectionType(display.get(), &type).isOk()); |
| } |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, getDisplayAttribute) { |
| for (const auto& display : mDisplays) { |
| std::vector<int32_t> configs; |
| EXPECT_TRUE(mComposerClient->getDisplayConfigs(display.get(), &configs).isOk()); |
| for (const auto& config : configs) { |
| const std::array<DisplayAttribute, 4> requiredAttributes = {{ |
| DisplayAttribute::WIDTH, |
| DisplayAttribute::HEIGHT, |
| DisplayAttribute::VSYNC_PERIOD, |
| DisplayAttribute::CONFIG_GROUP, |
| }}; |
| int32_t value; |
| for (const auto& attribute : requiredAttributes) { |
| EXPECT_TRUE(mComposerClient |
| ->getDisplayAttribute(display.get(), config, attribute, &value) |
| .isOk()); |
| EXPECT_NE(-1, value); |
| } |
| |
| const std::array<DisplayAttribute, 2> optionalAttributes = {{ |
| DisplayAttribute::DPI_X, |
| DisplayAttribute::DPI_Y, |
| }}; |
| for (const auto& attribute : optionalAttributes) { |
| const auto error = mComposerClient->getDisplayAttribute(display.get(), config, |
| attribute, &value); |
| if (error.isOk()) { |
| EXPECT_EQ(EX_NONE, error.getServiceSpecificError()); |
| } else { |
| EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, error.getServiceSpecificError()); |
| } |
| } |
| } |
| } |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, checkConfigsAreValid) { |
| for (const auto& display : mDisplays) { |
| std::vector<int32_t> configs; |
| EXPECT_TRUE(mComposerClient->getDisplayConfigs(display.get(), &configs).isOk()); |
| |
| EXPECT_FALSE(std::any_of(configs.begin(), configs.end(), [](auto config) { |
| return config == IComposerClient::INVALID_CONFIGURATION; |
| })); |
| } |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, getDisplayAttributeConfigsInAGroupDifferOnlyByVsyncPeriod) { |
| struct Resolution { |
| int32_t width; |
| int32_t height; |
| }; |
| struct Dpi { |
| int32_t x; |
| int32_t y; |
| }; |
| for (const auto& display : mDisplays) { |
| std::vector<int32_t> configs; |
| EXPECT_TRUE(mComposerClient->getDisplayConfigs(display.get(), &configs).isOk()); |
| std::unordered_map<int32_t, Resolution> configGroupToResolutionMap; |
| std::unordered_map<int32_t, Dpi> configGroupToDpiMap; |
| for (const auto& config : configs) { |
| int32_t configGroup = -1; |
| EXPECT_TRUE(mComposerClient |
| ->getDisplayAttribute(display.get(), config, |
| DisplayAttribute::CONFIG_GROUP, &configGroup) |
| .isOk()); |
| int32_t width = -1; |
| EXPECT_TRUE(mComposerClient |
| ->getDisplayAttribute(display.get(), config, |
| DisplayAttribute::WIDTH, &width) |
| .isOk()); |
| int32_t height = -1; |
| EXPECT_TRUE(mComposerClient |
| ->getDisplayAttribute(display.get(), config, |
| DisplayAttribute::HEIGHT, &height) |
| .isOk()); |
| if (configGroupToResolutionMap.find(configGroup) == configGroupToResolutionMap.end()) { |
| configGroupToResolutionMap[configGroup] = {width, height}; |
| } |
| EXPECT_EQ(configGroupToResolutionMap[configGroup].width, width); |
| EXPECT_EQ(configGroupToResolutionMap[configGroup].height, height); |
| |
| int32_t dpiX = -1; |
| mComposerClient->getDisplayAttribute(display.get(), config, DisplayAttribute::DPI_X, |
| &dpiX); |
| |
| int32_t dpiY = -1; |
| mComposerClient->getDisplayAttribute(display.get(), config, DisplayAttribute::DPI_Y, |
| &dpiY); |
| if (dpiX == -1 && dpiY == -1) { |
| continue; |
| } |
| |
| if (configGroupToDpiMap.find(configGroup) == configGroupToDpiMap.end()) { |
| configGroupToDpiMap[configGroup] = {dpiX, dpiY}; |
| } |
| EXPECT_EQ(configGroupToDpiMap[configGroup].x, dpiX); |
| EXPECT_EQ(configGroupToDpiMap[configGroup].y, dpiY); |
| } |
| } |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, getDisplayVsyncPeriod_BadDisplay) { |
| int32_t vsyncPeriodNanos; |
| const auto error = mComposerClient->getDisplayVsyncPeriod(mInvalidDisplayId, &vsyncPeriodNanos); |
| EXPECT_FALSE(error.isOk()); |
| EXPECT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, setActiveConfigWithConstraints_BadDisplay) { |
| VsyncPeriodChangeTimeline timeline; |
| VsyncPeriodChangeConstraints constraints; |
| |
| constraints.seamlessRequired = false; |
| constraints.desiredTimeNanos = systemTime(); |
| int32_t config = 0; |
| auto const error = mComposerClient->setActiveConfigWithConstraints(mInvalidDisplayId, config, |
| constraints, &timeline); |
| |
| EXPECT_FALSE(error.isOk()); |
| EXPECT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, setActiveConfigWithConstraints_BadConfig) { |
| VsyncPeriodChangeTimeline timeline; |
| VsyncPeriodChangeConstraints constraints; |
| |
| constraints.seamlessRequired = false; |
| constraints.desiredTimeNanos = systemTime(); |
| |
| for (VtsDisplay& display : mDisplays) { |
| int32_t invalidConfigId = GetInvalidConfigId(); |
| const auto error = |
| setActiveConfigWithConstraints(display, invalidConfigId, constraints, &timeline); |
| EXPECT_FALSE(error.isOk()); |
| EXPECT_EQ(IComposerClient::EX_BAD_CONFIG, error.getServiceSpecificError()); |
| } |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, setAutoLowLatencyModeBadDisplay) { |
| EXPECT_EQ(IComposerClient::EX_BAD_DISPLAY, |
| mComposerClient->setAutoLowLatencyMode(mInvalidDisplayId, true) |
| .getServiceSpecificError()); |
| EXPECT_EQ(IComposerClient::EX_BAD_DISPLAY, |
| mComposerClient->setAutoLowLatencyMode(mInvalidDisplayId, false) |
| .getServiceSpecificError()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, setAutoLowLatencyMode) { |
| for (const auto& display : mDisplays) { |
| std::vector<DisplayCapability> capabilities; |
| const auto error = mComposerClient->getDisplayCapabilities(display.get(), &capabilities); |
| EXPECT_TRUE(error.isOk()); |
| |
| const bool allmSupport = |
| std::find(capabilities.begin(), capabilities.end(), |
| DisplayCapability::AUTO_LOW_LATENCY_MODE) != capabilities.end(); |
| |
| if (!allmSupport) { |
| const auto errorIsOn = mComposerClient->setAutoLowLatencyMode(display.get(), true); |
| EXPECT_FALSE(errorIsOn.isOk()); |
| EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, errorIsOn.getServiceSpecificError()); |
| const auto errorIsOff = mComposerClient->setAutoLowLatencyMode(display.get(), false); |
| EXPECT_FALSE(errorIsOff.isOk()); |
| EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, errorIsOff.getServiceSpecificError()); |
| GTEST_SUCCEED() << "Auto Low Latency Mode is not supported on display " |
| << std::to_string(display.get()) << ", skipping test"; |
| return; |
| } |
| |
| EXPECT_TRUE(mComposerClient->setAutoLowLatencyMode(display.get(), true).isOk()); |
| EXPECT_TRUE(mComposerClient->setAutoLowLatencyMode(display.get(), false).isOk()); |
| } |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, getSupportedContentTypesBadDisplay) { |
| std::vector<ContentType> supportedContentTypes; |
| const auto error = |
| mComposerClient->getSupportedContentTypes(mInvalidDisplayId, &supportedContentTypes); |
| EXPECT_FALSE(error.isOk()); |
| EXPECT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, getSupportedContentTypes) { |
| std::vector<ContentType> supportedContentTypes; |
| for (const auto& display : mDisplays) { |
| supportedContentTypes.clear(); |
| const auto error = |
| mComposerClient->getSupportedContentTypes(display.get(), &supportedContentTypes); |
| |
| ASSERT_TRUE(error.isOk()); |
| |
| const bool noneSupported = |
| std::find(supportedContentTypes.begin(), supportedContentTypes.end(), |
| ContentType::NONE) != supportedContentTypes.end(); |
| EXPECT_FALSE(noneSupported); |
| } |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, setContentTypeNoneAlwaysAccepted) { |
| for (const auto& display : mDisplays) { |
| const auto error = mComposerClient->setContentType(display.get(), ContentType::NONE); |
| EXPECT_TRUE(error.isOk()); |
| } |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, setContentTypeBadDisplay) { |
| constexpr ContentType types[] = {ContentType::NONE, ContentType::GRAPHICS, ContentType::PHOTO, |
| ContentType::CINEMA, ContentType::GAME}; |
| for (const auto& type : types) { |
| auto const error = mComposerClient->setContentType(mInvalidDisplayId, type); |
| |
| EXPECT_FALSE(error.isOk()); |
| EXPECT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError()); |
| } |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, setGraphicsContentType) { |
| Test_setContentType(ContentType::GRAPHICS, "GRAPHICS"); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, setPhotoContentType) { |
| Test_setContentType(ContentType::PHOTO, "PHOTO"); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, setCinemaContentType) { |
| Test_setContentType(ContentType::CINEMA, "CINEMA"); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, setGameContentType) { |
| Test_setContentType(ContentType::GAME, "GAME"); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, getLayerGenericMetadataKeys) { |
| std::vector<LayerGenericMetadataKey> keys; |
| EXPECT_TRUE(mComposerClient->getLayerGenericMetadataKeys(&keys).isOk()); |
| |
| std::regex reverseDomainName("^[a-zA-Z-]{2,}(\\.[a-zA-Z0-9-]+)+$"); |
| std::unordered_set<std::string> uniqueNames; |
| for (const auto& key : keys) { |
| std::string name(key.name); |
| |
| // Keys must not start with 'android' or 'com.android' |
| EXPECT_FALSE(name.find("android") == 0); |
| EXPECT_FALSE(name.find("com.android") == 0); |
| |
| // Keys must be in reverse domain name format |
| EXPECT_TRUE(std::regex_match(name, reverseDomainName)); |
| |
| // Keys must be unique within this list |
| const auto& [iter, inserted] = uniqueNames.insert(name); |
| EXPECT_TRUE(inserted); |
| } |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, CreateVirtualDisplay) { |
| int32_t maxVirtualDisplayCount; |
| EXPECT_TRUE(mComposerClient->getMaxVirtualDisplayCount(&maxVirtualDisplayCount).isOk()); |
| if (maxVirtualDisplayCount == 0) { |
| GTEST_SUCCEED() << "no virtual display support"; |
| return; |
| } |
| |
| VirtualDisplay virtualDisplay; |
| |
| EXPECT_TRUE(mComposerClient |
| ->createVirtualDisplay(64, 64, common::PixelFormat::IMPLEMENTATION_DEFINED, |
| kBufferSlotCount, &virtualDisplay) |
| .isOk()); |
| |
| ASSERT_TRUE(mDisplayResources.insert({virtualDisplay.display, DisplayResource(true)}).second) |
| << "duplicated virtual display id " << virtualDisplay.display; |
| |
| EXPECT_TRUE(mComposerClient->destroyVirtualDisplay(virtualDisplay.display).isOk()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, DestroyVirtualDisplayBadDisplay) { |
| int32_t maxDisplayCount = 0; |
| EXPECT_TRUE(mComposerClient->getMaxVirtualDisplayCount(&maxDisplayCount).isOk()); |
| if (maxDisplayCount == 0) { |
| GTEST_SUCCEED() << "no virtual display support"; |
| return; |
| } |
| const auto error = mComposerClient->destroyVirtualDisplay(mInvalidDisplayId); |
| |
| EXPECT_FALSE(error.isOk()); |
| ASSERT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, CreateLayer) { |
| int64_t layer; |
| EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk()); |
| |
| EXPECT_TRUE(mComposerClient->destroyLayer(mPrimaryDisplay, layer).isOk()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, CreateLayerBadDisplay) { |
| int64_t layer; |
| const auto error = mComposerClient->createLayer(mInvalidDisplayId, kBufferSlotCount, &layer); |
| |
| EXPECT_FALSE(error.isOk()); |
| ASSERT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, DestroyLayerBadDisplay) { |
| int64_t layer; |
| EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk()); |
| |
| const auto error = mComposerClient->destroyLayer(mInvalidDisplayId, layer); |
| |
| EXPECT_FALSE(error.isOk()); |
| EXPECT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError()); |
| EXPECT_TRUE(mComposerClient->destroyLayer(mPrimaryDisplay, layer).isOk()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, DestroyLayerBadLayerError) { |
| // We haven't created any layers yet, so any id should be invalid |
| const auto error = mComposerClient->destroyLayer(mPrimaryDisplay, 1); |
| |
| EXPECT_FALSE(error.isOk()); |
| EXPECT_EQ(IComposerClient::EX_BAD_LAYER, error.getServiceSpecificError()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, GetActiveConfigBadDisplay) { |
| int32_t config; |
| const auto error = mComposerClient->getActiveConfig(mInvalidDisplayId, &config); |
| |
| EXPECT_FALSE(error.isOk()); |
| ASSERT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, GetDisplayConfig) { |
| std::vector<int32_t> configs; |
| EXPECT_TRUE(mComposerClient->getDisplayConfigs(mPrimaryDisplay, &configs).isOk()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, GetDisplayConfigBadDisplay) { |
| std::vector<int32_t> configs; |
| const auto error = mComposerClient->getDisplayConfigs(mInvalidDisplayId, &configs); |
| |
| EXPECT_FALSE(error.isOk()); |
| ASSERT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, GetDisplayName) { |
| std::string displayName; |
| EXPECT_TRUE(mComposerClient->getDisplayName(mPrimaryDisplay, &displayName).isOk()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, SetClientTargetSlotCount) { |
| EXPECT_TRUE( |
| mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kBufferSlotCount).isOk()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, SetActiveConfig) { |
| std::vector<int32_t> configs; |
| EXPECT_TRUE(mComposerClient->getDisplayConfigs(mPrimaryDisplay, &configs).isOk()); |
| for (auto config : configs) { |
| EXPECT_TRUE(mComposerClient->setActiveConfig(mPrimaryDisplay, config).isOk()); |
| int32_t config1; |
| EXPECT_TRUE(mComposerClient->getActiveConfig(mPrimaryDisplay, &config1).isOk()); |
| EXPECT_EQ(config, config1); |
| } |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, SetActiveConfigPowerCycle) { |
| EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::OFF).isOk()); |
| EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON).isOk()); |
| |
| std::vector<int32_t> configs; |
| EXPECT_TRUE(mComposerClient->getDisplayConfigs(mPrimaryDisplay, &configs).isOk()); |
| for (auto config : configs) { |
| EXPECT_TRUE(mComposerClient->setActiveConfig(mPrimaryDisplay, config).isOk()); |
| int32_t config1; |
| EXPECT_TRUE(mComposerClient->getActiveConfig(mPrimaryDisplay, &config1).isOk()); |
| EXPECT_EQ(config, config1); |
| |
| EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::OFF).isOk()); |
| EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON).isOk()); |
| EXPECT_TRUE(mComposerClient->getActiveConfig(mPrimaryDisplay, &config1).isOk()); |
| EXPECT_EQ(config, config1); |
| } |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, GetDozeSupportBadDisplay) { |
| bool isDozeSupport; |
| const auto error = mComposerClient->getDozeSupport(mInvalidDisplayId, &isDozeSupport); |
| EXPECT_FALSE(error.isOk()); |
| ASSERT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, SetPowerModeUnsupported) { |
| bool isDozeSupported; |
| mComposerClient->getDozeSupport(mPrimaryDisplay, &isDozeSupported).isOk(); |
| if (!isDozeSupported) { |
| auto error = mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::DOZE); |
| EXPECT_FALSE(error.isOk()); |
| EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, error.getServiceSpecificError()); |
| |
| error = mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::DOZE_SUSPEND); |
| EXPECT_FALSE(error.isOk()); |
| EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, error.getServiceSpecificError()); |
| } |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, SetVsyncEnabled) { |
| mComposerCallback->setVsyncAllowed(true); |
| |
| EXPECT_TRUE(mComposerClient->setVsyncEnabled(mPrimaryDisplay, true).isOk()); |
| usleep(60 * 1000); |
| EXPECT_TRUE(mComposerClient->setVsyncEnabled(mPrimaryDisplay, false).isOk()); |
| |
| mComposerCallback->setVsyncAllowed(false); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, SetPowerMode) { |
| std::vector<PowerMode> modes; |
| modes.push_back(PowerMode::OFF); |
| modes.push_back(PowerMode::ON_SUSPEND); |
| modes.push_back(PowerMode::ON); |
| |
| bool isDozeSupported; |
| EXPECT_TRUE(mComposerClient->getDozeSupport(mPrimaryDisplay, &isDozeSupported).isOk()); |
| if (isDozeSupported) { |
| modes.push_back(PowerMode::DOZE); |
| modes.push_back(PowerMode::DOZE_SUSPEND); |
| } |
| |
| for (auto mode : modes) { |
| EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, mode).isOk()); |
| } |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, SetPowerModeVariations) { |
| std::vector<PowerMode> modes; |
| |
| modes.push_back(PowerMode::OFF); |
| modes.push_back(PowerMode::ON); |
| modes.push_back(PowerMode::OFF); |
| for (auto mode : modes) { |
| EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, mode).isOk()); |
| } |
| modes.clear(); |
| |
| modes.push_back(PowerMode::OFF); |
| modes.push_back(PowerMode::OFF); |
| for (auto mode : modes) { |
| EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, mode).isOk()); |
| } |
| modes.clear(); |
| |
| modes.push_back(PowerMode::ON); |
| modes.push_back(PowerMode::ON); |
| for (auto mode : modes) { |
| EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, mode).isOk()); |
| } |
| modes.clear(); |
| |
| modes.push_back(PowerMode::ON_SUSPEND); |
| modes.push_back(PowerMode::ON_SUSPEND); |
| for (auto mode : modes) { |
| EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, mode).isOk()); |
| } |
| modes.clear(); |
| |
| bool isDozeSupported = false; |
| ASSERT_TRUE(mComposerClient->getDozeSupport(mPrimaryDisplay, &isDozeSupported).isOk()); |
| if (isDozeSupported) { |
| modes.push_back(PowerMode::DOZE); |
| modes.push_back(PowerMode::DOZE); |
| for (auto mode : modes) { |
| EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, mode).isOk()); |
| } |
| modes.clear(); |
| |
| modes.push_back(PowerMode::DOZE_SUSPEND); |
| modes.push_back(PowerMode::DOZE_SUSPEND); |
| for (auto mode : modes) { |
| EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, mode).isOk()); |
| } |
| } |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, SetPowerModeBadDisplay) { |
| const auto error = mComposerClient->setPowerMode(mInvalidDisplayId, PowerMode::ON); |
| |
| EXPECT_FALSE(error.isOk()); |
| ASSERT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, SetPowerModeBadParameter) { |
| const auto error = mComposerClient->setPowerMode(mPrimaryDisplay, static_cast<PowerMode>(-1)); |
| |
| EXPECT_FALSE(error.isOk()); |
| ASSERT_EQ(IComposerClient::EX_BAD_PARAMETER, error.getServiceSpecificError()); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, GetDataspaceSaturationMatrix) { |
| std::vector<float> matrix; |
| EXPECT_TRUE( |
| mComposerClient->getDataspaceSaturationMatrix(common::Dataspace::SRGB_LINEAR, &matrix) |
| .isOk()); |
| |
| // the last row is known |
| ASSERT_EQ(0.0f, matrix[12]); |
| ASSERT_EQ(0.0f, matrix[13]); |
| ASSERT_EQ(0.0f, matrix[14]); |
| ASSERT_EQ(1.0f, matrix[15]); |
| } |
| |
| TEST_P(GraphicsComposerAidlTest, GetDataspaceSaturationMatrixBadParameter) { |
| std::vector<float> matrix; |
| const auto error = |
| mComposerClient->getDataspaceSaturationMatrix(common::Dataspace::UNKNOWN, &matrix); |
| |
| EXPECT_FALSE(error.isOk()); |
| EXPECT_EQ(IComposerClient::EX_BAD_PARAMETER, error.getServiceSpecificError()); |
| } |
| |
| // Tests for Command. |
| class GraphicsComposerAidlCommandTest : public GraphicsComposerAidlTest { |
| protected: |
| void TearDown() override { |
| const auto errors = mReader.takeErrors(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| std::vector<int64_t> layers; |
| std::vector<Composition> types; |
| mReader.takeChangedCompositionTypes(mPrimaryDisplay, &layers, &types); |
| |
| ASSERT_TRUE(layers.empty()); |
| ASSERT_TRUE(types.empty()); |
| |
| ASSERT_NO_FATAL_FAILURE(GraphicsComposerAidlTest::TearDown()); |
| } |
| |
| void execute() { |
| const auto& commands = mWriter.getPendingCommands(); |
| if (commands.empty()) { |
| mWriter.reset(); |
| return; |
| } |
| |
| std::vector<CommandResultPayload> results; |
| const auto status = mComposerClient->executeCommands(commands, &results); |
| ASSERT_TRUE(status.isOk()) << "executeCommands failed " << status.getDescription(); |
| |
| mReader.parse(results); |
| mWriter.reset(); |
| } |
| |
| static inline auto toTimePoint(nsecs_t time) { |
| return std::chrono::time_point<std::chrono::steady_clock>(std::chrono::nanoseconds(time)); |
| } |
| |
| void setActiveConfig(VtsDisplay& display, int32_t config) { |
| EXPECT_TRUE(mComposerClient->setActiveConfig(display.get(), config).isOk()); |
| int32_t displayWidth; |
| EXPECT_TRUE(mComposerClient |
| ->getDisplayAttribute(display.get(), config, DisplayAttribute::WIDTH, |
| &displayWidth) |
| .isOk()); |
| int32_t displayHeight; |
| EXPECT_TRUE(mComposerClient |
| ->getDisplayAttribute(display.get(), config, DisplayAttribute::HEIGHT, |
| &displayHeight) |
| .isOk()); |
| display.setDimensions(displayWidth, displayHeight); |
| } |
| |
| void forEachTwoConfigs(int64_t display, std::function<void(int32_t, int32_t)> func) { |
| std::vector<int32_t> displayConfigs; |
| EXPECT_TRUE(mComposerClient->getDisplayConfigs(display, &displayConfigs).isOk()); |
| for (const int32_t config1 : displayConfigs) { |
| for (const int32_t config2 : displayConfigs) { |
| if (config1 != config2) { |
| func(config1, config2); |
| } |
| } |
| } |
| } |
| |
| void waitForVsyncPeriodChange(int64_t display, const VsyncPeriodChangeTimeline& timeline, |
| int64_t desiredTimeNanos, int64_t oldPeriodNanos, |
| int64_t newPeriodNanos) { |
| const auto kChangeDeadline = toTimePoint(timeline.newVsyncAppliedTimeNanos) + 100ms; |
| while (std::chrono::steady_clock::now() <= kChangeDeadline) { |
| int32_t vsyncPeriodNanos; |
| EXPECT_TRUE(mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos).isOk()); |
| if (systemTime() <= desiredTimeNanos) { |
| EXPECT_EQ(vsyncPeriodNanos, oldPeriodNanos); |
| } else if (vsyncPeriodNanos == newPeriodNanos) { |
| break; |
| } |
| std::this_thread::sleep_for(std::chrono::nanoseconds(oldPeriodNanos)); |
| } |
| } |
| |
| sp<GraphicBuffer> allocate() { |
| return sp<GraphicBuffer>::make( |
| static_cast<uint32_t>(mDisplayWidth), static_cast<uint32_t>(mDisplayHeight), |
| ::android::PIXEL_FORMAT_RGBA_8888, |
| /*layerCount*/ 1, |
| (static_cast<uint64_t>(common::BufferUsage::CPU_WRITE_OFTEN) | |
| static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) | |
| static_cast<uint64_t>(common::BufferUsage::COMPOSER_OVERLAY)), |
| "VtsHalGraphicsComposer3_TargetTest"); |
| } |
| |
| void sendRefreshFrame(const VtsDisplay& display, const VsyncPeriodChangeTimeline* timeline) { |
| if (timeline != nullptr) { |
| // Refresh time should be before newVsyncAppliedTimeNanos |
| EXPECT_LT(timeline->refreshTimeNanos, timeline->newVsyncAppliedTimeNanos); |
| |
| std::this_thread::sleep_until(toTimePoint(timeline->refreshTimeNanos)); |
| } |
| |
| EXPECT_TRUE(mComposerClient->setPowerMode(display.get(), PowerMode::ON).isOk()); |
| EXPECT_TRUE( |
| mComposerClient |
| ->setColorMode(display.get(), ColorMode::NATIVE, RenderIntent::COLORIMETRIC) |
| .isOk()); |
| |
| int64_t layer = 0; |
| ASSERT_NO_FATAL_FAILURE(layer = createLayer(display)); |
| { |
| auto buffer = allocate(); |
| ASSERT_NE(nullptr, buffer); |
| ASSERT_EQ(::android::OK, buffer->initCheck()); |
| ASSERT_NE(nullptr, buffer->handle); |
| |
| mWriter.setLayerCompositionType(display.get(), layer, Composition::DEVICE); |
| mWriter.setLayerDisplayFrame(display.get(), layer, display.getFrameRect()); |
| mWriter.setLayerPlaneAlpha(display.get(), layer, 1); |
| mWriter.setLayerSourceCrop(display.get(), layer, display.getCrop()); |
| mWriter.setLayerTransform(display.get(), layer, static_cast<Transform>(0)); |
| mWriter.setLayerVisibleRegion(display.get(), layer, |
| std::vector<Rect>(1, display.getFrameRect())); |
| mWriter.setLayerZOrder(display.get(), layer, 10); |
| mWriter.setLayerBlendMode(display.get(), layer, BlendMode::NONE); |
| mWriter.setLayerSurfaceDamage(display.get(), layer, |
| std::vector<Rect>(1, display.getFrameRect())); |
| mWriter.setLayerBuffer(display.get(), layer, 0, buffer->handle, -1); |
| mWriter.setLayerDataspace(display.get(), layer, common::Dataspace::UNKNOWN); |
| |
| mWriter.validateDisplay(display.get()); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| mWriter.presentDisplay(display.get()); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| } |
| |
| { |
| auto buffer = allocate(); |
| ASSERT_NE(nullptr, buffer->handle); |
| |
| mWriter.setLayerBuffer(display.get(), layer, 0, buffer->handle, -1); |
| mWriter.setLayerSurfaceDamage(display.get(), layer, |
| std::vector<Rect>(1, {0, 0, 10, 10})); |
| mWriter.validateDisplay(display.get()); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| mWriter.presentDisplay(display.get()); |
| execute(); |
| } |
| |
| ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer)); |
| } |
| |
| void Test_setActiveConfigWithConstraints(const TestParameters& params) { |
| for (VtsDisplay& display : mDisplays) { |
| forEachTwoConfigs(display.get(), [&](int32_t config1, int32_t config2) { |
| setActiveConfig(display, config1); |
| sendRefreshFrame(display, nullptr); |
| |
| int32_t vsyncPeriod1; |
| EXPECT_TRUE(mComposerClient |
| ->getDisplayAttribute(display.get(), config1, |
| DisplayAttribute::VSYNC_PERIOD, |
| &vsyncPeriod1) |
| .isOk()); |
| int32_t configGroup1; |
| EXPECT_TRUE(mComposerClient |
| ->getDisplayAttribute(display.get(), config1, |
| DisplayAttribute::CONFIG_GROUP, |
| &configGroup1) |
| .isOk()); |
| int32_t vsyncPeriod2; |
| EXPECT_TRUE(mComposerClient |
| ->getDisplayAttribute(display.get(), config2, |
| DisplayAttribute::VSYNC_PERIOD, |
| &vsyncPeriod2) |
| .isOk()); |
| int32_t configGroup2; |
| EXPECT_TRUE(mComposerClient |
| ->getDisplayAttribute(display.get(), config2, |
| DisplayAttribute::CONFIG_GROUP, |
| &configGroup2) |
| .isOk()); |
| |
| if (vsyncPeriod1 == vsyncPeriod2) { |
| return; // continue |
| } |
| |
| // We don't allow delayed change when changing config groups |
| if (params.delayForChange > 0 && configGroup1 != configGroup2) { |
| return; // continue |
| } |
| |
| VsyncPeriodChangeTimeline timeline; |
| VsyncPeriodChangeConstraints constraints = { |
| .desiredTimeNanos = systemTime() + params.delayForChange, |
| .seamlessRequired = false}; |
| EXPECT_TRUE(setActiveConfigWithConstraints(display, config2, constraints, &timeline) |
| .isOk()); |
| |
| EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos >= constraints.desiredTimeNanos); |
| // Refresh rate should change within a reasonable time |
| constexpr std::chrono::nanoseconds kReasonableTimeForChange = 1s; // 1 second |
| EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos - constraints.desiredTimeNanos <= |
| kReasonableTimeForChange.count()); |
| |
| if (timeline.refreshRequired) { |
| if (params.refreshMiss) { |
| // Miss the refresh frame on purpose to make sure the implementation sends a |
| // callback |
| std::this_thread::sleep_until(toTimePoint(timeline.refreshTimeNanos) + |
| 100ms); |
| } |
| sendRefreshFrame(display, &timeline); |
| } |
| waitForVsyncPeriodChange(display.get(), timeline, constraints.desiredTimeNanos, |
| vsyncPeriod1, vsyncPeriod2); |
| |
| // At this point the refresh rate should have changed already, however in rare |
| // cases the implementation might have missed the deadline. In this case a new |
| // timeline should have been provided. |
| auto newTimeline = mComposerCallback->takeLastVsyncPeriodChangeTimeline(); |
| if (timeline.refreshRequired && params.refreshMiss) { |
| EXPECT_TRUE(newTimeline.has_value()); |
| } |
| |
| if (newTimeline.has_value()) { |
| if (newTimeline->refreshRequired) { |
| sendRefreshFrame(display, &newTimeline.value()); |
| } |
| waitForVsyncPeriodChange(display.get(), newTimeline.value(), |
| constraints.desiredTimeNanos, vsyncPeriod1, |
| vsyncPeriod2); |
| } |
| |
| int32_t vsyncPeriodNanos; |
| EXPECT_TRUE(mComposerClient->getDisplayVsyncPeriod(display.get(), &vsyncPeriodNanos) |
| .isOk()); |
| EXPECT_EQ(vsyncPeriodNanos, vsyncPeriod2); |
| }); |
| } |
| } |
| |
| // clang-format off |
| const std::array<float, 16> kIdentity = {{ |
| 1.0f, 0.0f, 0.0f, 0.0f, |
| 0.0f, 1.0f, 0.0f, 0.0f, |
| 0.0f, 0.0f, 1.0f, 0.0f, |
| 0.0f, 0.0f, 0.0f, 1.0f, |
| }}; |
| // clang-format on |
| |
| CommandWriterBase mWriter; |
| CommandReaderBase mReader; |
| }; |
| |
| TEST_P(GraphicsComposerAidlCommandTest, SET_COLOR_TRANSFORM) { |
| mWriter.setColorTransform(mPrimaryDisplay, kIdentity.data(), ColorTransform::IDENTITY); |
| execute(); |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, SetLayerColorTransform) { |
| int64_t layer; |
| EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk()); |
| mWriter.setLayerColorTransform(mPrimaryDisplay, layer, kIdentity.data()); |
| execute(); |
| |
| const auto errors = mReader.takeErrors(); |
| if (errors.size() == 1 && errors[0].errorCode == EX_UNSUPPORTED_OPERATION) { |
| GTEST_SUCCEED() << "setLayerColorTransform is not supported"; |
| return; |
| } |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, SET_CLIENT_TARGET) { |
| EXPECT_TRUE( |
| mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kBufferSlotCount).isOk()); |
| |
| mWriter.setClientTarget(mPrimaryDisplay, 0, nullptr, -1, Dataspace::UNKNOWN, |
| std::vector<Rect>()); |
| |
| execute(); |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, SET_OUTPUT_BUFFER) { |
| int32_t virtualDisplayCount; |
| EXPECT_TRUE(mComposerClient->getMaxVirtualDisplayCount(&virtualDisplayCount).isOk()); |
| if (virtualDisplayCount == 0) { |
| GTEST_SUCCEED() << "no virtual display support"; |
| return; |
| } |
| |
| VirtualDisplay display; |
| EXPECT_TRUE(mComposerClient |
| ->createVirtualDisplay(64, 64, common::PixelFormat::IMPLEMENTATION_DEFINED, |
| kBufferSlotCount, &display) |
| .isOk()); |
| |
| auto handle = allocate()->handle; |
| mWriter.setOutputBuffer(display.display, 0, handle, -1); |
| execute(); |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, VALIDATE_DISPLAY) { |
| mWriter.validateDisplay(mPrimaryDisplay); |
| execute(); |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, ACCEPT_DISPLAY_CHANGES) { |
| mWriter.validateDisplay(mPrimaryDisplay); |
| mWriter.acceptDisplayChanges(mPrimaryDisplay); |
| execute(); |
| } |
| |
| // TODO(b/208441745) fix the test failure |
| TEST_P(GraphicsComposerAidlCommandTest, PRESENT_DISPLAY) { |
| mWriter.validateDisplay(mPrimaryDisplay); |
| mWriter.presentDisplay(mPrimaryDisplay); |
| execute(); |
| } |
| |
| /** |
| * Test IComposerClient::Command::PRESENT_DISPLAY |
| * |
| * Test that IComposerClient::Command::PRESENT_DISPLAY works without |
| * additional call to validateDisplay when only the layer buffer handle and |
| * surface damage have been set |
| */ |
| // TODO(b/208441745) fix the test failure |
| TEST_P(GraphicsComposerAidlCommandTest, PRESENT_DISPLAY_NO_LAYER_STATE_CHANGES) { |
| std::vector<Capability> capabilities; |
| EXPECT_TRUE(mComposer->getCapabilities(&capabilities).isOk()); |
| if (none_of(capabilities.begin(), capabilities.end(), |
| [&](auto item) { return item == Capability::SKIP_VALIDATE; })) { |
| GTEST_SUCCEED() << "Device does not have skip validate capability, skipping"; |
| return; |
| } |
| mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON); |
| |
| std::vector<RenderIntent> renderIntents; |
| mComposerClient->getRenderIntents(mPrimaryDisplay, ColorMode::NATIVE, &renderIntents); |
| for (auto intent : renderIntents) { |
| mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::NATIVE, intent); |
| |
| auto handle = allocate()->handle; |
| ASSERT_NE(nullptr, handle); |
| |
| Rect displayFrame{0, 0, mDisplayWidth, mDisplayHeight}; |
| |
| int64_t layer; |
| EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk()); |
| mWriter.setLayerCompositionType(mPrimaryDisplay, layer, Composition::DEVICE); |
| mWriter.setLayerDisplayFrame(mPrimaryDisplay, layer, displayFrame); |
| mWriter.setLayerPlaneAlpha(mPrimaryDisplay, layer, 1); |
| mWriter.setLayerSourceCrop(mPrimaryDisplay, layer, |
| {0, 0, (float)mDisplayWidth, (float)mDisplayHeight}); |
| mWriter.setLayerTransform(mPrimaryDisplay, layer, static_cast<Transform>(0)); |
| mWriter.setLayerVisibleRegion(mPrimaryDisplay, layer, std::vector<Rect>(1, displayFrame)); |
| mWriter.setLayerZOrder(mPrimaryDisplay, layer, 10); |
| mWriter.setLayerBlendMode(mPrimaryDisplay, layer, BlendMode::NONE); |
| mWriter.setLayerSurfaceDamage(mPrimaryDisplay, layer, std::vector<Rect>(1, displayFrame)); |
| mWriter.setLayerBuffer(mPrimaryDisplay, layer, 0, handle, -1); |
| mWriter.setLayerDataspace(mPrimaryDisplay, layer, Dataspace::UNKNOWN); |
| |
| mWriter.validateDisplay(mPrimaryDisplay); |
| execute(); |
| std::vector<int64_t> layers; |
| std::vector<Composition> types; |
| mReader.takeChangedCompositionTypes(mPrimaryDisplay, &layers, &types); |
| if (!layers.empty()) { |
| GTEST_SUCCEED() << "Composition change requested, skipping test"; |
| return; |
| } |
| |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| mWriter.presentDisplay(mPrimaryDisplay); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| auto handle2 = allocate()->handle; |
| ASSERT_NE(nullptr, handle2); |
| mWriter.setLayerBuffer(mPrimaryDisplay, layer, 0, handle2, -1); |
| mWriter.setLayerSurfaceDamage(mPrimaryDisplay, layer, std::vector<Rect>(1, {0, 0, 10, 10})); |
| mWriter.presentDisplay(mPrimaryDisplay); |
| execute(); |
| } |
| } |
| |
| // TODO(b/208441745) fix the test failure |
| TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_CURSOR_POSITION) { |
| int64_t layer; |
| EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk()); |
| |
| auto handle = allocate()->handle; |
| ASSERT_NE(nullptr, handle); |
| Rect displayFrame{0, 0, mDisplayWidth, mDisplayHeight}; |
| |
| mWriter.setLayerBuffer(mPrimaryDisplay, layer, 0, handle, -1); |
| mWriter.setLayerCompositionType(mPrimaryDisplay, layer, Composition::CURSOR); |
| mWriter.setLayerDisplayFrame(mPrimaryDisplay, layer, displayFrame); |
| mWriter.setLayerPlaneAlpha(mPrimaryDisplay, layer, 1); |
| mWriter.setLayerSourceCrop(mPrimaryDisplay, layer, |
| {0, 0, (float)mDisplayWidth, (float)mDisplayHeight}); |
| mWriter.setLayerTransform(mPrimaryDisplay, layer, static_cast<Transform>(0)); |
| mWriter.setLayerVisibleRegion(mPrimaryDisplay, layer, std::vector<Rect>(1, displayFrame)); |
| mWriter.setLayerZOrder(mPrimaryDisplay, layer, 10); |
| mWriter.setLayerBlendMode(mPrimaryDisplay, layer, BlendMode::NONE); |
| mWriter.setLayerSurfaceDamage(mPrimaryDisplay, layer, std::vector<Rect>(1, displayFrame)); |
| mWriter.setLayerDataspace(mPrimaryDisplay, layer, Dataspace::UNKNOWN); |
| mWriter.validateDisplay(mPrimaryDisplay); |
| |
| execute(); |
| std::vector<int64_t> layers; |
| std::vector<Composition> types; |
| mReader.takeChangedCompositionTypes(mPrimaryDisplay, &layers, &types); |
| if (!layers.empty()) { |
| GTEST_SUCCEED() << "Composition change requested, skipping test"; |
| return; |
| } |
| mWriter.presentDisplay(mPrimaryDisplay); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| mWriter.setLayerCursorPosition(mPrimaryDisplay, layer, 1, 1); |
| execute(); |
| |
| mWriter.setLayerCursorPosition(mPrimaryDisplay, layer, 0, 0); |
| mWriter.validateDisplay(mPrimaryDisplay); |
| mWriter.presentDisplay(mPrimaryDisplay); |
| execute(); |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_BUFFER) { |
| auto handle = allocate()->handle; |
| ASSERT_NE(nullptr, handle); |
| |
| int64_t layer; |
| EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk()); |
| mWriter.setLayerBuffer(mPrimaryDisplay, layer, 0, handle, -1); |
| execute(); |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_SURFACE_DAMAGE) { |
| int64_t layer; |
| EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk()); |
| |
| Rect empty{0, 0, 0, 0}; |
| Rect unit{0, 0, 1, 1}; |
| |
| mWriter.setLayerSurfaceDamage(mPrimaryDisplay, layer, std::vector<Rect>(1, empty)); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| mWriter.setLayerSurfaceDamage(mPrimaryDisplay, layer, std::vector<Rect>(1, unit)); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| mWriter.setLayerSurfaceDamage(mPrimaryDisplay, layer, std::vector<Rect>()); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_BLEND_MODE) { |
| int64_t layer; |
| EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk()); |
| |
| mWriter.setLayerBlendMode(mPrimaryDisplay, layer, BlendMode::NONE); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| mWriter.setLayerBlendMode(mPrimaryDisplay, layer, BlendMode::PREMULTIPLIED); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| mWriter.setLayerBlendMode(mPrimaryDisplay, layer, BlendMode::COVERAGE); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_COLOR) { |
| int64_t layer; |
| EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk()); |
| |
| mWriter.setLayerColor(mPrimaryDisplay, layer, |
| Color{static_cast<int8_t>(0xff), static_cast<int8_t>(0xff), |
| static_cast<int8_t>(0xff), static_cast<int8_t>(0xff)}); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| mWriter.setLayerColor(mPrimaryDisplay, layer, Color{0, 0, 0, 0}); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_COMPOSITION_TYPE) { |
| int64_t layer; |
| EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk()); |
| |
| mWriter.setLayerCompositionType(mPrimaryDisplay, layer, Composition::CLIENT); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| mWriter.setLayerCompositionType(mPrimaryDisplay, layer, Composition::DEVICE); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| mWriter.setLayerCompositionType(mPrimaryDisplay, layer, Composition::SOLID_COLOR); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| mWriter.setLayerCompositionType(mPrimaryDisplay, layer, Composition::CURSOR); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_DATASPACE) { |
| int64_t layer; |
| EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk()); |
| |
| mWriter.setLayerDataspace(mPrimaryDisplay, layer, Dataspace::UNKNOWN); |
| execute(); |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_DISPLAY_FRAME) { |
| int64_t layer; |
| EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk()); |
| |
| mWriter.setLayerDisplayFrame(mPrimaryDisplay, layer, Rect{0, 0, 1, 1}); |
| execute(); |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_PLANE_ALPHA) { |
| int64_t layer; |
| EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk()); |
| |
| mWriter.setLayerPlaneAlpha(mPrimaryDisplay, layer, 0.0f); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| mWriter.setLayerPlaneAlpha(mPrimaryDisplay, layer, 1.0f); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_SIDEBAND_STREAM) { |
| std::vector<Capability> capabilities; |
| EXPECT_TRUE(mComposer->getCapabilities(&capabilities).isOk()); |
| if (none_of(capabilities.begin(), capabilities.end(), |
| [&](auto& item) { return item == Capability::SIDEBAND_STREAM; })) { |
| GTEST_SUCCEED() << "no sideband stream support"; |
| return; |
| } |
| |
| auto handle = allocate()->handle; |
| ASSERT_NE(nullptr, handle); |
| |
| int64_t layer; |
| EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk()); |
| |
| mWriter.setLayerSidebandStream(mPrimaryDisplay, layer, handle); |
| execute(); |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_SOURCE_CROP) { |
| int64_t layer; |
| EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk()); |
| |
| mWriter.setLayerSourceCrop(mPrimaryDisplay, layer, FRect{0.0f, 0.0f, 1.0f, 1.0f}); |
| execute(); |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_TRANSFORM) { |
| int64_t layer; |
| EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk()); |
| |
| mWriter.setLayerTransform(mPrimaryDisplay, layer, static_cast<Transform>(0)); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| mWriter.setLayerTransform(mPrimaryDisplay, layer, Transform::FLIP_H); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| mWriter.setLayerTransform(mPrimaryDisplay, layer, Transform::FLIP_V); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| mWriter.setLayerTransform(mPrimaryDisplay, layer, Transform::ROT_90); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| mWriter.setLayerTransform(mPrimaryDisplay, layer, Transform::ROT_180); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| mWriter.setLayerTransform(mPrimaryDisplay, layer, Transform::ROT_270); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| mWriter.setLayerTransform(mPrimaryDisplay, layer, |
| static_cast<Transform>(static_cast<int>(Transform::FLIP_H) | |
| static_cast<int>(Transform::ROT_90))); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| mWriter.setLayerTransform(mPrimaryDisplay, layer, |
| static_cast<Transform>(static_cast<int>(Transform::FLIP_V) | |
| static_cast<int>(Transform::ROT_90))); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_VISIBLE_REGION) { |
| int64_t layer; |
| EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk()); |
| |
| Rect empty{0, 0, 0, 0}; |
| Rect unit{0, 0, 1, 1}; |
| |
| mWriter.setLayerVisibleRegion(mPrimaryDisplay, layer, std::vector<Rect>(1, empty)); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| mWriter.setLayerVisibleRegion(mPrimaryDisplay, layer, std::vector<Rect>(1, unit)); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| mWriter.setLayerVisibleRegion(mPrimaryDisplay, layer, std::vector<Rect>()); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_Z_ORDER) { |
| int64_t layer; |
| EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk()); |
| |
| mWriter.setLayerZOrder(mPrimaryDisplay, layer, 10); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| |
| mWriter.setLayerZOrder(mPrimaryDisplay, layer, 0); |
| execute(); |
| ASSERT_TRUE(mReader.takeErrors().empty()); |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, SET_LAYER_PER_FRAME_METADATA) { |
| int64_t layer; |
| EXPECT_TRUE(mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount, &layer).isOk()); |
| |
| /** |
| * DISPLAY_P3 is a color space that uses the DCI_P3 primaries, |
| * the D65 white point and the SRGB transfer functions. |
| * Rendering Intent: Colorimetric |
| * Primaries: |
| * x y |
| * green 0.265 0.690 |
| * blue 0.150 0.060 |
| * red 0.680 0.320 |
| * white (D65) 0.3127 0.3290 |
| */ |
| |
| std::vector<PerFrameMetadata> aidlMetadata; |
| aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X, 0.680f}); |
| aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y, 0.320f}); |
| aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X, 0.265f}); |
| aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_Y, 0.690f}); |
| aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X, 0.150f}); |
| aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y, 0.060f}); |
| aidlMetadata.push_back({PerFrameMetadataKey::WHITE_POINT_X, 0.3127f}); |
| aidlMetadata.push_back({PerFrameMetadataKey::WHITE_POINT_Y, 0.3290f}); |
| aidlMetadata.push_back({PerFrameMetadataKey::MAX_LUMINANCE, 100.0f}); |
| aidlMetadata.push_back({PerFrameMetadataKey::MIN_LUMINANCE, 0.1f}); |
| aidlMetadata.push_back({PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL, 78.0}); |
| aidlMetadata.push_back({PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL, 62.0}); |
| mWriter.setLayerPerFrameMetadata(mPrimaryDisplay, layer, aidlMetadata); |
| execute(); |
| |
| const auto errors = mReader.takeErrors(); |
| if (errors.size() == 1 && errors[0].errorCode == EX_UNSUPPORTED_OPERATION) { |
| GTEST_SUCCEED() << "SetLayerPerFrameMetadata is not supported"; |
| EXPECT_TRUE(mComposerClient->destroyLayer(mPrimaryDisplay, layer).isOk()); |
| return; |
| } |
| |
| EXPECT_TRUE(mComposerClient->destroyLayer(mPrimaryDisplay, layer).isOk()); |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, setActiveConfigWithConstraints) { |
| Test_setActiveConfigWithConstraints({.delayForChange = 0, .refreshMiss = false}); |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, setActiveConfigWithConstraints_Delayed) { |
| Test_setActiveConfigWithConstraints({.delayForChange = 300'000'000, // 300ms |
| .refreshMiss = false}); |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, setActiveConfigWithConstraints_MissRefresh) { |
| Test_setActiveConfigWithConstraints({.delayForChange = 0, .refreshMiss = true}); |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, getDisplayVsyncPeriod) { |
| for (VtsDisplay& display : mDisplays) { |
| std::vector<int32_t> configs; |
| EXPECT_TRUE(mComposerClient->getDisplayConfigs(display.get(), &configs).isOk()); |
| for (int32_t config : configs) { |
| int32_t expectedVsyncPeriodNanos = -1; |
| EXPECT_TRUE(mComposerClient |
| ->getDisplayAttribute(display.get(), config, |
| DisplayAttribute::VSYNC_PERIOD, |
| &expectedVsyncPeriodNanos) |
| .isOk()); |
| |
| VsyncPeriodChangeTimeline timeline; |
| VsyncPeriodChangeConstraints constraints; |
| |
| constraints.desiredTimeNanos = systemTime(); |
| constraints.seamlessRequired = false; |
| EXPECT_TRUE(mComposerClient |
| ->setActiveConfigWithConstraints(display.get(), config, constraints, |
| &timeline) |
| .isOk()); |
| |
| if (timeline.refreshRequired) { |
| sendRefreshFrame(display, &timeline); |
| } |
| waitForVsyncPeriodChange(display.get(), timeline, constraints.desiredTimeNanos, 0, |
| expectedVsyncPeriodNanos); |
| |
| int32_t vsyncPeriodNanos; |
| int retryCount = 100; |
| do { |
| std::this_thread::sleep_for(10ms); |
| vsyncPeriodNanos = 0; |
| EXPECT_TRUE(mComposerClient->getDisplayVsyncPeriod(display.get(), &vsyncPeriodNanos) |
| .isOk()); |
| --retryCount; |
| } while (vsyncPeriodNanos != expectedVsyncPeriodNanos && retryCount > 0); |
| |
| EXPECT_EQ(vsyncPeriodNanos, expectedVsyncPeriodNanos); |
| |
| // Make sure that the vsync period stays the same if the active config is not |
| // changed. |
| auto timeout = 1ms; |
| for (int i = 0; i < 10; i++) { |
| std::this_thread::sleep_for(timeout); |
| timeout *= 2; |
| vsyncPeriodNanos = 0; |
| EXPECT_TRUE(mComposerClient->getDisplayVsyncPeriod(display.get(), &vsyncPeriodNanos) |
| .isOk()); |
| EXPECT_EQ(vsyncPeriodNanos, expectedVsyncPeriodNanos); |
| } |
| } |
| } |
| } |
| |
| TEST_P(GraphicsComposerAidlCommandTest, setActiveConfigWithConstraints_SeamlessNotAllowed) { |
| VsyncPeriodChangeTimeline timeline; |
| VsyncPeriodChangeConstraints constraints; |
| |
| constraints.seamlessRequired = true; |
| constraints.desiredTimeNanos = systemTime(); |
| |
| for (VtsDisplay& display : mDisplays) { |
| forEachTwoConfigs(display.get(), [&](int32_t config1, int32_t config2) { |
| int32_t configGroup1; |
| EXPECT_TRUE(mComposerClient |
| ->getDisplayAttribute(display.get(), config1, |
| DisplayAttribute::CONFIG_GROUP, &configGroup1) |
| .isOk()); |
| int32_t configGroup2; |
| EXPECT_TRUE(mComposerClient |
| ->getDisplayAttribute(display.get(), config2, |
| DisplayAttribute::CONFIG_GROUP, &configGroup2) |
| .isOk()); |
| if (configGroup1 != configGroup2) { |
| setActiveConfig(display, config1); |
| sendRefreshFrame(display, nullptr); |
| EXPECT_EQ(IComposerClient::EX_SEAMLESS_NOT_ALLOWED, |
| setActiveConfigWithConstraints(display, config2, constraints, &timeline) |
| .getServiceSpecificError()); |
| } |
| }); |
| } |
| } |
| |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerAidlCommandTest); |
| INSTANTIATE_TEST_SUITE_P( |
| PerInstance, GraphicsComposerAidlCommandTest, |
| testing::ValuesIn(::android::getAidlHalInstanceNames(IComposer::descriptor)), |
| ::android::PrintInstanceNameToString); |
| |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerAidlTest); |
| INSTANTIATE_TEST_SUITE_P( |
| PerInstance, GraphicsComposerAidlTest, |
| testing::ValuesIn(::android::getAidlHalInstanceNames(IComposer::descriptor)), |
| ::android::PrintInstanceNameToString); |
| } // namespace |
| } // namespace aidl::android::hardware::graphics::composer3::vts |
| |
| int main(int argc, char** argv) { |
| ::testing::InitGoogleTest(&argc, argv); |
| |
| using namespace std::chrono_literals; |
| if (!android::base::WaitForProperty("init.svc.surfaceflinger", "stopped", 10s)) { |
| ALOGE("Failed to stop init.svc.surfaceflinger"); |
| return -1; |
| } |
| return RUN_ALL_TESTS(); |
| } |