2707 lines
113 KiB
C++
2707 lines
113 KiB
C++
/**
|
|
* Copyright (c) 2022, The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <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/PixelFormat.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_process.h>
|
|
#include <android/hardware/graphics/composer3/ComposerClientReader.h>
|
|
#include <android/hardware/graphics/composer3/ComposerClientWriter.h>
|
|
#include <binder/ProcessState.h>
|
|
#include <gtest/gtest.h>
|
|
#include <ui/Fence.h>
|
|
#include <ui/GraphicBuffer.h>
|
|
#include <ui/PixelFormat.h>
|
|
#include <algorithm>
|
|
#include <iterator>
|
|
#include <numeric>
|
|
#include <string>
|
|
#include <thread>
|
|
#include <unordered_map>
|
|
#include "GraphicsComposerCallback.h"
|
|
#include "VtsComposerClient.h"
|
|
|
|
#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 GraphicsComposerAidlTest : public ::testing::TestWithParam<std::string> {
|
|
protected:
|
|
void SetUp() override {
|
|
mComposerClient = std::make_unique<VtsComposerClient>(GetParam());
|
|
ASSERT_TRUE(mComposerClient->createClient().isOk());
|
|
|
|
const auto& [status, displays] = mComposerClient->getDisplays();
|
|
ASSERT_TRUE(status.isOk());
|
|
mDisplays = displays;
|
|
|
|
// explicitly disable vsync
|
|
for (const auto& display : mDisplays) {
|
|
EXPECT_TRUE(mComposerClient->setVsync(display.getDisplayId(), false).isOk());
|
|
}
|
|
mComposerClient->setVsyncAllowed(false);
|
|
}
|
|
|
|
void TearDown() override {
|
|
ASSERT_TRUE(mComposerClient->tearDown());
|
|
mComposerClient.reset();
|
|
}
|
|
|
|
void assertServiceSpecificError(const ScopedAStatus& status, int32_t serviceSpecificError) {
|
|
ASSERT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC);
|
|
ASSERT_EQ(status.getServiceSpecificError(), serviceSpecificError);
|
|
}
|
|
|
|
void Test_setContentTypeForDisplay(int64_t display,
|
|
const std::vector<ContentType>& supportedContentTypes,
|
|
ContentType contentType, const char* contentTypeStr) {
|
|
const bool contentTypeSupport =
|
|
std::find(supportedContentTypes.begin(), supportedContentTypes.end(),
|
|
contentType) != supportedContentTypes.end();
|
|
|
|
if (!contentTypeSupport) {
|
|
const auto& status = mComposerClient->setContentType(display, contentType);
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(
|
|
assertServiceSpecificError(status, IComposerClient::EX_UNSUPPORTED));
|
|
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(ContentType contentType, const char* contentTypeStr) {
|
|
for (const auto& display : mDisplays) {
|
|
const auto& [status, supportedContentTypes] =
|
|
mComposerClient->getSupportedContentTypes(display.getDisplayId());
|
|
EXPECT_TRUE(status.isOk());
|
|
Test_setContentTypeForDisplay(display.getDisplayId(), supportedContentTypes,
|
|
contentType, contentTypeStr);
|
|
}
|
|
}
|
|
|
|
bool hasCapability(Capability capability) {
|
|
const auto& [status, capabilities] = mComposerClient->getCapabilities();
|
|
EXPECT_TRUE(status.isOk());
|
|
return std::any_of(
|
|
capabilities.begin(), capabilities.end(),
|
|
[&](const Capability& activeCapability) { return activeCapability == capability; });
|
|
}
|
|
|
|
int getInterfaceVersion() {
|
|
const auto& [versionStatus, version] = mComposerClient->getInterfaceVersion();
|
|
EXPECT_TRUE(versionStatus.isOk());
|
|
return version;
|
|
}
|
|
|
|
const VtsDisplay& getPrimaryDisplay() const { return mDisplays[0]; }
|
|
|
|
int64_t getPrimaryDisplayId() const { return getPrimaryDisplay().getDisplayId(); }
|
|
|
|
int64_t getInvalidDisplayId() const { return mComposerClient->getInvalidDisplayId(); }
|
|
|
|
VtsDisplay& getEditablePrimaryDisplay() { return mDisplays[0]; }
|
|
|
|
struct TestParameters {
|
|
nsecs_t delayForChange;
|
|
bool refreshMiss;
|
|
};
|
|
|
|
std::unique_ptr<VtsComposerClient> mComposerClient;
|
|
std::vector<VtsDisplay> mDisplays;
|
|
// use the slot count usually set by SF
|
|
static constexpr uint32_t kBufferSlotCount = 64;
|
|
};
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetDisplayCapabilities_BadDisplay) {
|
|
const auto& [status, _] = mComposerClient->getDisplayCapabilities(getInvalidDisplayId());
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_DISPLAY));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetDisplayCapabilities) {
|
|
for (const auto& display : mDisplays) {
|
|
const auto& [status, capabilities] =
|
|
mComposerClient->getDisplayCapabilities(display.getDisplayId());
|
|
|
|
EXPECT_TRUE(status.isOk());
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, DumpDebugInfo) {
|
|
ASSERT_TRUE(mComposerClient->dumpDebugInfo().isOk());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, CreateClientSingleton) {
|
|
std::shared_ptr<IComposerClient> composerClient;
|
|
const auto& status = mComposerClient->createClient();
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_NO_RESOURCES));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetDisplayIdentificationData) {
|
|
const auto& [status0, displayIdentification0] =
|
|
mComposerClient->getDisplayIdentificationData(getPrimaryDisplayId());
|
|
if (!status0.isOk() && status0.getExceptionCode() == EX_SERVICE_SPECIFIC &&
|
|
status0.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED) {
|
|
GTEST_SUCCEED() << "Display identification data not supported, skipping test";
|
|
return;
|
|
}
|
|
ASSERT_TRUE(status0.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";
|
|
|
|
const auto& [status1, displayIdentification1] =
|
|
mComposerClient->getDisplayIdentificationData(getPrimaryDisplayId());
|
|
ASSERT_TRUE(status1.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) {
|
|
const auto& [status, hdrCapabilities] =
|
|
mComposerClient->getHdrCapabilities(getPrimaryDisplayId());
|
|
|
|
ASSERT_TRUE(status.isOk());
|
|
EXPECT_TRUE(hdrCapabilities.maxLuminance >= hdrCapabilities.minLuminance);
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetPerFrameMetadataKeys) {
|
|
const auto& [status, keys] = mComposerClient->getPerFrameMetadataKeys(getPrimaryDisplayId());
|
|
if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC &&
|
|
status.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED) {
|
|
GTEST_SUCCEED() << "getPerFrameMetadataKeys is not supported";
|
|
return;
|
|
}
|
|
|
|
ASSERT_TRUE(status.isOk());
|
|
EXPECT_TRUE(keys.size() >= 0);
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetReadbackBufferAttributes) {
|
|
const auto& [status, _] = mComposerClient->getReadbackBufferAttributes(getPrimaryDisplayId());
|
|
if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC &&
|
|
status.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED) {
|
|
GTEST_SUCCEED() << "getReadbackBufferAttributes is not supported";
|
|
return;
|
|
}
|
|
|
|
ASSERT_TRUE(status.isOk());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetRenderIntents) {
|
|
const auto& [status, modes] = mComposerClient->getColorModes(getPrimaryDisplayId());
|
|
EXPECT_TRUE(status.isOk());
|
|
|
|
for (auto mode : modes) {
|
|
const auto& [intentStatus, intents] =
|
|
mComposerClient->getRenderIntents(getPrimaryDisplayId(), mode);
|
|
EXPECT_TRUE(intentStatus.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;
|
|
|
|
const auto iter = std::find(intents.cbegin(), intents.cend(), requiredIntent);
|
|
EXPECT_NE(intents.cend(), iter);
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetRenderIntents_BadDisplay) {
|
|
const auto& [status, modes] = mComposerClient->getColorModes(getPrimaryDisplayId());
|
|
ASSERT_TRUE(status.isOk());
|
|
|
|
for (auto mode : modes) {
|
|
const auto& [intentStatus, _] =
|
|
mComposerClient->getRenderIntents(getInvalidDisplayId(), mode);
|
|
|
|
EXPECT_FALSE(intentStatus.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(
|
|
assertServiceSpecificError(intentStatus, IComposerClient::EX_BAD_DISPLAY));
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetRenderIntents_BadParameter) {
|
|
const auto& [status, _] =
|
|
mComposerClient->getRenderIntents(getPrimaryDisplayId(), static_cast<ColorMode>(-1));
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_PARAMETER));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetColorModes) {
|
|
const auto& [status, colorModes] = mComposerClient->getColorModes(getPrimaryDisplayId());
|
|
ASSERT_TRUE(status.isOk());
|
|
|
|
const auto native = std::find(colorModes.cbegin(), colorModes.cend(), ColorMode::NATIVE);
|
|
EXPECT_NE(colorModes.cend(), native);
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetColorMode_BadDisplay) {
|
|
const auto& [status, _] = mComposerClient->getColorModes(getInvalidDisplayId());
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_DISPLAY));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetColorMode) {
|
|
const auto& [status, colorModes] = mComposerClient->getColorModes(getPrimaryDisplayId());
|
|
EXPECT_TRUE(status.isOk());
|
|
|
|
for (auto mode : colorModes) {
|
|
const auto& [intentStatus, intents] =
|
|
mComposerClient->getRenderIntents(getPrimaryDisplayId(), mode);
|
|
EXPECT_TRUE(intentStatus.isOk()) << "failed to get render intents";
|
|
|
|
for (auto intent : intents) {
|
|
const auto modeStatus =
|
|
mComposerClient->setColorMode(getPrimaryDisplayId(), mode, intent);
|
|
EXPECT_TRUE(modeStatus.isOk() ||
|
|
(modeStatus.getExceptionCode() == EX_SERVICE_SPECIFIC &&
|
|
IComposerClient::EX_UNSUPPORTED == modeStatus.getServiceSpecificError()))
|
|
<< "failed to set color mode";
|
|
}
|
|
}
|
|
|
|
const auto modeStatus = mComposerClient->setColorMode(getPrimaryDisplayId(), ColorMode::NATIVE,
|
|
RenderIntent::COLORIMETRIC);
|
|
EXPECT_TRUE(modeStatus.isOk() ||
|
|
(modeStatus.getExceptionCode() == EX_SERVICE_SPECIFIC &&
|
|
IComposerClient::EX_UNSUPPORTED == modeStatus.getServiceSpecificError()))
|
|
<< "failed to set color mode";
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetColorMode_BadDisplay) {
|
|
const auto& [status, colorModes] = mComposerClient->getColorModes(getPrimaryDisplayId());
|
|
ASSERT_TRUE(status.isOk());
|
|
|
|
for (auto mode : colorModes) {
|
|
const auto& [intentStatus, intents] =
|
|
mComposerClient->getRenderIntents(getPrimaryDisplayId(), mode);
|
|
ASSERT_TRUE(intentStatus.isOk()) << "failed to get render intents";
|
|
|
|
for (auto intent : intents) {
|
|
auto const modeStatus =
|
|
mComposerClient->setColorMode(getInvalidDisplayId(), mode, intent);
|
|
|
|
EXPECT_FALSE(modeStatus.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(
|
|
assertServiceSpecificError(modeStatus, IComposerClient::EX_BAD_DISPLAY));
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetColorMode_BadParameter) {
|
|
auto status = mComposerClient->setColorMode(getPrimaryDisplayId(), static_cast<ColorMode>(-1),
|
|
RenderIntent::COLORIMETRIC);
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_PARAMETER));
|
|
|
|
status = mComposerClient->setColorMode(getPrimaryDisplayId(), ColorMode::NATIVE,
|
|
static_cast<RenderIntent>(-1));
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_PARAMETER));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetDisplayedContentSamplingAttributes) {
|
|
int constexpr kInvalid = -1;
|
|
const auto& [status, format] =
|
|
mComposerClient->getDisplayedContentSamplingAttributes(getPrimaryDisplayId());
|
|
|
|
if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC &&
|
|
status.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED) {
|
|
SUCCEED() << "Device does not support optional extension. Test skipped";
|
|
return;
|
|
}
|
|
|
|
ASSERT_TRUE(status.isOk());
|
|
EXPECT_NE(kInvalid, static_cast<int>(format.format));
|
|
EXPECT_NE(kInvalid, static_cast<int>(format.dataspace));
|
|
EXPECT_NE(kInvalid, static_cast<int>(format.componentMask));
|
|
};
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetDisplayedContentSamplingEnabled) {
|
|
int constexpr kMaxFrames = 10;
|
|
FormatColorComponent enableAllComponents = FormatColorComponent::FORMAT_COMPONENT_0;
|
|
auto status = mComposerClient->setDisplayedContentSamplingEnabled(
|
|
getPrimaryDisplayId(), /*isEnabled*/ true, enableAllComponents, kMaxFrames);
|
|
if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC &&
|
|
status.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED) {
|
|
SUCCEED() << "Device does not support optional extension. Test skipped";
|
|
return;
|
|
}
|
|
EXPECT_TRUE(status.isOk());
|
|
|
|
status = mComposerClient->setDisplayedContentSamplingEnabled(
|
|
getPrimaryDisplayId(), /*isEnabled*/ false, enableAllComponents, kMaxFrames);
|
|
EXPECT_TRUE(status.isOk());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetDisplayedContentSample) {
|
|
const auto& [status, displayContentSamplingAttributes] =
|
|
mComposerClient->getDisplayedContentSamplingAttributes(getPrimaryDisplayId());
|
|
if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC &&
|
|
status.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED) {
|
|
SUCCEED() << "Sampling attributes aren't supported on this device, test skipped";
|
|
return;
|
|
}
|
|
|
|
int64_t constexpr kMaxFrames = 10;
|
|
int64_t constexpr kTimestamp = 0;
|
|
const auto& [sampleStatus, displayContentSample] = mComposerClient->getDisplayedContentSample(
|
|
getPrimaryDisplayId(), kMaxFrames, kTimestamp);
|
|
if (!sampleStatus.isOk() && sampleStatus.getExceptionCode() == EX_SERVICE_SPECIFIC &&
|
|
sampleStatus.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED) {
|
|
SUCCEED() << "Device does not support optional extension. Test skipped";
|
|
return;
|
|
}
|
|
|
|
EXPECT_TRUE(sampleStatus.isOk());
|
|
const 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, GetDisplayConnectionType) {
|
|
const auto& [status, type] = mComposerClient->getDisplayConnectionType(getInvalidDisplayId());
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_DISPLAY));
|
|
|
|
for (const auto& display : mDisplays) {
|
|
const auto& [connectionTypeStatus, _] =
|
|
mComposerClient->getDisplayConnectionType(display.getDisplayId());
|
|
EXPECT_TRUE(connectionTypeStatus.isOk());
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetDisplayAttribute) {
|
|
for (const auto& display : mDisplays) {
|
|
const auto& [status, configs] = mComposerClient->getDisplayConfigs(display.getDisplayId());
|
|
EXPECT_TRUE(status.isOk());
|
|
|
|
for (const auto& config : configs) {
|
|
const std::array<DisplayAttribute, 4> requiredAttributes = {{
|
|
DisplayAttribute::WIDTH,
|
|
DisplayAttribute::HEIGHT,
|
|
DisplayAttribute::VSYNC_PERIOD,
|
|
DisplayAttribute::CONFIG_GROUP,
|
|
}};
|
|
for (const auto& attribute : requiredAttributes) {
|
|
const auto& [attribStatus, value] = mComposerClient->getDisplayAttribute(
|
|
display.getDisplayId(), config, attribute);
|
|
EXPECT_TRUE(attribStatus.isOk());
|
|
EXPECT_NE(-1, value);
|
|
}
|
|
|
|
const std::array<DisplayAttribute, 2> optionalAttributes = {{
|
|
DisplayAttribute::DPI_X,
|
|
DisplayAttribute::DPI_Y,
|
|
}};
|
|
for (const auto& attribute : optionalAttributes) {
|
|
const auto& [attribStatus, value] = mComposerClient->getDisplayAttribute(
|
|
display.getDisplayId(), config, attribute);
|
|
EXPECT_TRUE(attribStatus.isOk() ||
|
|
(attribStatus.getExceptionCode() == EX_SERVICE_SPECIFIC &&
|
|
IComposerClient::EX_UNSUPPORTED ==
|
|
attribStatus.getServiceSpecificError()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, CheckConfigsAreValid) {
|
|
for (const auto& display : mDisplays) {
|
|
const auto& [status, configs] = mComposerClient->getDisplayConfigs(display.getDisplayId());
|
|
EXPECT_TRUE(status.isOk());
|
|
|
|
EXPECT_FALSE(std::any_of(configs.begin(), configs.end(), [](auto config) {
|
|
return config == IComposerClient::INVALID_CONFIGURATION;
|
|
}));
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetDisplayVsyncPeriod_BadDisplay) {
|
|
const auto& [status, vsyncPeriodNanos] =
|
|
mComposerClient->getDisplayVsyncPeriod(getInvalidDisplayId());
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_DISPLAY));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetActiveConfigWithConstraints_BadDisplay) {
|
|
VsyncPeriodChangeConstraints constraints;
|
|
constraints.seamlessRequired = false;
|
|
constraints.desiredTimeNanos = systemTime();
|
|
auto invalidDisplay = VtsDisplay(getInvalidDisplayId());
|
|
|
|
const auto& [status, timeline] = mComposerClient->setActiveConfigWithConstraints(
|
|
&invalidDisplay, /*config*/ 0, constraints);
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_DISPLAY));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetActiveConfigWithConstraints_BadConfig) {
|
|
VsyncPeriodChangeConstraints constraints;
|
|
constraints.seamlessRequired = false;
|
|
constraints.desiredTimeNanos = systemTime();
|
|
|
|
for (VtsDisplay& display : mDisplays) {
|
|
int32_t constexpr kInvalidConfigId = IComposerClient::INVALID_CONFIGURATION;
|
|
const auto& [status, _] = mComposerClient->setActiveConfigWithConstraints(
|
|
&display, kInvalidConfigId, constraints);
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_CONFIG));
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetBootDisplayConfig_BadDisplay) {
|
|
if (!hasCapability(Capability::BOOT_DISPLAY_CONFIG)) {
|
|
GTEST_SUCCEED() << "Boot Display Config not supported";
|
|
return;
|
|
}
|
|
const auto& status = mComposerClient->setBootDisplayConfig(getInvalidDisplayId(), /*config*/ 0);
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_DISPLAY));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetBootDisplayConfig_BadConfig) {
|
|
if (!hasCapability(Capability::BOOT_DISPLAY_CONFIG)) {
|
|
GTEST_SUCCEED() << "Boot Display Config not supported";
|
|
return;
|
|
}
|
|
for (VtsDisplay& display : mDisplays) {
|
|
int32_t constexpr kInvalidConfigId = IComposerClient::INVALID_CONFIGURATION;
|
|
const auto& status =
|
|
mComposerClient->setBootDisplayConfig(display.getDisplayId(), kInvalidConfigId);
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_CONFIG));
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetBootDisplayConfig) {
|
|
if (!hasCapability(Capability::BOOT_DISPLAY_CONFIG)) {
|
|
GTEST_SUCCEED() << "Boot Display Config not supported";
|
|
return;
|
|
}
|
|
const auto& [status, configs] = mComposerClient->getDisplayConfigs(getPrimaryDisplayId());
|
|
EXPECT_TRUE(status.isOk());
|
|
for (const auto& config : configs) {
|
|
EXPECT_TRUE(mComposerClient->setBootDisplayConfig(getPrimaryDisplayId(), config).isOk());
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, ClearBootDisplayConfig_BadDisplay) {
|
|
if (!hasCapability(Capability::BOOT_DISPLAY_CONFIG)) {
|
|
GTEST_SUCCEED() << "Boot Display Config not supported";
|
|
return;
|
|
}
|
|
const auto& status = mComposerClient->clearBootDisplayConfig(getInvalidDisplayId());
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_DISPLAY));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, ClearBootDisplayConfig) {
|
|
if (!hasCapability(Capability::BOOT_DISPLAY_CONFIG)) {
|
|
GTEST_SUCCEED() << "Boot Display Config not supported";
|
|
return;
|
|
}
|
|
EXPECT_TRUE(mComposerClient->clearBootDisplayConfig(getPrimaryDisplayId()).isOk());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetPreferredBootDisplayConfig_BadDisplay) {
|
|
if (!hasCapability(Capability::BOOT_DISPLAY_CONFIG)) {
|
|
GTEST_SUCCEED() << "Boot Display Config not supported";
|
|
return;
|
|
}
|
|
const auto& [status, _] = mComposerClient->getPreferredBootDisplayConfig(getInvalidDisplayId());
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_DISPLAY));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetPreferredBootDisplayConfig) {
|
|
if (!hasCapability(Capability::BOOT_DISPLAY_CONFIG)) {
|
|
GTEST_SUCCEED() << "Boot Display Config not supported";
|
|
return;
|
|
}
|
|
const auto& [status, preferredDisplayConfig] =
|
|
mComposerClient->getPreferredBootDisplayConfig(getPrimaryDisplayId());
|
|
EXPECT_TRUE(status.isOk());
|
|
|
|
const auto& [configStatus, configs] = mComposerClient->getDisplayConfigs(getPrimaryDisplayId());
|
|
|
|
EXPECT_TRUE(configStatus.isOk());
|
|
EXPECT_NE(configs.end(), std::find(configs.begin(), configs.end(), preferredDisplayConfig));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, BootDisplayConfig_Unsupported) {
|
|
if (!hasCapability(Capability::BOOT_DISPLAY_CONFIG)) {
|
|
const auto& [configStatus, config] =
|
|
mComposerClient->getActiveConfig(getPrimaryDisplayId());
|
|
EXPECT_TRUE(configStatus.isOk());
|
|
|
|
auto status = mComposerClient->setBootDisplayConfig(getPrimaryDisplayId(), config);
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(
|
|
assertServiceSpecificError(status, IComposerClient::EX_UNSUPPORTED));
|
|
|
|
status = mComposerClient->getPreferredBootDisplayConfig(getPrimaryDisplayId()).first;
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(
|
|
assertServiceSpecificError(status, IComposerClient::EX_UNSUPPORTED));
|
|
|
|
status = mComposerClient->clearBootDisplayConfig(getPrimaryDisplayId());
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(
|
|
assertServiceSpecificError(status, IComposerClient::EX_UNSUPPORTED));
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetHdrConversionCapabilities) {
|
|
if (!hasCapability(Capability::HDR_OUTPUT_CONVERSION_CONFIG)) {
|
|
GTEST_SUCCEED() << "HDR output conversion not supported";
|
|
return;
|
|
}
|
|
const auto& [status, conversionCapabilities] = mComposerClient->getHdrConversionCapabilities();
|
|
EXPECT_TRUE(status.isOk());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetHdrConversionStrategy_Passthrough) {
|
|
if (!hasCapability(Capability::HDR_OUTPUT_CONVERSION_CONFIG)) {
|
|
GTEST_SUCCEED() << "HDR output conversion not supported";
|
|
return;
|
|
}
|
|
common::HdrConversionStrategy hdrConversionStrategy;
|
|
hdrConversionStrategy.set<common::HdrConversionStrategy::Tag::passthrough>(true);
|
|
const auto& [status, preferredHdrOutputType] =
|
|
mComposerClient->setHdrConversionStrategy(hdrConversionStrategy);
|
|
EXPECT_TRUE(status.isOk());
|
|
EXPECT_EQ(common::Hdr::INVALID, preferredHdrOutputType);
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetHdrConversionStrategy_Force) {
|
|
if (!hasCapability(Capability::HDR_OUTPUT_CONVERSION_CONFIG)) {
|
|
GTEST_SUCCEED() << "HDR output conversion not supported";
|
|
return;
|
|
}
|
|
const auto& [status, conversionCapabilities] = mComposerClient->getHdrConversionCapabilities();
|
|
const auto& [status2, hdrCapabilities] =
|
|
mComposerClient->getHdrCapabilities(getPrimaryDisplayId());
|
|
const auto& hdrTypes = hdrCapabilities.types;
|
|
for (auto conversionCapability : conversionCapabilities) {
|
|
if (conversionCapability.outputType != common::Hdr::INVALID) {
|
|
if (std::find(hdrTypes.begin(), hdrTypes.end(), conversionCapability.outputType) ==
|
|
hdrTypes.end()) {
|
|
continue;
|
|
}
|
|
common::HdrConversionStrategy hdrConversionStrategy;
|
|
hdrConversionStrategy.set<common::HdrConversionStrategy::Tag::forceHdrConversion>(
|
|
conversionCapability.outputType);
|
|
const auto& [statusSet, preferredHdrOutputType] =
|
|
mComposerClient->setHdrConversionStrategy(hdrConversionStrategy);
|
|
EXPECT_TRUE(statusSet.isOk());
|
|
EXPECT_EQ(common::Hdr::INVALID, preferredHdrOutputType);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetHdrConversionStrategy_Auto) {
|
|
if (!hasCapability(Capability::HDR_OUTPUT_CONVERSION_CONFIG)) {
|
|
GTEST_SUCCEED() << "HDR output conversion not supported";
|
|
return;
|
|
}
|
|
const auto& [status, conversionCapabilities] = mComposerClient->getHdrConversionCapabilities();
|
|
const auto& [status2, hdrCapabilities] =
|
|
mComposerClient->getHdrCapabilities(getPrimaryDisplayId());
|
|
if (hdrCapabilities.types.size() <= 0) {
|
|
return;
|
|
}
|
|
std::vector<aidl::android::hardware::graphics::common::Hdr> autoHdrTypes;
|
|
for (auto conversionCapability : conversionCapabilities) {
|
|
if (conversionCapability.outputType != common::Hdr::INVALID) {
|
|
autoHdrTypes.push_back(conversionCapability.outputType);
|
|
}
|
|
}
|
|
common::HdrConversionStrategy hdrConversionStrategy;
|
|
hdrConversionStrategy.set<common::HdrConversionStrategy::Tag::autoAllowedHdrTypes>(
|
|
autoHdrTypes);
|
|
const auto& [statusSet, preferredHdrOutputType] =
|
|
mComposerClient->setHdrConversionStrategy(hdrConversionStrategy);
|
|
EXPECT_TRUE(statusSet.isOk());
|
|
EXPECT_NE(common::Hdr::INVALID, preferredHdrOutputType);
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetAutoLowLatencyMode_BadDisplay) {
|
|
auto status = mComposerClient->setAutoLowLatencyMode(getInvalidDisplayId(), /*isEnabled*/ true);
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_DISPLAY));
|
|
|
|
status = mComposerClient->setAutoLowLatencyMode(getInvalidDisplayId(), /*isEnabled*/ false);
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_DISPLAY));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetAutoLowLatencyMode) {
|
|
for (const auto& display : mDisplays) {
|
|
const auto& [status, capabilities] =
|
|
mComposerClient->getDisplayCapabilities(display.getDisplayId());
|
|
ASSERT_TRUE(status.isOk());
|
|
|
|
const bool allmSupport =
|
|
std::find(capabilities.begin(), capabilities.end(),
|
|
DisplayCapability::AUTO_LOW_LATENCY_MODE) != capabilities.end();
|
|
|
|
if (!allmSupport) {
|
|
const auto& statusIsOn = mComposerClient->setAutoLowLatencyMode(display.getDisplayId(),
|
|
/*isEnabled*/ true);
|
|
EXPECT_FALSE(statusIsOn.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(
|
|
assertServiceSpecificError(statusIsOn, IComposerClient::EX_UNSUPPORTED));
|
|
const auto& statusIsOff = mComposerClient->setAutoLowLatencyMode(display.getDisplayId(),
|
|
/*isEnabled*/ false);
|
|
EXPECT_FALSE(statusIsOff.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(
|
|
assertServiceSpecificError(statusIsOff, IComposerClient::EX_UNSUPPORTED));
|
|
GTEST_SUCCEED() << "Auto Low Latency Mode is not supported on display "
|
|
<< std::to_string(display.getDisplayId()) << ", skipping test";
|
|
return;
|
|
}
|
|
|
|
EXPECT_TRUE(mComposerClient->setAutoLowLatencyMode(display.getDisplayId(), true).isOk());
|
|
EXPECT_TRUE(mComposerClient->setAutoLowLatencyMode(display.getDisplayId(), false).isOk());
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetSupportedContentTypes_BadDisplay) {
|
|
const auto& [status, _] = mComposerClient->getSupportedContentTypes(getInvalidDisplayId());
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_DISPLAY));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetSupportedContentTypes) {
|
|
for (const auto& display : mDisplays) {
|
|
const auto& [status, supportedContentTypes] =
|
|
mComposerClient->getSupportedContentTypes(display.getDisplayId());
|
|
ASSERT_TRUE(status.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) {
|
|
EXPECT_TRUE(
|
|
mComposerClient->setContentType(display.getDisplayId(), ContentType::NONE).isOk());
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetContentType_BadDisplay) {
|
|
constexpr ContentType types[] = {ContentType::NONE, ContentType::GRAPHICS, ContentType::PHOTO,
|
|
ContentType::CINEMA, ContentType::GAME};
|
|
for (const auto& type : types) {
|
|
const auto& status = mComposerClient->setContentType(getInvalidDisplayId(), type);
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(
|
|
assertServiceSpecificError(status, IComposerClient::EX_BAD_DISPLAY));
|
|
}
|
|
}
|
|
|
|
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, CreateVirtualDisplay) {
|
|
const auto& [status, maxVirtualDisplayCount] = mComposerClient->getMaxVirtualDisplayCount();
|
|
EXPECT_TRUE(status.isOk());
|
|
|
|
if (maxVirtualDisplayCount == 0) {
|
|
GTEST_SUCCEED() << "no virtual display support";
|
|
return;
|
|
}
|
|
|
|
const auto& [virtualDisplayStatus, virtualDisplay] = mComposerClient->createVirtualDisplay(
|
|
/*width*/ 64, /*height*/ 64, common::PixelFormat::IMPLEMENTATION_DEFINED,
|
|
kBufferSlotCount);
|
|
|
|
ASSERT_TRUE(virtualDisplayStatus.isOk());
|
|
EXPECT_TRUE(mComposerClient->destroyVirtualDisplay(virtualDisplay.display).isOk());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, DestroyVirtualDisplay_BadDisplay) {
|
|
const auto& [status, maxDisplayCount] = mComposerClient->getMaxVirtualDisplayCount();
|
|
EXPECT_TRUE(status.isOk());
|
|
|
|
if (maxDisplayCount == 0) {
|
|
GTEST_SUCCEED() << "no virtual display support";
|
|
return;
|
|
}
|
|
|
|
const auto& destroyStatus = mComposerClient->destroyVirtualDisplay(getInvalidDisplayId());
|
|
|
|
EXPECT_FALSE(destroyStatus.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(
|
|
assertServiceSpecificError(destroyStatus, IComposerClient::EX_BAD_DISPLAY));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, CreateLayer) {
|
|
const auto& [status, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
|
|
EXPECT_TRUE(status.isOk());
|
|
EXPECT_TRUE(mComposerClient->destroyLayer(getPrimaryDisplayId(), layer).isOk());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, CreateLayer_BadDisplay) {
|
|
const auto& [status, _] = mComposerClient->createLayer(getInvalidDisplayId(), kBufferSlotCount);
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_DISPLAY));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, DestroyLayer_BadDisplay) {
|
|
const auto& [status, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(status.isOk());
|
|
|
|
const auto& destroyStatus = mComposerClient->destroyLayer(getInvalidDisplayId(), layer);
|
|
|
|
EXPECT_FALSE(destroyStatus.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(
|
|
assertServiceSpecificError(destroyStatus, IComposerClient::EX_BAD_DISPLAY));
|
|
ASSERT_TRUE(mComposerClient->destroyLayer(getPrimaryDisplayId(), layer).isOk());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, DestroyLayer_BadLayerError) {
|
|
// We haven't created any layers yet, so any id should be invalid
|
|
const auto& status = mComposerClient->destroyLayer(getPrimaryDisplayId(), /*layer*/ 1);
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_LAYER));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetActiveConfig_BadDisplay) {
|
|
const auto& [status, _] = mComposerClient->getActiveConfig(getInvalidDisplayId());
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_DISPLAY));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetDisplayConfig) {
|
|
const auto& [status, _] = mComposerClient->getDisplayConfigs(getPrimaryDisplayId());
|
|
EXPECT_TRUE(status.isOk());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetDisplayConfig_BadDisplay) {
|
|
const auto& [status, _] = mComposerClient->getDisplayConfigs(getInvalidDisplayId());
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_DISPLAY));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetDisplayName) {
|
|
const auto& [status, _] = mComposerClient->getDisplayName(getPrimaryDisplayId());
|
|
EXPECT_TRUE(status.isOk());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetOverlaySupport) {
|
|
if (getInterfaceVersion() <= 1) {
|
|
GTEST_SUCCEED() << "Device does not support the new API for overlay support";
|
|
return;
|
|
}
|
|
|
|
const auto& [status, properties] = mComposerClient->getOverlaySupport();
|
|
if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC &&
|
|
status.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED) {
|
|
GTEST_SUCCEED() << "getOverlaySupport is not supported";
|
|
return;
|
|
}
|
|
|
|
ASSERT_TRUE(status.isOk());
|
|
for (const auto& i : properties.combinations) {
|
|
for (const auto standard : i.standards) {
|
|
const auto val = static_cast<int32_t>(standard) &
|
|
static_cast<int32_t>(common::Dataspace::STANDARD_MASK);
|
|
ASSERT_TRUE(val == static_cast<int32_t>(standard));
|
|
}
|
|
for (const auto transfer : i.transfers) {
|
|
const auto val = static_cast<int32_t>(transfer) &
|
|
static_cast<int32_t>(common::Dataspace::TRANSFER_MASK);
|
|
ASSERT_TRUE(val == static_cast<int32_t>(transfer));
|
|
}
|
|
for (const auto range : i.ranges) {
|
|
const auto val = static_cast<int32_t>(range) &
|
|
static_cast<int32_t>(common::Dataspace::RANGE_MASK);
|
|
ASSERT_TRUE(val == static_cast<int32_t>(range));
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetDisplayPhysicalOrientation_BadDisplay) {
|
|
const auto& [status, _] = mComposerClient->getDisplayPhysicalOrientation(getInvalidDisplayId());
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_DISPLAY));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetDisplayPhysicalOrientation) {
|
|
const auto allowedDisplayOrientations = std::array<Transform, 4>{
|
|
Transform::NONE,
|
|
Transform::ROT_90,
|
|
Transform::ROT_180,
|
|
Transform::ROT_270,
|
|
};
|
|
|
|
const auto& [status, displayOrientation] =
|
|
mComposerClient->getDisplayPhysicalOrientation(getPrimaryDisplayId());
|
|
|
|
EXPECT_TRUE(status.isOk());
|
|
EXPECT_NE(std::find(allowedDisplayOrientations.begin(), allowedDisplayOrientations.end(),
|
|
displayOrientation),
|
|
allowedDisplayOrientations.end());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetClientTargetSlotCount) {
|
|
EXPECT_TRUE(mComposerClient->setClientTargetSlotCount(getPrimaryDisplayId(), kBufferSlotCount)
|
|
.isOk());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetActiveConfig) {
|
|
const auto& [status, configs] = mComposerClient->getDisplayConfigs(getPrimaryDisplayId());
|
|
EXPECT_TRUE(status.isOk());
|
|
|
|
for (const auto& config : configs) {
|
|
auto display = getEditablePrimaryDisplay();
|
|
EXPECT_TRUE(mComposerClient->setActiveConfig(&display, config).isOk());
|
|
const auto& [configStatus, config1] =
|
|
mComposerClient->getActiveConfig(getPrimaryDisplayId());
|
|
EXPECT_TRUE(configStatus.isOk());
|
|
EXPECT_EQ(config, config1);
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetActiveConfigPowerCycle) {
|
|
EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::OFF).isOk());
|
|
EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::ON).isOk());
|
|
|
|
const auto& [status, configs] = mComposerClient->getDisplayConfigs(getPrimaryDisplayId());
|
|
EXPECT_TRUE(status.isOk());
|
|
|
|
for (const auto& config : configs) {
|
|
auto display = getEditablePrimaryDisplay();
|
|
EXPECT_TRUE(mComposerClient->setActiveConfig(&display, config).isOk());
|
|
const auto& [config1Status, config1] =
|
|
mComposerClient->getActiveConfig(getPrimaryDisplayId());
|
|
EXPECT_TRUE(config1Status.isOk());
|
|
EXPECT_EQ(config, config1);
|
|
|
|
EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::OFF).isOk());
|
|
EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::ON).isOk());
|
|
const auto& [config2Status, config2] =
|
|
mComposerClient->getActiveConfig(getPrimaryDisplayId());
|
|
EXPECT_TRUE(config2Status.isOk());
|
|
EXPECT_EQ(config, config2);
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetPowerModeUnsupported) {
|
|
const auto& [status, capabilities] =
|
|
mComposerClient->getDisplayCapabilities(getPrimaryDisplayId());
|
|
ASSERT_TRUE(status.isOk());
|
|
|
|
const bool isDozeSupported = std::find(capabilities.begin(), capabilities.end(),
|
|
DisplayCapability::DOZE) != capabilities.end();
|
|
const bool isSuspendSupported = std::find(capabilities.begin(), capabilities.end(),
|
|
DisplayCapability::SUSPEND) != capabilities.end();
|
|
|
|
if (!isDozeSupported) {
|
|
const auto& powerModeDozeStatus =
|
|
mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::DOZE);
|
|
EXPECT_FALSE(powerModeDozeStatus.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(
|
|
assertServiceSpecificError(powerModeDozeStatus, IComposerClient::EX_UNSUPPORTED));
|
|
|
|
const auto& powerModeDozeSuspendStatus =
|
|
mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::DOZE_SUSPEND);
|
|
EXPECT_FALSE(powerModeDozeSuspendStatus.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(powerModeDozeSuspendStatus,
|
|
IComposerClient::EX_UNSUPPORTED));
|
|
}
|
|
|
|
if (!isSuspendSupported) {
|
|
const auto& powerModeSuspendStatus =
|
|
mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::ON_SUSPEND);
|
|
EXPECT_FALSE(powerModeSuspendStatus.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(powerModeSuspendStatus,
|
|
IComposerClient::EX_UNSUPPORTED));
|
|
|
|
const auto& powerModeDozeSuspendStatus =
|
|
mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::DOZE_SUSPEND);
|
|
EXPECT_FALSE(powerModeDozeSuspendStatus.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(powerModeDozeSuspendStatus,
|
|
IComposerClient::EX_UNSUPPORTED));
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetVsyncEnabled) {
|
|
mComposerClient->setVsyncAllowed(true);
|
|
|
|
EXPECT_TRUE(mComposerClient->setVsync(getPrimaryDisplayId(), true).isOk());
|
|
usleep(60 * 1000);
|
|
EXPECT_TRUE(mComposerClient->setVsync(getPrimaryDisplayId(), false).isOk());
|
|
|
|
mComposerClient->setVsyncAllowed(false);
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetPowerMode) {
|
|
const auto& [status, capabilities] =
|
|
mComposerClient->getDisplayCapabilities(getPrimaryDisplayId());
|
|
ASSERT_TRUE(status.isOk());
|
|
|
|
const bool isDozeSupported = std::find(capabilities.begin(), capabilities.end(),
|
|
DisplayCapability::DOZE) != capabilities.end();
|
|
const bool isSuspendSupported = std::find(capabilities.begin(), capabilities.end(),
|
|
DisplayCapability::SUSPEND) != capabilities.end();
|
|
|
|
std::vector<PowerMode> modes;
|
|
modes.push_back(PowerMode::OFF);
|
|
modes.push_back(PowerMode::ON);
|
|
|
|
if (isSuspendSupported) {
|
|
modes.push_back(PowerMode::ON_SUSPEND);
|
|
}
|
|
|
|
if (isDozeSupported) {
|
|
modes.push_back(PowerMode::DOZE);
|
|
}
|
|
|
|
if (isSuspendSupported && isDozeSupported) {
|
|
modes.push_back(PowerMode::DOZE_SUSPEND);
|
|
}
|
|
|
|
for (auto mode : modes) {
|
|
EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), mode).isOk());
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetPowerModeVariations) {
|
|
const auto& [status, capabilities] =
|
|
mComposerClient->getDisplayCapabilities(getPrimaryDisplayId());
|
|
ASSERT_TRUE(status.isOk());
|
|
|
|
const bool isDozeSupported = std::find(capabilities.begin(), capabilities.end(),
|
|
DisplayCapability::DOZE) != capabilities.end();
|
|
const bool isSuspendSupported = std::find(capabilities.begin(), capabilities.end(),
|
|
DisplayCapability::SUSPEND) != capabilities.end();
|
|
|
|
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(getPrimaryDisplayId(), mode).isOk());
|
|
}
|
|
modes.clear();
|
|
|
|
modes.push_back(PowerMode::OFF);
|
|
modes.push_back(PowerMode::OFF);
|
|
for (auto mode : modes) {
|
|
EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), mode).isOk());
|
|
}
|
|
modes.clear();
|
|
|
|
modes.push_back(PowerMode::ON);
|
|
modes.push_back(PowerMode::ON);
|
|
for (auto mode : modes) {
|
|
EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), mode).isOk());
|
|
}
|
|
modes.clear();
|
|
|
|
if (isSuspendSupported) {
|
|
modes.push_back(PowerMode::ON_SUSPEND);
|
|
modes.push_back(PowerMode::ON_SUSPEND);
|
|
for (auto mode : modes) {
|
|
EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), mode).isOk());
|
|
}
|
|
modes.clear();
|
|
}
|
|
|
|
if (isDozeSupported) {
|
|
modes.push_back(PowerMode::DOZE);
|
|
modes.push_back(PowerMode::DOZE);
|
|
for (auto mode : modes) {
|
|
EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), mode).isOk());
|
|
}
|
|
modes.clear();
|
|
}
|
|
|
|
if (isSuspendSupported && isDozeSupported) {
|
|
modes.push_back(PowerMode::DOZE_SUSPEND);
|
|
modes.push_back(PowerMode::DOZE_SUSPEND);
|
|
for (auto mode : modes) {
|
|
EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), mode).isOk());
|
|
}
|
|
modes.clear();
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetPowerMode_BadDisplay) {
|
|
const auto& status = mComposerClient->setPowerMode(getInvalidDisplayId(), PowerMode::ON);
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_DISPLAY));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, SetPowerMode_BadParameter) {
|
|
const auto& status =
|
|
mComposerClient->setPowerMode(getPrimaryDisplayId(), static_cast<PowerMode>(-1));
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_PARAMETER));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetDataspaceSaturationMatrix) {
|
|
const auto& [status, matrix] =
|
|
mComposerClient->getDataspaceSaturationMatrix(common::Dataspace::SRGB_LINEAR);
|
|
ASSERT_TRUE(status.isOk());
|
|
ASSERT_EQ(16, matrix.size()); // matrix should not be empty if call succeeded.
|
|
|
|
// the last row is known
|
|
EXPECT_EQ(0.0f, matrix[12]);
|
|
EXPECT_EQ(0.0f, matrix[13]);
|
|
EXPECT_EQ(0.0f, matrix[14]);
|
|
EXPECT_EQ(1.0f, matrix[15]);
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlTest, GetDataspaceSaturationMatrix_BadParameter) {
|
|
const auto& [status, matrix] =
|
|
mComposerClient->getDataspaceSaturationMatrix(common::Dataspace::UNKNOWN);
|
|
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_PARAMETER));
|
|
}
|
|
|
|
// Tests for Command.
|
|
class GraphicsComposerAidlCommandTest : public GraphicsComposerAidlTest {
|
|
protected:
|
|
void TearDown() override {
|
|
const auto errors = mReader.takeErrors();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
ASSERT_TRUE(mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty());
|
|
|
|
ASSERT_NO_FATAL_FAILURE(GraphicsComposerAidlTest::TearDown());
|
|
}
|
|
|
|
void execute() {
|
|
std::vector<CommandResultPayload> payloads;
|
|
for (auto& [_, writer] : mWriters) {
|
|
auto commands = writer.takePendingCommands();
|
|
if (commands.empty()) {
|
|
continue;
|
|
}
|
|
|
|
auto [status, results] = mComposerClient->executeCommands(commands);
|
|
ASSERT_TRUE(status.isOk()) << "executeCommands failed " << status.getDescription();
|
|
|
|
payloads.reserve(payloads.size() + results.size());
|
|
payloads.insert(payloads.end(), std::make_move_iterator(results.begin()),
|
|
std::make_move_iterator(results.end()));
|
|
}
|
|
mReader.parse(std::move(payloads));
|
|
}
|
|
|
|
static inline auto toTimePoint(nsecs_t time) {
|
|
return std::chrono::time_point<std::chrono::steady_clock>(std::chrono::nanoseconds(time));
|
|
}
|
|
|
|
void forEachTwoConfigs(int64_t display, std::function<void(int32_t, int32_t)> func) {
|
|
const auto& [status, displayConfigs] = mComposerClient->getDisplayConfigs(display);
|
|
ASSERT_TRUE(status.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) {
|
|
const auto& [status, vsyncPeriodNanos] =
|
|
mComposerClient->getDisplayVsyncPeriod(display);
|
|
EXPECT_TRUE(status.isOk());
|
|
if (systemTime() <= desiredTimeNanos) {
|
|
EXPECT_EQ(vsyncPeriodNanos, oldPeriodNanos);
|
|
} else if (vsyncPeriodNanos == newPeriodNanos) {
|
|
break;
|
|
}
|
|
std::this_thread::sleep_for(std::chrono::nanoseconds(oldPeriodNanos));
|
|
}
|
|
}
|
|
|
|
bool checkIfCallbackRefreshRateChangedDebugEnabledReceived(
|
|
std::function<bool(RefreshRateChangedDebugData)> filter) {
|
|
const auto list = mComposerClient->takeListOfRefreshRateChangedDebugData();
|
|
return std::any_of(list.begin(), list.end(), [&](auto refreshRateChangedDebugData) {
|
|
return filter(refreshRateChangedDebugData);
|
|
});
|
|
}
|
|
|
|
sp<GraphicBuffer> allocate(uint32_t width, uint32_t height,
|
|
::android::PixelFormat pixelFormat) {
|
|
return sp<GraphicBuffer>::make(
|
|
width, height, pixelFormat, /*layerCount*/ 1U,
|
|
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");
|
|
}
|
|
|
|
sp<GraphicBuffer> allocate(::android::PixelFormat pixelFormat) {
|
|
return allocate(static_cast<uint32_t>(getPrimaryDisplay().getDisplayWidth()),
|
|
static_cast<uint32_t>(getPrimaryDisplay().getDisplayHeight()), pixelFormat);
|
|
}
|
|
|
|
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.getDisplayId(), PowerMode::ON).isOk());
|
|
EXPECT_TRUE(mComposerClient
|
|
->setColorMode(display.getDisplayId(), ColorMode::NATIVE,
|
|
RenderIntent::COLORIMETRIC)
|
|
.isOk());
|
|
|
|
const auto& [status, layer] =
|
|
mComposerClient->createLayer(display.getDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(status.isOk());
|
|
auto& writer = getWriter(display.getDisplayId());
|
|
{
|
|
const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
|
|
ASSERT_NE(nullptr, buffer);
|
|
ASSERT_EQ(::android::OK, buffer->initCheck());
|
|
ASSERT_NE(nullptr, buffer->handle);
|
|
|
|
configureLayer(display, layer, Composition::DEVICE, display.getFrameRect(),
|
|
display.getCrop());
|
|
writer.setLayerBuffer(display.getDisplayId(), layer, /*slot*/ 0, buffer->handle,
|
|
/*acquireFence*/ -1);
|
|
writer.setLayerDataspace(display.getDisplayId(), layer, common::Dataspace::UNKNOWN);
|
|
|
|
writer.validateDisplay(display.getDisplayId(), ComposerClientWriter::kNoTimestamp);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.presentDisplay(display.getDisplayId());
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
}
|
|
|
|
{
|
|
const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
|
|
ASSERT_NE(nullptr, buffer->handle);
|
|
|
|
writer.setLayerBuffer(display.getDisplayId(), layer, /*slot*/ 0, buffer->handle,
|
|
/*acquireFence*/ -1);
|
|
writer.setLayerSurfaceDamage(display.getDisplayId(), layer,
|
|
std::vector<Rect>(1, {0, 0, 10, 10}));
|
|
writer.validateDisplay(display.getDisplayId(), ComposerClientWriter::kNoTimestamp);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.presentDisplay(display.getDisplayId());
|
|
execute();
|
|
}
|
|
|
|
EXPECT_TRUE(mComposerClient->destroyLayer(display.getDisplayId(), layer).isOk());
|
|
}
|
|
|
|
sp<::android::Fence> presentAndGetFence(
|
|
std::optional<ClockMonotonicTimestamp> expectedPresentTime) {
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.validateDisplay(getPrimaryDisplayId(), expectedPresentTime);
|
|
execute();
|
|
EXPECT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.presentDisplay(getPrimaryDisplayId());
|
|
execute();
|
|
EXPECT_TRUE(mReader.takeErrors().empty());
|
|
|
|
auto presentFence = mReader.takePresentFence(getPrimaryDisplayId());
|
|
// take ownership
|
|
const int fenceOwner = presentFence.get();
|
|
*presentFence.getR() = -1;
|
|
EXPECT_NE(-1, fenceOwner);
|
|
return sp<::android::Fence>::make(fenceOwner);
|
|
}
|
|
|
|
int32_t getVsyncPeriod() {
|
|
const auto& [status, activeConfig] =
|
|
mComposerClient->getActiveConfig(getPrimaryDisplayId());
|
|
EXPECT_TRUE(status.isOk());
|
|
|
|
const auto& [vsyncPeriodStatus, vsyncPeriod] = mComposerClient->getDisplayAttribute(
|
|
getPrimaryDisplayId(), activeConfig, DisplayAttribute::VSYNC_PERIOD);
|
|
EXPECT_TRUE(vsyncPeriodStatus.isOk());
|
|
return vsyncPeriod;
|
|
}
|
|
|
|
int64_t createOnScreenLayer(Composition composition = Composition::DEVICE) {
|
|
const auto& [status, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(status.isOk());
|
|
Rect displayFrame{0, 0, getPrimaryDisplay().getDisplayWidth(),
|
|
getPrimaryDisplay().getDisplayHeight()};
|
|
FRect cropRect{0, 0, (float)getPrimaryDisplay().getDisplayWidth(),
|
|
(float)getPrimaryDisplay().getDisplayHeight()};
|
|
configureLayer(getPrimaryDisplay(), layer, composition, displayFrame, cropRect);
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.setLayerDataspace(getPrimaryDisplayId(), layer, common::Dataspace::UNKNOWN);
|
|
return layer;
|
|
}
|
|
|
|
void sendBufferUpdate(int64_t layer) {
|
|
const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
|
|
ASSERT_NE(nullptr, buffer->handle);
|
|
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, buffer->handle,
|
|
/*acquireFence*/ -1);
|
|
|
|
const sp<::android::Fence> presentFence =
|
|
presentAndGetFence(ComposerClientWriter::kNoTimestamp);
|
|
presentFence->waitForever(LOG_TAG);
|
|
}
|
|
|
|
bool hasDisplayCapability(int64_t display, DisplayCapability cap) {
|
|
const auto& [status, capabilities] = mComposerClient->getDisplayCapabilities(display);
|
|
EXPECT_TRUE(status.isOk());
|
|
|
|
return std::find(capabilities.begin(), capabilities.end(), cap) != capabilities.end();
|
|
}
|
|
|
|
void Test_setActiveConfigWithConstraints(const TestParameters& params) {
|
|
for (VtsDisplay& display : mDisplays) {
|
|
forEachTwoConfigs(display.getDisplayId(), [&](int32_t config1, int32_t config2) {
|
|
EXPECT_TRUE(mComposerClient->setActiveConfig(&display, config1).isOk());
|
|
sendRefreshFrame(display, nullptr);
|
|
|
|
const auto displayConfigGroup1 = display.getDisplayConfig(config1);
|
|
int32_t vsyncPeriod1 = displayConfigGroup1.vsyncPeriod;
|
|
int32_t configGroup1 = displayConfigGroup1.configGroup;
|
|
|
|
const auto displayConfigGroup2 = display.getDisplayConfig(config2);
|
|
int32_t vsyncPeriod2 = displayConfigGroup2.vsyncPeriod;
|
|
int32_t configGroup2 = displayConfigGroup2.configGroup;
|
|
|
|
if (vsyncPeriod1 == vsyncPeriod2) {
|
|
return; // continue
|
|
}
|
|
|
|
// We don't allow delayed change when changing config groups
|
|
if (params.delayForChange > 0 && configGroup1 != configGroup2) {
|
|
return; // continue
|
|
}
|
|
|
|
VsyncPeriodChangeConstraints constraints = {
|
|
.desiredTimeNanos = systemTime() + params.delayForChange,
|
|
.seamlessRequired = false};
|
|
const auto& [status, timeline] = mComposerClient->setActiveConfigWithConstraints(
|
|
&display, config2, constraints);
|
|
EXPECT_TRUE(status.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.getDisplayId(), 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 = mComposerClient->takeLastVsyncPeriodChangeTimeline();
|
|
if (timeline.refreshRequired && params.refreshMiss) {
|
|
EXPECT_TRUE(newTimeline.has_value());
|
|
}
|
|
|
|
if (newTimeline.has_value()) {
|
|
if (newTimeline->refreshRequired) {
|
|
sendRefreshFrame(display, &newTimeline.value());
|
|
}
|
|
waitForVsyncPeriodChange(display.getDisplayId(), newTimeline.value(),
|
|
constraints.desiredTimeNanos, vsyncPeriod1,
|
|
vsyncPeriod2);
|
|
}
|
|
|
|
const auto& [vsyncPeriodNanosStatus, vsyncPeriodNanos] =
|
|
mComposerClient->getDisplayVsyncPeriod(display.getDisplayId());
|
|
EXPECT_TRUE(vsyncPeriodNanosStatus.isOk());
|
|
EXPECT_EQ(vsyncPeriodNanos, vsyncPeriod2);
|
|
});
|
|
}
|
|
}
|
|
|
|
void Test_expectedPresentTime(std::optional<int> framesDelay) {
|
|
if (hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE)) {
|
|
GTEST_SUCCEED() << "Device has unreliable present fences capability, skipping";
|
|
return;
|
|
}
|
|
|
|
ASSERT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::ON).isOk());
|
|
|
|
const auto vsyncPeriod = getVsyncPeriod();
|
|
|
|
const auto buffer1 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
|
|
const auto buffer2 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
|
|
ASSERT_NE(nullptr, buffer1);
|
|
ASSERT_NE(nullptr, buffer2);
|
|
|
|
const auto layer = createOnScreenLayer();
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, buffer1->handle,
|
|
/*acquireFence*/ -1);
|
|
const sp<::android::Fence> presentFence1 =
|
|
presentAndGetFence(ComposerClientWriter::kNoTimestamp);
|
|
presentFence1->waitForever(LOG_TAG);
|
|
|
|
auto expectedPresentTime = presentFence1->getSignalTime() + vsyncPeriod;
|
|
if (framesDelay.has_value()) {
|
|
expectedPresentTime += *framesDelay * vsyncPeriod;
|
|
}
|
|
|
|
writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, buffer2->handle,
|
|
/*acquireFence*/ -1);
|
|
const auto setExpectedPresentTime = [&]() -> std::optional<ClockMonotonicTimestamp> {
|
|
if (!framesDelay.has_value()) {
|
|
return ComposerClientWriter::kNoTimestamp;
|
|
} else if (*framesDelay == 0) {
|
|
return ClockMonotonicTimestamp{0};
|
|
}
|
|
return ClockMonotonicTimestamp{expectedPresentTime};
|
|
}();
|
|
|
|
const sp<::android::Fence> presentFence2 = presentAndGetFence(setExpectedPresentTime);
|
|
presentFence2->waitForever(LOG_TAG);
|
|
|
|
const auto actualPresentTime = presentFence2->getSignalTime();
|
|
EXPECT_GE(actualPresentTime, expectedPresentTime - vsyncPeriod / 2);
|
|
|
|
ASSERT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::OFF).isOk());
|
|
}
|
|
|
|
void configureLayer(const VtsDisplay& display, int64_t layer, Composition composition,
|
|
const Rect& displayFrame, const FRect& cropRect) {
|
|
auto& writer = getWriter(display.getDisplayId());
|
|
writer.setLayerCompositionType(display.getDisplayId(), layer, composition);
|
|
writer.setLayerDisplayFrame(display.getDisplayId(), layer, displayFrame);
|
|
writer.setLayerPlaneAlpha(display.getDisplayId(), layer, /*alpha*/ 1);
|
|
writer.setLayerSourceCrop(display.getDisplayId(), layer, cropRect);
|
|
writer.setLayerTransform(display.getDisplayId(), layer, static_cast<Transform>(0));
|
|
writer.setLayerVisibleRegion(display.getDisplayId(), layer,
|
|
std::vector<Rect>(1, displayFrame));
|
|
writer.setLayerZOrder(display.getDisplayId(), layer, /*z*/ 10);
|
|
writer.setLayerBlendMode(display.getDisplayId(), layer, BlendMode::NONE);
|
|
writer.setLayerSurfaceDamage(display.getDisplayId(), layer,
|
|
std::vector<Rect>(1, displayFrame));
|
|
}
|
|
// 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
|
|
|
|
ComposerClientWriter& getWriter(int64_t display) {
|
|
auto [it, _] = mWriters.try_emplace(display, display);
|
|
return it->second;
|
|
}
|
|
|
|
ComposerClientReader mReader;
|
|
|
|
private:
|
|
std::unordered_map<int64_t, ComposerClientWriter> mWriters;
|
|
};
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetColorTransform) {
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.setColorTransform(getPrimaryDisplayId(), kIdentity.data());
|
|
execute();
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetLayerColorTransform) {
|
|
const auto& [status, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(status.isOk());
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.setLayerColorTransform(getPrimaryDisplayId(), layer, kIdentity.data());
|
|
execute();
|
|
|
|
const auto errors = mReader.takeErrors();
|
|
if (errors.size() == 1 && errors[0].errorCode == IComposerClient::EX_UNSUPPORTED) {
|
|
GTEST_SUCCEED() << "setLayerColorTransform is not supported";
|
|
return;
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetDisplayBrightness) {
|
|
const auto& [status, capabilities] =
|
|
mComposerClient->getDisplayCapabilities(getPrimaryDisplayId());
|
|
ASSERT_TRUE(status.isOk());
|
|
bool brightnessSupport = std::find(capabilities.begin(), capabilities.end(),
|
|
DisplayCapability::BRIGHTNESS) != capabilities.end();
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
if (!brightnessSupport) {
|
|
writer.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 0.5f, -1.f);
|
|
execute();
|
|
const auto errors = mReader.takeErrors();
|
|
EXPECT_EQ(1, errors.size());
|
|
EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, errors[0].errorCode);
|
|
GTEST_SUCCEED() << "SetDisplayBrightness is not supported";
|
|
return;
|
|
}
|
|
|
|
writer.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 0.0f, -1.f);
|
|
execute();
|
|
EXPECT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 0.5f, -1.f);
|
|
execute();
|
|
EXPECT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 1.0f, -1.f);
|
|
execute();
|
|
EXPECT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ -1.0f, -1.f);
|
|
execute();
|
|
EXPECT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 2.0f, -1.f);
|
|
execute();
|
|
{
|
|
const auto errors = mReader.takeErrors();
|
|
ASSERT_EQ(1, errors.size());
|
|
EXPECT_EQ(IComposerClient::EX_BAD_PARAMETER, errors[0].errorCode);
|
|
}
|
|
|
|
writer.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ -2.0f, -1.f);
|
|
execute();
|
|
{
|
|
const auto errors = mReader.takeErrors();
|
|
ASSERT_EQ(1, errors.size());
|
|
EXPECT_EQ(IComposerClient::EX_BAD_PARAMETER, errors[0].errorCode);
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetClientTarget) {
|
|
EXPECT_TRUE(mComposerClient->setClientTargetSlotCount(getPrimaryDisplayId(), kBufferSlotCount)
|
|
.isOk());
|
|
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.setClientTarget(getPrimaryDisplayId(), /*slot*/ 0, nullptr, /*acquireFence*/ -1,
|
|
Dataspace::UNKNOWN, std::vector<Rect>());
|
|
|
|
execute();
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetOutputBuffer) {
|
|
const auto& [status, virtualDisplayCount] = mComposerClient->getMaxVirtualDisplayCount();
|
|
EXPECT_TRUE(status.isOk());
|
|
if (virtualDisplayCount == 0) {
|
|
GTEST_SUCCEED() << "no virtual display support";
|
|
return;
|
|
}
|
|
|
|
const auto& [displayStatus, display] = mComposerClient->createVirtualDisplay(
|
|
/*width*/ 64, /*height*/ 64, common::PixelFormat::IMPLEMENTATION_DEFINED,
|
|
kBufferSlotCount);
|
|
EXPECT_TRUE(displayStatus.isOk());
|
|
|
|
const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
|
|
const auto handle = buffer->handle;
|
|
auto& writer = getWriter(display.display);
|
|
writer.setOutputBuffer(display.display, /*slot*/ 0, handle, /*releaseFence*/ -1);
|
|
execute();
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, ValidDisplay) {
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
|
|
execute();
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, AcceptDisplayChanges) {
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
|
|
writer.acceptDisplayChanges(getPrimaryDisplayId());
|
|
execute();
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, PresentDisplay) {
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
|
|
writer.presentDisplay(getPrimaryDisplayId());
|
|
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
|
|
*/
|
|
TEST_P(GraphicsComposerAidlCommandTest, PresentDisplayNoLayerStateChanges) {
|
|
if (!hasCapability(Capability::SKIP_VALIDATE)) {
|
|
GTEST_SUCCEED() << "Device does not have skip validate capability, skipping";
|
|
return;
|
|
}
|
|
EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::ON).isOk());
|
|
|
|
const auto& [renderIntentsStatus, renderIntents] =
|
|
mComposerClient->getRenderIntents(getPrimaryDisplayId(), ColorMode::NATIVE);
|
|
EXPECT_TRUE(renderIntentsStatus.isOk());
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
for (auto intent : renderIntents) {
|
|
EXPECT_TRUE(mComposerClient->setColorMode(getPrimaryDisplayId(), ColorMode::NATIVE, intent)
|
|
.isOk());
|
|
|
|
const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
|
|
const auto handle = buffer->handle;
|
|
ASSERT_NE(nullptr, handle);
|
|
|
|
const auto& [layerStatus, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(layerStatus.isOk());
|
|
|
|
Rect displayFrame{0, 0, getPrimaryDisplay().getDisplayWidth(),
|
|
getPrimaryDisplay().getDisplayHeight()};
|
|
FRect cropRect{0, 0, (float)getPrimaryDisplay().getDisplayWidth(),
|
|
(float)getPrimaryDisplay().getDisplayHeight()};
|
|
configureLayer(getPrimaryDisplay(), layer, Composition::CURSOR, displayFrame, cropRect);
|
|
writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle,
|
|
/*acquireFence*/ -1);
|
|
writer.setLayerDataspace(getPrimaryDisplayId(), layer, Dataspace::UNKNOWN);
|
|
writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
|
|
execute();
|
|
if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
|
|
GTEST_SUCCEED() << "Composition change requested, skipping test";
|
|
return;
|
|
}
|
|
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
writer.presentDisplay(getPrimaryDisplayId());
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
const auto buffer2 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
|
|
const auto handle2 = buffer2->handle;
|
|
ASSERT_NE(nullptr, handle2);
|
|
writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle2,
|
|
/*acquireFence*/ -1);
|
|
writer.setLayerSurfaceDamage(getPrimaryDisplayId(), layer,
|
|
std::vector<Rect>(1, {0, 0, 10, 10}));
|
|
writer.presentDisplay(getPrimaryDisplayId());
|
|
execute();
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetLayerCursorPosition) {
|
|
const auto& [layerStatus, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(layerStatus.isOk());
|
|
|
|
const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
|
|
const auto handle = buffer->handle;
|
|
ASSERT_NE(nullptr, handle);
|
|
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle, /*acquireFence*/ -1);
|
|
|
|
Rect displayFrame{0, 0, getPrimaryDisplay().getDisplayWidth(),
|
|
getPrimaryDisplay().getDisplayHeight()};
|
|
FRect cropRect{0, 0, (float)getPrimaryDisplay().getDisplayWidth(),
|
|
(float)getPrimaryDisplay().getDisplayHeight()};
|
|
configureLayer(getPrimaryDisplay(), layer, Composition::CURSOR, displayFrame, cropRect);
|
|
writer.setLayerDataspace(getPrimaryDisplayId(), layer, Dataspace::UNKNOWN);
|
|
writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
|
|
|
|
execute();
|
|
|
|
if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
|
|
GTEST_SUCCEED() << "Composition change requested, skipping test";
|
|
return;
|
|
}
|
|
writer.presentDisplay(getPrimaryDisplayId());
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerCursorPosition(getPrimaryDisplayId(), layer, /*x*/ 1, /*y*/ 1);
|
|
execute();
|
|
|
|
writer.setLayerCursorPosition(getPrimaryDisplayId(), layer, /*x*/ 0, /*y*/ 0);
|
|
writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
|
|
writer.presentDisplay(getPrimaryDisplayId());
|
|
execute();
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetLayerBuffer) {
|
|
const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
|
|
const auto handle = buffer->handle;
|
|
ASSERT_NE(nullptr, handle);
|
|
|
|
const auto& [layerStatus, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(layerStatus.isOk());
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle, /*acquireFence*/ -1);
|
|
execute();
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetLayerBufferSlotsToClear) {
|
|
// Older HAL versions use a backwards compatible way of clearing buffer slots
|
|
const auto& [versionStatus, version] = mComposerClient->getInterfaceVersion();
|
|
ASSERT_TRUE(versionStatus.isOk());
|
|
if (version <= 1) {
|
|
GTEST_SUCCEED() << "HAL at version 1 or lower does not have "
|
|
"LayerCommand::bufferSlotsToClear.";
|
|
return;
|
|
}
|
|
|
|
const auto& [layerStatus, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(layerStatus.isOk());
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
|
|
// setup 3 buffers in the buffer cache, with the last buffer being active
|
|
// then emulate the Android platform code that clears all 3 buffer slots
|
|
|
|
const auto buffer1 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
|
|
ASSERT_NE(nullptr, buffer1);
|
|
const auto handle1 = buffer1->handle;
|
|
writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle1, /*acquireFence*/ -1);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
const auto buffer2 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
|
|
ASSERT_NE(nullptr, buffer2);
|
|
const auto handle2 = buffer2->handle;
|
|
writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 1, handle2, /*acquireFence*/ -1);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
const auto buffer3 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
|
|
ASSERT_NE(nullptr, buffer3);
|
|
const auto handle3 = buffer3->handle;
|
|
writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 2, handle3, /*acquireFence*/ -1);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
// Ensure we can clear all 3 buffer slots, even the active buffer - it is assumed the
|
|
// current active buffer's slot will be cleared, but still remain the active buffer and no
|
|
// errors will occur.
|
|
writer.setLayerBufferSlotsToClear(getPrimaryDisplayId(), layer, {0, 1, 2});
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetLayerBufferMultipleTimes) {
|
|
const auto& [layerStatus, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(layerStatus.isOk());
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
|
|
// Setup 3 buffers in the buffer cache, with the last buffer being active. Then, emulate the
|
|
// Android platform code that clears all 3 buffer slots by setting all but the active buffer
|
|
// slot to a placeholder buffer, and then restoring the active buffer.
|
|
|
|
// This is used on HALs that don't support setLayerBufferSlotsToClear (version <= 3.1).
|
|
|
|
const auto buffer1 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
|
|
ASSERT_NE(nullptr, buffer1);
|
|
const auto handle1 = buffer1->handle;
|
|
writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle1, /*acquireFence*/ -1);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
const auto buffer2 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
|
|
ASSERT_NE(nullptr, buffer2);
|
|
const auto handle2 = buffer2->handle;
|
|
writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 1, handle2, /*acquireFence*/ -1);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
const auto buffer3 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
|
|
ASSERT_NE(nullptr, buffer3);
|
|
const auto handle3 = buffer3->handle;
|
|
writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 2, handle3, /*acquireFence*/ -1);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
// Older versions of the HAL clear all but the active buffer slot with a placeholder buffer,
|
|
// and then restoring the current active buffer at the end
|
|
auto clearSlotBuffer = allocate(1u, 1u, ::android::PIXEL_FORMAT_RGB_888);
|
|
ASSERT_NE(nullptr, clearSlotBuffer);
|
|
auto clearSlotBufferHandle = clearSlotBuffer->handle;
|
|
|
|
// clear buffer slots 0 and 1 with new layer commands... and then...
|
|
writer.setLayerBufferWithNewCommand(getPrimaryDisplayId(), layer, /* slot */ 0,
|
|
clearSlotBufferHandle, /*acquireFence*/ -1);
|
|
writer.setLayerBufferWithNewCommand(getPrimaryDisplayId(), layer, /* slot */ 1,
|
|
clearSlotBufferHandle, /*acquireFence*/ -1);
|
|
// ...reset the layer buffer to the current active buffer slot with a final new command
|
|
writer.setLayerBufferWithNewCommand(getPrimaryDisplayId(), layer, /*slot*/ 2, nullptr,
|
|
/*acquireFence*/ -1);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetLayerSurfaceDamage) {
|
|
const auto& [layerStatus, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(layerStatus.isOk());
|
|
|
|
Rect empty{0, 0, 0, 0};
|
|
Rect unit{0, 0, 1, 1};
|
|
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.setLayerSurfaceDamage(getPrimaryDisplayId(), layer, std::vector<Rect>(1, empty));
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerSurfaceDamage(getPrimaryDisplayId(), layer, std::vector<Rect>(1, unit));
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerSurfaceDamage(getPrimaryDisplayId(), layer, std::vector<Rect>());
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetLayerBlockingRegion) {
|
|
const auto& [layerStatus, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(layerStatus.isOk());
|
|
|
|
Rect empty{0, 0, 0, 0};
|
|
Rect unit{0, 0, 1, 1};
|
|
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.setLayerBlockingRegion(getPrimaryDisplayId(), layer, std::vector<Rect>(1, empty));
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerBlockingRegion(getPrimaryDisplayId(), layer, std::vector<Rect>(1, unit));
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerBlockingRegion(getPrimaryDisplayId(), layer, std::vector<Rect>());
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetLayerBlendMode) {
|
|
const auto& [layerStatus, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(layerStatus.isOk());
|
|
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.setLayerBlendMode(getPrimaryDisplayId(), layer, BlendMode::NONE);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerBlendMode(getPrimaryDisplayId(), layer, BlendMode::PREMULTIPLIED);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerBlendMode(getPrimaryDisplayId(), layer, BlendMode::COVERAGE);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetLayerColor) {
|
|
const auto& [layerStatus, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(layerStatus.isOk());
|
|
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.setLayerColor(getPrimaryDisplayId(), layer, Color{1.0f, 1.0f, 1.0f, 1.0f});
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerColor(getPrimaryDisplayId(), layer, Color{0.0f, 0.0f, 0.0f, 0.0f});
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetLayerCompositionType) {
|
|
const auto& [layerStatus, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(layerStatus.isOk());
|
|
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.setLayerCompositionType(getPrimaryDisplayId(), layer, Composition::CLIENT);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerCompositionType(getPrimaryDisplayId(), layer, Composition::DEVICE);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerCompositionType(getPrimaryDisplayId(), layer, Composition::SOLID_COLOR);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerCompositionType(getPrimaryDisplayId(), layer, Composition::CURSOR);
|
|
execute();
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, DisplayDecoration) {
|
|
for (VtsDisplay& display : mDisplays) {
|
|
const auto [layerStatus, layer] =
|
|
mComposerClient->createLayer(display.getDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(layerStatus.isOk());
|
|
|
|
const auto [error, support] =
|
|
mComposerClient->getDisplayDecorationSupport(display.getDisplayId());
|
|
|
|
const auto format = (error.isOk() && support) ? support->format
|
|
: aidl::android::hardware::graphics::common::PixelFormat::RGBA_8888;
|
|
const auto decorBuffer = allocate(static_cast<::android::PixelFormat>(format));
|
|
ASSERT_NE(nullptr, decorBuffer);
|
|
if (::android::OK != decorBuffer->initCheck()) {
|
|
if (support) {
|
|
FAIL() << "Device advertised display decoration support with format "
|
|
<< aidl::android::hardware::graphics::common::toString(format)
|
|
<< " but failed to allocate it!";
|
|
} else {
|
|
FAIL() << "Device advertised NO display decoration support, but it should "
|
|
<< "still be able to allocate "
|
|
<< aidl::android::hardware::graphics::common::toString(format);
|
|
}
|
|
}
|
|
|
|
configureLayer(display, layer, Composition::DISPLAY_DECORATION, display.getFrameRect(),
|
|
display.getCrop());
|
|
auto& writer = getWriter(display.getDisplayId());
|
|
writer.setLayerBuffer(display.getDisplayId(), layer, /*slot*/ 0, decorBuffer->handle,
|
|
/*acquireFence*/ -1);
|
|
writer.validateDisplay(display.getDisplayId(), ComposerClientWriter::kNoTimestamp);
|
|
execute();
|
|
if (support) {
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
} else {
|
|
const auto errors = mReader.takeErrors();
|
|
ASSERT_EQ(1, errors.size());
|
|
EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, errors[0].errorCode);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetLayerDataspace) {
|
|
const auto& [layerStatus, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(layerStatus.isOk());
|
|
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.setLayerDataspace(getPrimaryDisplayId(), layer, Dataspace::UNKNOWN);
|
|
execute();
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetLayerDisplayFrame) {
|
|
const auto& [layerStatus, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(layerStatus.isOk());
|
|
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.setLayerDisplayFrame(getPrimaryDisplayId(), layer, Rect{0, 0, 1, 1});
|
|
execute();
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetLayerPlaneAlpha) {
|
|
const auto& [layerStatus, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(layerStatus.isOk());
|
|
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.setLayerPlaneAlpha(getPrimaryDisplayId(), layer, /*alpha*/ 0.0f);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerPlaneAlpha(getPrimaryDisplayId(), layer, /*alpha*/ 1.0f);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetLayerSidebandStream) {
|
|
if (!hasCapability(Capability::SIDEBAND_STREAM)) {
|
|
GTEST_SUCCEED() << "no sideband stream support";
|
|
return;
|
|
}
|
|
|
|
const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
|
|
const auto handle = buffer->handle;
|
|
ASSERT_NE(nullptr, handle);
|
|
|
|
const auto& [layerStatus, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(layerStatus.isOk());
|
|
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.setLayerSidebandStream(getPrimaryDisplayId(), layer, handle);
|
|
execute();
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetLayerSourceCrop) {
|
|
const auto& [layerStatus, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(layerStatus.isOk());
|
|
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.setLayerSourceCrop(getPrimaryDisplayId(), layer, FRect{0.0f, 0.0f, 1.0f, 1.0f});
|
|
execute();
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetLayerTransform) {
|
|
const auto& [layerStatus, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(layerStatus.isOk());
|
|
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.setLayerTransform(getPrimaryDisplayId(), layer, static_cast<Transform>(0));
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerTransform(getPrimaryDisplayId(), layer, Transform::FLIP_H);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerTransform(getPrimaryDisplayId(), layer, Transform::FLIP_V);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerTransform(getPrimaryDisplayId(), layer, Transform::ROT_90);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerTransform(getPrimaryDisplayId(), layer, Transform::ROT_180);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerTransform(getPrimaryDisplayId(), layer, Transform::ROT_270);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerTransform(getPrimaryDisplayId(), layer,
|
|
static_cast<Transform>(static_cast<int>(Transform::FLIP_H) |
|
|
static_cast<int>(Transform::ROT_90)));
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerTransform(getPrimaryDisplayId(), 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, SetLayerVisibleRegion) {
|
|
const auto& [layerStatus, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(layerStatus.isOk());
|
|
|
|
Rect empty{0, 0, 0, 0};
|
|
Rect unit{0, 0, 1, 1};
|
|
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.setLayerVisibleRegion(getPrimaryDisplayId(), layer, std::vector<Rect>(1, empty));
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerVisibleRegion(getPrimaryDisplayId(), layer, std::vector<Rect>(1, unit));
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerVisibleRegion(getPrimaryDisplayId(), layer, std::vector<Rect>());
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetLayerZOrder) {
|
|
const auto& [layerStatus, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(layerStatus.isOk());
|
|
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.setLayerZOrder(getPrimaryDisplayId(), layer, /*z*/ 10);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerZOrder(getPrimaryDisplayId(), layer, /*z*/ 0);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetLayerPerFrameMetadata) {
|
|
const auto& [layerStatus, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
EXPECT_TRUE(layerStatus.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
|
|
*/
|
|
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
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});
|
|
writer.setLayerPerFrameMetadata(getPrimaryDisplayId(), 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(getPrimaryDisplayId(), layer).isOk());
|
|
return;
|
|
}
|
|
|
|
EXPECT_TRUE(mComposerClient->destroyLayer(getPrimaryDisplayId(), layer).isOk());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, setLayerBrightness) {
|
|
const auto& [layerStatus, layer] =
|
|
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
|
|
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.setLayerBrightness(getPrimaryDisplayId(), layer, 0.2f);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerBrightness(getPrimaryDisplayId(), layer, 1.f);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerBrightness(getPrimaryDisplayId(), layer, 0.f);
|
|
execute();
|
|
ASSERT_TRUE(mReader.takeErrors().empty());
|
|
|
|
writer.setLayerBrightness(getPrimaryDisplayId(), layer, -1.f);
|
|
execute();
|
|
{
|
|
const auto errors = mReader.takeErrors();
|
|
ASSERT_EQ(1, errors.size());
|
|
EXPECT_EQ(IComposerClient::EX_BAD_PARAMETER, errors[0].errorCode);
|
|
}
|
|
|
|
writer.setLayerBrightness(getPrimaryDisplayId(), layer, std::nanf(""));
|
|
execute();
|
|
{
|
|
const auto errors = mReader.takeErrors();
|
|
ASSERT_EQ(1, errors.size());
|
|
EXPECT_EQ(IComposerClient::EX_BAD_PARAMETER, errors[0].errorCode);
|
|
}
|
|
}
|
|
|
|
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) {
|
|
const auto& [status, configs] = mComposerClient->getDisplayConfigs(display.getDisplayId());
|
|
EXPECT_TRUE(status.isOk());
|
|
|
|
for (int32_t config : configs) {
|
|
int32_t expectedVsyncPeriodNanos = display.getDisplayConfig(config).vsyncPeriod;
|
|
|
|
VsyncPeriodChangeConstraints constraints;
|
|
|
|
constraints.desiredTimeNanos = systemTime();
|
|
constraints.seamlessRequired = false;
|
|
|
|
const auto& [timelineStatus, timeline] =
|
|
mComposerClient->setActiveConfigWithConstraints(&display, config, constraints);
|
|
EXPECT_TRUE(timelineStatus.isOk());
|
|
|
|
if (timeline.refreshRequired) {
|
|
sendRefreshFrame(display, &timeline);
|
|
}
|
|
waitForVsyncPeriodChange(display.getDisplayId(), timeline, constraints.desiredTimeNanos,
|
|
/*odPeriodNanos*/ 0, expectedVsyncPeriodNanos);
|
|
|
|
int32_t vsyncPeriodNanos;
|
|
int retryCount = 100;
|
|
do {
|
|
std::this_thread::sleep_for(10ms);
|
|
const auto& [vsyncPeriodNanosStatus, vsyncPeriodNanosValue] =
|
|
mComposerClient->getDisplayVsyncPeriod(display.getDisplayId());
|
|
|
|
EXPECT_TRUE(vsyncPeriodNanosStatus.isOk());
|
|
vsyncPeriodNanos = vsyncPeriodNanosValue;
|
|
--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;
|
|
const auto& [vsyncPeriodNanosStatus, vsyncPeriodNanosValue] =
|
|
mComposerClient->getDisplayVsyncPeriod(display.getDisplayId());
|
|
|
|
EXPECT_TRUE(vsyncPeriodNanosStatus.isOk());
|
|
vsyncPeriodNanos = vsyncPeriodNanosValue;
|
|
EXPECT_EQ(vsyncPeriodNanos, expectedVsyncPeriodNanos);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetActiveConfigWithConstraints_SeamlessNotAllowed) {
|
|
VsyncPeriodChangeConstraints constraints;
|
|
constraints.seamlessRequired = true;
|
|
constraints.desiredTimeNanos = systemTime();
|
|
|
|
for (VtsDisplay& display : mDisplays) {
|
|
forEachTwoConfigs(display.getDisplayId(), [&](int32_t config1, int32_t config2) {
|
|
int32_t configGroup1 = display.getDisplayConfig(config1).configGroup;
|
|
int32_t configGroup2 = display.getDisplayConfig(config2).configGroup;
|
|
if (configGroup1 != configGroup2) {
|
|
EXPECT_TRUE(mComposerClient->setActiveConfig(&display, config1).isOk());
|
|
sendRefreshFrame(display, nullptr);
|
|
const auto& [status, _] = mComposerClient->setActiveConfigWithConstraints(
|
|
&display, config2, constraints);
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(
|
|
status, IComposerClient::EX_SEAMLESS_NOT_ALLOWED));
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, ExpectedPresentTime_NoTimestamp) {
|
|
ASSERT_NO_FATAL_FAILURE(Test_expectedPresentTime(/*framesDelay*/ std::nullopt));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, ExpectedPresentTime_0) {
|
|
ASSERT_NO_FATAL_FAILURE(Test_expectedPresentTime(/*framesDelay*/ 0));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, ExpectedPresentTime_5) {
|
|
ASSERT_NO_FATAL_FAILURE(Test_expectedPresentTime(/*framesDelay*/ 5));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetIdleTimerEnabled_Unsupported) {
|
|
const bool hasDisplayIdleTimerSupport =
|
|
hasDisplayCapability(getPrimaryDisplayId(), DisplayCapability::DISPLAY_IDLE_TIMER);
|
|
if (!hasDisplayIdleTimerSupport) {
|
|
const auto& status =
|
|
mComposerClient->setIdleTimerEnabled(getPrimaryDisplayId(), /*timeout*/ 0);
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(
|
|
assertServiceSpecificError(status, IComposerClient::EX_UNSUPPORTED));
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetIdleTimerEnabled_BadParameter) {
|
|
const bool hasDisplayIdleTimerSupport =
|
|
hasDisplayCapability(getPrimaryDisplayId(), DisplayCapability::DISPLAY_IDLE_TIMER);
|
|
if (!hasDisplayIdleTimerSupport) {
|
|
GTEST_SUCCEED() << "DisplayCapability::DISPLAY_IDLE_TIMER is not supported";
|
|
return;
|
|
}
|
|
|
|
const auto& status =
|
|
mComposerClient->setIdleTimerEnabled(getPrimaryDisplayId(), /*timeout*/ -1);
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_PARAMETER));
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetIdleTimerEnabled_Disable) {
|
|
const bool hasDisplayIdleTimerSupport =
|
|
hasDisplayCapability(getPrimaryDisplayId(), DisplayCapability::DISPLAY_IDLE_TIMER);
|
|
if (!hasDisplayIdleTimerSupport) {
|
|
GTEST_SUCCEED() << "DisplayCapability::DISPLAY_IDLE_TIMER is not supported";
|
|
return;
|
|
}
|
|
|
|
EXPECT_TRUE(mComposerClient->setIdleTimerEnabled(getPrimaryDisplayId(), /*timeout*/ 0).isOk());
|
|
std::this_thread::sleep_for(1s);
|
|
EXPECT_EQ(0, mComposerClient->getVsyncIdleCount());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetIdleTimerEnabled_Timeout_2) {
|
|
const bool hasDisplayIdleTimerSupport =
|
|
hasDisplayCapability(getPrimaryDisplayId(), DisplayCapability::DISPLAY_IDLE_TIMER);
|
|
if (!hasDisplayIdleTimerSupport) {
|
|
GTEST_SUCCEED() << "DisplayCapability::DISPLAY_IDLE_TIMER is not supported";
|
|
return;
|
|
}
|
|
|
|
EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::ON).isOk());
|
|
EXPECT_TRUE(mComposerClient->setIdleTimerEnabled(getPrimaryDisplayId(), /*timeout*/ 0).isOk());
|
|
|
|
const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
|
|
ASSERT_NE(nullptr, buffer->handle);
|
|
|
|
const auto layer = createOnScreenLayer();
|
|
auto& writer = getWriter(getPrimaryDisplayId());
|
|
writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, buffer->handle,
|
|
/*acquireFence*/ -1);
|
|
int32_t vsyncIdleCount = mComposerClient->getVsyncIdleCount();
|
|
auto earlyVsyncIdleTime = systemTime() + std::chrono::nanoseconds(2s).count();
|
|
EXPECT_TRUE(
|
|
mComposerClient->setIdleTimerEnabled(getPrimaryDisplayId(), /*timeout*/ 2000).isOk());
|
|
|
|
const sp<::android::Fence> presentFence =
|
|
presentAndGetFence(ComposerClientWriter::kNoTimestamp);
|
|
presentFence->waitForever(LOG_TAG);
|
|
|
|
std::this_thread::sleep_for(3s);
|
|
if (vsyncIdleCount < mComposerClient->getVsyncIdleCount()) {
|
|
EXPECT_GE(mComposerClient->getVsyncIdleTime(), earlyVsyncIdleTime);
|
|
}
|
|
|
|
EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::OFF).isOk());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetRefreshRateChangedCallbackDebug_Unsupported) {
|
|
if (getInterfaceVersion() <= 1) {
|
|
GTEST_SUCCEED() << "Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG is "
|
|
"not supported on older version of the service";
|
|
return;
|
|
}
|
|
if (!hasCapability(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG)) {
|
|
auto status = mComposerClient->setRefreshRateChangedCallbackDebugEnabled(
|
|
getPrimaryDisplayId(), /*enabled*/ true);
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(
|
|
assertServiceSpecificError(status, IComposerClient::EX_UNSUPPORTED));
|
|
|
|
status = mComposerClient->setRefreshRateChangedCallbackDebugEnabled(getPrimaryDisplayId(),
|
|
/*enabled*/ false);
|
|
EXPECT_FALSE(status.isOk());
|
|
EXPECT_NO_FATAL_FAILURE(
|
|
assertServiceSpecificError(status, IComposerClient::EX_UNSUPPORTED));
|
|
}
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest, SetRefreshRateChangedCallbackDebug_Enabled) {
|
|
if (getInterfaceVersion() <= 1) {
|
|
GTEST_SUCCEED() << "Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG is "
|
|
"not supported on older version of the service";
|
|
return;
|
|
}
|
|
if (!hasCapability(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG)) {
|
|
GTEST_SUCCEED() << "Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG is not supported";
|
|
return;
|
|
}
|
|
|
|
const auto displayId = getPrimaryDisplayId();
|
|
EXPECT_TRUE(mComposerClient->setPowerMode(displayId, PowerMode::ON).isOk());
|
|
// Enable the callback
|
|
ASSERT_TRUE(mComposerClient
|
|
->setRefreshRateChangedCallbackDebugEnabled(displayId,
|
|
/*enabled*/ true)
|
|
.isOk());
|
|
std::this_thread::sleep_for(100ms);
|
|
|
|
const auto displayFilter = [displayId](auto refreshRateChangedDebugData) {
|
|
return displayId == refreshRateChangedDebugData.display;
|
|
};
|
|
|
|
// Check that we immediately got a callback
|
|
EXPECT_TRUE(checkIfCallbackRefreshRateChangedDebugEnabledReceived(displayFilter));
|
|
|
|
ASSERT_TRUE(mComposerClient
|
|
->setRefreshRateChangedCallbackDebugEnabled(displayId,
|
|
/*enabled*/ false)
|
|
.isOk());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest,
|
|
SetRefreshRateChangedCallbackDebugEnabled_noCallbackWhenIdle) {
|
|
if (getInterfaceVersion() <= 1) {
|
|
GTEST_SUCCEED() << "Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG is "
|
|
"not supported on older version of the service";
|
|
return;
|
|
}
|
|
if (!hasCapability(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG)) {
|
|
GTEST_SUCCEED() << "Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG is not supported";
|
|
return;
|
|
}
|
|
|
|
auto display = getEditablePrimaryDisplay();
|
|
const auto displayId = display.getDisplayId();
|
|
|
|
if (!hasDisplayCapability(displayId, DisplayCapability::DISPLAY_IDLE_TIMER)) {
|
|
GTEST_SUCCEED() << "DisplayCapability::DISPLAY_IDLE_TIMER is not supported";
|
|
return;
|
|
}
|
|
|
|
EXPECT_TRUE(mComposerClient->setPowerMode(displayId, PowerMode::ON).isOk());
|
|
EXPECT_TRUE(mComposerClient->setPeakRefreshRateConfig(&display).isOk());
|
|
|
|
ASSERT_TRUE(mComposerClient->setIdleTimerEnabled(displayId, /*timeoutMs*/ 500).isOk());
|
|
// Enable the callback
|
|
ASSERT_TRUE(mComposerClient
|
|
->setRefreshRateChangedCallbackDebugEnabled(displayId,
|
|
/*enabled*/ true)
|
|
.isOk());
|
|
|
|
const auto displayFilter = [displayId](auto refreshRateChangedDebugData) {
|
|
return displayId == refreshRateChangedDebugData.display;
|
|
};
|
|
|
|
int retryCount = 3;
|
|
do {
|
|
// Wait for 1s so that we enter the idle state
|
|
std::this_thread::sleep_for(1s);
|
|
if (!checkIfCallbackRefreshRateChangedDebugEnabledReceived(displayFilter)) {
|
|
// DID NOT receive a callback, we are in the idle state.
|
|
break;
|
|
}
|
|
} while (--retryCount > 0);
|
|
|
|
if (retryCount == 0) {
|
|
GTEST_SUCCEED() << "Unable to enter the idle mode";
|
|
return;
|
|
}
|
|
|
|
// Send the REFRESH_RATE_INDICATOR update
|
|
ASSERT_NO_FATAL_FAILURE(
|
|
sendBufferUpdate(createOnScreenLayer(Composition::REFRESH_RATE_INDICATOR)));
|
|
std::this_thread::sleep_for(1s);
|
|
EXPECT_FALSE(checkIfCallbackRefreshRateChangedDebugEnabledReceived(displayFilter))
|
|
<< "A callback should not be received for REFRESH_RATE_INDICATOR";
|
|
|
|
EXPECT_TRUE(mComposerClient
|
|
->setRefreshRateChangedCallbackDebugEnabled(displayId,
|
|
/*enabled*/ false)
|
|
.isOk());
|
|
}
|
|
|
|
TEST_P(GraphicsComposerAidlCommandTest,
|
|
SetRefreshRateChangedCallbackDebugEnabled_SetActiveConfigWithConstraints) {
|
|
if (getInterfaceVersion() <= 1) {
|
|
GTEST_SUCCEED() << "Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG is "
|
|
"not supported on older version of the service";
|
|
return;
|
|
}
|
|
if (!hasCapability(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG)) {
|
|
GTEST_SUCCEED() << "Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG is not supported";
|
|
return;
|
|
}
|
|
|
|
VsyncPeriodChangeConstraints constraints;
|
|
constraints.seamlessRequired = false;
|
|
constraints.desiredTimeNanos = systemTime();
|
|
|
|
for (VtsDisplay& display : mDisplays) {
|
|
const auto displayId = display.getDisplayId();
|
|
EXPECT_TRUE(mComposerClient->setPowerMode(displayId, PowerMode::ON).isOk());
|
|
|
|
// Enable the callback
|
|
ASSERT_TRUE(mComposerClient
|
|
->setRefreshRateChangedCallbackDebugEnabled(displayId, /*enabled*/ true)
|
|
.isOk());
|
|
|
|
forEachTwoConfigs(displayId, [&](int32_t config1, int32_t config2) {
|
|
const int32_t vsyncPeriod1 = display.getDisplayConfig(config1).vsyncPeriod;
|
|
const int32_t vsyncPeriod2 = display.getDisplayConfig(config2).vsyncPeriod;
|
|
|
|
if (vsyncPeriod1 == vsyncPeriod2) {
|
|
return; // continue
|
|
}
|
|
|
|
EXPECT_TRUE(mComposerClient->setActiveConfig(&display, config1).isOk());
|
|
sendRefreshFrame(display, nullptr);
|
|
|
|
const auto& [status, timeline] =
|
|
mComposerClient->setActiveConfigWithConstraints(&display, config2, constraints);
|
|
EXPECT_TRUE(status.isOk());
|
|
|
|
if (timeline.refreshRequired) {
|
|
sendRefreshFrame(display, &timeline);
|
|
}
|
|
|
|
const auto callbackFilter = [displayId,
|
|
vsyncPeriod2](auto refreshRateChangedDebugData) {
|
|
constexpr int kVsyncThreshold = 1000;
|
|
return displayId == refreshRateChangedDebugData.display &&
|
|
std::abs(vsyncPeriod2 - refreshRateChangedDebugData.vsyncPeriodNanos) <=
|
|
kVsyncThreshold;
|
|
};
|
|
|
|
int retryCount = 3;
|
|
do {
|
|
std::this_thread::sleep_for(100ms);
|
|
if (checkIfCallbackRefreshRateChangedDebugEnabledReceived(callbackFilter)) {
|
|
GTEST_SUCCEED() << "Received a callback successfully";
|
|
break;
|
|
}
|
|
} while (--retryCount > 0);
|
|
|
|
if (retryCount == 0) {
|
|
GTEST_FAIL() << "failed to get a callback for the display " << displayId
|
|
<< " with config " << config2;
|
|
}
|
|
});
|
|
|
|
EXPECT_TRUE(
|
|
mComposerClient
|
|
->setRefreshRateChangedCallbackDebugEnabled(displayId, /*enabled*/ false)
|
|
.isOk());
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Test that no two display configs are exactly the same.
|
|
*/
|
|
TEST_P(GraphicsComposerAidlTest, GetDisplayConfigNoRepetitions) {
|
|
for (const auto& display : mDisplays) {
|
|
const auto& [status, configs] = mComposerClient->getDisplayConfigs(display.getDisplayId());
|
|
for (std::vector<int>::size_type i = 0; i < configs.size(); i++) {
|
|
for (std::vector<int>::size_type j = i + 1; j < configs.size(); j++) {
|
|
const auto& [widthStatus1, width1] = mComposerClient->getDisplayAttribute(
|
|
display.getDisplayId(), configs[i], DisplayAttribute::WIDTH);
|
|
const auto& [heightStatus1, height1] = mComposerClient->getDisplayAttribute(
|
|
display.getDisplayId(), configs[i], DisplayAttribute::HEIGHT);
|
|
const auto& [vsyncPeriodStatus1, vsyncPeriod1] =
|
|
mComposerClient->getDisplayAttribute(display.getDisplayId(), configs[i],
|
|
DisplayAttribute::VSYNC_PERIOD);
|
|
const auto& [groupStatus1, group1] = mComposerClient->getDisplayAttribute(
|
|
display.getDisplayId(), configs[i], DisplayAttribute::CONFIG_GROUP);
|
|
|
|
const auto& [widthStatus2, width2] = mComposerClient->getDisplayAttribute(
|
|
display.getDisplayId(), configs[j], DisplayAttribute::WIDTH);
|
|
const auto& [heightStatus2, height2] = mComposerClient->getDisplayAttribute(
|
|
display.getDisplayId(), configs[j], DisplayAttribute::HEIGHT);
|
|
const auto& [vsyncPeriodStatus2, vsyncPeriod2] =
|
|
mComposerClient->getDisplayAttribute(display.getDisplayId(), configs[j],
|
|
DisplayAttribute::VSYNC_PERIOD);
|
|
const auto& [groupStatus2, group2] = mComposerClient->getDisplayAttribute(
|
|
display.getDisplayId(), configs[j], DisplayAttribute::CONFIG_GROUP);
|
|
|
|
ASSERT_FALSE(width1 == width2 && height1 == height2 &&
|
|
vsyncPeriod1 == vsyncPeriod2 && group1 == group2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test Capability::SKIP_VALIDATE
|
|
*
|
|
* Capability::SKIP_VALIDATE has been deprecated and should not be enabled.
|
|
*/
|
|
TEST_P(GraphicsComposerAidlCommandTest, SkipValidateDeprecatedTest) {
|
|
if (getInterfaceVersion() <= 1) {
|
|
GTEST_SUCCEED() << "HAL at version 1 or lower can contain Capability::SKIP_VALIDATE.";
|
|
return;
|
|
}
|
|
ASSERT_FALSE(hasCapability(Capability::SKIP_VALIDATE))
|
|
<< "Found Capability::SKIP_VALIDATE capability.";
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
android::ProcessState::self()->setThreadPoolMaxThreadCount(4);
|
|
|
|
// The binder threadpool we start will inherit sched policy and priority
|
|
// of (this) creating thread. We want the binder thread pool to have
|
|
// SCHED_FIFO policy and priority 1 (lowest RT priority)
|
|
// Once the pool is created we reset this thread's priority back to
|
|
// original.
|
|
// This thread policy is based on what we do in the SurfaceFlinger while starting
|
|
// the thread pool and we need to replicate that for the VTS tests.
|
|
int newPriority = 0;
|
|
int origPolicy = sched_getscheduler(0);
|
|
struct sched_param origSchedParam;
|
|
|
|
int errorInPriorityModification = sched_getparam(0, &origSchedParam);
|
|
if (errorInPriorityModification == 0) {
|
|
int policy = SCHED_FIFO;
|
|
newPriority = sched_get_priority_min(policy);
|
|
|
|
struct sched_param param;
|
|
param.sched_priority = newPriority;
|
|
|
|
errorInPriorityModification = sched_setscheduler(0, policy, ¶m);
|
|
}
|
|
|
|
// start the thread pool
|
|
android::ProcessState::self()->startThreadPool();
|
|
|
|
// Reset current thread's policy and priority
|
|
if (errorInPriorityModification == 0) {
|
|
errorInPriorityModification = sched_setscheduler(0, origPolicy, &origSchedParam);
|
|
} else {
|
|
ALOGE("Failed to set VtsHalGraphicsComposer3_TargetTest binder threadpool priority to "
|
|
"SCHED_FIFO");
|
|
}
|
|
|
|
return RUN_ALL_TESTS();
|
|
}
|