SF: Move/Refactor Layer::setPerFrameData
Moves functionality out of ColorLayer, BufferLayer, BufferStateLayer and
BufferQueueLayer related to setting the per-frame data.
Instead each of the front-end classes now implements a minimal function
to set the per-frame state into the LayerFECompositionState structure.
compositionengine::OutputLayer now takes care of sending the state to
the HWC, and in particular with detecting when client composition needs
to be forced due to lack of HWC support (though the front-end can also
set a flag to force client composition for a few things it knows about).
SurfaceFlinger::calculateWorkingSet is also refactored to work with the
changes made, and prepare it to be moved over to CompositionEngine.
Test: atest libsurfaceflinger_unittest libcompositionengine_test
Test: atest CtsColorModeTestCases
Test: atest CtsDisplayTestCases
Test: atest CtsGraphicsTestCases
Test: atest CtsUiRenderingTestCases
Test: atest CtsViewTestCases
Test: atest android.media.cts.EncodeVirtualDisplayWithCompositionTest
Bug: 121291683
Change-Id: I2cb0442f68ec5c5f65f5b4cb418dda4c42e5dc39
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index f51fbb4..c3b1718 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -25,6 +25,7 @@
#include <compositionengine/Display.h>
#include <compositionengine/Layer.h>
#include <compositionengine/LayerCreationArgs.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/LayerCompositionState.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
@@ -253,90 +254,20 @@
mActiveBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102);
}
-void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice,
- const ui::Transform& transform, const Rect& viewport,
- int32_t supportedPerFrameMetadata,
- const ui::Dataspace targetDataspace) {
- RETURN_IF_NO_HWC_LAYER(displayDevice);
-
- // Apply this display's projection's viewport to the visible region
- // before giving it to the HWC HAL.
- Region visible = transform.transform(visibleRegion.intersect(viewport));
-
- const auto outputLayer = findOutputLayerForDisplay(displayDevice);
- LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc);
-
- auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
- auto error = hwcLayer->setVisibleRegion(visible);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- visible.dump(LOG_TAG);
- }
- outputLayer->editState().visibleRegion = visible;
-
- auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
-
- error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- surfaceDamageRegion.dump(LOG_TAG);
- }
- layerCompositionState.surfaceDamage = surfaceDamageRegion;
+void BufferLayer::latchPerFrameState(
+ compositionengine::LayerFECompositionState& compositionState) const {
+ Layer::latchPerFrameState(compositionState);
// Sideband layers
- if (layerCompositionState.sidebandStream.get()) {
- setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::SIDEBAND);
- ALOGV("[%s] Requesting Sideband composition", mName.string());
- error = hwcLayer->setSidebandStream(layerCompositionState.sidebandStream->handle());
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", mName.string(),
- layerCompositionState.sidebandStream->handle(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
- layerCompositionState.compositionType = Hwc2::IComposerClient::Composition::SIDEBAND;
- return;
- }
-
- // Device or Cursor layers
- if (mPotentialCursor) {
- ALOGV("[%s] Requesting Cursor composition", mName.string());
- setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::CURSOR);
+ if (compositionState.sidebandStream.get()) {
+ compositionState.compositionType = Hwc2::IComposerClient::Composition::SIDEBAND;
} else {
- ALOGV("[%s] Requesting Device composition", mName.string());
- setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::DEVICE);
+ // Normal buffer layers
+ compositionState.hdrMetadata = getDrawingHdrMetadata();
+ compositionState.compositionType = mPotentialCursor
+ ? Hwc2::IComposerClient::Composition::CURSOR
+ : Hwc2::IComposerClient::Composition::DEVICE;
}
-
- ui::Dataspace dataspace = isColorSpaceAgnostic() && targetDataspace != ui::Dataspace::UNKNOWN
- ? targetDataspace
- : mCurrentDataSpace;
- error = hwcLayer->setDataspace(dataspace);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), dataspace,
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
-
- const HdrMetadata& metadata = getDrawingHdrMetadata();
- error = hwcLayer->setPerFrameMetadata(supportedPerFrameMetadata, metadata);
- if (error != HWC2::Error::None && error != HWC2::Error::Unsupported) {
- ALOGE("[%s] Failed to set hdrMetadata: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
-
- error = hwcLayer->setColorTransform(getColorTransform());
- if (error == HWC2::Error::Unsupported) {
- // If per layer color transform is not supported, we use GPU composition.
- setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::CLIENT);
- } else if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to setColorTransform: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
- layerCompositionState.dataspace = mCurrentDataSpace;
- layerCompositionState.colorTransform = getColorTransform();
- layerCompositionState.hdrMetadata = metadata;
-
- setHwcLayerBuffer(displayDevice);
}
bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index b679380..6bde7b4 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -82,10 +82,6 @@
bool isHdrY410() const override;
- void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
- const Rect& viewport, int32_t supportedPerFrameMetadata,
- const ui::Dataspace targetDataspace) override;
-
bool onPreComposition(nsecs_t refreshStartTime) override;
bool onPostComposition(const std::optional<DisplayId>& displayId,
const std::shared_ptr<FenceTime>& glDoneFence,
@@ -147,9 +143,9 @@
virtual status_t updateActiveBuffer() = 0;
virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
- virtual void setHwcLayerBuffer(const sp<const DisplayDevice>& displayDevice) = 0;
-
protected:
+ void latchPerFrameState(compositionengine::LayerFECompositionState& outState) const override;
+
// Loads the corresponding system property once per process
static bool latchUnsignaledBuffers();
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index d685366..2c3da1a 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -377,7 +377,6 @@
mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot, &mActiveBufferFence);
auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
layerCompositionState.buffer = mActiveBuffer;
- layerCompositionState.bufferSlot = mActiveBufferSlot;
if (mActiveBuffer == nullptr) {
// this can only happen if the very first buffer was rejected.
@@ -397,32 +396,17 @@
return NO_ERROR;
}
-void BufferQueueLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer);
- LOG_FATAL_IF(!outputLayer->getState.hwc);
- auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
-
- uint32_t hwcSlot = 0;
- sp<GraphicBuffer> hwcBuffer;
-
- // INVALID_BUFFER_SLOT is used to identify BufferStateLayers. Default to 0
- // for BufferQueueLayers
- int slot = (mActiveBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) ? 0 : mActiveBufferSlot;
- (*outputLayer->editState().hwc)
- .hwcBufferCache.getHwcBuffer(slot, mActiveBuffer, &hwcSlot, &hwcBuffer);
-
- auto acquireFence = mConsumer->getCurrentFence();
- auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(), mActiveBuffer->handle,
- to_string(error).c_str(), static_cast<int32_t>(error));
+void BufferQueueLayer::latchPerFrameState(
+ compositionengine::LayerFECompositionState& compositionState) const {
+ BufferLayer::latchPerFrameState(compositionState);
+ if (compositionState.compositionType == Hwc2::IComposerClient::Composition::SIDEBAND) {
+ return;
}
- auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
- layerCompositionState.bufferSlot = mActiveBufferSlot;
- layerCompositionState.buffer = mActiveBuffer;
- layerCompositionState.acquireFence = acquireFence;
+ compositionState.buffer = mActiveBuffer;
+ compositionState.bufferSlot =
+ (mActiveBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) ? 0 : mActiveBufferSlot;
+ compositionState.acquireFence = mConsumer->getCurrentFence();
}
// -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 7def33a..9c537ad 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -94,7 +94,7 @@
status_t updateActiveBuffer() override;
status_t updateFrameNumber(nsecs_t latchTime) override;
- void setHwcLayerBuffer(const sp<const DisplayDevice>& displayDevice) override;
+ void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
// -----------------------------------------------------------------------
// Interface implementation for BufferLayerConsumer::ContentsChangedListener
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 4b01301..d0fa2e0 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -569,7 +569,6 @@
mActiveBufferFence = s.acquireFence;
auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
layerCompositionState.buffer = mActiveBuffer;
- layerCompositionState.bufferSlot = 0;
return NO_ERROR;
}
@@ -580,24 +579,18 @@
return NO_ERROR;
}
-void BufferStateLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc);
- auto& hwcInfo = *outputLayer->editState().hwc;
- auto& hwcLayer = hwcInfo.hwcLayer;
+void BufferStateLayer::latchPerFrameState(
+ compositionengine::LayerFECompositionState& compositionState) const {
+ BufferLayer::latchPerFrameState(compositionState);
+ if (compositionState.compositionType == Hwc2::IComposerClient::Composition::SIDEBAND) {
+ return;
+ }
const State& s(getDrawingState());
- uint32_t hwcSlot;
- sp<GraphicBuffer> buffer;
- hwcInfo.hwcBufferCache.getHwcBuffer(mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId),
- s.buffer, &hwcSlot, &buffer);
-
- auto error = hwcLayer->setBuffer(hwcSlot, buffer, s.acquireFence);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
- s.buffer->handle, to_string(error).c_str(), static_cast<int32_t>(error));
- }
+ compositionState.buffer = s.buffer;
+ compositionState.bufferSlot = mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId);
+ compositionState.acquireFence = s.acquireFence;
mFrameNumber++;
}
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index db8ae0d..75c8552 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -136,7 +136,7 @@
status_t updateActiveBuffer() override;
status_t updateFrameNumber(nsecs_t latchTime) override;
- void setHwcLayerBuffer(const sp<const DisplayDevice>& display) override;
+ void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
private:
friend class SlotGenerationTest;
@@ -151,11 +151,11 @@
std::atomic<bool> mSidebandStreamChanged{false};
- uint32_t mFrameNumber{0};
+ mutable uint32_t mFrameNumber{0};
sp<Fence> mPreviousReleaseFence;
- bool mCurrentStateModified = false;
+ mutable bool mCurrentStateModified = false;
bool mReleasePreviousBuffer = false;
nsecs_t mCallbackHandleAcquireTime = -1;
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index fcc2d97..f15957a 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -18,6 +18,8 @@
#undef LOG_TAG
#define LOG_TAG "ColorLayer"
+#include "ColorLayer.h"
+
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
@@ -26,6 +28,7 @@
#include <compositionengine/Display.h>
#include <compositionengine/Layer.h>
#include <compositionengine/LayerCreationArgs.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/LayerCompositionState.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
@@ -34,7 +37,6 @@
#include <utils/Errors.h>
#include <utils/Log.h>
-#include "ColorLayer.h"
#include "DisplayDevice.h"
#include "SurfaceFlinger.h"
@@ -91,75 +93,12 @@
return true;
}
-void ColorLayer::setPerFrameData(const sp<const DisplayDevice>& display,
- const ui::Transform& transform, const Rect& viewport,
- int32_t /* supportedPerFrameMetadata */,
- const ui::Dataspace targetDataspace) {
- RETURN_IF_NO_HWC_LAYER(display);
+void ColorLayer::latchPerFrameState(
+ compositionengine::LayerFECompositionState& compositionState) const {
+ Layer::latchPerFrameState(compositionState);
- Region visible = transform.transform(visibleRegion.intersect(viewport));
-
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc);
-
- auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
-
- auto error = hwcLayer->setVisibleRegion(visible);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- visible.dump(LOG_TAG);
- }
- outputLayer->editState().visibleRegion = visible;
-
- setCompositionType(display, Hwc2::IComposerClient::Composition::SOLID_COLOR);
-
- const ui::Dataspace dataspace =
- isColorSpaceAgnostic() && targetDataspace != ui::Dataspace::UNKNOWN ? targetDataspace
- : mCurrentDataSpace;
- error = hwcLayer->setDataspace(dataspace);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), dataspace,
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
-
- auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
- layerCompositionState.dataspace = mCurrentDataSpace;
-
- half4 color = getColor();
- error = hwcLayer->setColor({static_cast<uint8_t>(std::round(255.0f * color.r)),
- static_cast<uint8_t>(std::round(255.0f * color.g)),
- static_cast<uint8_t>(std::round(255.0f * color.b)), 255});
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set color: %s (%d)", mName.string(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
- layerCompositionState.color = {static_cast<uint8_t>(std::round(255.0f * color.r)),
- static_cast<uint8_t>(std::round(255.0f * color.g)),
- static_cast<uint8_t>(std::round(255.0f * color.b)), 255};
-
- // Clear out the transform, because it doesn't make sense absent a source buffer
- error = hwcLayer->setTransform(HWC2::Transform::None);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to clear transform: %s (%d)", mName.string(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
- outputLayer->editState().bufferTransform = static_cast<Hwc2::Transform>(0);
-
- error = hwcLayer->setColorTransform(getColorTransform());
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to setColorTransform: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
- layerCompositionState.colorTransform = getColorTransform();
-
- error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- surfaceDamageRegion.dump(LOG_TAG);
- }
- layerCompositionState.surfaceDamage = surfaceDamageRegion;
+ compositionState.color = getColor();
+ compositionState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
}
void ColorLayer::commitTransaction(const State& stateToCommit) {
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 53d5b5b..2483ff0 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -37,10 +37,6 @@
bool setDataspace(ui::Dataspace dataspace) override;
- void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
- const Rect& viewport, int32_t supportedPerFrameMetadata,
- const ui::Dataspace targetDataspace) override;
-
void commitTransaction(const State& stateToCommit) override;
bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
@@ -52,6 +48,8 @@
renderengine::LayerSettings& layer);
private:
+ void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
+
std::shared_ptr<compositionengine::Layer> mCompositionLayer;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
index e2a0d42..d93bfa3 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
@@ -17,6 +17,7 @@
#pragma once
#include <cstdint>
+#include <string>
#include <ui/GraphicTypes.h>
@@ -75,6 +76,13 @@
// Gets the supported HDR capabilities for the profile
virtual const HdrCapabilities& getHdrCapabilities() const = 0;
+ // Returns true if HWC for this profile supports the dataspace
+ virtual bool isDataspaceSupported(ui::Dataspace) const = 0;
+
+ // Returns the target dataspace for picked color mode and dataspace
+ virtual ui::Dataspace getTargetDataspace(ui::ColorMode, ui::Dataspace,
+ ui::Dataspace colorSpaceAgnosticDataspace) const = 0;
+
// Debugging
virtual void dump(std::string&) const = 0;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index e6ee078..d96d58c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -36,9 +36,9 @@
* Used by LayerFE::getCompositionState
*/
struct LayerFECompositionState {
- // TODO(lpique): b/121291683 Remove this one we are sure we don't need the
- // value recomputed / set every frame.
- Region geomVisibleRegion;
+ // If set to true, forces client composition on all output layers until
+ // the next geometry change.
+ bool forceClientComposition{false};
/*
* Geometry state
@@ -56,6 +56,10 @@
Region geomActiveTransparentRegion;
FloatRect geomLayerBounds;
+ // TODO(lpique): b/121291683 Remove this one we are sure we don't need the
+ // value recomputed / set every frame.
+ Region geomVisibleRegion;
+
/*
* Presentation
*/
@@ -93,12 +97,16 @@
sp<NativeHandle> sidebandStream;
// The color for this layer
- Hwc2::IComposerClient::Color color;
+ half4 color;
/*
* Per-frame presentation state
*/
+ // If true, this layer will use the dataspace chosen for the output and
+ // ignore the dataspace value just below
+ bool isColorspaceAgnostic{false};
+
// The dataspace for this layer
ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
@@ -107,6 +115,7 @@
// The color transform
mat4 colorTransform;
+ bool colorTransformIsIdentity{true};
};
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 54e6bd6..591382d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -71,7 +71,8 @@
virtual void setColorTransform(const mat4&) = 0;
// Sets the output color mode
- virtual void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) = 0;
+ virtual void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent,
+ ui::Dataspace colorSpaceAgnosticDataspace) = 0;
// Outputs a string with a state dump
virtual void dump(std::string&) const = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index cd63b57..d3a4e09 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -71,7 +71,7 @@
// Writes the geometry state to the HWC, or does nothing if this layer does
// not use the HWC. If includeGeometry is false, the geometry state can be
// skipped.
- virtual void writeStateToHWC(bool includeGeometry) const = 0;
+ virtual void writeStateToHWC(bool includeGeometry) = 0;
// Debugging
virtual void dump(std::string& result) const = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 0e20c43..1265533 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -39,7 +39,7 @@
// compositionengine::Output overrides
void dump(std::string&) const override;
void setColorTransform(const mat4&) override;
- void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) override;
+ void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace) override;
// compositionengine::Display overrides
const std::optional<DisplayId>& getId() const override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h
index 49c2d2c..e84a36e 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h
@@ -54,6 +54,8 @@
bool hasDolbyVisionSupport() const override;
const HdrCapabilities& getHdrCapabilities() const override;
+ bool isDataspaceSupported(ui::Dataspace) const override;
+ ui::Dataspace getTargetDataspace(ui::ColorMode, ui::Dataspace, ui::Dataspace) const override;
void dump(std::string&) const override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index b1d1f42..f245936 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -45,7 +45,7 @@
void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override;
void setColorTransform(const mat4&) override;
- void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) override;
+ void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace) override;
void dump(std::string&) const override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index 0c47eb5..45b8308 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -88,9 +88,12 @@
// Current active render intent
ui::RenderIntent renderIntent{ui::RenderIntent::COLORIMETRIC};
- // Current active dstaspace
+ // Current active dataspace
ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
+ // Current target dataspace
+ ui::Dataspace targetDataspace{ui::Dataspace::UNKNOWN};
+
// Debugging
void dump(std::string& result) const;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index 6a4818f..708f3a1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -26,7 +26,11 @@
#include "DisplayHardware/DisplayIdentification.h"
-namespace android::compositionengine::impl {
+namespace android::compositionengine {
+
+struct LayerFECompositionState;
+
+namespace impl {
class OutputLayer : public compositionengine::OutputLayer {
public:
@@ -44,7 +48,7 @@
OutputLayerCompositionState& editState() override;
void updateCompositionState(bool) override;
- void writeStateToHWC(bool) const override;
+ void writeStateToHWC(bool) override;
void dump(std::string& result) const override;
@@ -54,6 +58,14 @@
private:
Rect calculateInitialCrop() const;
+ void writeOutputDependentGeometryStateToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition);
+ void writeOutputIndependentGeometryStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
+ void writeOutputDependentPerFrameStateToHWC(HWC2::Layer*);
+ void writeOutputIndependentPerFrameStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
+ void writeSolidColorStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
+ void writeSidebandStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
+ void writeBufferStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
+ void writeCompositionTypeToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition);
const compositionengine::Output& mOutput;
std::shared_ptr<compositionengine::Layer> mLayer;
@@ -66,4 +78,5 @@
const CompositionEngine&, std::optional<DisplayId>, const compositionengine::Output&,
std::shared_ptr<compositionengine::Layer>, sp<compositionengine::LayerFE>);
-} // namespace android::compositionengine::impl
+} // namespace impl
+} // namespace android::compositionengine
\ No newline at end of file
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index b78e9e0..de0f08a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -23,6 +23,7 @@
#include <compositionengine/impl/HwcBufferCache.h>
#include <renderengine/Mesh.h>
#include <ui/FloatRect.h>
+#include <ui/GraphicTypes.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -57,6 +58,9 @@
// The buffer transform to use for this layer o on this output.
Hwc2::Transform bufferTransform{static_cast<Hwc2::Transform>(0)};
+ // The dataspace for this layer
+ ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
+
// The Z order index of this layer on this output
uint32_t z;
@@ -70,7 +74,7 @@
// The HWC Layer backing this layer
std::shared_ptr<HWC2::Layer> hwcLayer;
- // The HWC composition type for this layer
+ // The most recently set HWC composition type for this layer
Hwc2::IComposerClient::Composition hwcCompositionType{
Hwc2::IComposerClient::Composition::INVALID};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h
index 8056c9d..1aaebea 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h
@@ -42,6 +42,9 @@
MOCK_CONST_METHOD0(hasDolbyVisionSupport, bool());
MOCK_CONST_METHOD0(getHdrCapabilities, const HdrCapabilities&());
+ MOCK_CONST_METHOD1(isDataspaceSupported, bool(ui::Dataspace));
+ MOCK_CONST_METHOD3(getTargetDataspace,
+ ui::Dataspace(ui::ColorMode, ui::Dataspace, ui::Dataspace));
MOCK_CONST_METHOD1(dump, void(std::string&));
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index d0e7b19..cf82107 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -41,17 +41,18 @@
MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool));
MOCK_METHOD1(setColorTransform, void(const mat4&));
- MOCK_METHOD3(setColorMode, void(ui::ColorMode, ui::Dataspace, ui::RenderIntent));
+ MOCK_METHOD4(setColorMode, void(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace));
MOCK_CONST_METHOD1(dump, void(std::string&));
MOCK_CONST_METHOD0(getName, const std::string&());
MOCK_METHOD1(setName, void(const std::string&));
- MOCK_CONST_METHOD0(getDisplayColorProfile, DisplayColorProfile*());
- MOCK_METHOD1(setDisplayColorProfile, void(std::unique_ptr<DisplayColorProfile>));
+ MOCK_CONST_METHOD0(getDisplayColorProfile, compositionengine::DisplayColorProfile*());
+ MOCK_METHOD1(setDisplayColorProfile,
+ void(std::unique_ptr<compositionengine::DisplayColorProfile>));
- MOCK_CONST_METHOD0(getRenderSurface, RenderSurface*());
- MOCK_METHOD1(setRenderSurface, void(std::unique_ptr<RenderSurface>));
+ MOCK_CONST_METHOD0(getRenderSurface, compositionengine::RenderSurface*());
+ MOCK_METHOD1(setRenderSurface, void(std::unique_ptr<compositionengine::RenderSurface>));
MOCK_CONST_METHOD0(getState, const OutputCompositionState&());
MOCK_METHOD0(editState, OutputCompositionState&());
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
index 29cd08a..dab8b9d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -39,7 +39,7 @@
MOCK_METHOD0(editState, impl::OutputLayerCompositionState&());
MOCK_METHOD1(updateCompositionState, void(bool));
- MOCK_CONST_METHOD1(writeStateToHWC, void(bool));
+ MOCK_METHOD1(writeStateToHWC, void(bool));
MOCK_CONST_METHOD1(dump, void(std::string&));
};
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index f9d70e3..8520d70 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -74,9 +74,14 @@
}
void Display::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace,
- ui::RenderIntent renderIntent) {
+ ui::RenderIntent renderIntent,
+ ui::Dataspace colorSpaceAgnosticDataspace) {
+ ui::Dataspace targetDataspace =
+ getDisplayColorProfile()->getTargetDataspace(mode, dataspace,
+ colorSpaceAgnosticDataspace);
+
if (mode == getState().colorMode && dataspace == getState().dataspace &&
- renderIntent == getState().renderIntent) {
+ renderIntent == getState().renderIntent && targetDataspace == getState().targetDataspace) {
return;
}
@@ -85,7 +90,7 @@
return;
}
- Output::setColorMode(mode, dataspace, renderIntent);
+ Output::setColorMode(mode, dataspace, renderIntent, colorSpaceAgnosticDataspace);
auto& hwc = getCompositionEngine().getHwComposer();
hwc.setActiveColorMode(*mId, mode, renderIntent);
diff --git a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
index 130ab1d..5ef9097 100644
--- a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
@@ -64,6 +64,12 @@
RenderIntent::TONE_MAP_COLORIMETRIC,
};
+// Returns true if the given colorMode is considered an HDR color mode
+bool isHdrColorMode(const ColorMode colorMode) {
+ return std::any_of(std::begin(sHdrColorModes), std::end(sHdrColorModes),
+ [colorMode](ColorMode hdrColorMode) { return hdrColorMode == colorMode; });
+}
+
// map known color mode to dataspace
Dataspace colorModeToDataspace(ColorMode mode) {
switch (mode) {
@@ -90,13 +96,7 @@
candidates.push_back(mode);
// check if mode is HDR
- bool isHdr = false;
- for (auto hdrMode : sHdrColorModes) {
- if (hdrMode == mode) {
- isHdr = true;
- break;
- }
- }
+ bool isHdr = isHdrColorMode(mode);
// add other HDR candidates when mode is HDR
if (isHdr) {
@@ -376,6 +376,32 @@
}
}
+bool DisplayColorProfile::isDataspaceSupported(Dataspace dataspace) const {
+ switch (dataspace) {
+ case Dataspace::BT2020_PQ:
+ case Dataspace::BT2020_ITU_PQ:
+ return hasHDR10Support();
+
+ case Dataspace::BT2020_HLG:
+ case Dataspace::BT2020_ITU_HLG:
+ return hasHLGSupport();
+
+ default:
+ return true;
+ }
+}
+
+ui::Dataspace DisplayColorProfile::getTargetDataspace(ColorMode mode, Dataspace dataspace,
+ Dataspace colorSpaceAgnosticDataspace) const {
+ if (isHdrColorMode(mode)) {
+ return Dataspace::UNKNOWN;
+ }
+ if (colorSpaceAgnosticDataspace != ui::Dataspace::UNKNOWN) {
+ return colorSpaceAgnosticDataspace;
+ }
+ return dataspace;
+}
+
void DisplayColorProfile::dump(std::string& out) const {
out.append(" Composition Display Color State:");
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
index 40c4da9..37d6eaa 100644
--- a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
@@ -24,9 +24,10 @@
using android::compositionengine::impl::dumpVal;
-void dumpVal(std::string& out, const char* name, Hwc2::IComposerClient::Color value) {
+void dumpVal(std::string& out, const char* name, half4 value) {
using android::base::StringAppendF;
- StringAppendF(&out, "%s=[%d %d %d] ", name, value.r, value.g, value.b);
+ StringAppendF(&out, "%s=[%f %f %f] ", name, static_cast<float>(value.r),
+ static_cast<float>(value.g), static_cast<float>(value.b));
}
void dumpFrontEnd(std::string& out, const LayerFECompositionState& state) {
@@ -60,8 +61,8 @@
dumpVal(out, "composition type", toString(state.compositionType), state.compositionType);
out.append("\n buffer: ");
+ dumpVal(out, "bufferSlot", state.bufferSlot);
dumpVal(out, "buffer", state.buffer.get());
- dumpVal(out, "slot", state.bufferSlot);
out.append("\n ");
dumpVal(out, "sideband stream", state.sidebandStream.get());
@@ -70,6 +71,7 @@
dumpVal(out, "color", state.color);
out.append("\n ");
+ dumpVal(out, "isColorspaceAgnostic", state.isColorspaceAgnostic);
dumpVal(out, "dataspace", toString(state.dataspace), state.dataspace);
dumpVal(out, "hdr metadata types", state.hdrMetadata.validTypes);
dumpVal(out, "colorTransform", state.colorTransform);
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 01b5781..0725926 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -104,15 +104,21 @@
}
void Output::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace,
- ui::RenderIntent renderIntent) {
+ ui::RenderIntent renderIntent,
+ ui::Dataspace colorSpaceAgnosticDataspace) {
+ ui::Dataspace targetDataspace =
+ getDisplayColorProfile()->getTargetDataspace(mode, dataspace,
+ colorSpaceAgnosticDataspace);
+
if (mState.colorMode == mode && mState.dataspace == dataspace &&
- mState.renderIntent == renderIntent) {
+ mState.renderIntent == renderIntent && mState.targetDataspace == targetDataspace) {
return;
}
mState.colorMode = mode;
mState.dataspace = dataspace;
mState.renderIntent = renderIntent;
+ mState.targetDataspace = targetDataspace;
mRenderSurface->setBufferDataspace(dataspace);
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index 9549054..0b15dad 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -44,6 +44,7 @@
dumpVal(out, "renderIntent", toString(renderIntent), renderIntent);
dumpVal(out, "dataspace", toString(dataspace), dataspace);
dumpVal(out, "colorTransform", colorTransform);
+ dumpVal(out, "target dataspace", toString(targetDataspace), targetDataspace);
out.append("\n");
}
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 5ce72b0..ebfc704 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -16,6 +16,7 @@
#include <android-base/stringprintf.h>
#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/DisplayColorProfile.h>
#include <compositionengine/Layer.h>
#include <compositionengine/LayerFE.h>
#include <compositionengine/Output.h>
@@ -290,20 +291,43 @@
} // namespace impl
void OutputLayer::updateCompositionState(bool includeGeometry) {
+ const auto& layerFEState = mLayer->getState().frontEnd;
+ const auto& outputState = mOutput.getState();
+ const auto& profile = *mOutput.getDisplayColorProfile();
+
if (includeGeometry) {
mState.displayFrame = calculateOutputDisplayFrame();
mState.sourceCrop = calculateOutputSourceCrop();
mState.bufferTransform =
static_cast<Hwc2::Transform>(calculateOutputRelativeBufferTransform());
- if ((mLayer->getState().frontEnd.isSecure && !mOutput.getState().isSecure) ||
+ if ((layerFEState.isSecure && !outputState.isSecure) ||
(mState.bufferTransform & ui::Transform::ROT_INVALID)) {
mState.forceClientComposition = true;
}
}
+
+ // Determine the output dependent dataspace for this layer. If it is
+ // colorspace agnostic, it just uses the dataspace chosen for the output to
+ // avoid the need for color conversion.
+ mState.dataspace = layerFEState.isColorspaceAgnostic &&
+ outputState.targetDataspace != ui::Dataspace::UNKNOWN
+ ? outputState.targetDataspace
+ : layerFEState.dataspace;
+
+ // TODO(lpique): b/121291683 Remove this one we are sure we don't need the
+ // value recomputed / set every frame.
+ mState.visibleRegion = outputState.transform.transform(
+ layerFEState.geomVisibleRegion.intersect(outputState.viewport));
+
+ // These are evaluated every frame as they can potentially change at any
+ // time.
+ if (layerFEState.forceClientComposition || !profile.isDataspaceSupported(mState.dataspace)) {
+ mState.forceClientComposition = true;
+ }
}
-void OutputLayer::writeStateToHWC(bool includeGeometry) const {
+void OutputLayer::writeStateToHWC(bool includeGeometry) {
// Skip doing this if there is no HWC interface
if (!mState.hwc) {
return;
@@ -316,63 +340,213 @@
return;
}
+ const auto& outputIndependentState = mLayer->getState().frontEnd;
+ auto requestedCompositionType = outputIndependentState.compositionType;
+
if (includeGeometry) {
- // Output dependent state
+ writeOutputDependentGeometryStateToHWC(hwcLayer.get(), requestedCompositionType);
+ writeOutputIndependentGeometryStateToHWC(hwcLayer.get(), outputIndependentState);
+ }
- if (auto error = hwcLayer->setDisplayFrame(mState.displayFrame);
- error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)",
- mLayerFE->getDebugName(), mState.displayFrame.left, mState.displayFrame.top,
- mState.displayFrame.right, mState.displayFrame.bottom, to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
+ writeOutputDependentPerFrameStateToHWC(hwcLayer.get());
+ writeOutputIndependentPerFrameStateToHWC(hwcLayer.get(), outputIndependentState);
- if (auto error = hwcLayer->setSourceCrop(mState.sourceCrop); error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: "
- "%s (%d)",
- mLayerFE->getDebugName(), mState.sourceCrop.left, mState.sourceCrop.top,
- mState.sourceCrop.right, mState.sourceCrop.bottom, to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
+ writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType);
+}
- if (auto error = hwcLayer->setZOrder(mState.z); error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set Z %u: %s (%d)", mLayerFE->getDebugName(), mState.z,
+void OutputLayer::writeOutputDependentGeometryStateToHWC(
+ HWC2::Layer* hwcLayer, Hwc2::IComposerClient::Composition requestedCompositionType) {
+ const auto& outputDependentState = getState();
+
+ if (auto error = hwcLayer->setDisplayFrame(outputDependentState.displayFrame);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)",
+ mLayerFE->getDebugName(), outputDependentState.displayFrame.left,
+ outputDependentState.displayFrame.top, outputDependentState.displayFrame.right,
+ outputDependentState.displayFrame.bottom, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+
+ if (auto error = hwcLayer->setSourceCrop(outputDependentState.sourceCrop);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: "
+ "%s (%d)",
+ mLayerFE->getDebugName(), outputDependentState.sourceCrop.left,
+ outputDependentState.sourceCrop.top, outputDependentState.sourceCrop.right,
+ outputDependentState.sourceCrop.bottom, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+
+ if (auto error = hwcLayer->setZOrder(outputDependentState.z); error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set Z %u: %s (%d)", mLayerFE->getDebugName(), outputDependentState.z,
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+
+ // Solid-color layers should always use an identity transform.
+ const auto bufferTransform =
+ requestedCompositionType != Hwc2::IComposerClient::Composition::SOLID_COLOR
+ ? outputDependentState.bufferTransform
+ : static_cast<Hwc2::Transform>(0);
+ if (auto error = hwcLayer->setTransform(static_cast<HWC2::Transform>(bufferTransform));
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set transform %s: %s (%d)", mLayerFE->getDebugName(),
+ toString(outputDependentState.bufferTransform).c_str(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeOutputIndependentGeometryStateToHWC(
+ HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState) {
+ if (auto error = hwcLayer->setBlendMode(
+ static_cast<HWC2::BlendMode>(outputIndependentState.blendMode));
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set blend mode %s: %s (%d)", mLayerFE->getDebugName(),
+ toString(outputIndependentState.blendMode).c_str(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+
+ if (auto error = hwcLayer->setPlaneAlpha(outputIndependentState.alpha);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set plane alpha %.3f: %s (%d)", mLayerFE->getDebugName(),
+ outputIndependentState.alpha, to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+
+ if (auto error = hwcLayer->setInfo(outputIndependentState.type, outputIndependentState.appId);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set info %s (%d)", mLayerFE->getDebugName(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeOutputDependentPerFrameStateToHWC(HWC2::Layer* hwcLayer) {
+ const auto& outputDependentState = getState();
+
+ // TODO(lpique): b/121291683 visibleRegion is output-dependent geometry
+ // state and should not change every frame.
+ if (auto error = hwcLayer->setVisibleRegion(outputDependentState.visibleRegion);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set visible region: %s (%d)", mLayerFE->getDebugName(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ outputDependentState.visibleRegion.dump(LOG_TAG);
+ }
+
+ if (auto error = hwcLayer->setDataspace(outputDependentState.dataspace);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mLayerFE->getDebugName(),
+ outputDependentState.dataspace, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeOutputIndependentPerFrameStateToHWC(
+ HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState) {
+ switch (auto error = hwcLayer->setColorTransform(outputIndependentState.colorTransform)) {
+ case HWC2::Error::None:
+ break;
+ case HWC2::Error::Unsupported:
+ editState().forceClientComposition = true;
+ break;
+ default:
+ ALOGE("[%s] Failed to set color transform: %s (%d)", mLayerFE->getDebugName(),
to_string(error).c_str(), static_cast<int32_t>(error));
- }
+ }
- if (auto error =
- hwcLayer->setTransform(static_cast<HWC2::Transform>(mState.bufferTransform));
+ if (auto error = hwcLayer->setSurfaceDamage(outputIndependentState.surfaceDamage);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set surface damage: %s (%d)", mLayerFE->getDebugName(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ outputIndependentState.surfaceDamage.dump(LOG_TAG);
+ }
+
+ // Content-specific per-frame state
+ switch (outputIndependentState.compositionType) {
+ case Hwc2::IComposerClient::Composition::SOLID_COLOR:
+ writeSolidColorStateToHWC(hwcLayer, outputIndependentState);
+ break;
+ case Hwc2::IComposerClient::Composition::SIDEBAND:
+ writeSidebandStateToHWC(hwcLayer, outputIndependentState);
+ break;
+ case Hwc2::IComposerClient::Composition::CURSOR:
+ case Hwc2::IComposerClient::Composition::DEVICE:
+ writeBufferStateToHWC(hwcLayer, outputIndependentState);
+ break;
+ case Hwc2::IComposerClient::Composition::INVALID:
+ case Hwc2::IComposerClient::Composition::CLIENT:
+ // Ignored
+ break;
+ }
+}
+
+void OutputLayer::writeSolidColorStateToHWC(HWC2::Layer* hwcLayer,
+ const LayerFECompositionState& outputIndependentState) {
+ hwc_color_t color = {static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.r)),
+ static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.g)),
+ static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.b)),
+ 255};
+
+ if (auto error = hwcLayer->setColor(color); error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set color: %s (%d)", mLayerFE->getDebugName(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeSidebandStateToHWC(HWC2::Layer* hwcLayer,
+ const LayerFECompositionState& outputIndependentState) {
+ if (auto error = hwcLayer->setSidebandStream(outputIndependentState.sidebandStream->handle());
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", mLayerFE->getDebugName(),
+ outputIndependentState.sidebandStream->handle(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeBufferStateToHWC(HWC2::Layer* hwcLayer,
+ const LayerFECompositionState& outputIndependentState) {
+ auto supportedPerFrameMetadata =
+ mOutput.getDisplayColorProfile()->getSupportedPerFrameMetadata();
+ if (auto error = hwcLayer->setPerFrameMetadata(supportedPerFrameMetadata,
+ outputIndependentState.hdrMetadata);
+ error != HWC2::Error::None && error != HWC2::Error::Unsupported) {
+ ALOGE("[%s] Failed to set hdrMetadata: %s (%d)", mLayerFE->getDebugName(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+
+ uint32_t hwcSlot = 0;
+ sp<GraphicBuffer> hwcBuffer;
+ // We need access to the output-dependent state for the buffer cache there,
+ // though otherwise the buffer is not output-dependent.
+ editState().hwc->hwcBufferCache.getHwcBuffer(outputIndependentState.bufferSlot,
+ outputIndependentState.buffer, &hwcSlot,
+ &hwcBuffer);
+
+ if (auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, outputIndependentState.acquireFence);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set buffer %p: %s (%d)", mLayerFE->getDebugName(),
+ outputIndependentState.buffer->handle, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeCompositionTypeToHWC(
+ HWC2::Layer* hwcLayer, Hwc2::IComposerClient::Composition requestedCompositionType) {
+ auto& outputDependentState = editState();
+
+ // If we are forcing client composition, we need to tell the HWC
+ if (outputDependentState.forceClientComposition) {
+ requestedCompositionType = Hwc2::IComposerClient::Composition::CLIENT;
+ }
+
+ // Set the requested composition type with the HWC whenever it changes
+ if (outputDependentState.hwc->hwcCompositionType != requestedCompositionType) {
+ outputDependentState.hwc->hwcCompositionType = requestedCompositionType;
+
+ if (auto error = hwcLayer->setCompositionType(
+ static_cast<HWC2::Composition>(requestedCompositionType));
error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set transform %s: %s (%d)", mLayerFE->getDebugName(),
- toString(mState.bufferTransform).c_str(), to_string(error).c_str(),
+ ALOGE("[%s] Failed to set composition type %s: %s (%d)", mLayerFE->getDebugName(),
+ toString(requestedCompositionType).c_str(), to_string(error).c_str(),
static_cast<int32_t>(error));
}
-
- // Output independent state
-
- const auto& outputIndependentState = mLayer->getState().frontEnd;
-
- if (auto error = hwcLayer->setBlendMode(
- static_cast<HWC2::BlendMode>(outputIndependentState.blendMode));
- error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set blend mode %s: %s (%d)", mLayerFE->getDebugName(),
- toString(outputIndependentState.blendMode).c_str(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
-
- if (auto error = hwcLayer->setPlaneAlpha(outputIndependentState.alpha);
- error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set plane alpha %.3f: %s (%d)", mLayerFE->getDebugName(),
- outputIndependentState.alpha, to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
-
- if (auto error =
- hwcLayer->setInfo(outputIndependentState.type, outputIndependentState.appId);
- error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set info %s (%d)", mLayerFE->getDebugName(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
}
}
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
index 861ea57..e320bee 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
@@ -47,6 +47,7 @@
dumpVal(out, "displayFrame", displayFrame);
dumpVal(out, "sourceCrop", sourceCrop);
dumpVal(out, "bufferTransform", toString(bufferTransform), bufferTransform);
+ dumpVal(out, "dataspace", toString(dataspace), dataspace);
dumpVal(out, "z-index", z);
if (hwc) {
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
index 9215884..c07dfbb 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
@@ -638,5 +638,66 @@
checkGetBestColorMode(profile, expectedResults);
}
+/*
+ * RenderSurface::isDataspaceSupported()
+ */
+
+TEST_F(DisplayColorProfileTest, isDataspaceSupportedWorksForProfileWithNoHdrSupport) {
+ auto profile = ProfileFactory::createProfileWithNoColorModeSupport();
+
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::UNKNOWN));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::V0_SRGB));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_PQ));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_PQ));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_HLG));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_HLG));
+}
+
+TEST_F(DisplayColorProfileTest, isDataspaceSupportedWorksForProfileWithHdr10Support) {
+ auto profile = ProfileFactory::createProfileWithSRGBColorModeSupport();
+
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::UNKNOWN));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::V0_SRGB));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::BT2020_PQ));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_PQ));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_HLG));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_HLG));
+}
+
+TEST_F(DisplayColorProfileTest, isDataspaceSupportedWorksForProfileWithHlgSupport) {
+ auto profile = ProfileFactory::createProfileWithBT2100PQSupport();
+
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::UNKNOWN));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::V0_SRGB));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_PQ));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_PQ));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::BT2020_HLG));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_HLG));
+}
+
+/*
+ * RenderSurface::getTargetDataspace()
+ */
+
+TEST_F(DisplayColorProfileTest, getTargetDataspaceWorks) {
+ auto profile = ProfileFactory::createProfileWithNoColorModeSupport();
+
+ // For a non-HDR colorspace with no colorSpaceAgnosticDataspace override,
+ // the input dataspace should be returned.
+ EXPECT_EQ(Dataspace::DISPLAY_P3,
+ profile.getTargetDataspace(ColorMode::DISPLAY_P3, Dataspace::DISPLAY_P3,
+ Dataspace::UNKNOWN));
+
+ // If colorSpaceAgnosticDataspace is set, its value should be returned
+ EXPECT_EQ(Dataspace::V0_SRGB,
+ profile.getTargetDataspace(ColorMode::DISPLAY_P3, Dataspace::DISPLAY_P3,
+ Dataspace::V0_SRGB));
+
+ // For an HDR colorspace, Dataspace::UNKNOWN should be returned.
+ EXPECT_EQ(Dataspace::UNKNOWN,
+ profile.getTargetDataspace(ColorMode::BT2100_PQ, Dataspace::BT2020_PQ,
+ Dataspace::UNKNOWN));
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 33444a5..f0aea25 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -22,6 +22,7 @@
#include <compositionengine/RenderSurfaceCreationArgs.h>
#include <compositionengine/impl/Display.h>
#include <compositionengine/mock/CompositionEngine.h>
+#include <compositionengine/mock/DisplayColorProfile.h>
#include <compositionengine/mock/NativeWindow.h>
#include <compositionengine/mock/RenderSurface.h>
#include <gtest/gtest.h>
@@ -31,6 +32,7 @@
namespace android::compositionengine {
namespace {
+using testing::_;
using testing::Return;
using testing::ReturnRef;
using testing::StrictMock;
@@ -140,21 +142,27 @@
TEST_F(DisplayTest, setColorModeSetsModeUnlessNoChange) {
mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
mDisplay.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+ mock::DisplayColorProfile* colorProfile = new StrictMock<mock::DisplayColorProfile>();
+ mDisplay.setDisplayColorProfileForTest(std::unique_ptr<DisplayColorProfile>(colorProfile));
EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+ EXPECT_CALL(*colorProfile, getTargetDataspace(_, _, _))
+ .WillRepeatedly(Return(ui::Dataspace::UNKNOWN));
// These values are expected to be the initial state.
ASSERT_EQ(ui::ColorMode::NATIVE, mDisplay.getState().colorMode);
ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().dataspace);
ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay.getState().renderIntent);
+ ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace);
- // Otherwise if the values are unchanged, nothing happens
+ // If the set values are unchanged, nothing happens
mDisplay.setColorMode(ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN,
- ui::RenderIntent::COLORIMETRIC);
+ ui::RenderIntent::COLORIMETRIC, ui::Dataspace::UNKNOWN);
EXPECT_EQ(ui::ColorMode::NATIVE, mDisplay.getState().colorMode);
EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().dataspace);
EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay.getState().renderIntent);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace);
// Otherwise if the values are different, updates happen
EXPECT_CALL(*renderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1);
@@ -164,23 +172,34 @@
.Times(1);
mDisplay.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
- ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN);
EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mDisplay.getState().colorMode);
EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mDisplay.getState().dataspace);
EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mDisplay.getState().renderIntent);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace);
}
TEST_F(DisplayTest, setColorModeDoesNothingForVirtualDisplay) {
impl::Display virtualDisplay{mCompositionEngine,
DisplayCreationArgs{false, true, DEFAULT_DISPLAY_ID}};
+ mock::DisplayColorProfile* colorProfile = new StrictMock<mock::DisplayColorProfile>();
+ virtualDisplay.setDisplayColorProfileForTest(
+ std::unique_ptr<DisplayColorProfile>(colorProfile));
+
+ EXPECT_CALL(*colorProfile,
+ getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
+ ui::Dataspace::UNKNOWN))
+ .WillOnce(Return(ui::Dataspace::UNKNOWN));
+
virtualDisplay.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
- ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN);
EXPECT_EQ(ui::ColorMode::NATIVE, virtualDisplay.getState().colorMode);
EXPECT_EQ(ui::Dataspace::UNKNOWN, virtualDisplay.getState().dataspace);
EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, virtualDisplay.getState().renderIntent);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace);
}
/* ------------------------------------------------------------------------
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index ae906cd..7b9528b 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -16,6 +16,7 @@
#include <compositionengine/impl/OutputLayer.h>
#include <compositionengine/mock/CompositionEngine.h>
+#include <compositionengine/mock/DisplayColorProfile.h>
#include <compositionengine/mock/Layer.h>
#include <compositionengine/mock/LayerFE.h>
#include <compositionengine/mock/Output.h>
@@ -25,6 +26,7 @@
#include "MockHWC2.h"
#include "MockHWComposer.h"
#include "RectMatcher.h"
+#include "RegionMatcher.h"
namespace android::compositionengine {
namespace {
@@ -45,6 +47,15 @@
const std::string kOutputName{"Test Output"};
+MATCHER_P(ColorEq, expected, "") {
+ *result_listener << "Colors are not equal\n";
+ *result_listener << "expected " << expected.r << " " << expected.g << " " << expected.b << " "
+ << expected.a << "\n";
+ *result_listener << "actual " << arg.r << " " << arg.g << " " << arg.b << " " << arg.a << "\n";
+
+ return expected.r == arg.r && expected.g == arg.g && expected.b == arg.b && expected.a == arg.a;
+}
+
class OutputLayerTest : public testing::Test {
public:
OutputLayerTest() {
@@ -429,6 +440,9 @@
OutputLayerUpdateCompositionStateTest() {
EXPECT_CALL(*mLayer, getState()).WillRepeatedly(ReturnRef(mLayerState));
EXPECT_CALL(mOutput, getState()).WillRepeatedly(ReturnRef(mOutputState));
+ EXPECT_CALL(mOutput, getDisplayColorProfile())
+ .WillRepeatedly(Return(&mDisplayColorProfile));
+ EXPECT_CALL(mDisplayColorProfile, isDataspaceSupported(_)).WillRepeatedly(Return(true));
}
~OutputLayerUpdateCompositionStateTest() = default;
@@ -453,6 +467,7 @@
using OutputLayer = OutputLayerPartialMockForUpdateCompositionState;
StrictMock<OutputLayer> mOutputLayer{mOutput, mLayer, mLayerFE};
+ StrictMock<mock::DisplayColorProfile> mDisplayColorProfile;
};
TEST_F(OutputLayerUpdateCompositionStateTest, setsStateNormally) {
@@ -498,12 +513,50 @@
EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
}
+TEST_F(OutputLayerUpdateCompositionStateTest, setsOutputLayerColorspaceCorrectly) {
+ mLayerState.frontEnd.dataspace = ui::Dataspace::DISPLAY_P3;
+ mOutputState.targetDataspace = ui::Dataspace::V0_SCRGB;
+
+ // If the layer is not colorspace agnostic, the output layer dataspace
+ // should use the layers requested colorspace.
+ mLayerState.frontEnd.isColorspaceAgnostic = false;
+
+ mOutputLayer.updateCompositionState(false);
+
+ EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutputLayer.getState().dataspace);
+
+ // If the layer is colorspace agnostic, the output layer dataspace
+ // should use the colorspace chosen for the whole output.
+ mLayerState.frontEnd.isColorspaceAgnostic = true;
+
+ mOutputLayer.updateCompositionState(false);
+
+ EXPECT_EQ(ui::Dataspace::V0_SCRGB, mOutputLayer.getState().dataspace);
+}
+
TEST_F(OutputLayerUpdateCompositionStateTest, doesNotRecomputeGeometryIfNotRequested) {
mOutputLayer.updateCompositionState(false);
EXPECT_EQ(false, mOutputLayer.getState().forceClientComposition);
}
+TEST_F(OutputLayerUpdateCompositionStateTest, clientCompositionForcedFromFrontEndFlagAtAnyTime) {
+ mLayerState.frontEnd.forceClientComposition = true;
+
+ mOutputLayer.updateCompositionState(false);
+
+ EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
+}
+
+TEST_F(OutputLayerUpdateCompositionStateTest,
+ clientCompositionForcedFromUnsupportedDataspaceAtAnyTime) {
+ EXPECT_CALL(mDisplayColorProfile, isDataspaceSupported(_)).WillRepeatedly(Return(false));
+
+ mOutputLayer.updateCompositionState(false);
+
+ EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
+}
+
/*
* OutputLayer::writeStateToHWC()
*/
@@ -518,8 +571,19 @@
static constexpr float kAlpha = 51.f;
static constexpr uint32_t kType = 61u;
static constexpr uint32_t kAppId = 62u;
+ static constexpr ui::Dataspace kDataspace = static_cast<ui::Dataspace>(71);
+ static constexpr int kSupportedPerFrameMetadata = 101;
+ static constexpr int kExpectedHwcSlot = 0;
+ static const half4 kColor;
static const Rect kDisplayFrame;
+ static const Region kVisibleRegion;
+ static const mat4 kColorTransform;
+ static const Region kSurfaceDamage;
+ static const HdrMetadata kHdrMetadata;
+ static native_handle_t* kSidebandStreamHandle;
+ static const sp<GraphicBuffer> kBuffer;
+ static const sp<Fence> kFence;
OutputLayerWriteStateToHWCTest() {
auto& outputLayerState = mOutputLayer.editState();
@@ -529,13 +593,31 @@
outputLayerState.sourceCrop = kSourceCrop;
outputLayerState.z = kZOrder;
outputLayerState.bufferTransform = static_cast<Hwc2::Transform>(kBufferTransform);
+ outputLayerState.visibleRegion = kVisibleRegion;
+ outputLayerState.dataspace = kDataspace;
mLayerState.frontEnd.blendMode = kBlendMode;
mLayerState.frontEnd.alpha = kAlpha;
mLayerState.frontEnd.type = kType;
mLayerState.frontEnd.appId = kAppId;
+ mLayerState.frontEnd.colorTransform = kColorTransform;
+ mLayerState.frontEnd.color = kColor;
+ mLayerState.frontEnd.surfaceDamage = kSurfaceDamage;
+ mLayerState.frontEnd.hdrMetadata = kHdrMetadata;
+ mLayerState.frontEnd.sidebandStream = NativeHandle::create(kSidebandStreamHandle, false);
+ mLayerState.frontEnd.buffer = kBuffer;
+ mLayerState.frontEnd.bufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
+ mLayerState.frontEnd.acquireFence = kFence;
+
+ EXPECT_CALL(mOutput, getDisplayColorProfile())
+ .WillRepeatedly(Return(&mDisplayColorProfile));
+ EXPECT_CALL(mDisplayColorProfile, getSupportedPerFrameMetadata())
+ .WillRepeatedly(Return(kSupportedPerFrameMetadata));
}
+ // Some tests may need to simulate unsupported HWC calls
+ enum class SimulateUnsupported { None, ColorTransform };
+
void expectGeometryCommonCalls() {
EXPECT_CALL(*mHwcLayer, setDisplayFrame(kDisplayFrame)).WillOnce(Return(kError));
EXPECT_CALL(*mHwcLayer, setSourceCrop(kSourceCrop)).WillOnce(Return(kError));
@@ -549,10 +631,62 @@
EXPECT_CALL(*mHwcLayer, setInfo(kType, kAppId)).WillOnce(Return(kError));
}
+ void expectPerFrameCommonCalls(SimulateUnsupported unsupported = SimulateUnsupported::None) {
+ EXPECT_CALL(*mHwcLayer, setVisibleRegion(RegionEq(kVisibleRegion)))
+ .WillOnce(Return(kError));
+ EXPECT_CALL(*mHwcLayer, setDataspace(kDataspace)).WillOnce(Return(kError));
+ EXPECT_CALL(*mHwcLayer, setColorTransform(kColorTransform))
+ .WillOnce(Return(unsupported == SimulateUnsupported::ColorTransform
+ ? HWC2::Error::Unsupported
+ : HWC2::Error::None));
+ EXPECT_CALL(*mHwcLayer, setSurfaceDamage(RegionEq(kSurfaceDamage)))
+ .WillOnce(Return(kError));
+ }
+
+ void expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition compositionType) {
+ EXPECT_CALL(*mHwcLayer, setCompositionType(static_cast<HWC2::Composition>(compositionType)))
+ .WillOnce(Return(kError));
+ }
+
+ void expectNoSetCompositionTypeCall() {
+ EXPECT_CALL(*mHwcLayer, setCompositionType(_)).Times(0);
+ }
+
+ void expectSetColorCall() {
+ hwc_color_t color = {static_cast<uint8_t>(std::round(kColor.r * 255)),
+ static_cast<uint8_t>(std::round(kColor.g * 255)),
+ static_cast<uint8_t>(std::round(kColor.b * 255)), 255};
+
+ EXPECT_CALL(*mHwcLayer, setColor(ColorEq(color))).WillOnce(Return(kError));
+ }
+
+ void expectSetSidebandHandleCall() {
+ EXPECT_CALL(*mHwcLayer, setSidebandStream(kSidebandStreamHandle));
+ }
+
+ void expectSetHdrMetadataAndBufferCalls() {
+ EXPECT_CALL(*mHwcLayer, setPerFrameMetadata(kSupportedPerFrameMetadata, kHdrMetadata));
+ EXPECT_CALL(*mHwcLayer, setBuffer(kExpectedHwcSlot, kBuffer, kFence));
+ }
+
std::shared_ptr<HWC2::mock::Layer> mHwcLayer{std::make_shared<StrictMock<HWC2::mock::Layer>>()};
+ StrictMock<mock::DisplayColorProfile> mDisplayColorProfile;
};
+const half4 OutputLayerWriteStateToHWCTest::kColor{81.f / 255.f, 82.f / 255.f, 83.f / 255.f,
+ 84.f / 255.f};
const Rect OutputLayerWriteStateToHWCTest::kDisplayFrame{1001, 1002, 1003, 10044};
+const Region OutputLayerWriteStateToHWCTest::kVisibleRegion{Rect{1005, 1006, 1007, 1008}};
+const mat4 OutputLayerWriteStateToHWCTest::kColorTransform{
+ 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016,
+ 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024,
+};
+const Region OutputLayerWriteStateToHWCTest::kSurfaceDamage{Rect{1025, 1026, 1027, 1028}};
+const HdrMetadata OutputLayerWriteStateToHWCTest::kHdrMetadata{{/* LightFlattenable */}, 1029};
+native_handle_t* OutputLayerWriteStateToHWCTest::kSidebandStreamHandle =
+ reinterpret_cast<native_handle_t*>(1031);
+const sp<GraphicBuffer> OutputLayerWriteStateToHWCTest::kBuffer;
+const sp<Fence> OutputLayerWriteStateToHWCTest::kFence;
TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoHWCState) {
mOutputLayer.editState().hwc.reset();
@@ -566,11 +700,89 @@
mOutputLayer.writeStateToHWC(true);
}
-TEST_F(OutputLayerWriteStateToHWCTest, canSetsAllState) {
+TEST_F(OutputLayerWriteStateToHWCTest, canSetAllState) {
expectGeometryCommonCalls();
+ expectPerFrameCommonCalls();
+
+ expectNoSetCompositionTypeCall();
mOutputLayer.writeStateToHWC(true);
}
+TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSolidColor) {
+ mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
+
+ expectPerFrameCommonCalls();
+ expectSetColorCall();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::SOLID_COLOR);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSideband) {
+ mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::SIDEBAND;
+
+ expectPerFrameCommonCalls();
+ expectSetSidebandHandleCall();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::SIDEBAND);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForCursor) {
+ mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::CURSOR;
+
+ expectPerFrameCommonCalls();
+ expectSetHdrMetadataAndBufferCalls();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CURSOR);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForDevice) {
+ mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::DEVICE;
+
+ expectPerFrameCommonCalls();
+ expectSetHdrMetadataAndBufferCalls();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsNotSetIfUnchanged) {
+ (*mOutputLayer.editState().hwc).hwcCompositionType =
+ Hwc2::IComposerClient::Composition::SOLID_COLOR;
+
+ mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
+
+ expectPerFrameCommonCalls();
+ expectSetColorCall();
+ expectNoSetCompositionTypeCall();
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfColorTransformNotSupported) {
+ mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
+
+ expectPerFrameCommonCalls(SimulateUnsupported::ColorTransform);
+ expectSetColorCall();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CLIENT);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfClientCompositionForced) {
+ mOutputLayer.editState().forceClientComposition = true;
+
+ mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
+
+ expectPerFrameCommonCalls();
+ expectSetColorCall();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CLIENT);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index fee0c11..6f087d9 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -205,24 +205,36 @@
*/
TEST_F(OutputTest, setColorModeSetsStateAndDirtiesOutputIfChanged) {
+ EXPECT_CALL(*mDisplayColorProfile,
+ getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
+ ui::Dataspace::UNKNOWN))
+ .WillOnce(Return(ui::Dataspace::UNKNOWN));
EXPECT_CALL(*mRenderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1);
mOutput.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
- ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN);
EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mOutput.getState().colorMode);
EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutput.getState().dataspace);
EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mOutput.getState().renderIntent);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, mOutput.getState().targetDataspace);
+
EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
}
TEST_F(OutputTest, setColorModeDoesNothingIfNoChange) {
+ EXPECT_CALL(*mDisplayColorProfile,
+ getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
+ ui::Dataspace::UNKNOWN))
+ .WillOnce(Return(ui::Dataspace::UNKNOWN));
+
mOutput.editState().colorMode = ui::ColorMode::DISPLAY_P3;
mOutput.editState().dataspace = ui::Dataspace::DISPLAY_P3;
mOutput.editState().renderIntent = ui::RenderIntent::TONE_MAP_COLORIMETRIC;
+ mOutput.editState().targetDataspace = ui::Dataspace::UNKNOWN;
mOutput.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
- ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN);
EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
}
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 7927fa9..3a5f3fa 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -39,7 +39,4 @@
return !isHiddenByPolicy();
}
-void ContainerLayer::setPerFrameData(const sp<const DisplayDevice>&, const ui::Transform&,
- const Rect&, int32_t, const ui::Dataspace) {}
-
} // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index 7222a3e..57267c7 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -33,10 +33,6 @@
bool canReceiveInput() const override;
- void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
- const Rect& viewport, int32_t supportedPerFrameMetadata,
- const ui::Dataspace targetDataspace) override;
-
bool isCreatedFromMainThread() const override { return true; }
bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 414c8dd..c3da653 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -242,20 +242,6 @@
// h/w composer set-up
// ---------------------------------------------------------------------------
-bool Layer::hasHwcLayer(const sp<const DisplayDevice>& displayDevice) {
- auto outputLayer = findOutputLayerForDisplay(displayDevice);
- LOG_FATAL_IF(!outputLayer);
- return outputLayer->getState().hwc && (*outputLayer->getState().hwc).hwcLayer != nullptr;
-}
-
-HWC2::Layer* Layer::getHwcLayer(const sp<const DisplayDevice>& displayDevice) {
- auto outputLayer = findOutputLayerForDisplay(displayDevice);
- if (!outputLayer || !outputLayer->getState().hwc) {
- return nullptr;
- }
- return (*outputLayer->getState().hwc).hwcLayer.get();
-}
-
Rect Layer::getContentCrop() const {
// this is the crop rectangle that applies to the buffer
// itself (as opposed to the window)
@@ -454,29 +440,38 @@
compositionState.appId = appId;
}
+void Layer::latchPerFrameState(compositionengine::LayerFECompositionState& compositionState) const {
+ compositionState.forceClientComposition = false;
+
+ // TODO(lpique): b/121291683 Remove this one we are sure we don't need the
+ // value recomputed / set every frame.
+ compositionState.geomVisibleRegion = visibleRegion;
+
+ compositionState.isColorspaceAgnostic = isColorSpaceAgnostic();
+ compositionState.dataspace = mCurrentDataSpace;
+ compositionState.colorTransform = getColorTransform();
+ compositionState.colorTransformIsIdentity = !hasColorTransform();
+ compositionState.surfaceDamage = surfaceDamageRegion;
+
+ // Force client composition for special cases known only to the front-end.
+ if (isHdrY410() || getRoundedCornerState().radius > 0.0f) {
+ compositionState.forceClientComposition = true;
+ }
+}
+
void Layer::latchCompositionState(compositionengine::LayerFECompositionState& compositionState,
bool includeGeometry) const {
if (includeGeometry) {
latchGeometry(compositionState);
}
+
+ latchPerFrameState(compositionState);
}
const char* Layer::getDebugName() const {
return mName.string();
}
-void Layer::forceClientComposition(const sp<DisplayDevice>& display) {
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer);
- outputLayer->editState().forceClientComposition = true;
-}
-
-bool Layer::getForceClientComposition(const sp<DisplayDevice>& display) {
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer);
- return outputLayer->getState().forceClientComposition;
-}
-
void Layer::updateCursorPosition(const sp<const DisplayDevice>& display) {
const auto outputLayer = findOutputLayerForDisplay(display);
LOG_FATAL_IF(!outputLayer);
@@ -563,29 +558,6 @@
return true;
}
-void Layer::setCompositionType(const sp<const DisplayDevice>& display,
- Hwc2::IComposerClient::Composition type) {
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer);
- LOG_FATAL_IF(!outputLayer->getState().hwc);
- auto& compositionState = outputLayer->editState();
-
- ALOGV("setCompositionType(%" PRIx64 ", %s, %d)", ((*compositionState.hwc).hwcLayer)->getId(),
- toString(type).c_str(), 1);
- if ((*compositionState.hwc).hwcCompositionType != type) {
- ALOGV(" actually setting");
- (*compositionState.hwc).hwcCompositionType = type;
-
- auto error = (*compositionState.hwc)
- .hwcLayer->setCompositionType(static_cast<HWC2::Composition>(type));
- ALOGE_IF(error != HWC2::Error::None,
- "[%s] Failed to set "
- "composition type %s: %s (%d)",
- mName.string(), toString(type).c_str(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
-}
-
Hwc2::IComposerClient::Composition Layer::getCompositionType(
const sp<const DisplayDevice>& display) const {
const auto outputLayer = findOutputLayerForDisplay(display);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index b693a47..b1ce86b 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -469,23 +469,13 @@
protected:
void latchGeometry(compositionengine::LayerFECompositionState& outState) const;
+ virtual void latchPerFrameState(compositionengine::LayerFECompositionState& outState) const;
public:
virtual void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {}
virtual bool isHdrY410() const { return false; }
- void forceClientComposition(const sp<DisplayDevice>& display);
- bool getForceClientComposition(const sp<DisplayDevice>& display);
- virtual void setPerFrameData(const sp<const DisplayDevice>& display,
- const ui::Transform& transform, const Rect& viewport,
- int32_t supportedPerFrameMetadata,
- const ui::Dataspace targetDataspace) = 0;
-
- // callIntoHwc exists so we can update our local state and call
- // acceptDisplayChanges without unnecessarily updating the device's state
- void setCompositionType(const sp<const DisplayDevice>& display,
- Hwc2::IComposerClient::Composition type);
Hwc2::IComposerClient::Composition getCompositionType(
const sp<const DisplayDevice>& display) const;
bool getClearClientTarget(const sp<const DisplayDevice>& display) const;
@@ -607,10 +597,6 @@
virtual int32_t getQueuedFrameCount() const { return 0; }
// -----------------------------------------------------------------------
-
- bool hasHwcLayer(const sp<const DisplayDevice>& displayDevice);
- HWC2::Layer* getHwcLayer(const sp<const DisplayDevice>& displayDevice);
-
inline const State& getDrawingState() const { return mDrawingState; }
inline const State& getCurrentState() const { return mCurrentState; }
inline State& getCurrentState() { return mCurrentState; }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 5b82556..7230152 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -160,28 +160,6 @@
return false;
}
-bool isHdrColorMode(const ColorMode colorMode) {
- switch (colorMode) {
- case ColorMode::BT2100_PQ:
- case ColorMode::BT2100_HLG:
- return true;
- case ColorMode::DISPLAY_P3:
- case ColorMode::ADOBE_RGB:
- case ColorMode::DCI_P3:
- case ColorMode::BT2020:
- case ColorMode::DISPLAY_BT2020:
- case ColorMode::NATIVE:
- case ColorMode::STANDARD_BT601_625:
- case ColorMode::STANDARD_BT601_625_UNADJUSTED:
- case ColorMode::STANDARD_BT601_525:
- case ColorMode::STANDARD_BT601_525_UNADJUSTED:
- case ColorMode::STANDARD_BT709:
- case ColorMode::SRGB:
- return false;
- }
- return false;
-}
-
ui::Transform::orientation_flags fromSurfaceComposerRotation(ISurfaceComposer::Rotation rotation) {
switch (rotation) {
case ISurfaceComposer::eRotateNone:
@@ -1153,7 +1131,8 @@
decodeColorMode(mode).c_str(), mode);
} else {
display->getCompositionDisplay()->setColorMode(mode, Dataspace::UNKNOWN,
- RenderIntent::COLORIMETRIC);
+ RenderIntent::COLORIMETRIC,
+ Dataspace::UNKNOWN);
}
}));
@@ -1853,104 +1832,80 @@
ATRACE_CALL();
ALOGV(__FUNCTION__);
- // build the h/w work list
- if (CC_UNLIKELY(mGeometryInvalid)) {
- mGeometryInvalid = false;
+ const bool updatingGeometryThisFrame = mGeometryInvalid;
+ mGeometryInvalid = false;
+
+ {
+ // Use a map so that we latch the state of each front-end layer once.
+ std::unordered_map<compositionengine::LayerFE*, compositionengine::LayerFECompositionState*>
+ uniqueVisibleLayers;
+
+ // Figure out which frontend layers are being composed, and build the unique
+ // set of them (and the corresponding composition layer)
for (const auto& [token, displayDevice] : mDisplays) {
auto display = displayDevice->getCompositionDisplay();
+ for (auto& layer : display->getOutputLayersOrderedByZ()) {
+ uniqueVisibleLayers.insert(std::make_pair(&layer->getLayerFE(),
+ &layer->getLayer().editState().frontEnd));
+ }
+ }
+ // Update the composition state from each front-end layer.
+ for (auto& [layerFE, state] : uniqueVisibleLayers) {
+ layerFE->latchCompositionState(*state, updatingGeometryThisFrame);
+ }
+ }
+
+ if (CC_UNLIKELY(updatingGeometryThisFrame)) {
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
uint32_t zOrder = 0;
for (auto& layer : display->getOutputLayersOrderedByZ()) {
- auto& compositionState = layer->editState();
- compositionState.forceClientComposition = false;
- if (!compositionState.hwc || mDebugDisableHWC || mDebugRegion) {
- compositionState.forceClientComposition = true;
- }
-
- // The output Z order is set here based on a simple counter.
- compositionState.z = zOrder++;
-
- // Update the display independent composition state. This goes
- // to the general composition layer state structure.
- // TODO: Do this once per compositionengine::CompositionLayer.
- layer->getLayerFE().latchCompositionState(layer->getLayer().editState().frontEnd,
- true);
-
- // Recalculate the geometry state of the output layer.
- layer->updateCompositionState(true);
-
- // Write the updated geometry state to the HWC
- layer->writeStateToHWC(true);
+ // Assign a simple Z order sequence to each visible layer.
+ layer->editState().z = zOrder++;
}
}
}
- // Set the per-frame data
+ // Determine the color configuration of each output
for (const auto& [token, displayDevice] : mDisplays) {
auto display = displayDevice->getCompositionDisplay();
- const auto displayId = display->getId();
- if (!displayId) {
- continue;
- }
- auto* profile = display->getDisplayColorProfile();
- if (mDrawingState.colorMatrixChanged) {
+ ColorMode colorMode = ColorMode::NATIVE;
+ Dataspace dataspace = Dataspace::UNKNOWN;
+ RenderIntent renderIntent = RenderIntent::COLORIMETRIC;
+ if (useColorManagement) {
+ pickColorMode(displayDevice, &colorMode, &dataspace, &renderIntent);
+ }
+ display->setColorMode(colorMode, dataspace, renderIntent, mColorSpaceAgnosticDataspace);
+ }
+
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
+
+ for (auto& layer : display->getOutputLayersOrderedByZ()) {
+ // Update the composition state of the output layer, as needed
+ // recomputing it from the state given by the front-end layer.
+ layer->updateCompositionState(updatingGeometryThisFrame);
+ }
+ }
+
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
+
+ for (auto& layer : display->getOutputLayersOrderedByZ()) {
+ // Send the updated state to the HWC, if appropriate.
+ layer->writeStateToHWC(updatingGeometryThisFrame);
+ }
+ }
+
+ if (CC_UNLIKELY(mDrawingState.colorMatrixChanged)) {
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
display->setColorTransform(mDrawingState.colorMatrix);
}
- Dataspace targetDataspace = Dataspace::UNKNOWN;
- if (useColorManagement) {
- ColorMode colorMode;
- RenderIntent renderIntent;
- pickColorMode(displayDevice, &colorMode, &targetDataspace, &renderIntent);
- display->setColorMode(colorMode, targetDataspace, renderIntent);
-
- if (isHdrColorMode(colorMode)) {
- targetDataspace = Dataspace::UNKNOWN;
- } else if (mColorSpaceAgnosticDataspace != Dataspace::UNKNOWN) {
- targetDataspace = mColorSpaceAgnosticDataspace;
- }
- }
-
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- if (layer->isHdrY410()) {
- layer->forceClientComposition(displayDevice);
- } else if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
- layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
- !profile->hasHDR10Support()) {
- layer->forceClientComposition(displayDevice);
- } else if ((layer->getDataSpace() == Dataspace::BT2020_HLG ||
- layer->getDataSpace() == Dataspace::BT2020_ITU_HLG) &&
- !profile->hasHLGSupport()) {
- layer->forceClientComposition(displayDevice);
- }
-
- if (layer->getRoundedCornerState().radius > 0.0f) {
- layer->forceClientComposition(displayDevice);
- }
-
- if (layer->getForceClientComposition(displayDevice)) {
- ALOGV("[%s] Requesting Client composition", layer->getName().string());
- layer->setCompositionType(displayDevice,
- Hwc2::IComposerClient::Composition::CLIENT);
- continue;
- }
-
- const auto& displayState = display->getState();
- layer->setPerFrameData(displayDevice, displayState.transform, displayState.viewport,
- displayDevice->getSupportedPerFrameMetadata(), targetDataspace);
- }
- }
-
- mDrawingState.colorMatrixChanged = false;
-
- for (const auto& [token, displayDevice] : mDisplays) {
- auto display = displayDevice->getCompositionDisplay();
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- auto& layerState = layer->getCompositionLayer()->editState().frontEnd;
- layerState.compositionType = static_cast<Hwc2::IComposerClient::Composition>(
- layer->getCompositionType(displayDevice));
- }
+ mDrawingState.colorMatrixChanged = false;
}
}
@@ -2347,7 +2302,8 @@
case Dataspace::BT2020_ITU_PQ:
bestDataSpace = Dataspace::DISPLAY_P3;
*outHdrDataSpace = Dataspace::BT2020_PQ;
- *outIsHdrClientComposition = layer->getForceClientComposition(display);
+ *outIsHdrClientComposition =
+ layer->getCompositionLayer()->getState().frontEnd.forceClientComposition;
break;
case Dataspace::BT2020_HLG:
case Dataspace::BT2020_ITU_HLG:
@@ -2688,7 +2644,7 @@
defaultDataSpace = Dataspace::V0_SRGB;
}
display->getCompositionDisplay()->setColorMode(defaultColorMode, defaultDataSpace,
- RenderIntent::COLORIMETRIC);
+ RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN);
if (!state.isVirtual()) {
LOG_ALWAYS_FATAL_IF(!displayId);
display->setActiveConfig(getHwComposer().getActiveConfigIndex(*displayId));
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index e6211c4..38d7026 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -988,7 +988,9 @@
struct ForcedClientCompositionResultVariant : public RECompositionResultVariant {
static void setupLayerState(CompositionTest* test, sp<Layer> layer) {
- layer->forceClientComposition(test->mDisplay);
+ const auto outputLayer = layer->findOutputLayerForDisplay(test->mDisplay);
+ LOG_FATAL_IF(!outputLayer);
+ outputLayer->editState().forceClientComposition = true;
}
template <typename Case>