Synchronize brightness change with frame update for hdr layers.
When the brightness changes while hdr layers are on screen, the dimming
ratio may also change based on ambient conditions, so HWC must
recomposite the scene with the new brightness value.
Bug: 210151839
Test: builds, boots
Change-Id: I4741b28d13f4528a7b5c9045bec7a5823e802935
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 73770b7..6cb12dd 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -173,6 +173,8 @@
// Sets the projection state to use
virtual void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
const Rect& orientedDisplaySpaceRect) = 0;
+ // Sets the brightness that will take effect next frame.
+ virtual void setNextBrightness(float brightness) = 0;
// Sets the bounds to use
virtual void setDisplaySize(const ui::Size&) = 0;
// Gets the transform hint used in layers that belong to this output. Used to guide
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 844876a..a7a8e97 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -45,6 +45,7 @@
void setLayerCachingTexturePoolEnabled(bool) override;
void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
const Rect& orientedDisplaySpaceRect) override;
+ void setNextBrightness(float brightness) override;
void setDisplaySize(const ui::Size&) override;
void setLayerFilter(ui::LayerFilter) override;
ui::Transform::RotationFlags getTransformHint() const override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index c8f177b..cc7c257 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -133,6 +133,10 @@
// White point of the client target
float clientTargetWhitePointNits{-1.f};
+ // Display brightness that will take effect this frame.
+ // This is slightly distinct from nits, in that nits cannot be passed to hw composer.
+ std::optional<float> displayBrightness = std::nullopt;
+
// Debugging
void dump(std::string& result) const;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 7b0d028..b68b95d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -39,6 +39,7 @@
MOCK_METHOD1(setLayerCachingEnabled, void(bool));
MOCK_METHOD1(setLayerCachingTexturePoolEnabled, void(bool));
MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&));
+ MOCK_METHOD1(setNextBrightness, void(float));
MOCK_METHOD1(setDisplaySize, void(const ui::Size&));
MOCK_CONST_METHOD0(getTransformHint, ui::Transform::RotationFlags());
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 08dd22d..186e191 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -226,6 +226,17 @@
// Get any composition changes requested by the HWC device, and apply them.
std::optional<android::HWComposer::DeviceRequestedChanges> changes;
auto& hwc = getCompositionEngine().getHwComposer();
+ if (const auto physicalDisplayId = PhysicalDisplayId::tryCast(*halDisplayId);
+ physicalDisplayId && getState().displayBrightness) {
+ const status_t result =
+ hwc.setDisplayBrightness(*physicalDisplayId, *getState().displayBrightness,
+ Hwc2::Composer::DisplayBrightnessOptions{
+ .applyImmediately = false})
+ .get();
+ ALOGE_IF(result != NO_ERROR, "setDisplayBrightness failed for %s: %d, (%s)",
+ getName().c_str(), result, strerror(-result));
+ }
+
if (status_t result =
hwc.getDeviceCompositionChanges(*halDisplayId, anyLayersRequireClientComposition(),
getState().earliestPresentTime,
@@ -248,6 +259,8 @@
auto& state = editState();
state.usesClientComposition = anyLayersRequireClientComposition();
state.usesDeviceComposition = !allLayersRequireClientComposition();
+ // Clear out the display brightness now that it's been communicated to composer.
+ state.displayBrightness.reset();
}
bool Display::getSkipColorTransform() const {
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 6833584..192ee04 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -197,6 +197,10 @@
dirtyEntireOutput();
}
+void Output::setNextBrightness(float brightness) {
+ editState().displayBrightness = brightness;
+}
+
void Output::setDisplaySize(const ui::Size& size) {
mRenderSurface->setDisplaySize(size);
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 8558a80..7dd4c21 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -37,6 +37,7 @@
#include "MockHWC2.h"
#include "MockHWComposer.h"
#include "MockPowerAdvisor.h"
+#include "ftl/future.h"
#include <aidl/android/hardware/graphics/composer3/Composition.h>
@@ -48,6 +49,7 @@
namespace hal = android::hardware::graphics::composer::hal;
using testing::_;
+using testing::ByMove;
using testing::DoAll;
using testing::Eq;
using testing::InSequence;
@@ -594,6 +596,38 @@
EXPECT_TRUE(state.usesDeviceComposition);
}
+TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithDisplayBrightness) {
+ // Since two calls are made to anyLayersRequireClientComposition with different return
+ // values, use a Sequence to control the matching so the values are returned in a known
+ // order.
+ constexpr float kDisplayBrightness = 0.5f;
+ Sequence s;
+ EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition())
+ .InSequence(s)
+ .WillOnce(Return(true));
+ EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition())
+ .InSequence(s)
+ .WillOnce(Return(false));
+ EXPECT_CALL(mHwComposer,
+ setDisplayBrightness(DEFAULT_DISPLAY_ID, kDisplayBrightness,
+ Hwc2::Composer::DisplayBrightnessOptions{.applyImmediately =
+ false}))
+ .WillOnce(Return(ByMove(ftl::yield<status_t>(NO_ERROR))));
+
+ EXPECT_CALL(mHwComposer,
+ getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
+
+ mDisplay->setNextBrightness(kDisplayBrightness);
+ mDisplay->chooseCompositionStrategy();
+
+ auto& state = mDisplay->getState();
+ EXPECT_FALSE(state.usesClientComposition);
+ EXPECT_TRUE(state.usesDeviceComposition);
+ EXPECT_FALSE(state.displayBrightness.has_value());
+}
+
TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) {
android::HWComposer::DeviceRequestedChanges changes{
{{nullptr, Composition::CLIENT}},
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index a590e2a..dc5c5c8 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -83,7 +83,9 @@
MOCK_METHOD4(setDisplayContentSamplingEnabled, status_t(HalDisplayId, bool, uint8_t, uint64_t));
MOCK_METHOD4(getDisplayedContentSample,
status_t(HalDisplayId, uint64_t, uint64_t, DisplayedFrameStats*));
- MOCK_METHOD2(setDisplayBrightness, std::future<status_t>(PhysicalDisplayId, float));
+ MOCK_METHOD3(setDisplayBrightness,
+ std::future<status_t>(PhysicalDisplayId, float,
+ const Hwc2::Composer::DisplayBrightnessOptions&));
MOCK_METHOD2(getDisplayBrightnessSupport, status_t(PhysicalDisplayId, bool*));
MOCK_METHOD2(onHotplug,
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 6d96260..f7c7533 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -574,6 +574,17 @@
EXPECT_EQ(Rect(newDisplaySize), mOutput->getState().framebufferSpace.getBoundsAsRect());
}
+/**
+ * Output::setDisplayBrightness()
+ */
+
+TEST_F(OutputTest, setNextBrightness) {
+ constexpr float kDisplayBrightness = 0.5f;
+ mOutput->setNextBrightness(kDisplayBrightness);
+ ASSERT_TRUE(mOutput->getState().displayBrightness.has_value());
+ EXPECT_EQ(kDisplayBrightness, mOutput->getState().displayBrightness);
+}
+
/*
* Output::getDirtyRegion()
*/
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 76bbe2c..a36ea72 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -311,6 +311,22 @@
orientedDisplaySpaceRect);
}
+void DisplayDevice::stageBrightness(float brightness) {
+ mStagedBrightness = brightness;
+}
+
+void DisplayDevice::persistBrightness(bool needsComposite) {
+ if (needsComposite && mStagedBrightness && mBrightness != *mStagedBrightness) {
+ getCompositionDisplay()->setNextBrightness(*mStagedBrightness);
+ mBrightness = *mStagedBrightness;
+ }
+ mStagedBrightness = std::nullopt;
+}
+
+std::optional<float> DisplayDevice::getStagedBrightness() const {
+ return mStagedBrightness;
+}
+
ui::Transform::RotationFlags DisplayDevice::getPrimaryDisplayRotationFlags() {
return sPrimaryDisplayRotationFlags;
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 324145e..d2accaa 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -99,6 +99,9 @@
void setLayerStack(ui::LayerStack);
void setDisplaySize(int width, int height);
void setProjection(ui::Rotation orientation, Rect viewport, Rect frame);
+ void stageBrightness(float brightness) REQUIRES(SF_MAIN_THREAD);
+ void persistBrightness(bool needsComposite) REQUIRES(SF_MAIN_THREAD);
+ bool isBrightnessStale() const REQUIRES(SF_MAIN_THREAD);
void setFlags(uint32_t flags);
ui::Rotation getPhysicalOrientation() const { return mPhysicalOrientation; }
@@ -106,6 +109,7 @@
static ui::Transform::RotationFlags getPrimaryDisplayRotationFlags();
+ std::optional<float> getStagedBrightness() const REQUIRES(SF_MAIN_THREAD);
ui::Transform::RotationFlags getTransformHint() const;
const ui::Transform& getTransform() const;
const Rect& getLayerStackSpaceRect() const;
@@ -271,6 +275,8 @@
hardware::graphics::composer::hal::PowerMode mPowerMode =
hardware::graphics::composer::hal::PowerMode::OFF;
DisplayModePtr mActiveMode;
+ std::optional<float> mStagedBrightness = std::nullopt;
+ float mBrightness = -1.f;
const DisplayModes mSupportedModes;
std::atomic<nsecs_t> mLastHwVsync = 0;
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index 1091a75..34f5a39 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -246,6 +246,7 @@
switch (feature) {
case OptionalFeature::RefreshRateSwitching:
case OptionalFeature::ExpectedPresentTime:
+ case OptionalFeature::DisplayBrightnessCommand:
return true;
}
}
@@ -906,13 +907,24 @@
return Error::NONE;
}
-Error AidlComposer::setDisplayBrightness(Display display, float brightness) {
- const auto status =
- mAidlComposerClient->setDisplayBrightness(translate<int64_t>(display), brightness);
- if (!status.isOk()) {
- ALOGE("setDisplayBrightness failed %s", status.getDescription().c_str());
- return static_cast<Error>(status.getServiceSpecificError());
+Error AidlComposer::setDisplayBrightness(Display display, float brightness,
+ const DisplayBrightnessOptions& options) {
+ if (!options.sdrDimmingEnabled) {
+ const auto status =
+ mAidlComposerClient->setDisplayBrightness(translate<int64_t>(display), brightness);
+ if (!status.isOk()) {
+ ALOGE("setDisplayBrightness failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ return Error::NONE;
}
+
+ mWriter.setDisplayBrightness(translate<int64_t>(display), brightness);
+
+ if (options.applyImmediately) {
+ return execute();
+ }
+
return Error::NONE;
}
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index 5c41982..c720932 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -180,7 +180,8 @@
Error setLayerPerFrameMetadataBlobs(
Display display, Layer layer,
const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) override;
- Error setDisplayBrightness(Display display, float brightness) override;
+ Error setDisplayBrightness(Display display, float brightness,
+ const DisplayBrightnessOptions& options) override;
// Composer HAL 2.4
Error getDisplayCapabilities(
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index f491a00..e492997 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -78,6 +78,8 @@
enum class OptionalFeature {
RefreshRateSwitching,
ExpectedPresentTime,
+ // Whether setDisplayBrightness is able to be applied as part of a display command.
+ DisplayBrightnessCommand,
};
virtual bool isSupported(OptionalFeature) const = 0;
@@ -204,7 +206,22 @@
DisplayedFrameStats* outStats) = 0;
virtual Error setLayerPerFrameMetadataBlobs(
Display display, Layer layer, const std::vector<PerFrameMetadataBlob>& metadata) = 0;
- virtual Error setDisplayBrightness(Display display, float brightness) = 0;
+ // Options for setting the display brightness
+ struct DisplayBrightnessOptions {
+ // If true, then immediately submits a brightness change request to composer. Otherwise,
+ // submission of the brightness change may be deferred until presenting the next frame.
+ // applyImmediately should only be false if OptionalFeature::DisplayBrightnessCommand is
+ // supported.
+ bool applyImmediately = true;
+ bool sdrDimmingEnabled = true;
+
+ bool operator==(const DisplayBrightnessOptions& other) const {
+ return applyImmediately == other.applyImmediately &&
+ sdrDimmingEnabled == other.sdrDimmingEnabled;
+ }
+ };
+ virtual Error setDisplayBrightness(Display display, float brightness,
+ const DisplayBrightnessOptions& options) = 0;
// Composer HAL 2.4
virtual Error getDisplayCapabilities(
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 548d839..715d9fd 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -37,8 +37,6 @@
#include <iterator>
#include <set>
-#include "ComposerHal.h"
-
using aidl::android::hardware::graphics::composer3::Composition;
using aidl::android::hardware::graphics::composer3::DisplayCapability;
@@ -532,9 +530,10 @@
return error;
}
-std::future<Error> Display::setDisplayBrightness(float brightness) {
- return ftl::defer([composer = &mComposer, id = mId, brightness] {
- const auto intError = composer->setDisplayBrightness(id, brightness);
+std::future<Error> Display::setDisplayBrightness(
+ float brightness, const Hwc2::Composer::DisplayBrightnessOptions& options) {
+ return ftl::defer([composer = &mComposer, id = mId, brightness, options] {
+ const auto intError = composer->setDisplayBrightness(id, brightness, options);
return static_cast<Error>(intError);
});
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 731d7f6..df4e4b8 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -34,6 +34,7 @@
#include <unordered_set>
#include <vector>
+#include "ComposerHal.h"
#include "Hal.h"
#include <aidl/android/hardware/graphics/composer3/Composition.h>
@@ -143,7 +144,7 @@
nsecs_t expectedPresentTime, uint32_t* outNumTypes, uint32_t* outNumRequests,
android::sp<android::Fence>* outPresentFence, uint32_t* state) = 0;
[[clang::warn_unused_result]] virtual std::future<hal::Error> setDisplayBrightness(
- float brightness) = 0;
+ float brightness, const Hwc2::Composer::DisplayBrightnessOptions& options) = 0;
[[clang::warn_unused_result]] virtual hal::Error setActiveConfigWithConstraints(
hal::HWConfigId configId, const hal::VsyncPeriodChangeConstraints& constraints,
hal::VsyncPeriodChangeTimeline* outTimeline) = 0;
@@ -211,7 +212,8 @@
uint32_t* outNumRequests,
android::sp<android::Fence>* outPresentFence,
uint32_t* state) override;
- std::future<hal::Error> setDisplayBrightness(float brightness) override;
+ std::future<hal::Error> setDisplayBrightness(
+ float brightness, const Hwc2::Composer::DisplayBrightnessOptions& options) override;
hal::Error setActiveConfigWithConstraints(hal::HWConfigId configId,
const hal::VsyncPeriodChangeConstraints& constraints,
hal::VsyncPeriodChangeTimeline* outTimeline) override;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 546e677..057db46 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -782,12 +782,13 @@
return NO_ERROR;
}
-std::future<status_t> HWComposer::setDisplayBrightness(PhysicalDisplayId displayId,
- float brightness) {
+std::future<status_t> HWComposer::setDisplayBrightness(
+ PhysicalDisplayId displayId, float brightness,
+ const Hwc2::Composer::DisplayBrightnessOptions& options) {
RETURN_IF_INVALID_DISPLAY(displayId, ftl::yield<status_t>(BAD_INDEX));
auto& display = mDisplayData[displayId].hwcDisplay;
- return ftl::chain(display->setDisplayBrightness(brightness))
+ return ftl::chain(display->setDisplayBrightness(brightness, options))
.then([displayId](hal::Error error) -> status_t {
if (error == hal::Error::UNSUPPORTED) {
RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 69adfcd..4fae06d 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -192,7 +192,9 @@
DisplayedFrameStats* outStats) = 0;
// Sets the brightness of a display.
- virtual std::future<status_t> setDisplayBrightness(PhysicalDisplayId, float brightness) = 0;
+ virtual std::future<status_t> setDisplayBrightness(
+ PhysicalDisplayId, float brightness,
+ const Hwc2::Composer::DisplayBrightnessOptions&) = 0;
// Events handling ---------------------------------------------------------
@@ -340,7 +342,9 @@
uint64_t maxFrames) override;
status_t getDisplayedContentSample(HalDisplayId, uint64_t maxFrames, uint64_t timestamp,
DisplayedFrameStats* outStats) override;
- std::future<status_t> setDisplayBrightness(PhysicalDisplayId, float brightness) override;
+ std::future<status_t> setDisplayBrightness(
+ PhysicalDisplayId, float brightness,
+ const Hwc2::Composer::DisplayBrightnessOptions&) override;
// Events handling ---------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index 7946002..b884755 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -161,6 +161,7 @@
case OptionalFeature::RefreshRateSwitching:
return mClient_2_4 != nullptr;
case OptionalFeature::ExpectedPresentTime:
+ case OptionalFeature::DisplayBrightnessCommand:
return false;
}
}
@@ -1013,7 +1014,8 @@
return Error::NONE;
}
-Error HidlComposer::setDisplayBrightness(Display display, float brightness) {
+Error HidlComposer::setDisplayBrightness(Display display, float brightness,
+ const DisplayBrightnessOptions&) {
if (!mClient_2_3) {
return Error::UNSUPPORTED;
}
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index 3b62fe0..6c8af5d 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -289,7 +289,8 @@
Error setLayerPerFrameMetadataBlobs(
Display display, Layer layer,
const std::vector<IComposerClient::PerFrameMetadataBlob>& metadata) override;
- Error setDisplayBrightness(Display display, float brightness) override;
+ Error setDisplayBrightness(Display display, float brightness,
+ const DisplayBrightnessOptions& options) override;
// Composer HAL 2.4
Error getDisplayCapabilities(
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 89f3bd6..58f2ab6 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1669,6 +1669,17 @@
return NO_ERROR;
}
+bool SurfaceFlinger::hasVisibleHdrLayer(const sp<DisplayDevice>& display) {
+ bool hasHdrLayers = false;
+ mDrawingState.traverse([&,
+ compositionDisplay = display->getCompositionDisplay()](Layer* layer) {
+ hasHdrLayers |= (layer->isVisible() &&
+ compositionDisplay->includesLayer(layer->getCompositionEngineLayerFE()) &&
+ isHdrDataspace(layer->getDataSpace()));
+ });
+ return hasHdrLayers;
+}
+
status_t SurfaceFlinger::setDisplayBrightness(const sp<IBinder>& displayToken,
const gui::DisplayBrightness& brightness) {
if (!displayToken) {
@@ -1678,13 +1689,33 @@
const char* const whence = __func__;
return ftl::chain(mScheduler->schedule([=]() MAIN_THREAD {
if (const auto display = getDisplayDeviceLocked(displayToken)) {
- if (enableSdrDimming) {
+ const bool supportsDisplayBrightnessCommand =
+ getHwComposer().getComposer()->isSupported(
+ Hwc2::Composer::OptionalFeature::DisplayBrightnessCommand);
+ // If we support applying display brightness as a command, then we also support
+ // dimming SDR layers.
+ // TODO(b/212634488): Once AIDL composer implementations are finalized, remove
+ // the enableSdrDimming check, as dimming support will be expected for AIDL
+ // composer.
+ if (enableSdrDimming && supportsDisplayBrightnessCommand) {
display->getCompositionDisplay()
->setDisplayBrightness(brightness.sdrWhitePointNits,
brightness.displayBrightnessNits);
+ MAIN_THREAD_GUARD(display->stageBrightness(brightness.displayBrightness));
+ if (hasVisibleHdrLayer(display)) {
+ scheduleComposite(FrameHint::kNone);
+ } else {
+ scheduleCommit(FrameHint::kNone);
+ }
+ return ftl::yield<status_t>(OK);
+ } else {
+ return getHwComposer().setDisplayBrightness(
+ display->getPhysicalId(), brightness.displayBrightness,
+ Hwc2::Composer::DisplayBrightnessOptions{.applyImmediately = true,
+ .sdrDimmingEnabled =
+ enableSdrDimming});
}
- return getHwComposer().setDisplayBrightness(display->getPhysicalId(),
- brightness.displayBrightness);
+
} else {
ALOGE("%s: Invalid display token %p", whence, displayToken.get());
return ftl::yield<status_t>(NAME_NOT_FOUND);
@@ -2069,6 +2100,8 @@
updateCursorAsync();
updateInputFlinger();
+ MAIN_THREAD_GUARD(persistDisplayBrightness(mustComposite));
+
return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER);
}
@@ -3101,6 +3134,34 @@
mInputWindowCommands.clear();
}
+void SurfaceFlinger::persistDisplayBrightness(bool needsComposite) {
+ const bool supportsDisplayBrightnessCommand = getHwComposer().getComposer()->isSupported(
+ Hwc2::Composer::OptionalFeature::DisplayBrightnessCommand);
+ if (!supportsDisplayBrightnessCommand) {
+ return;
+ }
+
+ const auto& displays = ON_MAIN_THREAD(mDisplays);
+
+ for (const auto& [_, display] : displays) {
+ if (const auto brightness = display->getStagedBrightness(); brightness) {
+ if (!needsComposite) {
+ const status_t error =
+ getHwComposer()
+ .setDisplayBrightness(display->getPhysicalId(), *brightness,
+ Hwc2::Composer::DisplayBrightnessOptions{
+ .applyImmediately = true})
+ .get();
+
+ ALOGE_IF(error != NO_ERROR,
+ "Error setting display brightness for display %s: %d (%s)",
+ display->getDebugName().c_str(), error, strerror(error));
+ }
+ display->persistBrightness(needsComposite);
+ }
+ }
+}
+
void SurfaceFlinger::buildWindowInfos(std::vector<WindowInfo>& outWindowInfos,
std::vector<DisplayInfo>& outDisplayInfos) {
std::unordered_map<uint32_t /*layerStackId*/,
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index e1b52c5..007eb9f 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -674,6 +674,9 @@
void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode)
REQUIRES(mStateLock);
+ // Returns true if the display has a visible HDR layer in its layer stack.
+ bool hasVisibleHdrLayer(const sp<DisplayDevice>& display) REQUIRES(mStateLock);
+
// Sets the desired display mode specs.
status_t setDesiredDisplayModeSpecsInternal(
const sp<DisplayDevice>& display,
@@ -690,6 +693,7 @@
void updateLayerGeometry();
void updateInputFlinger();
+ void persistDisplayBrightness(bool needsComposite) REQUIRES(SF_MAIN_THREAD);
void buildWindowInfos(std::vector<gui::WindowInfo>& outWindowInfos,
std::vector<gui::DisplayInfo>& outDisplayInfos);
void commitInputWindowCommands() REQUIRES(mStateLock);
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 5568418..bba880e 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -55,6 +55,7 @@
"DisplayTransactionTest.cpp",
"DisplayDevice_GetBestColorModeTest.cpp",
"DisplayDevice_InitiateModeChange.cpp",
+ "DisplayDevice_SetDisplayBrightnessTest.cpp",
"DisplayDevice_SetProjectionTest.cpp",
"EventThreadTest.cpp",
"FlagManagerTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp
new file mode 100644
index 0000000..73c60e1
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2021 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include "DisplayTransactionTestHelpers.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace {
+
+using hal::RenderIntent;
+
+using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
+
+class SetDisplayBrightnessTest : public DisplayTransactionTest {
+public:
+ sp<DisplayDevice> getDisplayDevice() { return injectDefaultInternalDisplay({}); }
+};
+
+TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessNoComposite) {
+ MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+ sp<DisplayDevice> displayDevice = getDisplayDevice();
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+
+ constexpr float kDisplayBrightness = 0.5f;
+ displayDevice->stageBrightness(kDisplayBrightness);
+
+ EXPECT_EQ(0.5f, displayDevice->getStagedBrightness());
+
+ displayDevice->persistBrightness(false);
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+ EXPECT_EQ(std::nullopt, displayDevice->getCompositionDisplay()->getState().displayBrightness);
+}
+
+TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessWithComposite) {
+ MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+ sp<DisplayDevice> displayDevice = getDisplayDevice();
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+
+ constexpr float kDisplayBrightness = 0.5f;
+ displayDevice->stageBrightness(kDisplayBrightness);
+
+ EXPECT_EQ(0.5f, displayDevice->getStagedBrightness());
+
+ displayDevice->persistBrightness(true);
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+ EXPECT_EQ(kDisplayBrightness,
+ displayDevice->getCompositionDisplay()->getState().displayBrightness);
+}
+
+TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessWithCompositeShortCircuitsOnNoOp) {
+ MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+ sp<DisplayDevice> displayDevice = getDisplayDevice();
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+
+ constexpr float kDisplayBrightness = 0.5f;
+ displayDevice->stageBrightness(kDisplayBrightness);
+
+ EXPECT_EQ(0.5f, displayDevice->getStagedBrightness());
+
+ displayDevice->persistBrightness(true);
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+ EXPECT_EQ(kDisplayBrightness,
+ displayDevice->getCompositionDisplay()->getState().displayBrightness);
+ displayDevice->getCompositionDisplay()->editState().displayBrightness = std::nullopt;
+
+ displayDevice->stageBrightness(kDisplayBrightness);
+ EXPECT_EQ(0.5f, displayDevice->getStagedBrightness());
+ displayDevice->persistBrightness(true);
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+ EXPECT_EQ(std::nullopt, displayDevice->getCompositionDisplay()->getState().displayBrightness);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index b1f704a..c318e28 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -60,6 +60,7 @@
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ mFlinger.resetScheduler(nullptr);
}
void DisplayTransactionTest::injectMockScheduler() {
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 0067997..361d629 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -347,6 +347,11 @@
auto notifyPowerBoost(int32_t boostId) { return mFlinger->notifyPowerBoost(boostId); }
+ auto setDisplayBrightness(const sp<IBinder>& display,
+ const gui::DisplayBrightness& brightness) {
+ return mFlinger->setDisplayBrightness(display, brightness);
+ }
+
// Allow reading display state without locking, as if called on the SF main thread.
auto setPowerModeInternal(const sp<DisplayDevice>& display,
hal::PowerMode mode) NO_THREAD_SAFETY_ANALYSIS {
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 8c51313..4932ad1 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -120,7 +120,7 @@
Error(Display, uint64_t, uint64_t, DisplayedFrameStats*));
MOCK_METHOD3(setLayerPerFrameMetadataBlobs,
Error(Display, Layer, const std::vector<IComposerClient::PerFrameMetadataBlob>&));
- MOCK_METHOD2(setDisplayBrightness, Error(Display, float));
+ MOCK_METHOD3(setDisplayBrightness, Error(Display, float, const DisplayBrightnessOptions&));
MOCK_METHOD2(
getDisplayCapabilities,
Error(Display,
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
index 821fc8f..0527d80 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -80,7 +80,8 @@
MOCK_METHOD(hal::Error, presentOrValidate,
(nsecs_t, uint32_t *, uint32_t *, android::sp<android::Fence> *, uint32_t *),
(override));
- MOCK_METHOD(std::future<hal::Error>, setDisplayBrightness, (float), (override));
+ MOCK_METHOD(std::future<hal::Error>, setDisplayBrightness,
+ (float, const Hwc2::Composer::DisplayBrightnessOptions &), (override));
MOCK_METHOD(hal::Error, setActiveConfigWithConstraints,
(hal::HWConfigId, const hal::VsyncPeriodChangeConstraints &,
hal::VsyncPeriodChangeTimeline *),
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
index 8b48e1c..0840a2f 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -34,6 +34,7 @@
MOCK_METHOD0(createClone, sp<Layer>());
MOCK_CONST_METHOD0(getFrameRateForLayerTree, FrameRate());
MOCK_CONST_METHOD0(getOwnerUid, uid_t());
+ MOCK_CONST_METHOD0(getDataSpace, ui::Dataspace());
};
} // namespace android::mock