[SurfaceFlinger] Query per display SkipClientColorTransform.
Previously the ability of SkipClientColorTransform is a global capability.
However, some hardwares can't apply it for all displays. Thus we introduced per
display capability. This patch plumbs it in SurfaceFlinger.
BUG: 69911676
Test: Build, flash and boot, verify with color blindness
Change-Id: Ibde2c5fe16b090bb07594702dd450ab863414589
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index b919da7..5b641a2 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -1050,6 +1050,23 @@
return error;
}
+Error Composer::getDisplayCapabilities(Display display,
+ std::vector<DisplayCapability>* outCapabilities) {
+ if (!mClient_2_3) {
+ return Error::UNSUPPORTED;
+ }
+ Error error = kDefaultError;
+ mClient_2_3->getDisplayCapabilities(display,
+ [&](const auto& tmpError, const auto& tmpCapabilities) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ *outCapabilities = tmpCapabilities;
+ });
+ return error;
+}
+
CommandReader::~CommandReader()
{
resetData();
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index c39171e..61af348 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -48,24 +48,20 @@
using types::V1_0::ColorTransform;
using types::V1_0::Hdr;
using types::V1_0::Transform;
-
using types::V1_1::PixelFormat;
using types::V1_1::RenderIntent;
using types::V1_2::ColorMode;
using types::V1_2::Dataspace;
-
using V2_1::Config;
using V2_1::Display;
using V2_1::Error;
using V2_1::IComposerCallback;
using V2_1::Layer;
-
using V2_3::CommandReaderBase;
using V2_3::CommandWriterBase;
-
using V2_3::IComposer;
using V2_3::IComposerClient;
-
+using DisplayCapability = IComposerClient::DisplayCapability;
using PerFrameMetadata = IComposerClient::PerFrameMetadata;
using PerFrameMetadataKey = IComposerClient::PerFrameMetadataKey;
@@ -196,6 +192,8 @@
virtual Error getDisplayedContentSamplingAttributes(Display display, PixelFormat* outFormat,
Dataspace* outDataspace,
uint8_t* outComponentMask) = 0;
+ virtual Error getDisplayCapabilities(Display display,
+ std::vector<DisplayCapability>* outCapabilities) = 0;
};
namespace impl {
@@ -398,6 +396,8 @@
Error getDisplayedContentSamplingAttributes(Display display, PixelFormat* outFormat,
Dataspace* outDataspace,
uint8_t* outComponentMask) override;
+ Error getDisplayCapabilities(Display display,
+ std::vector<DisplayCapability>* outCapabilities) override;
private:
class CommandWriter : public CommandWriterBase {
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index b4ac506..2df2d3b 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -234,6 +234,22 @@
mId(id),
mIsConnected(false),
mType(type) {
+ std::vector<Hwc2::DisplayCapability> tmpCapabilities;
+ auto error = static_cast<Error>(mComposer.getDisplayCapabilities(mId, &tmpCapabilities));
+ if (error == Error::None) {
+ for (auto capability : tmpCapabilities) {
+ mDisplayCapabilities.emplace(static_cast<DisplayCapability>(capability));
+ }
+ } else if (error == Error::Unsupported) {
+ if (capabilities.count(Capability::SkipClientColorTransform)) {
+ mDisplayCapabilities.emplace(DisplayCapability::SkipClientColorTransform);
+ }
+ bool dozeSupport = false;
+ error = static_cast<Error>(mComposer.getDozeSupport(mId, &dozeSupport));
+ if (error == Error::None && dozeSupport) {
+ mDisplayCapabilities.emplace(DisplayCapability::Doze);
+ }
+ }
ALOGV("Created display %" PRIu64, id);
}
@@ -507,15 +523,8 @@
return Error::None;
}
-Error Display::supportsDoze(bool* outSupport) const
-{
- bool intSupport = false;
- auto intError = mComposer.getDozeSupport(mId, &intSupport);
- auto error = static_cast<Error>(intError);
- if (error != Error::None) {
- return error;
- }
- *outSupport = static_cast<bool>(intSupport);
+Error Display::supportsDoze(bool* outSupport) const {
+ *outSupport = mDisplayCapabilities.count(DisplayCapability::Doze) > 0;
return Error::None;
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 607d9ef..8c0f50c 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -272,6 +272,9 @@
hwc2_display_t getId() const { return mId; }
bool isConnected() const { return mIsConnected; }
void setConnected(bool connected); // For use by Device only
+ const std::unordered_set<DisplayCapability>& getCapabilities() const {
+ return mDisplayCapabilities;
+ };
private:
int32_t getAttribute(hwc2_config_t configId, Attribute attribute);
@@ -298,6 +301,7 @@
DisplayType mType;
std::unordered_map<hwc2_layer_t, std::unique_ptr<Layer>> mLayers;
std::unordered_map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs;
+ std::unordered_set<DisplayCapability> mDisplayCapabilities;
};
// Convenience C++ class to access hwc2_device_t Layer functions directly.
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index c93b4d6..a752a7d 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -95,6 +95,15 @@
return mHwcDevice->getCapabilities().count(capability) > 0;
}
+bool HWComposer::hasDisplayCapability(const std::optional<DisplayId>& displayId,
+ HWC2::DisplayCapability capability) const {
+ if (!displayId) {
+ return false;
+ }
+ RETURN_IF_INVALID_DISPLAY(*displayId, false);
+ return mDisplayData.at(*displayId).hwcDisplay->getCapabilities().count(capability) > 0;
+}
+
void HWComposer::validateChange(HWC2::Composition from, HWC2::Composition to) {
bool valid = true;
switch (from) {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 1e5f971..0375f74 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -59,6 +59,8 @@
DisplayIdentificationData* outData) const;
bool hasCapability(HWC2::Capability capability) const;
+ bool hasDisplayCapability(const std::optional<DisplayId>& displayId,
+ HWC2::DisplayCapability capability) const;
// Attempts to allocate a virtual display and returns its ID if created on the HWC device.
std::optional<DisplayId> allocateVirtualDisplay(uint32_t width, uint32_t height,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index adc46cc..3e5920f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3085,8 +3085,10 @@
display->getHdrCapabilities().getDesiredMaxLuminance());
const bool hasDeviceComposition = getBE().mHwc->hasDeviceComposition(displayId);
- const bool skipClientColorTransform = getBE().mHwc->hasCapability(
- HWC2::Capability::SkipClientColorTransform);
+ const bool skipClientColorTransform =
+ getBE().mHwc
+ ->hasDisplayCapability(displayId,
+ HWC2::DisplayCapability::SkipClientColorTransform);
// Compute the global color transform matrix.
applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform;
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 5aaf848..34cee3e 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -2553,14 +2553,23 @@
*/
// Used when we simulate a display that supports doze.
+template <typename Display>
struct DozeIsSupportedVariant {
static constexpr bool DOZE_SUPPORTED = true;
static constexpr IComposerClient::PowerMode ACTUAL_POWER_MODE_FOR_DOZE =
IComposerClient::PowerMode::DOZE;
static constexpr IComposerClient::PowerMode ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND =
IComposerClient::PowerMode::DOZE_SUSPEND;
+
+ static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getDisplayCapabilities(Display::HWC_DISPLAY_ID, _))
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::DisplayCapability>(
+ {Hwc2::DisplayCapability::DOZE})),
+ Return(Error::NONE)));
+ }
};
+template <typename Display>
// Used when we simulate a display that does not support doze.
struct DozeNotSupportedVariant {
static constexpr bool DOZE_SUPPORTED = false;
@@ -2568,6 +2577,12 @@
IComposerClient::PowerMode::ON;
static constexpr IComposerClient::PowerMode ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND =
IComposerClient::PowerMode::ON;
+
+ static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getDisplayCapabilities(Display::HWC_DISPLAY_ID, _))
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::DisplayCapability>({})),
+ Return(Error::NONE)));
+ }
};
struct EventThreadBaseSupportedVariant {
@@ -2824,17 +2839,19 @@
// A sample configuration for the primary display.
// In addition to having event thread support, we emulate doze support.
template <typename TransitionVariant>
-using PrimaryDisplayPowerCase = DisplayPowerCase<PrimaryDisplayVariant, DozeIsSupportedVariant,
- EventThreadIsSupportedVariant,
- DispSyncIsSupportedVariant, TransitionVariant>;
+using PrimaryDisplayPowerCase =
+ DisplayPowerCase<PrimaryDisplayVariant, DozeIsSupportedVariant<PrimaryDisplayVariant>,
+ EventThreadIsSupportedVariant, DispSyncIsSupportedVariant,
+ TransitionVariant>;
// A sample configuration for the external display.
// In addition to not having event thread support, we emulate not having doze
// support.
template <typename TransitionVariant>
-using ExternalDisplayPowerCase = DisplayPowerCase<ExternalDisplayVariant, DozeNotSupportedVariant,
- EventThreadNotSupportedVariant,
- DispSyncNotSupportedVariant, TransitionVariant>;
+using ExternalDisplayPowerCase =
+ DisplayPowerCase<ExternalDisplayVariant, DozeNotSupportedVariant<ExternalDisplayVariant>,
+ EventThreadNotSupportedVariant, DispSyncNotSupportedVariant,
+ TransitionVariant>;
class SetPowerModeInternalTest : public DisplayTransactionTest {
public:
@@ -2856,6 +2873,7 @@
// --------------------------------------------------------------------
// Preconditions
+ Case::Doze::setupComposerCallExpectations(this);
auto display =
Case::injectDisplayWithInitialPowerMode(this, Case::Transition::INITIAL_POWER_MODE);
Case::setInitialPrimaryHWVsyncEnabled(this,
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 03ef2f8..5a46c26 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -115,6 +115,7 @@
MOCK_METHOD3(setLayerColorTransform, Error(Display, Layer, const float*));
MOCK_METHOD4(getDisplayedContentSamplingAttributes,
Error(Display, PixelFormat*, Dataspace*, uint8_t*));
+ MOCK_METHOD2(getDisplayCapabilities, Error(Display, std::vector<DisplayCapability>*));
};
} // namespace mock