Apply additional CachedSet rendering fixes
1. Properly set the viewport to be the layer stack content rectangle,
rather than the cachedset bounds
2. The projection space of the output buffer must be stored alongside
the override buffer. This must feed back into RenderEngine when
re-rendering a CachedSet, as the displayFrame of the cached buffer has
to map back into layer stack space
3. The Transform for override buffers must collapse to the IDENTITY
transform, because cached buffers are in the same orientation as the
client target so there's no need to apply a transform
Bug: 180660547
Test: libcompositionengine_test
Test: Youtube fullscreen playback
Test: simulate virtual displays
Change-Id: Ie78c61853b2a712060b5f17045157a457b461cb7
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index a3e84e2..6c02759 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -16,10 +16,7 @@
#pragma once
-#include <cstdint>
-#include <optional>
-#include <string>
-
+#include <compositionengine/ProjectionSpace.h>
#include <compositionengine/impl/HwcBufferCache.h>
#include <renderengine/Mesh.h>
#include <ui/FloatRect.h>
@@ -27,6 +24,10 @@
#include <ui/Rect.h>
#include <ui/Region.h>
+#include <cstdint>
+#include <optional>
+#include <string>
+
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
@@ -90,6 +91,7 @@
sp<Fence> acquireFence = nullptr;
Rect displayFrame = {};
ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
+ ProjectionSpace displaySpace;
} overrideInfo;
/*
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
index cfb4962..fae17d9 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
@@ -64,6 +64,7 @@
size_t getAge() const { return mAge; }
const sp<GraphicBuffer>& getBuffer() const { return mTexture.getBuffer(); }
const sp<Fence>& getDrawFence() const { return mDrawFence; }
+ const ProjectionSpace& getOutputSpace() const { return mOutputSpace; }
ui::Dataspace getOutputDataspace() const { return mOutputDataspace; }
NonBufferHash getNonBufferHash() const;
@@ -134,6 +135,7 @@
Texture mTexture;
sp<Fence> mDrawFence;
+ ProjectionSpace mOutputSpace;
ui::Dataspace mOutputDataspace;
ui::Transform::RotationFlags mOrientation = ui::Transform::ROT_0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
index e21b5bc..313a180 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
@@ -16,6 +16,7 @@
#pragma once
+#include <compositionengine/Output.h>
#include <compositionengine/impl/planner/CachedSet.h>
#include <compositionengine/impl/planner/LayerState.h>
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index e662491..4832793 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -381,8 +381,9 @@
outputDependentState.z, to_string(error).c_str(), static_cast<int32_t>(error));
}
- // Solid-color layers should always use an identity transform.
- const auto bufferTransform = requestedCompositionType != hal::Composition::SOLID_COLOR
+ // Solid-color layers and overridden buffers should always use an identity transform.
+ const auto bufferTransform = (requestedCompositionType != hal::Composition::SOLID_COLOR &&
+ getState().overrideInfo.buffer == nullptr)
? outputDependentState.bufferTransform
: static_cast<hal::Transform>(0);
if (auto error = hwcLayer->setTransform(static_cast<hal::Transform>(bufferTransform));
@@ -674,16 +675,26 @@
return {};
}
+ // Compute the geometry boundaries in layer stack space: we need to transform from the
+ // framebuffer space of the override buffer to layer space.
+ const ProjectionSpace& layerSpace = getOutput().getState().layerStackSpace;
+ const ui::Transform transform = getState().overrideInfo.displaySpace.getTransform(layerSpace);
+ const Rect boundaries = transform.transform(getState().overrideInfo.displayFrame);
+
LayerFE::LayerSettings settings;
settings.geometry = renderengine::Geometry{
- .boundaries = getState().overrideInfo.displayFrame.toFloatRect(),
+ .boundaries = boundaries.toFloatRect(),
};
settings.bufferId = getState().overrideInfo.buffer->getId();
- settings.source =
- renderengine::PixelSource{.buffer = renderengine::Buffer{
- .buffer = getState().overrideInfo.buffer,
- .fence = getState().overrideInfo.acquireFence,
- }};
+ settings.source = renderengine::PixelSource{
+ .buffer = renderengine::Buffer{
+ .buffer = getState().overrideInfo.buffer,
+ .fence = getState().overrideInfo.acquireFence,
+ // If the transform from layer space to display space contains a rotation, we
+ // need to undo the rotation in the texture transform
+ .textureTransform =
+ ui::Transform(transform.inverse().getOrientation(), 1, 1).asMatrix4(),
+ }};
settings.sourceDataspace = getState().overrideInfo.dataspace;
settings.alpha = 1.0f;
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
index 45dce98..0f6804d 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
@@ -72,6 +72,7 @@
dumpVal(out, "override acquire fence", overrideInfo.acquireFence.get());
dumpVal(out, "override display frame", overrideInfo.displayFrame);
dumpVal(out, "override dataspace", toString(overrideInfo.dataspace), overrideInfo.dataspace);
+ dumpVal(out, "override display space", to_string(overrideInfo.displaySpace));
if (hwc) {
dumpHwc(*hwc, out);
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index e8c6de0..b95a3db 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -152,20 +152,20 @@
void CachedSet::render(renderengine::RenderEngine& renderEngine,
const OutputCompositionState& outputState) {
+ const Rect& viewport = outputState.layerStackSpace.content;
const ui::Dataspace& outputDataspace = outputState.dataspace;
const ui::Transform::RotationFlags orientation =
- ui::Transform::toRotationFlags(outputState.displaySpace.orientation);
+ ui::Transform::toRotationFlags(outputState.framebufferSpace.orientation);
renderengine::DisplaySettings displaySettings{
.physicalDisplay = Rect(0, 0, mBounds.getWidth(), mBounds.getHeight()),
- .clip = mBounds,
- .orientation = orientation,
+ .clip = viewport,
.outputDataspace = outputDataspace,
+ .orientation = orientation,
};
Region clearRegion = Region::INVALID_REGION;
- Rect viewport = mBounds;
LayerFE::ClientCompositionTargetSettings targetSettings{
- .clip = Region(mBounds),
+ .clip = Region(viewport),
.needsFiltering = false,
.isSecure = true,
.supportsProtectedContent = false,
@@ -223,6 +223,10 @@
if (result == NO_ERROR) {
mTexture.setBuffer(buffer, &renderEngine);
mDrawFence = new Fence(drawFence.release());
+ mOutputSpace = ProjectionSpace(ui::Size(outputState.framebufferSpace.bounds.getWidth(),
+ outputState.framebufferSpace.bounds.getHeight()),
+ mBounds);
+ mOutputSpace.orientation = outputState.framebufferSpace.orientation;
mOutputDataspace = outputDataspace;
mOrientation = orientation;
}
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 06f7e7a..439cfb3 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -213,6 +213,7 @@
.acquireFence = mNewCachedSet->getDrawFence(),
.displayFrame = mNewCachedSet->getBounds(),
.dataspace = mNewCachedSet->getOutputDataspace(),
+ .displaySpace = mNewCachedSet->getOutputSpace(),
};
++incomingLayerIter;
}
@@ -244,6 +245,7 @@
.acquireFence = currentLayerIter->getDrawFence(),
.displayFrame = currentLayerIter->getBounds(),
.dataspace = currentLayerIter->getOutputDataspace(),
+ .displaySpace = currentLayerIter->getOutputSpace(),
};
++incomingLayerIter;
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 83fb9e3..cbbc966 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -690,6 +690,7 @@
static constexpr FloatRect kSourceCrop{11.f, 12.f, 13.f, 14.f};
static constexpr uint32_t kZOrder = 21u;
static constexpr Hwc2::Transform kBufferTransform = static_cast<Hwc2::Transform>(31);
+ static constexpr Hwc2::Transform kOverrideBufferTransform = static_cast<Hwc2::Transform>(0);
static constexpr Hwc2::IComposerClient::BlendMode kBlendMode =
static_cast<Hwc2::IComposerClient::BlendMode>(41);
static constexpr float kAlpha = 51.f;
@@ -765,11 +766,12 @@
}
void expectGeometryCommonCalls(Rect displayFrame = kDisplayFrame,
- FloatRect sourceCrop = kSourceCrop) {
+ FloatRect sourceCrop = kSourceCrop,
+ Hwc2::Transform bufferTransform = kBufferTransform) {
EXPECT_CALL(*mHwcLayer, setDisplayFrame(displayFrame)).WillOnce(Return(kError));
EXPECT_CALL(*mHwcLayer, setSourceCrop(sourceCrop)).WillOnce(Return(kError));
EXPECT_CALL(*mHwcLayer, setZOrder(kZOrder)).WillOnce(Return(kError));
- EXPECT_CALL(*mHwcLayer, setTransform(kBufferTransform)).WillOnce(Return(kError));
+ EXPECT_CALL(*mHwcLayer, setTransform(bufferTransform)).WillOnce(Return(kError));
EXPECT_CALL(*mHwcLayer, setBlendMode(kBlendMode)).WillOnce(Return(kError));
EXPECT_CALL(*mHwcLayer, setPlaneAlpha(kAlpha)).WillOnce(Return(kError));
@@ -1006,7 +1008,8 @@
mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE;
includeOverrideInfo();
- expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideDisplayFrame.toFloatRect());
+ expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideDisplayFrame.toFloatRect(),
+ kOverrideBufferTransform);
expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace);
expectSetHdrMetadataAndBufferCalls(kOverrideBuffer, kOverrideFence);
expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index 0e7ef71..d3c4b1f 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -92,7 +92,9 @@
// set up minimium params needed for rendering
mOutputState.dataspace = ui::Dataspace::SRGB;
- mOutputState.displaySpace.orientation = ui::ROTATION_0;
+ mOutputState.framebufferSpace = ProjectionSpace(ui::Size(10, 20), Rect(10, 5));
+ mOutputState.framebufferSpace.orientation = ui::ROTATION_90;
+ mOutputState.layerStackSpace = ProjectionSpace(ui::Size(20, 10), Rect(5, 10));
}
}
@@ -294,7 +296,9 @@
const sp<GraphicBuffer>&, const bool, base::unique_fd&&,
base::unique_fd*) -> size_t {
EXPECT_EQ(Rect(0, 0, 2, 2), displaySettings.physicalDisplay);
- EXPECT_EQ(Rect(0, 0, 2, 2), displaySettings.clip);
+ EXPECT_EQ(mOutputState.layerStackSpace.content, displaySettings.clip);
+ EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.orientation),
+ displaySettings.orientation);
EXPECT_EQ(0.5f, layers[0]->alpha);
EXPECT_EQ(0.75f, layers[1]->alpha);
EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
@@ -309,6 +313,11 @@
cachedSet.render(mRenderEngine, mOutputState);
expectReadyBuffer(cachedSet);
+ EXPECT_EQ(Rect(0, 0, 2, 2), cachedSet.getOutputSpace().content);
+ EXPECT_EQ(Rect(mOutputState.framebufferSpace.bounds.getWidth(),
+ mOutputState.framebufferSpace.bounds.getHeight()),
+ cachedSet.getOutputSpace().bounds);
+
// Now check that appending a new cached set properly cleans up RenderEngine resources.
EXPECT_CALL(mRenderEngine, unbindExternalTextureBuffer(_));
CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index 211b4dc..1bbf11a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -125,7 +125,8 @@
// set up minimium params needed for rendering
mOutputState.dataspace = ui::Dataspace::SRGB;
- mOutputState.displaySpace.orientation = ui::ROTATION_0;
+ mOutputState.framebufferSpace = ProjectionSpace(ui::Size(10, 20), Rect(10, 5));
+ mOutputState.framebufferSpace.orientation = ui::ROTATION_90;
}
}
@@ -254,6 +255,30 @@
EXPECT_EQ(overrideBuffer2, overrideBuffer3);
}
+TEST_F(FlattenerTest, flattenLayers_FlattenedLayersSetsProjectionSpace) {
+ auto& layerState1 = mTestLayers[0]->layerState;
+ const auto& overrideDisplaySpace =
+ layerState1->getOutputLayer()->getState().overrideInfo.displaySpace;
+
+ auto& layerState2 = mTestLayers[1]->layerState;
+
+ const std::vector<const LayerState*> layers = {
+ layerState1.get(),
+ layerState2.get(),
+ };
+
+ initializeFlattener(layers);
+
+ // make all layers inactive
+ mTime += 200ms;
+ expectAllLayersFlattened(layers);
+ EXPECT_EQ(overrideDisplaySpace.bounds,
+ Rect(mOutputState.framebufferSpace.bounds.getWidth(),
+ mOutputState.framebufferSpace.bounds.getHeight()));
+ EXPECT_EQ(overrideDisplaySpace.content, Rect(0, 0, 2, 2));
+ EXPECT_EQ(overrideDisplaySpace.orientation, mOutputState.framebufferSpace.orientation);
+}
+
TEST_F(FlattenerTest, flattenLayers_addLayerToFlattenedCauseReset) {
auto& layerState1 = mTestLayers[0]->layerState;
const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer;
@@ -405,7 +430,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mOutputState.displaySpace.orientation = ui::ROTATION_90;
+ mOutputState.framebufferSpace.orientation = ui::ROTATION_90;
mFlattener->renderCachedSets(mRenderEngine, mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
@@ -418,7 +443,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mOutputState.displaySpace.orientation = ui::ROTATION_180;
+ mOutputState.framebufferSpace.orientation = ui::ROTATION_180;
mFlattener->renderCachedSets(mRenderEngine, mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);
@@ -445,7 +470,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mOutputState.displaySpace.orientation = ui::ROTATION_270;
+ mOutputState.framebufferSpace.orientation = ui::ROTATION_270;
mFlattener->renderCachedSets(mRenderEngine, mOutputState);
EXPECT_NE(nullptr, overrideBuffer1);