SF: Move doComposeSurfaces to CompositionEngine
Test: atest libsurfaceflinger_unittest libcompositionengine_test
Bug: 121291683
Change-Id: Iae3377a5ea018f9ec53c5a76ed6a86620f39b731
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 87bec11..13c748f 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -167,7 +167,7 @@
}
return std::nullopt;
}
- bool blackOutLayer = (isProtected() && !targetSettings.supportProtectedContent) ||
+ bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) ||
(isSecure() && !targetSettings.isSecure);
const State& s(getDrawingState());
auto& layer = *result;
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 6f076ad..ae6bdbc 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -94,6 +94,7 @@
"tests/LayerTest.cpp",
"tests/MockHWC2.cpp",
"tests/MockHWComposer.cpp",
+ "tests/MockPowerAdvisor.cpp",
"tests/OutputTest.cpp",
"tests/OutputLayerTest.cpp",
"tests/RenderSurfaceTest.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
index 0b6b4e4..0778936 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
@@ -20,6 +20,7 @@
#include <optional>
#include "DisplayHardware/DisplayIdentification.h"
+#include "DisplayHardware/PowerAdvisor.h"
namespace android::compositionengine {
@@ -37,6 +38,10 @@
// Identifies the display to the HWC, if composition is supported by it
std::optional<DisplayId> displayId;
+
+ // Optional pointer to the power advisor interface, if one is needed for
+ // this display.
+ Hwc2::PowerAdvisor* powerAdvisor = nullptr;
};
/**
@@ -68,6 +73,10 @@
mArgs.displayId = displayId;
return *this;
}
+ DisplayCreationArgsBuilder& setPowerAdvisor(Hwc2::PowerAdvisor* powerAdvisor) {
+ mArgs.powerAdvisor = powerAdvisor;
+ return *this;
+ }
private:
DisplayCreationArgs mArgs;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 94fab1f..2a901ae 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -59,7 +59,7 @@
const bool isSecure;
// If set to true, the target buffer has protected content support.
- const bool supportProtectedContent;
+ const bool supportsProtectedContent;
// Modified by each call to prepareClientComposition to indicate the
// region of the target buffer that should be cleared.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index d96d58c..d5763d5 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -116,6 +116,12 @@
// The color transform
mat4 colorTransform;
bool colorTransformIsIdentity{true};
+
+ // True if the layer is completely opaque
+ bool isOpaque{true};
+
+ // True if the layer has protected content
+ bool hasProtectedContent{false};
};
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 4dfcfa4..f73304d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -22,6 +22,7 @@
#include <unordered_map>
#include <math/mat4.h>
+#include <renderengine/LayerSettings.h>
#include <ui/Fence.h>
#include <ui/GraphicTypes.h>
#include <ui/Region.h>
@@ -156,6 +157,12 @@
// Prepares a frame for display
virtual void prepareFrame() = 0;
+ // Performs client composition as needed for layers on the output. The
+ // output fence is set to a fence to signal when client composition is
+ // finished.
+ // Returns false if client composition cannot be performed.
+ virtual bool composeSurfaces(const Region& debugFence, base::unique_fd* outReadyFence) = 0;
+
// Posts the new frame, and sets release fences.
virtual void postFramebuffer() = 0;
@@ -163,7 +170,14 @@
virtual void setDisplayColorProfile(std::unique_ptr<DisplayColorProfile>) = 0;
virtual void setRenderSurface(std::unique_ptr<RenderSurface>) = 0;
virtual void chooseCompositionStrategy() = 0;
+ virtual bool getSkipColorTransform() const = 0;
virtual FrameFences presentAndGetFrameFences() = 0;
+ virtual std::vector<renderengine::LayerSettings> generateClientCompositionRequests(
+ bool supportsProtectedContent, Region& clearRegion) = 0;
+ virtual void appendRegionFlashRequests(
+ const Region& flashRegion,
+ std::vector<renderengine::LayerSettings>& clientCompositionLayers) = 0;
+ virtual void setExpensiveRenderingExpected(bool enabled) = 0;
};
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index d7f00a9..5f62b32c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -93,6 +93,9 @@
// Applies a HWC device layer request
virtual void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) = 0;
+ // Returns true if the composition settings scale pixels
+ virtual bool needsFiltering() const = 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 795061a..36e4aac 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -23,6 +23,7 @@
#include "DisplayHardware/DisplayIdentification.h"
#include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/PowerAdvisor.h"
namespace android::compositionengine {
@@ -42,7 +43,9 @@
void setColorTransform(const mat4&) override;
void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace) override;
void chooseCompositionStrategy() override;
+ bool getSkipColorTransform() const override;
compositionengine::Output::FrameFences presentAndGetFrameFences() override;
+ void setExpensiveRenderingExpected(bool) override;
// compositionengine::Display overrides
const std::optional<DisplayId>& getId() const override;
@@ -65,9 +68,11 @@
private:
const bool mIsVirtual;
std::optional<DisplayId> mId;
+ Hwc2::PowerAdvisor* const mPowerAdvisor{nullptr};
};
std::shared_ptr<Display> createDisplay(const compositionengine::CompositionEngine&,
compositionengine::DisplayCreationArgs&&);
+
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 5f4a764..3972f2b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -77,6 +77,7 @@
void beginFrame() override;
void prepareFrame() override;
+ bool composeSurfaces(const Region&, base::unique_fd*) override;
void postFramebuffer() override;
// Testing
@@ -86,7 +87,13 @@
protected:
const CompositionEngine& getCompositionEngine() const;
void chooseCompositionStrategy() override;
+ bool getSkipColorTransform() const override;
compositionengine::Output::FrameFences presentAndGetFrameFences() override;
+ std::vector<renderengine::LayerSettings> generateClientCompositionRequests(
+ bool supportsProtectedContent, Region& clearRegion) override;
+ void appendRegionFlashRequests(const Region&,
+ std::vector<renderengine::LayerSettings>&) override;
+ void setExpensiveRenderingExpected(bool enabled) override;
void dumpBase(std::string&) const;
private:
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index d8ad02a..4c3f935 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -55,6 +55,7 @@
void applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition) override;
void prepareForDeviceLayerRequests() override;
void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) override;
+ bool needsFiltering() const override;
void dump(std::string& result) const override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index d494413..c944bec 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -77,8 +77,17 @@
MOCK_METHOD0(prepareFrame, void());
MOCK_METHOD0(chooseCompositionStrategy, void());
+ MOCK_METHOD2(composeSurfaces, bool(const Region&, base::unique_fd*));
+ MOCK_CONST_METHOD0(getSkipColorTransform, bool());
+
MOCK_METHOD0(postFramebuffer, void());
MOCK_METHOD0(presentAndGetFrameFences, compositionengine::Output::FrameFences());
+
+ MOCK_METHOD2(generateClientCompositionRequests,
+ std::vector<renderengine::LayerSettings>(bool, Region&));
+ MOCK_METHOD2(appendRegionFlashRequests,
+ void(const Region&, std::vector<renderengine::LayerSettings>&));
+ MOCK_METHOD1(setExpensiveRenderingExpected, void(bool));
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
index 195648f..d8d637d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -46,6 +46,7 @@
MOCK_METHOD1(applyDeviceCompositionTypeChange, void(Hwc2::IComposerClient::Composition));
MOCK_METHOD0(prepareForDeviceLayerRequests, void());
MOCK_METHOD1(applyDeviceLayerRequest, void(Hwc2::IComposerClient::LayerRequest request));
+ MOCK_CONST_METHOD0(needsFiltering, 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 6831901..6cd392e 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -26,6 +26,7 @@
#include <utils/Trace.h>
#include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/PowerAdvisor.h"
namespace android::compositionengine::impl {
@@ -38,7 +39,8 @@
Display::Display(const CompositionEngine& compositionEngine, DisplayCreationArgs&& args)
: compositionengine::impl::Output(compositionEngine),
mIsVirtual(args.isVirtual),
- mId(args.displayId) {
+ mId(args.displayId),
+ mPowerAdvisor(args.powerAdvisor) {
editState().isSecure = args.isSecure;
}
@@ -160,6 +162,15 @@
state.usesDeviceComposition = !allLayersRequireClientComposition();
}
+bool Display::getSkipColorTransform() const {
+ if (!mId) {
+ return false;
+ }
+
+ auto& hwc = getCompositionEngine().getHwComposer();
+ return hwc.hasDisplayCapability(*mId, HWC2::DisplayCapability::SkipClientColorTransform);
+}
+
bool Display::anyLayersRequireClientComposition() const {
const auto& layers = getOutputLayersOrderedByZ();
return std::any_of(layers.cbegin(), layers.cend(),
@@ -240,4 +251,12 @@
return result;
}
+void Display::setExpensiveRenderingExpected(bool enabled) {
+ Output::setExpensiveRenderingExpected(enabled);
+
+ if (mPowerAdvisor && mId) {
+ mPowerAdvisor->setExpensiveRenderingExpected(*mId, enabled);
+ }
+}
+
} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
index 37d6eaa..0dc4bf1 100644
--- a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
@@ -71,6 +71,8 @@
dumpVal(out, "color", state.color);
out.append("\n ");
+ dumpVal(out, "isOpaque", state.isOpaque);
+ dumpVal(out, "hasProtectedContent", state.hasProtectedContent);
dumpVal(out, "isColorspaceAgnostic", state.isColorspaceAgnostic);
dumpVal(out, "dataspace", toString(state.dataspace), state.dataspace);
dumpVal(out, "hdr metadata types", state.hdrMetadata.validTypes);
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 6878e99..fb576e0 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -17,13 +17,20 @@
#include <android-base/stringprintf.h>
#include <compositionengine/CompositionEngine.h>
#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/Layer.h>
#include <compositionengine/LayerFE.h>
#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/LayerCompositionState.h>
#include <compositionengine/impl/Output.h>
#include <compositionengine/impl/OutputLayer.h>
+#include <renderengine/DisplaySettings.h>
+#include <renderengine/RenderEngine.h>
#include <ui/DebugUtils.h>
+#include <ui/HdrCapabilities.h>
#include <utils/Trace.h>
+#include "TracedOrdinal.h"
+
namespace android::compositionengine {
Output::~Output() = default;
@@ -73,10 +80,10 @@
dirtyEntireOutput();
}
-// TODO(lpique): Rename setSize() once more is moved.
+// TODO(b/121291683): Rename setSize() once more is moved.
void Output::setBounds(const ui::Size& size) {
mRenderSurface->setDisplaySize(size);
- // TODO(lpique): Rename mState.size once more is moved.
+ // TODO(b/121291683): Rename mState.size once more is moved.
mState.bounds = Rect(mRenderSurface->getSize());
dirtyEntireOutput();
@@ -292,6 +299,179 @@
mRenderSurface->prepareFrame(mState.usesClientComposition, mState.usesDeviceComposition);
}
+bool Output::composeSurfaces(const Region& debugRegion, base::unique_fd* readyFence) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
+ mState.usesClientComposition};
+ if (!hasClientComposition) {
+ return true;
+ }
+
+ ALOGV("hasClientComposition");
+
+ auto& renderEngine = mCompositionEngine.getRenderEngine();
+ const bool supportsProtectedContent = renderEngine.supportsProtectedContent();
+
+ renderengine::DisplaySettings clientCompositionDisplay;
+ clientCompositionDisplay.physicalDisplay = mState.frame;
+ clientCompositionDisplay.clip = mState.scissor;
+ clientCompositionDisplay.globalTransform = mState.transform.asMatrix4();
+ clientCompositionDisplay.orientation = mState.orientation;
+ clientCompositionDisplay.outputDataspace =
+ mDisplayColorProfile->hasWideColorGamut() ? mState.dataspace : ui::Dataspace::UNKNOWN;
+ clientCompositionDisplay.maxLuminance =
+ mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
+
+ // Compute the global color transform matrix.
+ if (!mState.usesDeviceComposition && !getSkipColorTransform()) {
+ clientCompositionDisplay.colorTransform = mState.colorTransformMat;
+ }
+
+ // Note: Updated by generateClientCompositionRequests
+ clientCompositionDisplay.clearRegion = Region::INVALID_REGION;
+
+ // Generate the client composition requests for the layers on this output.
+ std::vector<renderengine::LayerSettings> clientCompositionLayers =
+ generateClientCompositionRequests(supportsProtectedContent,
+ clientCompositionDisplay.clearRegion);
+ appendRegionFlashRequests(debugRegion, clientCompositionLayers);
+
+ // If we the display is secure, protected content support is enabled, and at
+ // least one layer has protected content, we need to use a secure back
+ // buffer.
+ if (mState.isSecure && supportsProtectedContent) {
+ bool needsProtected =
+ std::any_of(mOutputLayersOrderedByZ.begin(), mOutputLayersOrderedByZ.end(),
+ [](auto& layer) {
+ return layer->getLayer().getState().frontEnd.hasProtectedContent;
+ });
+ if (needsProtected != renderEngine.isProtected()) {
+ renderEngine.useProtectedContext(needsProtected);
+ }
+ if (needsProtected != mRenderSurface->isProtected() &&
+ needsProtected == renderEngine.isProtected()) {
+ mRenderSurface->setProtected(needsProtected);
+ }
+ }
+
+ base::unique_fd fd;
+ sp<GraphicBuffer> buf = mRenderSurface->dequeueBuffer(&fd);
+ if (buf == nullptr) {
+ ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
+ "client composition for this frame",
+ mName.c_str());
+ return false;
+ }
+
+ // We boost GPU frequency here because there will be color spaces conversion
+ // and it's expensive. We boost the GPU frequency so that GPU composition can
+ // finish in time. We must reset GPU frequency afterwards, because high frequency
+ // consumes extra battery.
+ const bool expensiveRenderingExpected =
+ clientCompositionDisplay.outputDataspace == ui::Dataspace::DISPLAY_P3;
+ if (expensiveRenderingExpected) {
+ setExpensiveRenderingExpected(true);
+ }
+
+ renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
+ buf->getNativeBuffer(), /*useFramebufferCache=*/true, std::move(fd),
+ readyFence);
+
+ if (expensiveRenderingExpected) {
+ setExpensiveRenderingExpected(false);
+ }
+
+ return true;
+}
+
+std::vector<renderengine::LayerSettings> Output::generateClientCompositionRequests(
+ bool supportsProtectedContent, Region& clearRegion) {
+ std::vector<renderengine::LayerSettings> clientCompositionLayers;
+ ALOGV("Rendering client layers");
+
+ const Region viewportRegion(mState.viewport);
+ const bool useIdentityTransform = false;
+ bool firstLayer = true;
+ // Used when a layer clears part of the buffer.
+ Region dummyRegion;
+
+ for (auto& layer : mOutputLayersOrderedByZ) {
+ const auto& layerState = layer->getState();
+ const auto& layerFEState = layer->getLayer().getState().frontEnd;
+ auto& layerFE = layer->getLayerFE();
+
+ const Region clip(viewportRegion.intersect(layer->getState().visibleRegion));
+ ALOGV("Layer: %s", layerFE.getDebugName());
+ if (clip.isEmpty()) {
+ ALOGV(" Skipping for empty clip");
+ firstLayer = false;
+ continue;
+ }
+
+ bool clientComposition = layer->requiresClientComposition();
+
+ // We clear the client target for non-client composed layers if
+ // requested by the HWC. We skip this if the layer is not an opaque
+ // rectangle, as by definition the layer must blend with whatever is
+ // underneath. We also skip the first layer as the buffer target is
+ // guaranteed to start out cleared.
+ bool clearClientComposition =
+ layerState.clearClientTarget && layerFEState.isOpaque && !firstLayer;
+
+ ALOGV(" Composition type: client %d clear %d", clientComposition, clearClientComposition);
+
+ if (clientComposition || clearClientComposition) {
+ compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
+ clip,
+ useIdentityTransform,
+ layer->needsFiltering() || mState.needsFiltering,
+ mState.isSecure,
+ supportsProtectedContent,
+ clientComposition ? clearRegion : dummyRegion,
+ };
+ if (auto result = layerFE.prepareClientComposition(targetSettings)) {
+ if (clearClientComposition) {
+ auto& layerSettings = *result;
+ layerSettings.source.buffer.buffer = nullptr;
+ layerSettings.source.solidColor = half3(0.0, 0.0, 0.0);
+ layerSettings.alpha = half(0.0);
+ layerSettings.disableBlending = true;
+ }
+
+ clientCompositionLayers.push_back(*result);
+ }
+ }
+
+ firstLayer = false;
+ }
+
+ return clientCompositionLayers;
+}
+
+void Output::appendRegionFlashRequests(
+ const Region& flashRegion,
+ std::vector<renderengine::LayerSettings>& clientCompositionLayers) {
+ if (flashRegion.isEmpty()) {
+ return;
+ }
+
+ renderengine::LayerSettings layerSettings;
+ layerSettings.source.buffer.buffer = nullptr;
+ layerSettings.source.solidColor = half3(1.0, 0.0, 1.0);
+ layerSettings.alpha = half(1.0);
+
+ for (const auto& rect : flashRegion) {
+ layerSettings.geometry.boundaries = rect.toFloatRect();
+ clientCompositionLayers.push_back(layerSettings);
+ }
+}
+
+void Output::setExpensiveRenderingExpected(bool) {
+ // The base class does nothing with this call.
+}
+
void Output::postFramebuffer() {
ATRACE_CALL();
ALOGV(__FUNCTION__);
@@ -353,6 +533,10 @@
mState.usesDeviceComposition = false;
}
+bool Output::getSkipColorTransform() const {
+ return true;
+}
+
compositionengine::Output::FrameFences Output::presentAndGetFrameFences() {
compositionengine::Output::FrameFences result;
if (mState.usesClientComposition) {
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 6e744b9..e721cf5 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -614,6 +614,13 @@
}
}
+bool OutputLayer::needsFiltering() const {
+ const auto& displayFrame = mState.displayFrame;
+ const auto& sourceCrop = mState.sourceCrop;
+ return sourceCrop.getHeight() != displayFrame.getHeight() ||
+ sourceCrop.getWidth() != displayFrame.getWidth();
+}
+
void OutputLayer::dump(std::string& out) const {
using android::base::StringAppendF;
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index e3be0d7..743da82 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -30,6 +30,7 @@
#include "MockHWC2.h"
#include "MockHWComposer.h"
+#include "MockPowerAdvisor.h"
namespace android::compositionengine {
namespace {
@@ -59,6 +60,7 @@
}
StrictMock<android::mock::HWComposer> mHwComposer;
+ StrictMock<Hwc2::mock::PowerAdvisor> mPowerAdvisor;
StrictMock<mock::CompositionEngine> mCompositionEngine;
sp<mock::NativeWindow> mNativeWindow = new StrictMock<mock::NativeWindow>();
StrictMock<HWC2::mock::Layer> mHWC2Layer1;
@@ -68,7 +70,10 @@
mock::OutputLayer* mLayer2 = new StrictMock<mock::OutputLayer>();
mock::OutputLayer* mLayer3 = new StrictMock<mock::OutputLayer>();
impl::Display mDisplay{mCompositionEngine,
- DisplayCreationArgsBuilder().setDisplayId(DEFAULT_DISPLAY_ID).build()};
+ DisplayCreationArgsBuilder()
+ .setDisplayId(DEFAULT_DISPLAY_ID)
+ .setPowerAdvisor(&mPowerAdvisor)
+ .build()};
};
/*
@@ -344,6 +349,24 @@
}
/*
+ * Display::getSkipColorTransform()
+ */
+
+TEST_F(DisplayTest, getSkipColorTransformDoesNothingIfNonHwcDisplay) {
+ auto nonHwcDisplay{
+ impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())};
+ EXPECT_FALSE(nonHwcDisplay->getSkipColorTransform());
+}
+
+TEST_F(DisplayTest, getSkipColorTransformChecksHwcCapability) {
+ EXPECT_CALL(mHwComposer,
+ hasDisplayCapability(std::make_optional(DEFAULT_DISPLAY_ID),
+ HWC2::DisplayCapability::SkipClientColorTransform))
+ .WillOnce(Return(true));
+ EXPECT_TRUE(mDisplay.getSkipColorTransform());
+}
+
+/*
* Display::anyLayersRequireClientComposition()
*/
@@ -502,5 +525,17 @@
EXPECT_EQ(layer2Fence, result.layerFences[&mHWC2Layer2]);
}
+/*
+ * Display::setExpensiveRenderingExpected()
+ */
+
+TEST_F(DisplayTest, setExpensiveRenderingExpectedForwardsToPowerAdvisor) {
+ EXPECT_CALL(mPowerAdvisor, setExpensiveRenderingExpected(DEFAULT_DISPLAY_ID, true)).Times(1);
+ mDisplay.setExpensiveRenderingExpected(true);
+
+ EXPECT_CALL(mPowerAdvisor, setExpensiveRenderingExpected(DEFAULT_DISPLAY_ID, false)).Times(1);
+ mDisplay.setExpensiveRenderingExpected(false);
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp
new file mode 100644
index 0000000..85b9403
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MockPowerAdvisor.h"
+
+namespace android {
+namespace Hwc2 {
+
+// This will go away once PowerAdvisor is moved into the "backend" library
+PowerAdvisor::~PowerAdvisor() = default;
+
+namespace mock {
+
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+PowerAdvisor::PowerAdvisor() = default;
+PowerAdvisor::~PowerAdvisor() = default;
+
+} // namespace mock
+} // namespace Hwc2
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
new file mode 100644
index 0000000..c5a73f2
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "DisplayHardware/PowerAdvisor.h"
+
+namespace android {
+namespace Hwc2 {
+namespace mock {
+
+class PowerAdvisor : public android::Hwc2::PowerAdvisor {
+public:
+ PowerAdvisor();
+ ~PowerAdvisor() override;
+
+ MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected));
+};
+
+} // namespace mock
+} // namespace Hwc2
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index a5428ad..c83cae6 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -875,5 +875,23 @@
EXPECT_FALSE(mOutputLayer.getState().clearClientTarget);
}
+/*
+ * OutputLayer::needsFiltering()
+ */
+
+TEST_F(OutputLayerTest, needsFilteringReturnsFalseIfDisplaySizeSameAsSourceSize) {
+ mOutputLayer.editState().displayFrame = Rect(100, 100, 200, 200);
+ mOutputLayer.editState().sourceCrop = FloatRect{0.f, 0.f, 100.f, 100.f};
+
+ EXPECT_FALSE(mOutputLayer.needsFiltering());
+}
+
+TEST_F(OutputLayerTest, needsFilteringReturnsTrueIfDisplaySizeDifferentFromSourceSize) {
+ mOutputLayer.editState().displayFrame = Rect(100, 100, 200, 200);
+ mOutputLayer.editState().sourceCrop = FloatRect{0.f, 0.f, 100.1f, 100.1f};
+
+ EXPECT_TRUE(mOutputLayer.needsFiltering());
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index d136562..b6d79d4 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -60,7 +60,7 @@
mDisplayInstallOrientation(args.displayInstallOrientation),
mCompositionDisplay{mFlinger->getCompositionEngine().createDisplay(
compositionengine::DisplayCreationArgs{args.isSecure, args.isVirtual,
- args.displayId})},
+ args.displayId, args.powerAdvisor})},
mIsVirtual(args.isVirtual),
mOrientation(),
mActiveConfig(0),
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 8bc19d4..4321e3d 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -40,6 +40,7 @@
#include <utils/Timers.h>
#include "DisplayHardware/DisplayIdentification.h"
+#include "DisplayHardware/PowerAdvisor.h"
#include "RenderArea.h"
namespace android {
@@ -241,6 +242,7 @@
std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hwcColorModes;
int initialPowerMode{HWC_POWER_MODE_NORMAL};
bool isPrimary{false};
+ Hwc2::PowerAdvisor* powerAdvisor{nullptr};
};
class DisplayRenderArea : public RenderArea {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index e7fbfe9..a2ee763 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -440,6 +440,7 @@
}
void Layer::latchPerFrameState(compositionengine::LayerFECompositionState& compositionState) const {
+ const auto& drawingState{getDrawingState()};
compositionState.forceClientComposition = false;
// TODO(lpique): b/121291683 Remove this one we are sure we don't need the
@@ -451,9 +452,14 @@
compositionState.colorTransform = getColorTransform();
compositionState.colorTransformIsIdentity = !hasColorTransform();
compositionState.surfaceDamage = surfaceDamageRegion;
+ compositionState.hasProtectedContent = isProtected();
+
+ const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f;
+ compositionState.isOpaque =
+ isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf;
// Force client composition for special cases known only to the front-end.
- if (isHdrY410() || getRoundedCornerState().radius > 0.0f) {
+ if (isHdrY410() || usesRoundedCorners) {
compositionState.forceClientComposition = true;
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d2d9ea5..af4fa98 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1943,7 +1943,7 @@
if (!dirtyRegion.isEmpty()) {
base::unique_fd readyFence;
// redraw the whole screen
- doComposeSurfaces(displayDevice, dirtyRegion, &readyFence);
+ display->composeSurfaces(dirtyRegion, &readyFence);
display->getRenderSurface()->queueBuffer(std::move(readyFence));
}
@@ -2488,6 +2488,7 @@
creationArgs.displaySurface = dispSurface;
creationArgs.hasWideColorGamut = false;
creationArgs.supportedPerFrameMetadata = 0;
+ creationArgs.powerAdvisor = displayId ? &mPowerAdvisor : nullptr;
const bool isInternalDisplay = displayId && displayId == getInternalDisplayIdLocked();
creationArgs.isPrimary = isInternalDisplay;
@@ -3228,201 +3229,12 @@
ALOGV("doDisplayComposition");
base::unique_fd readyFence;
- if (!doComposeSurfaces(displayDevice, Region::INVALID_REGION, &readyFence)) return;
+ if (!display->composeSurfaces(Region::INVALID_REGION, &readyFence)) return;
// swap buffers (presentation)
display->getRenderSurface()->queueBuffer(std::move(readyFence));
}
-bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice,
- const Region& debugRegion, base::unique_fd* readyFence) {
- ATRACE_CALL();
- ALOGV("doComposeSurfaces");
-
- auto display = displayDevice->getCompositionDisplay();
- const auto& displayState = display->getState();
- const auto displayId = display->getId();
- auto& renderEngine = getRenderEngine();
- const bool supportProtectedContent = renderEngine.supportsProtectedContent();
-
- const Region bounds(displayState.bounds);
- const DisplayRenderArea renderArea(displayDevice);
- const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
- displayState.usesClientComposition};
- bool applyColorMatrix = false;
-
- renderengine::DisplaySettings clientCompositionDisplay;
- std::vector<renderengine::LayerSettings> clientCompositionLayers;
- sp<GraphicBuffer> buf;
- base::unique_fd fd;
-
- if (hasClientComposition) {
- ALOGV("hasClientComposition");
-
- if (displayDevice->isPrimary() && supportProtectedContent) {
- bool needsProtected = false;
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- // If the layer is a protected layer, mark protected context is needed.
- if (layer->isProtected()) {
- needsProtected = true;
- break;
- }
- }
- if (needsProtected != renderEngine.isProtected()) {
- renderEngine.useProtectedContext(needsProtected);
- }
- if (needsProtected != display->getRenderSurface()->isProtected() &&
- needsProtected == renderEngine.isProtected()) {
- display->getRenderSurface()->setProtected(needsProtected);
- }
- }
-
- buf = display->getRenderSurface()->dequeueBuffer(&fd);
-
- if (buf == nullptr) {
- ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
- "client composition for this frame",
- displayDevice->getDisplayName().c_str());
- return false;
- }
-
- clientCompositionDisplay.physicalDisplay = displayState.scissor;
- clientCompositionDisplay.clip = displayState.scissor;
- const ui::Transform& displayTransform = displayState.transform;
- clientCompositionDisplay.globalTransform = displayTransform.asMatrix4();
- clientCompositionDisplay.orientation = displayState.orientation;
-
- const auto* profile = display->getDisplayColorProfile();
- Dataspace outputDataspace = Dataspace::UNKNOWN;
- if (profile->hasWideColorGamut()) {
- outputDataspace = displayState.dataspace;
- }
- clientCompositionDisplay.outputDataspace = outputDataspace;
- clientCompositionDisplay.maxLuminance =
- profile->getHdrCapabilities().getDesiredMaxLuminance();
-
- const bool hasDeviceComposition = displayState.usesDeviceComposition;
- const bool skipClientColorTransform =
- getHwComposer()
- .hasDisplayCapability(displayId,
- HWC2::DisplayCapability::SkipClientColorTransform);
-
- // Compute the global color transform matrix.
- applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform;
- if (applyColorMatrix) {
- clientCompositionDisplay.colorTransform = displayState.colorTransformMat;
- }
- }
-
- /*
- * and then, render the layers targeted at the framebuffer
- */
-
- ALOGV("Rendering client layers");
- const bool useIdentityTransform = false;
- bool firstLayer = true;
- Region clearRegion = Region::INVALID_REGION;
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- const Region viewportRegion(displayState.viewport);
- const Region clip(viewportRegion.intersect(layer->visibleRegion));
- ALOGV("Layer: %s", layer->getName().string());
- ALOGV(" Composition type: %s", toString(layer->getCompositionType(displayDevice)).c_str());
- if (!clip.isEmpty()) {
- switch (layer->getCompositionType(displayDevice)) {
- case Hwc2::IComposerClient::Composition::CURSOR:
- case Hwc2::IComposerClient::Composition::DEVICE:
- case Hwc2::IComposerClient::Composition::SIDEBAND:
- case Hwc2::IComposerClient::Composition::SOLID_COLOR: {
- LOG_ALWAYS_FATAL_IF(!displayId);
- const Layer::State& state(layer->getDrawingState());
- if (layer->getClearClientTarget(displayDevice) && !firstLayer &&
- layer->isOpaque(state) && (layer->getAlpha() == 1.0f) &&
- layer->getRoundedCornerState().radius == 0.0f && hasClientComposition) {
- // never clear the very first layer since we're
- // guaranteed the FB is already cleared
- Region dummyRegion;
- compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
- clip,
- useIdentityTransform,
- layer->needsFiltering(renderArea.getDisplayDevice()) ||
- renderArea.needsFiltering(),
- renderArea.isSecure(),
- supportProtectedContent,
- dummyRegion,
- };
- auto result = layer->prepareClientComposition(targetSettings);
-
- if (result) {
- auto& layerSettings = *result;
- layerSettings.source.buffer.buffer = nullptr;
- layerSettings.source.solidColor = half3(0.0, 0.0, 0.0);
- layerSettings.alpha = half(0.0);
- layerSettings.disableBlending = true;
- clientCompositionLayers.push_back(layerSettings);
- }
- }
- break;
- }
- case Hwc2::IComposerClient::Composition::CLIENT: {
- compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
- clip,
- useIdentityTransform,
- layer->needsFiltering(renderArea.getDisplayDevice()) ||
- renderArea.needsFiltering(),
- renderArea.isSecure(),
- supportProtectedContent,
- clearRegion,
- };
- auto result = layer->prepareClientComposition(targetSettings);
- if (result) {
- clientCompositionLayers.push_back(*result);
- }
- break;
- }
- default:
- break;
- }
- } else {
- ALOGV(" Skipping for empty clip");
- }
- firstLayer = false;
- }
-
- // Perform some cleanup steps if we used client composition.
- if (hasClientComposition) {
- clientCompositionDisplay.clearRegion = clearRegion;
-
- // We boost GPU frequency here because there will be color spaces conversion
- // and it's expensive. We boost the GPU frequency so that GPU composition can
- // finish in time. We must reset GPU frequency afterwards, because high frequency
- // consumes extra battery.
- const bool expensiveRenderingExpected =
- clientCompositionDisplay.outputDataspace == Dataspace::DISPLAY_P3;
- if (expensiveRenderingExpected && displayId) {
- mPowerAdvisor.setExpensiveRenderingExpected(*displayId, true);
- }
- if (!debugRegion.isEmpty()) {
- Region::const_iterator it = debugRegion.begin();
- Region::const_iterator end = debugRegion.end();
- while (it != end) {
- const Rect& rect = *it++;
- renderengine::LayerSettings layerSettings;
- layerSettings.source.buffer.buffer = nullptr;
- layerSettings.source.solidColor = half3(1.0, 0.0, 1.0);
- layerSettings.geometry.boundaries = rect.toFloatRect();
- layerSettings.alpha = half(1.0);
- clientCompositionLayers.push_back(layerSettings);
- }
- }
- renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
- buf->getNativeBuffer(), /*useFramebufferCache=*/true, std::move(fd),
- readyFence);
- } else if (displayId) {
- mPowerAdvisor.setExpensiveRenderingExpected(*displayId, false);
- }
- return true;
-}
-
status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc,
const sp<IBinder>& parentHandle,
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 64e87b1..ef096f8 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -768,12 +768,6 @@
void logLayerStats();
void doDisplayComposition(const sp<DisplayDevice>& display, const Region& dirtyRegion);
- // This fails if using GL and the surface has been destroyed. readyFence
- // will be populated if using GL and native fence sync is supported, to
- // signal when drawing has completed.
- bool doComposeSurfaces(const sp<DisplayDevice>& display, const Region& debugRegionm,
- base::unique_fd* readyFence);
-
void postFrame();
/* ------------------------------------------------------------------------