Provide dimming ratio instead of white point nits in composer

There are several reasons for limiting the notion of white point nits in
the composer interface:

1. Some KMS apis exposed by drivers only expose a notion of a per-plane
   brightness. While these are non-mobile drivers, e.g., nouveau, this
   does indicate that white point is not directly going to be understood
   by typical hardware
2. Changing the brightness without requiring a frame update introduces
   implicit state in composer. If the brightness and white point nits
   for a set of SDR layers are 200 nits, and the brightness changes to
   205 nits to respond to ambient conditions, then composer must not dim
   the layers, and in fact DisplayManager will tell SurfaceFlinger that
   the SDR white point will be 205 nits. But SurfaceFlinger will not
   tell composer that the SDR white point changed as that would
   otherwise introduce a re-composition cycle, meaning that
   HW Composer must track somehow that the layer white point changed
   without a corresponding change on the layer data structure, which is
   confusing.
3. It's poorly defined what the dimming ratio should be if
   SurfaceFlinger provides the following inputs: Layer A has a white
   point of 200 nits, Layer B has a white point of 400 nits, and display
   brightness is 300 nits. Current implementations may clamp the
   brightness of Layer B to be 300 nits and dim layer A by 2/3s, but
   there is an equally valid interpretation which is just dim Layer A to
   be 50% of Layer B's brightness.
4. The problem indicated by (2) and (3) suggests that layer white point is
   really an up-stack concept, that SurfaceFlinger can be aware of for
   properly computing the dimming ratios it can send to composer, but
   the composer hal shouldn't really be speaking in terms of nits.

Note that this patch does not yet change the interface for
ClientTargetWithNits, which may be done in a follow-up patch.

Bug: 217961164
Test: builds, boots
Change-Id: I4a1b4e8c300d22599a5683bd44b7b8afa9a29425
This commit is contained in:
Alec Mouri 2022-02-07 13:03:44 -08:00
parent 55a87cc169
commit b1f16725cc
10 changed files with 43 additions and 35 deletions

View file

@ -33,6 +33,6 @@
package android.hardware.graphics.composer3;
@VintfStability
parcelable Luminance {
float nits;
parcelable LayerBrightness {
float brightness;
}

View file

@ -50,7 +50,7 @@ parcelable LayerCommand {
@nullable android.hardware.graphics.common.Rect[] visibleRegion;
@nullable android.hardware.graphics.composer3.ZOrder z;
@nullable float[] colorTransform;
@nullable android.hardware.graphics.composer3.Luminance whitePointNits;
@nullable android.hardware.graphics.composer3.LayerBrightness brightness;
@nullable android.hardware.graphics.composer3.PerFrameMetadata[] perFrameMetadata;
@nullable android.hardware.graphics.composer3.PerFrameMetadataBlob[] perFrameMetadataBlob;
@nullable android.hardware.graphics.common.Rect[] blockingRegion;

View file

@ -77,15 +77,7 @@ parcelable DisplayCommand {
* the display brightness, for example when internally switching the display between multiple
* power modes to achieve higher luminance. In those cases, the underlying display panel's real
* brightness may not be applied atomically; however, layer dimming when mixing HDR and SDR
* content must be synchronized.
*
* As an illustrative example: suppose two layers have white
* points of 200 nits and 1000 nits respectively, the old display luminance is 200 nits, and the
* new display luminance is 1000 nits. If the new display luminance takes two frames to apply,
* then: In the first frame, there must not be any relative dimming of layers (treat both layers
* as 200 nits as the maximum luminance of the display is 200 nits). In the second frame, there
* dimming should be applied to ensure that the first layer does not become perceptually
* brighter during the transition.
* content must be synchronized to ensure that there is no user-perceptable flicker.
*
* The display luminance must be updated by this command even if there is not pending validate
* or present command.

View file

@ -17,10 +17,10 @@
package android.hardware.graphics.composer3;
@VintfStability
parcelable Luminance {
parcelable LayerBrightness {
/**
* Photometric measure of luminous intensity per unit area of light.
* Units are nits, or cd/m^2.
* Brightness of the current layer, ranging from 0 to 1, where 0 is the minimum brightness of
* the display, and 1 is the current brightness of the display.
*/
float nits;
float brightness;
}

View file

@ -22,7 +22,7 @@ import android.hardware.graphics.common.Point;
import android.hardware.graphics.common.Rect;
import android.hardware.graphics.composer3.Buffer;
import android.hardware.graphics.composer3.Color;
import android.hardware.graphics.composer3.Luminance;
import android.hardware.graphics.composer3.LayerBrightness;
import android.hardware.graphics.composer3.ParcelableBlendMode;
import android.hardware.graphics.composer3.ParcelableComposition;
import android.hardware.graphics.composer3.ParcelableDataspace;
@ -221,12 +221,12 @@ parcelable LayerCommand {
@nullable float[] colorTransform;
/**
* Sets the desired white point for the layer. This is intended to be used when presenting
* an SDR layer alongside HDR content. The HDR content will be presented at the display
* brightness in nits, and accordingly SDR content shall be dimmed to the desired white point
* provided.
* Sets the desired brightness for the layer. This is intended to be used for instance when
* presenting an SDR layer alongside HDR content. The HDR content will be presented at the
* display brightness in nits, and accordingly SDR content shall be dimmed according to the
* provided brightness ratio.
*/
@nullable Luminance whitePointNits;
@nullable LayerBrightness brightness;
/**
* Sets the PerFrameMetadata for the display. This metadata must be used

View file

@ -965,7 +965,7 @@ TEST_P(GraphicsCompositionTest, SetLayerZOrder) {
}
}
TEST_P(GraphicsCompositionTest, SetLayerWhitePointDims) {
TEST_P(GraphicsCompositionTest, SetLayerBrightnessDims) {
const auto& [status, capabilities] =
mComposerClient->getDisplayCapabilities(getPrimaryDisplayId());
ASSERT_TRUE(status.isOk());
@ -1013,6 +1013,7 @@ TEST_P(GraphicsCompositionTest, SetLayerWhitePointDims) {
redLayer->setColor(RED);
redLayer->setDisplayFrame(redRect);
redLayer->setWhitePointNits(maxBrightnessNits);
redLayer->setBrightness(1.f);
const auto dimmerRedLayer =
std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId());
@ -1022,6 +1023,7 @@ TEST_P(GraphicsCompositionTest, SetLayerWhitePointDims) {
// kick into GPU composition to apply dithering when the dimming ratio is high.
static constexpr float kDimmingRatio = 0.9f;
dimmerRedLayer->setWhitePointNits(maxBrightnessNits * kDimmingRatio);
dimmerRedLayer->setBrightness(kDimmingRatio);
const std::vector<std::shared_ptr<TestLayer>> layers = {redLayer, dimmerRedLayer};
std::vector<Color> expectedColors(

View file

@ -1798,26 +1798,37 @@ TEST_P(GraphicsComposerAidlCommandTest, SetLayerPerFrameMetadata) {
EXPECT_TRUE(mComposerClient->destroyLayer(getPrimaryDisplayId(), layer).isOk());
}
TEST_P(GraphicsComposerAidlCommandTest, SetLayerWhitePointNits) {
TEST_P(GraphicsComposerAidlCommandTest, setLayerBrightness) {
const auto& [layerStatus, layer] =
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
EXPECT_TRUE(layerStatus.isOk());
mWriter.setLayerWhitePointNits(getPrimaryDisplayId(), layer, /*whitePointNits*/ 200.f);
mWriter.setLayerBrightness(getPrimaryDisplayId(), layer, 0.2f);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
mWriter.setLayerWhitePointNits(getPrimaryDisplayId(), layer, /*whitePointNits*/ 1000.f);
mWriter.setLayerBrightness(getPrimaryDisplayId(), layer, 1.f);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
mWriter.setLayerWhitePointNits(getPrimaryDisplayId(), layer, /*whitePointNits*/ 0.f);
mWriter.setLayerBrightness(getPrimaryDisplayId(), layer, 0.f);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
mWriter.setLayerWhitePointNits(getPrimaryDisplayId(), layer, /*whitePointNits*/ -1.f);
mWriter.setLayerBrightness(getPrimaryDisplayId(), layer, -1.f);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
{
const auto errors = mReader.takeErrors();
ASSERT_EQ(1, errors.size());
EXPECT_EQ(IComposerClient::EX_BAD_PARAMETER, errors[0].errorCode);
}
mWriter.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) {

View file

@ -34,7 +34,7 @@ void TestLayer::write(ComposerClientWriter& writer) {
writer.setLayerTransform(mDisplay, mLayer, mTransform);
writer.setLayerPlaneAlpha(mDisplay, mLayer, mAlpha);
writer.setLayerBlendMode(mDisplay, mLayer, mBlendMode);
writer.setLayerWhitePointNits(mDisplay, mLayer, mWhitePointNits);
writer.setLayerBrightness(mDisplay, mLayer, mBrightness);
}
std::string ReadbackHelper::getColorModeString(ColorMode mode) {

View file

@ -67,6 +67,7 @@ class TestLayer {
void setSourceCrop(FRect crop) { mSourceCrop = crop; }
void setZOrder(uint32_t z) { mZOrder = z; }
void setWhitePointNits(float whitePointNits) { mWhitePointNits = whitePointNits; }
void setBrightness(float brightness) { mBrightness = brightness; }
void setSurfaceDamage(std::vector<Rect> surfaceDamage) {
mSurfaceDamage = std::move(surfaceDamage);
@ -84,12 +85,13 @@ class TestLayer {
int64_t getLayer() const { return mLayer; }
float getWhitePointNits() const { return mWhitePointNits; }
float getBrightness() const { return mBrightness; }
protected:
int64_t mDisplay;
int64_t mLayer;
Rect mDisplayFrame = {0, 0, 0, 0};
float mBrightness = 1.f;
float mWhitePointNits = -1.f;
std::vector<Rect> mSurfaceDamage;
Transform mTransform = static_cast<Transform>(0);

View file

@ -30,7 +30,7 @@
#include <aidl/android/hardware/graphics/composer3/Color.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
#include <aidl/android/hardware/graphics/composer3/DisplayBrightness.h>
#include <aidl/android/hardware/graphics/composer3/Luminance.h>
#include <aidl/android/hardware/graphics/composer3/LayerBrightness.h>
#include <aidl/android/hardware/graphics/composer3/PerFrameMetadata.h>
#include <aidl/android/hardware/graphics/composer3/PerFrameMetadataBlob.h>
@ -209,8 +209,9 @@ class ComposerClientWriter {
.perFrameMetadataBlob.emplace(metadata.begin(), metadata.end());
}
void setLayerWhitePointNits(int64_t display, int64_t layer, float whitePointNits) {
getLayerCommand(display, layer).whitePointNits.emplace(Luminance{.nits = whitePointNits});
void setLayerBrightness(int64_t display, int64_t layer, float brightness) {
getLayerCommand(display, layer)
.brightness.emplace(LayerBrightness{.brightness = brightness});
}
void setLayerBlockingRegion(int64_t display, int64_t layer, const std::vector<Rect>& blocking) {