Merge "Add multi-display support"
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index f6493bf..02416e4 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -19,6 +19,8 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <cutils/properties.h>
+
#include <gui/BLASTBufferQueue.h>
#include <gui/BufferItemConsumer.h>
#include <gui/GLConsumer.h>
@@ -99,7 +101,11 @@
mHeight(height),
mNextTransaction(nullptr) {
BufferQueue::createBufferQueue(&mProducer, &mConsumer);
- mConsumer->setMaxAcquiredBufferCount(MAX_ACQUIRED_BUFFERS);
+
+ int8_t disableTripleBuffer = property_get_bool("ro.sf.disable_triple_buffer", 0);
+ if (!disableTripleBuffer) {
+ mProducer->setMaxDequeuedBufferCount(2);
+ }
mBufferItemConsumer =
new BLASTBufferItemConsumer(mConsumer, AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, 1, true);
static int32_t id = 0;
@@ -183,7 +189,7 @@
void BLASTBufferQueue::processNextBufferLocked() {
ATRACE_CALL();
- if (mNumFrameAvailable == 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS) {
+ if (mNumFrameAvailable == 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1) {
return;
}
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index d72eb5a..1b22df2 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -98,7 +98,9 @@
std::mutex mMutex;
std::condition_variable mCallbackCV;
- static const int MAX_ACQUIRED_BUFFERS = 2;
+ // BufferQueue internally allows 1 more than
+ // the max to be acquired
+ static const int MAX_ACQUIRED_BUFFERS = 1;
int32_t mNumFrameAvailable GUARDED_BY(mMutex);
int32_t mNumAcquired GUARDED_BY(mMutex);
diff --git a/libs/renderengine/gl/filters/KawaseBlurFilter.cpp b/libs/renderengine/gl/filters/KawaseBlurFilter.cpp
index fc26bcc..7524c6d 100644
--- a/libs/renderengine/gl/filters/KawaseBlurFilter.cpp
+++ b/libs/renderengine/gl/filters/KawaseBlurFilter.cpp
@@ -106,21 +106,19 @@
precision mediump float;
uniform sampler2D uTexture;
- highp uniform vec2 uOffset;
+ uniform vec2 uOffset;
highp in vec2 vUV;
out vec4 fragColor;
- vec4 kawaseBlur() {
- return (texture(uTexture, vec2(-1.0, 1.0) * uOffset + vUV, 0.0)
- + texture(uTexture, uOffset + vUV, 0.0)
- + texture(uTexture, vec2(1.0, -1.0) * uOffset + vUV, 0.0)
- + texture(uTexture, vec2(-1.0) * uOffset + vUV, 0.0))
- * 0.25;
- }
-
void main() {
- fragColor = kawaseBlur();
+ fragColor = texture(uTexture, vUV, 0.0);
+ fragColor += texture(uTexture, vUV + vec2( uOffset.x, uOffset.y), 0.0);
+ fragColor += texture(uTexture, vUV + vec2( uOffset.x, -uOffset.y), 0.0);
+ fragColor += texture(uTexture, vUV + vec2(-uOffset.x, uOffset.y), 0.0);
+ fragColor += texture(uTexture, vUV + vec2(-uOffset.x, -uOffset.y), 0.0);
+
+ fragColor = vec4(fragColor.rgb * 0.2, 1.0);
}
)SHADER";
}
diff --git a/libs/renderengine/gl/filters/KawaseBlurFilter.h b/libs/renderengine/gl/filters/KawaseBlurFilter.h
index ec81f81..20009cf 100644
--- a/libs/renderengine/gl/filters/KawaseBlurFilter.h
+++ b/libs/renderengine/gl/filters/KawaseBlurFilter.h
@@ -30,7 +30,7 @@
class KawaseBlurFilter : public BlurFilter {
public:
- static constexpr uint32_t kMaxPasses = 8;
+ static constexpr uint32_t kMaxPasses = 6;
explicit KawaseBlurFilter(GLESRenderEngine& engine);
status_t prepare() override;
diff --git a/libs/ui/include/ui/DisplayInfo.h b/libs/ui/include/ui/DisplayInfo.h
index 7773319..69f86d3 100644
--- a/libs/ui/include/ui/DisplayInfo.h
+++ b/libs/ui/include/ui/DisplayInfo.h
@@ -20,8 +20,11 @@
namespace android {
+enum class DisplayConnectionType { Internal, External };
+
// Immutable information about physical display.
struct DisplayInfo {
+ DisplayConnectionType connectionType = DisplayConnectionType::Internal;
float density = 0.f;
bool secure = false;
};
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index f4f45be..d7ec868 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -180,95 +180,91 @@
}
bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) ||
(isSecure() && !targetSettings.isSecure);
- const State& s(getDrawingState());
compositionengine::LayerFE::LayerSettings& layer = *result;
- if (!blackOutLayer) {
- layer.source.buffer.buffer = mBufferInfo.mBuffer;
- layer.source.buffer.isOpaque = isOpaque(s);
- layer.source.buffer.fence = mBufferInfo.mFence;
- layer.source.buffer.textureName = mTextureName;
- layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha();
- layer.source.buffer.isY410BT2020 = isHdrY410();
- bool hasSmpte2086 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::SMPTE2086;
- bool hasCta861_3 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::CTA861_3;
- layer.source.buffer.maxMasteringLuminance = hasSmpte2086
- ? mBufferInfo.mHdrMetadata.smpte2086.maxLuminance
- : defaultMaxMasteringLuminance;
- layer.source.buffer.maxContentLuminance = hasCta861_3
- ? mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel
- : defaultMaxContentLuminance;
- layer.frameNumber = mCurrentFrameNumber;
- layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0;
-
- // TODO: we could be more subtle with isFixedSize()
- const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || isFixedSize();
-
- // Query the texture matrix given our current filtering mode.
- float textureMatrix[16];
- getDrawingTransformMatrix(useFiltering, textureMatrix);
-
- if (getTransformToDisplayInverse()) {
- /*
- * the code below applies the primary display's inverse transform to
- * the texture transform
- */
- uint32_t transform = DisplayDevice::getPrimaryDisplayRotationFlags();
- mat4 tr = inverseOrientation(transform);
-
- /**
- * TODO(b/36727915): This is basically a hack.
- *
- * Ensure that regardless of the parent transformation,
- * this buffer is always transformed from native display
- * orientation to display orientation. For example, in the case
- * of a camera where the buffer remains in native orientation,
- * we want the pixels to always be upright.
- */
- sp<Layer> p = mDrawingParent.promote();
- if (p != nullptr) {
- const auto parentTransform = p->getTransform();
- tr = tr * inverseOrientation(parentTransform.getOrientation());
- }
-
- // and finally apply it to the original texture matrix
- const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr);
- memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
- }
-
- const Rect win{getBounds()};
- float bufferWidth = getBufferSize(s).getWidth();
- float bufferHeight = getBufferSize(s).getHeight();
-
- // BufferStateLayers can have a "buffer size" of [0, 0, -1, -1] when no display frame has
- // been set and there is no parent layer bounds. In that case, the scale is meaningless so
- // ignore them.
- if (!getBufferSize(s).isValid()) {
- bufferWidth = float(win.right) - float(win.left);
- bufferHeight = float(win.bottom) - float(win.top);
- }
-
- const float scaleHeight = (float(win.bottom) - float(win.top)) / bufferHeight;
- const float scaleWidth = (float(win.right) - float(win.left)) / bufferWidth;
- const float translateY = float(win.top) / bufferHeight;
- const float translateX = float(win.left) / bufferWidth;
-
- // Flip y-coordinates because GLConsumer expects OpenGL convention.
- mat4 tr = mat4::translate(vec4(.5, .5, 0, 1)) * mat4::scale(vec4(1, -1, 1, 1)) *
- mat4::translate(vec4(-.5, -.5, 0, 1)) *
- mat4::translate(vec4(translateX, translateY, 0, 1)) *
- mat4::scale(vec4(scaleWidth, scaleHeight, 1.0, 1.0));
-
- layer.source.buffer.useTextureFiltering = useFiltering;
- layer.source.buffer.textureTransform = mat4(static_cast<const float*>(textureMatrix)) * tr;
- } else {
- // If layer is blacked out, force alpha to 1 so that we draw a black color
- // layer.
- layer.source.buffer.buffer = nullptr;
- layer.alpha = 1.0;
- layer.frameNumber = 0;
- layer.bufferId = 0;
+ if (blackOutLayer) {
+ prepareClearClientComposition(layer, true /* blackout */);
+ return layer;
}
+ const State& s(getDrawingState());
+ layer.source.buffer.buffer = mBufferInfo.mBuffer;
+ layer.source.buffer.isOpaque = isOpaque(s);
+ layer.source.buffer.fence = mBufferInfo.mFence;
+ layer.source.buffer.textureName = mTextureName;
+ layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha();
+ layer.source.buffer.isY410BT2020 = isHdrY410();
+ bool hasSmpte2086 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::SMPTE2086;
+ bool hasCta861_3 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::CTA861_3;
+ layer.source.buffer.maxMasteringLuminance = hasSmpte2086
+ ? mBufferInfo.mHdrMetadata.smpte2086.maxLuminance
+ : defaultMaxMasteringLuminance;
+ layer.source.buffer.maxContentLuminance = hasCta861_3
+ ? mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel
+ : defaultMaxContentLuminance;
+ layer.frameNumber = mCurrentFrameNumber;
+ layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0;
+
+ // TODO: we could be more subtle with isFixedSize()
+ const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || isFixedSize();
+
+ // Query the texture matrix given our current filtering mode.
+ float textureMatrix[16];
+ getDrawingTransformMatrix(useFiltering, textureMatrix);
+
+ if (getTransformToDisplayInverse()) {
+ /*
+ * the code below applies the primary display's inverse transform to
+ * the texture transform
+ */
+ uint32_t transform = DisplayDevice::getPrimaryDisplayRotationFlags();
+ mat4 tr = inverseOrientation(transform);
+
+ /**
+ * TODO(b/36727915): This is basically a hack.
+ *
+ * Ensure that regardless of the parent transformation,
+ * this buffer is always transformed from native display
+ * orientation to display orientation. For example, in the case
+ * of a camera where the buffer remains in native orientation,
+ * we want the pixels to always be upright.
+ */
+ sp<Layer> p = mDrawingParent.promote();
+ if (p != nullptr) {
+ const auto parentTransform = p->getTransform();
+ tr = tr * inverseOrientation(parentTransform.getOrientation());
+ }
+
+ // and finally apply it to the original texture matrix
+ const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr);
+ memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
+ }
+
+ const Rect win{getBounds()};
+ float bufferWidth = getBufferSize(s).getWidth();
+ float bufferHeight = getBufferSize(s).getHeight();
+
+ // BufferStateLayers can have a "buffer size" of [0, 0, -1, -1] when no display frame has
+ // been set and there is no parent layer bounds. In that case, the scale is meaningless so
+ // ignore them.
+ if (!getBufferSize(s).isValid()) {
+ bufferWidth = float(win.right) - float(win.left);
+ bufferHeight = float(win.bottom) - float(win.top);
+ }
+
+ const float scaleHeight = (float(win.bottom) - float(win.top)) / bufferHeight;
+ const float scaleWidth = (float(win.right) - float(win.left)) / bufferWidth;
+ const float translateY = float(win.top) / bufferHeight;
+ const float translateX = float(win.left) / bufferWidth;
+
+ // Flip y-coordinates because GLConsumer expects OpenGL convention.
+ mat4 tr = mat4::translate(vec4(.5, .5, 0, 1)) * mat4::scale(vec4(1, -1, 1, 1)) *
+ mat4::translate(vec4(-.5, -.5, 0, 1)) *
+ mat4::translate(vec4(translateX, translateY, 0, 1)) *
+ mat4::scale(vec4(scaleWidth, scaleHeight, 1.0, 1.0));
+
+ layer.source.buffer.useTextureFiltering = useFiltering;
+ layer.source.buffer.textureTransform = mat4(static_cast<const float*>(textureMatrix)) * tr;
+
return layer;
}
@@ -329,6 +325,7 @@
Mutex::Autolock lock(mFrameEventHistoryMutex);
mFrameEventHistory.addPostComposition(mCurrentFrameNumber, glDoneFence, presentFence,
compositorTiming);
+ finalizeFrameEventHistory(glDoneFence, compositorTiming);
}
// Update mFrameTracker.
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 4085b52..f678910 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -173,14 +173,15 @@
BufferInfo mBufferInfo;
virtual void gatherBufferInfo() = 0;
+ std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
+
/*
* compositionengine::LayerFE overrides
*/
const compositionengine::LayerFECompositionState* getCompositionState() const override;
bool onPreComposition(nsecs_t) override;
void preparePerFrameCompositionState() override;
- std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
- compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
// Loads the corresponding system property once per process
static bool latchUnsignaledBuffers();
@@ -202,12 +203,12 @@
void updateCloneBufferInfo() override;
uint64_t mPreviousFrameNumber = 0;
+ virtual uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const;
+
private:
// Returns true if this layer requires filtering
bool needsFiltering(const sp<const DisplayDevice>& displayDevice) const override;
- uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const;
-
// BufferStateLayers can return Rect::INVALID_RECT if the layer does not have a display frame
// and its parent layer is not bounded
Rect getBufferSize(const State& s) const override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 1188dfe..de5429b 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -468,6 +468,32 @@
return mDrawingState.frameNumber;
}
+/**
+ * This is the frameNumber used for deferred transaction signalling. We need to use this because
+ * of cases where we defer a transaction for a surface to itself. In the BLAST world this
+ * may not make a huge amount of sense (Why not just merge the Buffer transaction with the
+ * deferred transaction?) but this is an important legacy use case, for example moving
+ * a window at the same time it draws makes use of this kind of technique. So anyway
+ * imagine we have something like this:
+ *
+ * Transaction { // containing
+ * Buffer -> frameNumber = 2
+ * DeferTransactionUntil -> frameNumber = 2
+ * Random other stuff
+ * }
+ * Now imagine getHeadFrameNumber returned mDrawingState.mFrameNumber (or mCurrentFrameNumber).
+ * Prior to doTransaction SurfaceFlinger will call notifyAvailableFrames, but because we
+ * haven't swapped mCurrentState to mDrawingState yet we will think the sync point
+ * is not ready. So we will return false from applyPendingState and not swap
+ * current state to drawing state. But because we don't swap current state
+ * to drawing state the number will never update and we will be stuck. This way
+ * we can see we need to return the frame number for the buffer we are about
+ * to apply.
+ */
+uint64_t BufferStateLayer::getHeadFrameNumber(nsecs_t /* expectedPresentTime */) const {
+ return mCurrentState.frameNumber;
+}
+
bool BufferStateLayer::getAutoRefresh() const {
// TODO(marissaw): support shared buffer mode
return false;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 539442a..753a742 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -116,6 +116,7 @@
protected:
void gatherBufferInfo() override;
+ uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const;
private:
bool updateFrameEventHistory(const sp<Fence>& acquireFence, nsecs_t postedTime,
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 912dffd..6cc90cb 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -97,6 +97,21 @@
// Modified by each call to prepareClientComposition to indicate the
// region of the target buffer that should be cleared.
Region& clearRegion;
+
+ // Viewport of the target being rendered to. This is used to determine
+ // the shadow light position.
+ const Rect& viewport;
+
+ // Dataspace of the output so we can optimize how to render the shadow
+ // by avoiding unnecessary color space conversions.
+ const ui::Dataspace dataspace;
+
+ // True if the region excluding the shadow is visible.
+ const bool realContentIsVisible;
+
+ // If set to true, change the layer settings to render a clear output.
+ // This may be requested by the HWC
+ const bool clearContent;
};
// A superset of LayerSettings required by RenderEngine to compose a layer
@@ -109,18 +124,12 @@
uint64_t frameNumber = 0;
};
- // Returns the LayerSettings to pass to RenderEngine::drawLayers, or
- // nullopt_t if the layer does not render
- virtual std::optional<LayerSettings> prepareClientComposition(
+ // Returns the z-ordered list of LayerSettings to pass to RenderEngine::drawLayers. The list
+ // may contain shadows casted by the layer or the content of the layer itself. If the layer
+ // does not render then an empty list will be returned.
+ virtual std::vector<LayerSettings> prepareClientCompositionList(
ClientCompositionTargetSettings&) = 0;
- // Returns the LayerSettings used to draw shadows around a layer. It is passed
- // to RenderEngine::drawLayers. Returns nullopt_t if the layer does not render
- // shadows.
- virtual std::optional<LayerSettings> prepareShadowClientComposition(
- const LayerSettings& layerSettings, const Rect& displayViewport,
- ui::Dataspace outputDataspace) = 0;
-
// Called after the layer is displayed to update the presentation fence
virtual void onLayerDisplayed(const sp<Fence>&) = 0;
@@ -142,7 +151,10 @@
lhs.useIdentityTransform == rhs.useIdentityTransform &&
lhs.needsFiltering == rhs.needsFiltering && lhs.isSecure == rhs.isSecure &&
lhs.supportsProtectedContent == rhs.supportsProtectedContent &&
- lhs.clearRegion.hasSameRects(rhs.clearRegion);
+ lhs.clearRegion.hasSameRects(rhs.clearRegion) && lhs.viewport == rhs.viewport &&
+ lhs.dataspace == rhs.dataspace &&
+ lhs.realContentIsVisible == rhs.realContentIsVisible &&
+ lhs.clearContent == rhs.clearContent;
}
static inline bool operator==(const LayerFE::LayerSettings& lhs,
@@ -164,6 +176,12 @@
*os << "\n .supportsProtectedContent = " << settings.supportsProtectedContent;
*os << "\n .clearRegion = ";
PrintTo(settings.clearRegion, os);
+ *os << "\n .viewport = ";
+ PrintTo(settings.viewport, os);
+ *os << "\n .dataspace = ";
+ PrintTo(settings.dataspace, os);
+ *os << "\n .realContentIsVisible = " << settings.realContentIsVisible;
+ *os << "\n .clearContent = " << settings.clearContent;
*os << "\n}";
}
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index 5c2ad15..45891a7 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -35,11 +35,9 @@
MOCK_METHOD1(onPreComposition, bool(nsecs_t));
MOCK_METHOD1(prepareCompositionState, void(compositionengine::LayerFE::StateSubset));
- MOCK_METHOD1(prepareClientComposition,
- std::optional<LayerSettings>(
+ MOCK_METHOD1(prepareClientCompositionList,
+ std::vector<compositionengine::LayerFE::LayerSettings>(
compositionengine::LayerFE::ClientCompositionTargetSettings&));
- MOCK_METHOD3(prepareShadowClientComposition,
- std::optional<LayerSettings>(const LayerSettings&, const Rect&, ui::Dataspace));
MOCK_METHOD1(onLayerDisplayed, void(const sp<Fence>&));
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index a389bf3..e792f45 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -963,11 +963,16 @@
// 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 =
+ const bool clearClientComposition =
layerState.clearClientTarget && layerFEState->isOpaque && !firstLayer;
ALOGV(" Composition type: client %d clear %d", clientComposition, clearClientComposition);
+ // If the layer casts a shadow but the content casting the shadow is occluded, skip
+ // composing the non-shadow content and only draw the shadows.
+ const bool realContentIsVisible = clientComposition &&
+ !layerState.visibleRegion.subtract(layerState.shadowRegion).isEmpty();
+
if (clientComposition || clearClientComposition) {
compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
clip,
@@ -976,35 +981,21 @@
outputState.isSecure,
supportsProtectedContent,
clientComposition ? clearRegion : dummyRegion,
+ outputState.viewport,
+ outputDataspace,
+ realContentIsVisible,
+ !clientComposition, /* clearContent */
};
- if (std::optional<LayerFE::LayerSettings> result =
- layerFE.prepareClientComposition(targetSettings)) {
- if (!clientComposition) {
- LayerFE::LayerSettings& 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;
- layerSettings.frameNumber = 0;
- } else {
- std::optional<LayerFE::LayerSettings> shadowLayer =
- layerFE.prepareShadowClientComposition(*result, outputState.viewport,
- outputDataspace);
- if (shadowLayer) {
- clientCompositionLayers.push_back(*shadowLayer);
- }
- }
-
- // If the layer casts a shadow but the content casting the shadow is occluded, skip
- // composing the non-shadow content and only draw the shadows.
- const bool skipNonShadowContentComposition = clientComposition &&
- layerState.visibleRegion.subtract(layerState.shadowRegion).isEmpty();
-
- if (!skipNonShadowContentComposition) {
- layer->editState().clientCompositionTimestamp = systemTime();
- clientCompositionLayers.push_back(*result);
- }
+ std::vector<LayerFE::LayerSettings> results =
+ layerFE.prepareClientCompositionList(targetSettings);
+ if (realContentIsVisible && !results.empty()) {
+ layer->editState().clientCompositionTimestamp = systemTime();
}
+
+ clientCompositionLayers.insert(clientCompositionLayers.end(),
+ std::make_move_iterator(results.begin()),
+ std::make_move_iterator(results.end()));
+ results.clear();
}
firstLayer = false;
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 9995ce1..02226ab 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -88,6 +88,7 @@
MOCK_CONST_METHOD1(getColorModes, std::vector<ui::ColorMode>(DisplayId));
MOCK_METHOD3(setActiveColorMode, status_t(DisplayId, ui::ColorMode, ui::RenderIntent));
MOCK_CONST_METHOD0(isUsingVrComposer, bool());
+ MOCK_CONST_METHOD1(getDisplayConnectionType, DisplayConnectionType(DisplayId));
MOCK_CONST_METHOD1(isVsyncPeriodSwitchSupported, bool(DisplayId));
MOCK_CONST_METHOD1(getDisplayVsyncPeriod, nsecs_t(DisplayId));
MOCK_METHOD4(setActiveConfigWithConstraints,
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 2b45046..be0e9e4 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -3425,19 +3425,13 @@
LayerFE::LayerSettings mShadowSettings;
mShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f};
- EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(_)).WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[1].mLayerSettings));
- EXPECT_CALL(mLayers[1].mLayerFE,
- prepareShadowClientComposition(mLayers[1].mLayerSettings, kDisplayViewport,
- kDisplayDataspace))
- .WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mLayerSettings));
- EXPECT_CALL(mLayers[2].mLayerFE,
- prepareShadowClientComposition(mLayers[2].mLayerSettings, kDisplayViewport,
- kDisplayDataspace))
- .WillOnce(Return(mShadowSettings));
+ EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(_))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+ EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(_))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[1].mLayerSettings})));
+ EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(_))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>(
+ {mShadowSettings, mLayers[2].mLayerSettings})));
Region accumClearRegion(Rect(10, 11, 12, 13));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
@@ -3469,10 +3463,8 @@
mLayers[1].mLayerFEState.isOpaque = true;
mLayers[2].mLayerFEState.isOpaque = true;
- EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mLayerSettings));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareShadowClientComposition(_, _, _))
- .WillOnce(Return(std::nullopt));
+ EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(_))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[2].mLayerSettings})));
Region accumClearRegion(Rect(10, 11, 12, 13));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
@@ -3497,10 +3489,8 @@
mLayers[1].mLayerFEState.isOpaque = false;
mLayers[2].mLayerFEState.isOpaque = false;
- EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mLayerSettings));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareShadowClientComposition(_, _, _))
- .WillOnce(Return(std::nullopt));
+ EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(_))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[2].mLayerSettings})));
Region accumClearRegion(Rect(10, 11, 12, 13));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
@@ -3529,25 +3519,51 @@
mLayers[0].mLayerFEState.isOpaque = true;
mLayers[1].mLayerFEState.isOpaque = true;
mLayers[2].mLayerFEState.isOpaque = true;
-
- EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[1].mLayerSettings));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mLayerSettings));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareShadowClientComposition(_, _, _))
- .WillOnce(Return(std::nullopt));
-
Region accumClearRegion(Rect(10, 11, 12, 13));
+ Region dummyRegion;
+
+ compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
+ Region(kDisplayFrame),
+ false, /* identity transform */
+ false, /* needs filtering */
+ false, /* secure */
+ false, /* supports protected content */
+ dummyRegion, /* clear region */
+ kDisplayViewport,
+ kDisplayDataspace,
+ false /* realContentIsVisible */,
+ true /* clearContent */,
+ };
+ compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
+ Region(kDisplayFrame),
+ false, /* identity transform */
+ false, /* needs filtering */
+ false, /* secure */
+ false, /* supports protected content */
+ accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
+ };
+
+ LayerFE::LayerSettings mBlackoutSettings = mLayers[1].mLayerSettings;
+ mBlackoutSettings.source.buffer.buffer = nullptr;
+ mBlackoutSettings.source.solidColor = {0.1f, 0.1f, 0.1f};
+ mBlackoutSettings.alpha = 0.f;
+ mBlackoutSettings.disableBlending = true;
+
+ EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mBlackoutSettings})));
+ EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[2].mLayerSettings})));
+
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
accumClearRegion, kDisplayDataspace);
ASSERT_EQ(2u, requests.size());
// The second layer is expected to be rendered as alpha=0 black with no blending
- EXPECT_EQ(mLayers[1].mLayerSettings.geometry.boundaries, requests[0].geometry.boundaries);
- EXPECT_FALSE(requests[0].source.buffer.buffer);
- EXPECT_EQ((half3{0.f, 0.f, 0.f}), requests[0].source.solidColor);
- EXPECT_EQ(0.f, static_cast<float>(requests[0].alpha));
- EXPECT_EQ(true, requests[0].disableBlending);
+ EXPECT_EQ(mBlackoutSettings, requests[0]);
EXPECT_EQ(mLayers[2].mLayerSettings, requests[1]);
@@ -3569,6 +3585,10 @@
false, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
Region(Rect(0, 0, 30, 30)),
@@ -3577,6 +3597,10 @@
false, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
Region(Rect(0, 0, 40, 201)),
@@ -3585,14 +3609,18 @@
false, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
- EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings))))
- .WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings))))
- .WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings))))
- .WillOnce(Return(std::nullopt));
+ EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+ EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+ EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
static_cast<void>(
mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
@@ -3613,6 +3641,10 @@
false, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
Region(kDisplayFrame),
@@ -3621,6 +3653,10 @@
false, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
Region(kDisplayFrame),
@@ -3629,14 +3665,18 @@
false, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
- EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings))))
- .WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings))))
- .WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings))))
- .WillOnce(Return(std::nullopt));
+ EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+ EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+ EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
static_cast<void>(
mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
@@ -3657,6 +3697,11 @@
false, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
+
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
Region(kDisplayFrame),
@@ -3665,6 +3710,10 @@
false, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
Region(kDisplayFrame),
@@ -3673,14 +3722,18 @@
false, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
- EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings))))
- .WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings))))
- .WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings))))
- .WillOnce(Return(std::nullopt));
+ EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+ EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+ EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
static_cast<void>(
mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
@@ -3700,6 +3753,10 @@
true, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
Region(kDisplayFrame),
@@ -3708,6 +3765,10 @@
true, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
Region(kDisplayFrame),
@@ -3716,14 +3777,18 @@
true, /* secure */
false, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
- EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings))))
- .WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings))))
- .WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings))))
- .WillOnce(Return(std::nullopt));
+ EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+ EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+ EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
static_cast<void>(
mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
@@ -3741,6 +3806,10 @@
false, /* secure */
true, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
Region(kDisplayFrame),
@@ -3749,6 +3818,10 @@
false, /* secure */
true, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
Region(kDisplayFrame),
@@ -3757,14 +3830,18 @@
false, /* secure */
true, /* supports protected content */
accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
- EXPECT_CALL(mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings))))
- .WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[1].mLayerFE, prepareClientComposition(Eq(ByRef(layer1TargetSettings))))
- .WillOnce(Return(std::nullopt));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(Eq(ByRef(layer2TargetSettings))))
- .WillOnce(Return(std::nullopt));
+ EXPECT_CALL(mLayers[0].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer0TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+ EXPECT_CALL(mLayers[1].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer1TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
+ EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2TargetSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
static_cast<void>(mOutput.generateClientCompositionRequests(true /* supportsProtectedContent */,
accumClearRegion,
@@ -3847,16 +3924,16 @@
true, /* secure */
true, /* supports protected content */
accumClearRegion,
+ kPortraitViewport,
+ kOutputDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
EXPECT_CALL(leftLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
EXPECT_CALL(leftLayer.mOutputLayer, needsFiltering()).WillRepeatedly(Return(false));
- EXPECT_CALL(leftLayer.mLayerFE, prepareClientComposition(Eq(ByRef(leftLayerSettings))))
- .WillOnce(Return(leftLayer.mLayerSettings));
- EXPECT_CALL(leftLayer.mLayerFE,
- prepareShadowClientComposition(leftLayer.mLayerSettings, kPortraitViewport,
- kOutputDataspace))
- .WillOnce(Return(std::nullopt));
+ EXPECT_CALL(leftLayer.mLayerFE, prepareClientCompositionList(Eq(ByRef(leftLayerSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>({leftLayer.mLayerSettings})));
compositionengine::LayerFE::ClientCompositionTargetSettings rightLayerSettings{
Region(Rect(1000, 0, 2000, 1000)),
@@ -3865,16 +3942,16 @@
true, /* secure */
true, /* supports protected content */
accumClearRegion,
+ kPortraitViewport,
+ kOutputDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
};
EXPECT_CALL(rightLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
EXPECT_CALL(rightLayer.mOutputLayer, needsFiltering()).WillRepeatedly(Return(false));
- EXPECT_CALL(rightLayer.mLayerFE, prepareClientComposition(Eq(ByRef(rightLayerSettings))))
- .WillOnce(Return(rightLayer.mLayerSettings));
- EXPECT_CALL(rightLayer.mLayerFE,
- prepareShadowClientComposition(rightLayer.mLayerSettings, kPortraitViewport,
- kOutputDataspace))
- .WillOnce(Return(std::nullopt));
+ EXPECT_CALL(rightLayer.mLayerFE, prepareClientCompositionList(Eq(ByRef(rightLayerSettings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>({rightLayer.mLayerSettings})));
constexpr bool supportsProtectedContent = true;
auto requests = mOutput.generateClientCompositionRequests(supportsProtectedContent,
@@ -3891,6 +3968,20 @@
const Region kShadowRegion = Region(kContentWithShadow).subtract(kContent);
const Region kPartialShadowRegion = Region(kContentWithShadow).subtract(Rect(40, 40, 60, 80));
+ Region accumClearRegion(Rect(10, 11, 12, 13));
+ compositionengine::LayerFE::ClientCompositionTargetSettings layer2Settings{
+ Region(Rect(60, 40, 70, 80)).merge(Rect(40, 80, 70, 90)), /* visible region */
+ false, /* identity transform */
+ false, /* needs filtering */
+ false, /* secure */
+ false, /* supports protected content */
+ accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ false /* realContentIsVisible */,
+ false /* clearContent */,
+ };
+
LayerFE::LayerSettings mShadowSettings;
mShadowSettings.source.solidColor = {0.1f, 0.1f, 0.1f};
@@ -3899,14 +3990,9 @@
EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
EXPECT_CALL(mLayers[1].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mLayerSettings));
- EXPECT_CALL(mLayers[2].mLayerFE,
- prepareShadowClientComposition(mLayers[2].mLayerSettings, kDisplayViewport,
- kDisplayDataspace))
- .WillOnce(Return(mShadowSettings));
+ EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2Settings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>({mShadowSettings})));
- Region accumClearRegion(Rect(10, 11, 12, 13));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
accumClearRegion, kDisplayDataspace);
ASSERT_EQ(1u, requests.size());
@@ -3928,16 +4014,26 @@
mLayers[2].mOutputLayerState.visibleRegion = kPartialContentWithPartialShadowRegion;
mLayers[2].mOutputLayerState.shadowRegion = kShadowRegion;
+ Region accumClearRegion(Rect(10, 11, 12, 13));
+ compositionengine::LayerFE::ClientCompositionTargetSettings layer2Settings{
+ Region(Rect(50, 40, 70, 80)).merge(Rect(40, 80, 70, 90)), /* visible region */
+ false, /* identity transform */
+ false, /* needs filtering */
+ false, /* secure */
+ false, /* supports protected content */
+ accumClearRegion,
+ kDisplayViewport,
+ kDisplayDataspace,
+ true /* realContentIsVisible */,
+ false /* clearContent */,
+ };
+
EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
EXPECT_CALL(mLayers[1].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
- EXPECT_CALL(mLayers[2].mLayerFE, prepareClientComposition(_))
- .WillOnce(Return(mLayers[2].mLayerSettings));
- EXPECT_CALL(mLayers[2].mLayerFE,
- prepareShadowClientComposition(mLayers[2].mLayerSettings, kDisplayViewport,
- kDisplayDataspace))
- .WillOnce(Return(mShadowSettings));
+ EXPECT_CALL(mLayers[2].mLayerFE, prepareClientCompositionList(Eq(ByRef(layer2Settings))))
+ .WillOnce(Return(std::vector<LayerFE::LayerSettings>(
+ {mShadowSettings, mLayers[2].mLayerSettings})));
- Region accumClearRegion(Rect(10, 11, 12, 13));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
accumClearRegion, kDisplayDataspace);
ASSERT_EQ(2u, requests.size());
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 6ff39b4..cd6bbd1 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -49,16 +49,16 @@
DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(const sp<SurfaceFlinger>& flinger,
const wp<IBinder>& displayToken,
- const std::optional<DisplayId>& displayId)
+ std::optional<DisplayId> displayId)
: flinger(flinger), displayToken(displayToken), displayId(displayId) {}
DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs&& args)
: mFlinger(args.flinger),
mDisplayToken(args.displayToken),
mSequenceId(args.sequenceId),
- mIsVirtual(args.isVirtual),
+ mConnectionType(args.connectionType),
mCompositionDisplay{mFlinger->getCompositionEngine().createDisplay(
- compositionengine::DisplayCreationArgs{args.isVirtual, args.displayId,
+ compositionengine::DisplayCreationArgs{args.isVirtual(), args.displayId,
args.powerAdvisor})},
mPhysicalOrientation(args.physicalOrientation),
mIsPrimary(args.isPrimary) {
@@ -248,10 +248,18 @@
}
std::string DisplayDevice::getDebugName() const {
- const auto id = getId() ? to_string(*getId()) + ", " : std::string();
- return base::StringPrintf("DisplayDevice{%s%s%s\"%s\"}", id.c_str(),
- isPrimary() ? "primary, " : "", isVirtual() ? "virtual, " : "",
- mDisplayName.c_str());
+ std::string displayId;
+ if (const auto id = getId()) {
+ displayId = to_string(*id) + ", ";
+ }
+
+ const char* type = "virtual";
+ if (mConnectionType) {
+ type = *mConnectionType == DisplayConnectionType::Internal ? "internal" : "external";
+ }
+
+ return base::StringPrintf("DisplayDevice{%s%s%s, \"%s\"}", displayId.c_str(), type,
+ isPrimary() ? ", primary" : "", mDisplayName.c_str());
}
void DisplayDevice::dump(std::string& result) const {
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index f45feae..d970b82 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -28,6 +28,7 @@
#include <math/mat4.h>
#include <renderengine/RenderEngine.h>
#include <system/window.h>
+#include <ui/DisplayInfo.h>
#include <ui/DisplayState.h>
#include <ui/GraphicTypes.h>
#include <ui/HdrCapabilities.h>
@@ -52,7 +53,6 @@
struct CompositionInfo;
struct DisplayDeviceCreationArgs;
-struct DisplayInfo;
namespace compositionengine {
class Display;
@@ -71,7 +71,9 @@
return mCompositionDisplay;
}
- bool isVirtual() const { return mIsVirtual; }
+ std::optional<DisplayConnectionType> getConnectionType() const { return mConnectionType; }
+
+ bool isVirtual() const { return !mConnectionType; }
bool isPrimary() const { return mIsPrimary; }
// isSecure indicates whether this display can be trusted to display
@@ -159,7 +161,7 @@
const sp<SurfaceFlinger> mFlinger;
const wp<IBinder> mDisplayToken;
const int32_t mSequenceId;
- const bool mIsVirtual;
+ const std::optional<DisplayConnectionType> mConnectionType;
const std::shared_ptr<compositionengine::Display> mCompositionDisplay;
@@ -178,10 +180,19 @@
};
struct DisplayDeviceState {
- bool isVirtual() const { return !displayId.has_value(); }
+ struct Physical {
+ DisplayId id;
+ DisplayConnectionType type;
+
+ bool operator==(const Physical& other) const {
+ return id == other.id && type == other.type;
+ }
+ };
+
+ bool isVirtual() const { return !physical; }
int32_t sequenceId = sNextSequenceId++;
- std::optional<DisplayId> displayId;
+ std::optional<Physical> physical;
sp<IGraphicBufferProducer> surface;
ui::LayerStack layerStack = ui::NO_LAYER_STACK;
Rect viewport;
@@ -199,15 +210,17 @@
struct DisplayDeviceCreationArgs {
// We use a constructor to ensure some of the values are set, without
// assuming a default value.
- DisplayDeviceCreationArgs(const sp<SurfaceFlinger>& flinger, const wp<IBinder>& displayToken,
- const std::optional<DisplayId>& displayId);
+ DisplayDeviceCreationArgs(const sp<SurfaceFlinger>&, const wp<IBinder>& displayToken,
+ std::optional<DisplayId>);
+
+ bool isVirtual() const { return !connectionType; }
const sp<SurfaceFlinger> flinger;
const wp<IBinder> displayToken;
const std::optional<DisplayId> displayId;
int32_t sequenceId{0};
- bool isVirtual{false};
+ std::optional<DisplayConnectionType> connectionType;
bool isSecure{false};
sp<ANativeWindow> nativeWindow;
sp<compositionengine::DisplaySurface> displaySurface;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index e8bf2d8..fc5d441 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -95,13 +95,13 @@
}
namespace impl {
+
Display::Display(android::Hwc2::Composer& composer,
const std::unordered_set<Capability>& capabilities, hwc2_display_t id,
DisplayType type)
: mComposer(composer),
mCapabilities(capabilities),
mId(id),
- mIsConnected(false),
mType(type) {
ALOGV("Created display %" PRIu64, id);
}
@@ -109,20 +109,27 @@
Display::~Display() {
mLayers.clear();
- if (mType == DisplayType::Virtual) {
- ALOGV("Destroying virtual display");
- auto intError = mComposer.destroyVirtualDisplay(mId);
- auto error = static_cast<Error>(intError);
- ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64
- ") failed: %s (%d)", mId, to_string(error).c_str(), intError);
- } else if (mType == DisplayType::Physical) {
- auto error = setVsyncEnabled(HWC2::Vsync::Disable);
- if (error != Error::None) {
- ALOGE("~Display: Failed to disable vsync for display %" PRIu64
- ": %s (%d)", mId, to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
+ Error error = Error::None;
+ const char* msg;
+ switch (mType) {
+ case DisplayType::Physical:
+ error = setVsyncEnabled(HWC2::Vsync::Disable);
+ msg = "disable VSYNC for";
+ break;
+
+ case DisplayType::Virtual:
+ error = static_cast<Error>(mComposer.destroyVirtualDisplay(mId));
+ msg = "destroy virtual";
+ break;
+
+ case DisplayType::Invalid: // Used in unit tests.
+ break;
}
+
+ ALOGE_IF(error != Error::None, "%s: Failed to %s display %" PRIu64 ": %s (%d)", __FUNCTION__,
+ msg, mId, to_string(error).c_str(), static_cast<int32_t>(error));
+
+ ALOGV("Destroyed display %" PRIu64, mId);
}
// Required by HWC2 display
@@ -372,9 +379,19 @@
return Error::None;
}
-Error Display::getType(DisplayType* outType) const
-{
- *outType = mType;
+Error Display::getConnectionType(android::DisplayConnectionType* outType) const {
+ if (mType != DisplayType::Physical) return Error::BadDisplay;
+
+ using ConnectionType = Hwc2::IComposerClient::DisplayConnectionType;
+ ConnectionType connectionType;
+ const auto error = static_cast<Error>(mComposer.getDisplayConnectionType(mId, &connectionType));
+ if (error != Error::None) {
+ return error;
+ }
+
+ *outType = connectionType == ConnectionType::INTERNAL
+ ? android::DisplayConnectionType::Internal
+ : android::DisplayConnectionType::External;
return Error::None;
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 5804903..6549525 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -25,6 +25,7 @@
#include <gui/HdrMetadata.h>
#include <math/mat4.h>
+#include <ui/DisplayInfo.h>
#include <ui/GraphicTypes.h>
#include <ui/HdrCapabilities.h>
#include <ui/Region.h>
@@ -191,7 +192,8 @@
[[clang::warn_unused_result]] virtual Error getRequests(
DisplayRequest* outDisplayRequests,
std::unordered_map<Layer*, LayerRequest>* outLayerRequests) = 0;
- [[clang::warn_unused_result]] virtual Error getType(DisplayType* outType) const = 0;
+ [[clang::warn_unused_result]] virtual Error getConnectionType(
+ android::DisplayConnectionType*) const = 0;
[[clang::warn_unused_result]] virtual Error supportsDoze(bool* outSupport) const = 0;
[[clang::warn_unused_result]] virtual Error getHdrCapabilities(
android::HdrCapabilities* outCapabilities) const = 0;
@@ -268,7 +270,7 @@
Error getName(std::string* outName) const override;
Error getRequests(DisplayRequest* outDisplayRequests,
std::unordered_map<Layer*, LayerRequest>* outLayerRequests) override;
- Error getType(DisplayType* outType) const override;
+ Error getConnectionType(android::DisplayConnectionType*) const override;
Error supportsDoze(bool* outSupport) const override;
Error getHdrCapabilities(android::HdrCapabilities* outCapabilities) const override;
Error getDisplayedContentSamplingAttributes(android::ui::PixelFormat* outFormat,
@@ -332,16 +334,17 @@
android::Hwc2::Composer& mComposer;
const std::unordered_set<Capability>& mCapabilities;
- hwc2_display_t mId;
- bool mIsConnected;
+ const hwc2_display_t mId;
DisplayType mType;
- std::unordered_map<hwc2_layer_t, std::unique_ptr<Layer>> mLayers;
+ bool mIsConnected = false;
+ std::unordered_map<hwc2_layer_t, std::unique_ptr<Layer>> mLayers;
std::unordered_map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs;
std::once_flag mDisplayCapabilityQueryFlag;
std::unordered_set<DisplayCapability> mDisplayCapabilities;
};
+
} // namespace impl
class Layer {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index bb6f696..784fa74 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -405,18 +405,32 @@
// Composer 2.4
+DisplayConnectionType HWComposer::getDisplayConnectionType(DisplayId displayId) const {
+ RETURN_IF_INVALID_DISPLAY(displayId, DisplayConnectionType::Internal);
+ const auto& hwcDisplay = mDisplayData.at(displayId).hwcDisplay;
+
+ DisplayConnectionType type;
+ const auto error = hwcDisplay->getConnectionType(&type);
+
+ const auto FALLBACK_TYPE = hwcDisplay->getId() == mInternalHwcDisplayId
+ ? DisplayConnectionType::Internal
+ : DisplayConnectionType::External;
+
+ RETURN_IF_HWC_ERROR(error, displayId, FALLBACK_TYPE);
+ return type;
+}
+
bool HWComposer::isVsyncPeriodSwitchSupported(DisplayId displayId) const {
+ RETURN_IF_INVALID_DISPLAY(displayId, false);
return mDisplayData.at(displayId).hwcDisplay->isVsyncPeriodSwitchSupported();
}
nsecs_t HWComposer::getDisplayVsyncPeriod(DisplayId displayId) const {
+ RETURN_IF_INVALID_DISPLAY(displayId, 0);
+
nsecs_t vsyncPeriodNanos;
auto error = mDisplayData.at(displayId).hwcDisplay->getDisplayVsyncPeriod(&vsyncPeriodNanos);
- if (error != HWC2::Error::None) {
- LOG_DISPLAY_ERROR(displayId, "Failed to get Vsync Period");
- return 0;
- }
-
+ RETURN_IF_HWC_ERROR(error, displayId, 0);
return vsyncPeriodNanos;
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 76e831b..41db501 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -189,6 +189,7 @@
virtual bool isUsingVrComposer() const = 0;
// Composer 2.4
+ virtual DisplayConnectionType getDisplayConnectionType(DisplayId) const = 0;
virtual bool isVsyncPeriodSwitchSupported(DisplayId displayId) const = 0;
virtual nsecs_t getDisplayVsyncPeriod(DisplayId displayId) const = 0;
virtual status_t setActiveConfigWithConstraints(
@@ -326,6 +327,7 @@
bool isUsingVrComposer() const override;
// Composer 2.4
+ DisplayConnectionType getDisplayConnectionType(DisplayId) const override;
bool isVsyncPeriodSwitchSupported(DisplayId displayId) const override;
nsecs_t getDisplayVsyncPeriod(DisplayId displayId) const override;
status_t setActiveConfigWithConstraints(DisplayId displayId, size_t configId,
diff --git a/services/surfaceflinger/EffectLayer.cpp b/services/surfaceflinger/EffectLayer.cpp
index e928c57..9d45e33 100644
--- a/services/surfaceflinger/EffectLayer.cpp
+++ b/services/surfaceflinger/EffectLayer.cpp
@@ -47,18 +47,35 @@
EffectLayer::~EffectLayer() = default;
-std::optional<compositionengine::LayerFE::LayerSettings> EffectLayer::prepareClientComposition(
+std::vector<compositionengine::LayerFE::LayerSettings> EffectLayer::prepareClientCompositionList(
compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
- auto result = Layer::prepareClientComposition(targetSettings);
- if (!result) {
- return result;
+ std::vector<compositionengine::LayerFE::LayerSettings> results;
+ std::optional<compositionengine::LayerFE::LayerSettings> layerSettings =
+ prepareClientComposition(targetSettings);
+ // Nothing to render.
+ if (!layerSettings) {
+ return {};
}
- result->source.solidColor = getColor().rgb;
- return result;
+
+ std::optional<compositionengine::LayerFE::LayerSettings> shadowSettings =
+ prepareShadowClientComposition(*layerSettings, targetSettings.viewport,
+ targetSettings.dataspace);
+ if (shadowSettings) {
+ results.push_back(*shadowSettings);
+ }
+
+ // If fill bounds are occluded or the fill color is invalid skip the fill settings.
+ if (targetSettings.realContentIsVisible && fillsColor()) {
+ // Set color for color fill settings.
+ layerSettings->source.solidColor = getColor().rgb;
+ results.push_back(*layerSettings);
+ }
+
+ return results;
}
bool EffectLayer::isVisible() const {
- return !isHiddenByPolicy() && getAlpha() > 0.0_hf;
+ return !isHiddenByPolicy() && getAlpha() > 0.0_hf && hasSomethingToDraw();
}
bool EffectLayer::setColor(const half3& color) {
@@ -126,6 +143,11 @@
return layer;
}
+bool EffectLayer::fillsColor() const {
+ return mDrawingState.color.r >= 0.0_hf && mDrawingState.color.g >= 0.0_hf &&
+ mDrawingState.color.b >= 0.0_hf;
+}
+
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/EffectLayer.h b/services/surfaceflinger/EffectLayer.h
index 8694283..33758b6 100644
--- a/services/surfaceflinger/EffectLayer.h
+++ b/services/surfaceflinger/EffectLayer.h
@@ -52,12 +52,17 @@
*/
const compositionengine::LayerFECompositionState* getCompositionState() const override;
void preparePerFrameCompositionState() override;
- std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
- compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
+ std::vector<compositionengine::LayerFE::LayerSettings> prepareClientCompositionList(
+ compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) override;
std::unique_ptr<compositionengine::LayerFECompositionState> mCompositionState;
sp<Layer> createClone() override;
+
+private:
+ // Returns true if there is a valid color to fill.
+ bool fillsColor() const;
+ bool hasSomethingToDraw() const { return fillsColor() || drawShadows(); }
};
} // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 7271f42..da26a37 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -511,13 +511,12 @@
compositionState->hasProtectedContent = isProtected();
const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f;
- const bool drawsShadows = mEffectiveShadowRadius != 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() || usesRoundedCorners || drawsShadows) {
+ if (isHdrY410() || usesRoundedCorners || drawShadows()) {
compositionState->forceClientComposition = true;
}
}
@@ -672,6 +671,49 @@
return shadowLayer;
}
+void Layer::prepareClearClientComposition(LayerFE::LayerSettings& layerSettings,
+ bool blackout) const {
+ layerSettings.source.buffer.buffer = nullptr;
+ layerSettings.source.solidColor = half3(0.0, 0.0, 0.0);
+ layerSettings.disableBlending = true;
+ layerSettings.frameNumber = 0;
+
+ // If layer is blacked out, force alpha to 1 so that we draw a black color layer.
+ layerSettings.alpha = blackout ? 1.0f : 0.0f;
+}
+
+std::vector<compositionengine::LayerFE::LayerSettings> Layer::prepareClientCompositionList(
+ compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
+ std::optional<compositionengine::LayerFE::LayerSettings> layerSettings =
+ prepareClientComposition(targetSettings);
+ // Nothing to render.
+ if (!layerSettings) {
+ return {};
+ }
+
+ // HWC requests to clear this layer.
+ if (targetSettings.clearContent) {
+ prepareClearClientComposition(*layerSettings, false /* blackout */);
+ return {*layerSettings};
+ }
+
+ std::optional<compositionengine::LayerFE::LayerSettings> shadowSettings =
+ prepareShadowClientComposition(*layerSettings, targetSettings.viewport,
+ targetSettings.dataspace);
+ // There are no shadows to render.
+ if (!shadowSettings) {
+ return {*layerSettings};
+ }
+
+ // If the layer casts a shadow but the content casting the shadow is occluded, skip
+ // composing the non-shadow content and only draw the shadows.
+ if (targetSettings.realContentIsVisible) {
+ return {*shadowSettings, *layerSettings};
+ }
+
+ return {*shadowSettings};
+}
+
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 c2dbd14..37ae340 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -552,6 +552,14 @@
void updateClonedRelatives(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
void addChildToDrawing(const sp<Layer>& layer);
void updateClonedInputInfo(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
+ virtual std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings&);
+ virtual std::optional<compositionengine::LayerFE::LayerSettings> prepareShadowClientComposition(
+ const LayerFE::LayerSettings& layerSettings, const Rect& displayViewport,
+ ui::Dataspace outputDataspace);
+ // Modifies the passed in layer settings to clear the contents. If the blackout flag is set,
+ // the settings clears the content with a solid black fill.
+ void prepareClearClientComposition(LayerFE::LayerSettings& layerSettings, bool blackout) const;
public:
/*
@@ -560,11 +568,8 @@
const compositionengine::LayerFECompositionState* getCompositionState() const override;
bool onPreComposition(nsecs_t) override;
void prepareCompositionState(compositionengine::LayerFE::StateSubset subset) override;
- std::optional<LayerSettings> prepareClientComposition(
+ std::vector<compositionengine::LayerFE::LayerSettings> prepareClientCompositionList(
compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
- std::optional<LayerSettings> prepareShadowClientComposition(
- const LayerFE::LayerSettings& layerSettings, const Rect& displayViewport,
- ui::Dataspace outputDataspace) override;
void onLayerDisplayed(const sp<Fence>& releaseFence) override;
const char* getDebugName() const override;
@@ -704,6 +709,7 @@
half getAlpha() const;
half4 getColor() const;
int32_t getBackgroundBlurRadius() const;
+ bool drawShadows() const { return mEffectiveShadowRadius > 0.f; };
// Returns how rounded corners should be drawn for this layer.
// This will traverse the hierarchy until it reaches its root, finding topmost rounded
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 46fd893..a98ff4f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -783,14 +783,18 @@
return NAME_NOT_FOUND;
}
- if (display->isVirtual()) {
+ if (const auto connectionType = display->getConnectionType())
+ info->connectionType = *connectionType;
+ else {
return INVALID_OPERATION;
}
if (mEmulatedDisplayDensity) {
info->density = mEmulatedDisplayDensity;
} else {
- info->density = display->isPrimary() ? mInternalDisplayDensity : FALLBACK_DENSITY;
+ info->density = info->connectionType == DisplayConnectionType::Internal
+ ? mInternalDisplayDensity
+ : FALLBACK_DENSITY;
}
info->secure = display->isSecure();
@@ -2242,30 +2246,38 @@
continue;
}
+ const DisplayId displayId = info->id;
+ const auto it = mPhysicalDisplayTokens.find(displayId);
+
if (event.connection == HWC2::Connection::Connected) {
- if (!mPhysicalDisplayTokens.count(info->id)) {
- ALOGV("Creating display %s", to_string(info->id).c_str());
+ if (it == mPhysicalDisplayTokens.end()) {
+ ALOGV("Creating display %s", to_string(displayId).c_str());
+
if (event.hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) {
- initScheduler(info->id);
+ initScheduler(displayId);
}
- mPhysicalDisplayTokens[info->id] = new BBinder();
+
DisplayDeviceState state;
- state.displayId = info->id;
+ state.physical = {displayId, getHwComposer().getDisplayConnectionType(displayId)};
state.isSecure = true; // All physical displays are currently considered secure.
state.displayName = info->name;
- mCurrentState.displays.add(mPhysicalDisplayTokens[info->id], state);
+
+ sp<IBinder> token = new BBinder();
+ mCurrentState.displays.add(token, state);
+ mPhysicalDisplayTokens.emplace(displayId, std::move(token));
+
mInterceptor->saveDisplayCreation(state);
}
} else {
- ALOGV("Removing display %s", to_string(info->id).c_str());
+ ALOGV("Removing display %s", to_string(displayId).c_str());
- ssize_t index = mCurrentState.displays.indexOfKey(mPhysicalDisplayTokens[info->id]);
+ const ssize_t index = mCurrentState.displays.indexOfKey(it->second);
if (index >= 0) {
const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
mInterceptor->saveDisplayDeletion(state.sequenceId);
mCurrentState.displays.removeItemsAt(index);
}
- mPhysicalDisplayTokens.erase(info->id);
+ mPhysicalDisplayTokens.erase(it);
}
processDisplayChangesLocked();
@@ -2285,13 +2297,16 @@
const sp<IGraphicBufferProducer>& producer) {
DisplayDeviceCreationArgs creationArgs(this, displayToken, displayId);
creationArgs.sequenceId = state.sequenceId;
- creationArgs.isVirtual = state.isVirtual();
creationArgs.isSecure = state.isSecure;
creationArgs.displaySurface = dispSurface;
creationArgs.hasWideColorGamut = false;
creationArgs.supportedPerFrameMetadata = 0;
creationArgs.powerAdvisor = displayId ? &mPowerAdvisor : nullptr;
+ if (const auto& physical = state.physical) {
+ creationArgs.connectionType = physical->type;
+ }
+
const bool isInternalDisplay = displayId && displayId == getInternalDisplayIdLocked();
creationArgs.isPrimary = isInternalDisplay;
@@ -2482,8 +2497,8 @@
"surface is provided (%p), ignoring it",
state.surface.get());
- displayId = state.displayId;
- LOG_ALWAYS_FATAL_IF(!displayId);
+ LOG_FATAL_IF(!state.physical);
+ displayId = state.physical->id;
dispSurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer);
producer = bqProducer;
}
@@ -5552,17 +5567,18 @@
renderArea.isSecure(),
supportProtectedContent,
clearRegion,
+ displayViewport,
+ clientCompositionDisplay.outputDataspace,
+ true, /* realContentIsVisible */
+ false, /* clearContent */
};
- auto result = layer->prepareClientComposition(targetSettings);
- if (result) {
- std::optional<compositionengine::LayerFE::LayerSettings> shadowLayer =
- layer->prepareShadowClientComposition(*result, displayViewport,
- clientCompositionDisplay.outputDataspace);
- if (shadowLayer) {
- clientCompositionLayers.push_back(*shadowLayer);
- }
- clientCompositionLayers.push_back(*result);
- }
+ std::vector<compositionengine::LayerFE::LayerSettings> results =
+ layer->prepareClientCompositionList(targetSettings);
+ clientCompositionLayers.insert(clientCompositionLayers.end(),
+ std::make_move_iterator(results.begin()),
+ std::make_move_iterator(results.end()));
+ results.clear();
+
});
std::vector<const renderengine::LayerSettings*> clientCompositionLayerPointers;
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 6884b4c..1f9d46c 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -595,8 +595,8 @@
creation->set_id(info.sequenceId);
creation->set_name(info.displayName);
creation->set_is_secure(info.isSecure);
- if (info.displayId) {
- creation->set_display_id(info.displayId->value);
+ if (info.physical) {
+ creation->set_display_id(info.physical->id.value);
}
}
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 7c8c28e..8038eba 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -55,28 +55,6 @@
return result;
}
-AStatsManager_PullAtomCallbackReturn TimeStats::populateGlobalAtom(AStatsEventList* data) {
- std::lock_guard<std::mutex> lock(mMutex);
-
- if (mTimeStats.statsStart == 0) {
- return AStatsManager_PULL_SKIP;
- }
- flushPowerTimeLocked();
-
- AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data);
- mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFrames);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFrames);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFrames);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTime);
- mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresent.totalTime());
- mStatsDelegate->statsEventWriteInt32(event, mTimeStats.displayEventConnectionsCount);
- mStatsDelegate->statsEventBuild(event);
- clearGlobalLocked();
-
- return AStatsManager_PULL_SUCCESS;
-}
-
namespace {
// Histograms align with the order of fields in SurfaceflingerStatsLayerInfo.
const std::array<std::string, 6> kHistogramNames = {
@@ -112,6 +90,37 @@
}
} // namespace
+AStatsManager_PullAtomCallbackReturn TimeStats::populateGlobalAtom(AStatsEventList* data) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (mTimeStats.statsStart == 0) {
+ return AStatsManager_PULL_SKIP;
+ }
+ flushPowerTimeLocked();
+
+ AStatsEvent* event = mStatsDelegate->addStatsEventToPullData(data);
+ mStatsDelegate->statsEventSetAtomId(event, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.totalFrames);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.missedFrames);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFrames);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTime);
+ mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresent.totalTime());
+ mStatsDelegate->statsEventWriteInt32(event, mTimeStats.displayEventConnectionsCount);
+ std::string frameDurationBytes =
+ histogramToProtoByteString(mTimeStats.frameDuration.hist, mMaxPulledHistogramBuckets);
+ mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)frameDurationBytes.c_str(),
+ frameDurationBytes.size());
+ std::string renderEngineTimingBytes =
+ histogramToProtoByteString(mTimeStats.renderEngineTiming.hist,
+ mMaxPulledHistogramBuckets);
+ mStatsDelegate->statsEventWriteByteArray(event, (const uint8_t*)renderEngineTimingBytes.c_str(),
+ renderEngineTimingBytes.size());
+ mStatsDelegate->statsEventBuild(event);
+ clearGlobalLocked();
+
+ return AStatsManager_PULL_SUCCESS;
+}
+
AStatsManager_PullAtomCallbackReturn TimeStats::populateLayerAtom(AStatsEventList* data) {
std::lock_guard<std::mutex> lock(mMutex);
diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
index 6c8eb27..83e5060 100644
--- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
@@ -747,12 +747,26 @@
ISurfaceComposerClient::eFXSurfaceEffect));
Transaction()
.setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
- .setColor(colorLayer, half3(2.0f, -1.0f, 0.0f))
+ .setColor(colorLayer, half3(2.0f, 0.0f, 0.0f))
.apply();
getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
+// An invalid color will not render a color and the layer will not be visible.
+TEST_P(LayerRenderTypeTransactionTest, SetInvalidColor) {
+ sp<SurfaceControl> colorLayer;
+ ASSERT_NO_FATAL_FAILURE(colorLayer =
+ createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceEffect));
+ Transaction()
+ .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+ .setColor(colorLayer, half3(1.0f, -1.0f, 0.5f))
+ .apply();
+
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
TEST_P(LayerRenderTypeTransactionTest, SetColorWithAlpha) {
sp<SurfaceControl> bufferLayer;
sp<SurfaceControl> colorLayer;
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 0e7eba8..8d97f27 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -145,6 +145,7 @@
mBGSurfaceControl.clear();
mFGSurfaceControl.clear();
mComposerClient.clear();
+ system("setenforce 1");
}
sp<SurfaceComposerClient> mComposerClient;
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
index 2f89696..96a7541 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
@@ -183,6 +183,7 @@
// Wait for mock call signaling teardown?
property_set("debug.sf.nobootanimation", "0");
property_set("debug.sf.hwc_service_name", "default");
+ system("setenforce 1");
ALOGI("Test env tear down - done");
}
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 1dfb6ba..06ef8e7 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -284,13 +284,14 @@
EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
- test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, DEFAULT_DISPLAY_ID,
- false /* isVirtual */, true /* isPrimary */)
- .setDisplaySurface(test->mDisplaySurface)
- .setNativeWindow(test->mNativeWindow)
- .setSecure(Derived::IS_SECURE)
- .setPowerMode(Derived::INIT_POWER_MODE)
- .inject();
+ test->mDisplay =
+ FakeDisplayDeviceInjector(test->mFlinger, DEFAULT_DISPLAY_ID,
+ DisplayConnectionType::Internal, true /* isPrimary */)
+ .setDisplaySurface(test->mDisplaySurface)
+ .setNativeWindow(test->mNativeWindow)
+ .setSecure(Derived::IS_SECURE)
+ .setPowerMode(Derived::INIT_POWER_MODE)
+ .inject();
Mock::VerifyAndClear(test->mNativeWindow);
test->mDisplay->setLayerStack(DEFAULT_LAYER_STACK);
}
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 232255f..4da0647 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -310,6 +310,16 @@
static std::optional<DisplayId> get() { return {}; }
};
+template <typename>
+struct DisplayConnectionTypeGetter {
+ static constexpr std::optional<DisplayConnectionType> value;
+};
+
+template <typename PhysicalDisplay>
+struct DisplayConnectionTypeGetter<PhysicalDisplayId<PhysicalDisplay>> {
+ static constexpr std::optional<DisplayConnectionType> value = PhysicalDisplay::CONNECTION_TYPE;
+};
+
// DisplayIdType can be:
// 1) PhysicalDisplayId<...> for generated ID of physical display backed by HWC.
// 2) VirtualDisplayId<...> for hard-coded ID of virtual display backed by HWC.
@@ -318,6 +328,7 @@
Secure secure, Primary primary, int grallocUsage>
struct DisplayVariant {
using DISPLAY_ID = DisplayIdGetter<DisplayIdType>;
+ using CONNECTION_TYPE = DisplayConnectionTypeGetter<DisplayIdType>;
// The display width and height
static constexpr int WIDTH = width;
@@ -343,8 +354,8 @@
static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
auto injector =
- FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(),
- static_cast<bool>(VIRTUAL), static_cast<bool>(PRIMARY));
+ FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(), CONNECTION_TYPE::value,
+ static_cast<bool>(PRIMARY));
injector.setSecure(static_cast<bool>(SECURE));
injector.setNativeWindow(test->mNativeWindow);
@@ -448,6 +459,15 @@
}
static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) {
+ constexpr auto CONNECTION_TYPE =
+ PhysicalDisplay::CONNECTION_TYPE == DisplayConnectionType::Internal
+ ? IComposerClient::DisplayConnectionType::INTERNAL
+ : IComposerClient::DisplayConnectionType::EXTERNAL;
+
+ EXPECT_CALL(*test->mComposer, getDisplayConnectionType(HWC_DISPLAY_ID, _))
+ .WillOnce(
+ DoAll(SetArgPointee<1>(CONNECTION_TYPE), Return(Hwc2::V2_4::Error::NONE)));
+
EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE));
EXPECT_CALL(*test->mComposer, getDisplayConfigs(HWC_DISPLAY_ID, _))
.WillOnce(DoAll(SetArgPointee<1>(std::vector<unsigned>{HWC_ACTIVE_CONFIG_ID}),
@@ -512,6 +532,7 @@
template <bool hasIdentificationData>
struct PrimaryDisplay {
+ static constexpr auto CONNECTION_TYPE = DisplayConnectionType::Internal;
static constexpr Primary PRIMARY = Primary::TRUE;
static constexpr uint8_t PORT = 255;
static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
@@ -520,6 +541,7 @@
template <bool hasIdentificationData>
struct ExternalDisplay {
+ static constexpr auto CONNECTION_TYPE = DisplayConnectionType::External;
static constexpr Primary PRIMARY = Primary::FALSE;
static constexpr uint8_t PORT = 254;
static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
@@ -1181,7 +1203,8 @@
GetBestColorModeTest()
: DisplayTransactionTest(),
- mInjector(FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, false /* isVirtual */,
+ mInjector(FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID,
+ DisplayConnectionType::Internal,
true /* isPrimary */)) {}
void setHasWideColorGamut(bool hasWideColorGamut) { mHasWideColorGamut = hasWideColorGamut; }
@@ -1283,8 +1306,6 @@
class DisplayDeviceSetProjectionTest : public DisplayTransactionTest {
public:
static constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{777};
- static constexpr bool DEFAULT_DISPLAY_IS_VIRTUAL = false;
- static constexpr bool DEFAULT_DISPLAY_IS_PRIMARY = true;
static constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1080; // arbitrary
static constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1920; // arbitrary
@@ -1314,8 +1335,8 @@
EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64));
EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT));
- return FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, DEFAULT_DISPLAY_IS_VIRTUAL,
- DEFAULT_DISPLAY_IS_PRIMARY)
+ return FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID,
+ DisplayConnectionType::Internal, true /* isPrimary */)
.setNativeWindow(mNativeWindow)
.setPhysicalOrientation(mPhysicalOrientation)
.inject();
@@ -1645,8 +1666,12 @@
// Invocation
DisplayDeviceState state;
- state.displayId = static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
- : Case::Display::DISPLAY_ID::get();
+ if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) {
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ state.physical = {*displayId, *connectionType};
+ }
+
state.isSecure = static_cast<bool>(Case::Display::SECURE);
auto device =
@@ -1658,6 +1683,7 @@
ASSERT_TRUE(device != nullptr);
EXPECT_EQ(Case::Display::DISPLAY_ID::get(), device->getId());
+ EXPECT_EQ(Case::Display::CONNECTION_TYPE::value, device->getConnectionType());
EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), device->isVirtual());
EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
@@ -1821,21 +1847,24 @@
EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
+ std::optional<DisplayDeviceState::Physical> expectedPhysical;
+ if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) {
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ expectedPhysical = {*displayId, *connectionType};
+ }
+
// The display should have been set up in the current display state
ASSERT_TRUE(hasCurrentDisplayState(displayToken));
const auto& current = getCurrentDisplayState(displayToken);
EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), current.isVirtual());
- EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
- : Case::Display::DISPLAY_ID::get(),
- current.displayId);
+ EXPECT_EQ(expectedPhysical, current.physical);
// The display should have been set up in the drawing display state
ASSERT_TRUE(hasDrawingDisplayState(displayToken));
const auto& draw = getDrawingDisplayState(displayToken);
EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
- EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
- : Case::Display::DISPLAY_ID::get(),
- draw.displayId);
+ EXPECT_EQ(expectedPhysical, draw.physical);
}
template <typename Case>
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 685cfaf..3a4f349 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -543,10 +543,11 @@
class FakeDisplayDeviceInjector {
public:
FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger,
- const std::optional<DisplayId>& displayId, bool isVirtual,
+ std::optional<DisplayId> displayId,
+ std::optional<DisplayConnectionType> connectionType,
bool isPrimary)
: mFlinger(flinger), mCreationArgs(flinger.mFlinger.get(), mDisplayToken, displayId) {
- mCreationArgs.isVirtual = isVirtual;
+ mCreationArgs.connectionType = connectionType;
mCreationArgs.isPrimary = isPrimary;
}
@@ -609,7 +610,12 @@
sp<DisplayDevice> inject() {
DisplayDeviceState state;
- state.displayId = mCreationArgs.isVirtual ? std::nullopt : mCreationArgs.displayId;
+ if (const auto type = mCreationArgs.connectionType) {
+ const auto id = mCreationArgs.displayId;
+ LOG_ALWAYS_FATAL_IF(!id);
+ state.physical = {*id, *type};
+ }
+
state.isSecure = mCreationArgs.isSecure;
sp<DisplayDevice> device = new DisplayDevice(std::move(mCreationArgs));
@@ -617,9 +623,8 @@
mFlinger.mutableCurrentState().displays.add(mDisplayToken, state);
mFlinger.mutableDrawingState().displays.add(mDisplayToken, state);
- if (!mCreationArgs.isVirtual) {
- LOG_ALWAYS_FATAL_IF(!state.displayId);
- mFlinger.mutablePhysicalDisplayTokens()[*state.displayId] = mDisplayToken;
+ if (const auto& physical = state.physical) {
+ mFlinger.mutablePhysicalDisplayTokens()[physical->id] = mDisplayToken;
}
return device;
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 685dfba..a7a4d48 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -797,63 +797,6 @@
ASSERT_EQ(0, globalProto.stats_size());
}
-TEST_F(TimeStatsTest, globalStatsCallback) {
- constexpr size_t TOTAL_FRAMES = 5;
- constexpr size_t MISSED_FRAMES = 4;
- constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
- constexpr size_t DISPLAY_EVENT_CONNECTIONS = 14;
-
- mTimeStats->onBootFinished();
- EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
-
- for (size_t i = 0; i < TOTAL_FRAMES; i++) {
- mTimeStats->incrementTotalFrames();
- }
- for (size_t i = 0; i < MISSED_FRAMES; i++) {
- mTimeStats->incrementMissedFrames();
- }
- for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
- mTimeStats->incrementClientCompositionFrames();
- }
-
- mTimeStats->recordDisplayEventConnectionCount(DISPLAY_EVENT_CONNECTIONS);
-
- mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
- mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
- mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
-
- EXPECT_THAT(mDelegate->mAtomTags,
- UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
- android::util::SURFACEFLINGER_STATS_LAYER_INFO));
- EXPECT_NE(nullptr, mDelegate->mCallback);
- EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
-
- {
- InSequence seq;
- EXPECT_CALL(*mDelegate,
- statsEventSetAtomId(mDelegate->mEvent,
- android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
- EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, TOTAL_FRAMES));
- EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, MISSED_FRAMES));
- EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, CLIENT_COMPOSITION_FRAMES));
- EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, _));
- EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 2));
- EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, DISPLAY_EVENT_CONNECTIONS));
- EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
- }
- EXPECT_EQ(AStatsManager_PULL_SUCCESS,
- mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
- mDelegate->mCookie));
-
- SFTimeStatsGlobalProto globalProto;
- ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
-
- EXPECT_EQ(0, globalProto.total_frames());
- EXPECT_EQ(0, globalProto.missed_frames());
- EXPECT_EQ(0, globalProto.client_composition_frames());
- EXPECT_EQ(0, globalProto.present_to_present_size());
-}
-
namespace {
std::string buildExpectedHistogramBytestring(const std::vector<int32_t>& times,
const std::vector<int32_t>& frameCounts) {
@@ -897,6 +840,80 @@
return expected == actual;
}
+TEST_F(TimeStatsTest, globalStatsCallback) {
+ constexpr size_t TOTAL_FRAMES = 5;
+ constexpr size_t MISSED_FRAMES = 4;
+ constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
+ constexpr size_t DISPLAY_EVENT_CONNECTIONS = 14;
+
+ mTimeStats->onBootFinished();
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ for (size_t i = 0; i < TOTAL_FRAMES; i++) {
+ mTimeStats->incrementTotalFrames();
+ }
+ for (size_t i = 0; i < MISSED_FRAMES; i++) {
+ mTimeStats->incrementMissedFrames();
+ }
+ for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
+ mTimeStats->incrementClientCompositionFrames();
+ }
+
+ mTimeStats->recordDisplayEventConnectionCount(DISPLAY_EVENT_CONNECTIONS);
+ mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ mTimeStats->recordFrameDuration(1000000, 3000000);
+ mTimeStats->recordRenderEngineDuration(2000000, 4000000);
+ mTimeStats->recordRenderEngineDuration(2000000, std::make_shared<FenceTime>(3000000));
+
+ mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
+ mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
+
+ EXPECT_THAT(mDelegate->mAtomTags,
+ UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ EXPECT_NE(nullptr, mDelegate->mCallback);
+ EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+ std::string expectedFrameDuration = buildExpectedHistogramBytestring({2}, {1});
+ std::string expectedRenderEngineTiming = buildExpectedHistogramBytestring({1, 2}, {1, 1});
+
+ {
+ InSequence seq;
+ EXPECT_CALL(*mDelegate,
+ statsEventSetAtomId(mDelegate->mEvent,
+ android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, TOTAL_FRAMES));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, MISSED_FRAMES));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, CLIENT_COMPOSITION_FRAMES));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, _));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 2));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, DISPLAY_EVENT_CONNECTIONS));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteByteArray(mDelegate->mEvent,
+ BytesEq((const uint8_t*)expectedFrameDuration.c_str(),
+ expectedFrameDuration.size()),
+ expectedFrameDuration.size()));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteByteArray(mDelegate->mEvent,
+ BytesEq((const uint8_t*)
+ expectedRenderEngineTiming.c_str(),
+ expectedRenderEngineTiming.size()),
+ expectedRenderEngineTiming.size()));
+ EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
+ }
+ EXPECT_EQ(AStatsManager_PULL_SUCCESS,
+ mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ mDelegate->mCookie));
+
+ SFTimeStatsGlobalProto globalProto;
+ ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+
+ EXPECT_EQ(0, globalProto.total_frames());
+ EXPECT_EQ(0, globalProto.missed_frames());
+ EXPECT_EQ(0, globalProto.client_composition_frames());
+ EXPECT_EQ(0, globalProto.present_to_present_size());
+}
+
TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) {
constexpr size_t LATE_ACQUIRE_FRAMES = 2;
constexpr size_t BAD_DESIRED_PRESENT_FRAMES = 3;