Merge "SurfaceFlinger: Modify the meaning of composition strategy changes"
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml
index cf78102..ccf4dc8 100644
--- a/data/etc/car_core_hardware.xml
+++ b/data/etc/car_core_hardware.xml
@@ -38,7 +38,6 @@
<!-- basic system services -->
<feature name="android.software.connectionservice" />
<feature name="android.software.voice_recognizers" notLowRam="true" />
- <feature name="android.software.backup" />
<feature name="android.software.home_screen" />
<feature name="android.software.companion_device_setup" />
<feature name="android.software.autofill" />
diff --git a/include/input/Input.h b/include/input/Input.h
index 258adae..7d81fed 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -141,14 +141,6 @@
#define MAX_CONTROLLER_LEDS 4
/*
- * SystemUiVisibility constants from View.
- */
-enum {
- ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE = 0,
- ASYSTEM_UI_VISIBILITY_STATUS_BAR_HIDDEN = 0x00000001,
-};
-
-/*
* Maximum number of pointers supported per motion event.
* Smallest number of pointers is 1.
* (We want at least 10 but some touch controllers obstensibly configured for 10 pointers
diff --git a/libs/ui/include/ui/Rect.h b/libs/ui/include/ui/Rect.h
index 6670dc0..58323e5 100644
--- a/libs/ui/include/ui/Rect.h
+++ b/libs/ui/include/ui/Rect.h
@@ -202,6 +202,15 @@
// the input.
Rect transform(uint32_t xform, int32_t width, int32_t height) const;
+ Rect scale(float scaleX, float scaleY) const {
+ return Rect(FloatRect(left * scaleX, top * scaleY, right * scaleX, bottom * scaleY));
+ }
+
+ Rect& scaleSelf(float scaleX, float scaleY) {
+ set(scale(scaleX, scaleY));
+ return *this;
+ }
+
// this calculates (Region(*this) - exclude).bounds() efficiently
Rect reduce(const Rect& exclude) const;
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 28ef77a..032dd4c 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -85,6 +85,14 @@
}
cc_test {
+ name: "Rect_test",
+ test_suites: ["device-tests"],
+ shared_libs: ["libui"],
+ srcs: ["Rect_test.cpp"],
+ cflags: ["-Wall", "-Werror"],
+}
+
+cc_test {
name: "Size_test",
test_suites: ["device-tests"],
shared_libs: ["libui"],
diff --git a/libs/ui/tests/Rect_test.cpp b/libs/ui/tests/Rect_test.cpp
new file mode 100644
index 0000000..5499a5b
--- /dev/null
+++ b/libs/ui/tests/Rect_test.cpp
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <system/graphics.h>
+#include <ui/FloatRect.h>
+#include <ui/Point.h>
+#include <ui/Rect.h>
+#include <ui/Size.h>
+
+#include <gtest/gtest.h>
+
+namespace android::ui {
+
+TEST(RectTest, constructDefault) {
+ const Rect rect;
+ EXPECT_FALSE(rect.isValid());
+ EXPECT_TRUE(rect.isEmpty());
+}
+
+TEST(RectTest, constructFromWidthAndHeight) {
+ const Rect rect(100, 200);
+ EXPECT_TRUE(rect.isValid());
+ EXPECT_FALSE(rect.isEmpty());
+ EXPECT_EQ(0, rect.top);
+ EXPECT_EQ(0, rect.left);
+ EXPECT_EQ(100, rect.right);
+ EXPECT_EQ(200, rect.bottom);
+ EXPECT_EQ(100, rect.getWidth());
+ EXPECT_EQ(200, rect.getHeight());
+}
+
+TEST(RectTest, constructFromSize) {
+ const Rect rect(Size(100, 200));
+ EXPECT_TRUE(rect.isValid());
+ EXPECT_FALSE(rect.isEmpty());
+ EXPECT_EQ(0, rect.top);
+ EXPECT_EQ(0, rect.left);
+ EXPECT_EQ(100, rect.right);
+ EXPECT_EQ(200, rect.bottom);
+ EXPECT_EQ(100, rect.getWidth());
+ EXPECT_EQ(200, rect.getHeight());
+}
+
+TEST(RectTest, constructFromLTRB) {
+ const Rect rect(11, 12, 14, 14);
+ EXPECT_TRUE(rect.isValid());
+ EXPECT_FALSE(rect.isEmpty());
+ EXPECT_EQ(11, rect.left);
+ EXPECT_EQ(12, rect.top);
+ EXPECT_EQ(14, rect.right);
+ EXPECT_EQ(14, rect.bottom);
+ EXPECT_EQ(3, rect.getWidth());
+ EXPECT_EQ(2, rect.getHeight());
+}
+
+TEST(RectTest, constructFromPoints) {
+ const Rect rect(Point(11, 12), Point(14, 14));
+ EXPECT_TRUE(rect.isValid());
+ EXPECT_FALSE(rect.isEmpty());
+ EXPECT_EQ(11, rect.left);
+ EXPECT_EQ(12, rect.top);
+ EXPECT_EQ(14, rect.right);
+ EXPECT_EQ(14, rect.bottom);
+ EXPECT_EQ(3, rect.getWidth());
+ EXPECT_EQ(2, rect.getHeight());
+}
+
+TEST(RectTest, constructFromFloatRect) {
+ {
+ const Rect rect(FloatRect(10, 20, 30, 40));
+ EXPECT_TRUE(rect.isValid());
+ EXPECT_FALSE(rect.isEmpty());
+ EXPECT_EQ(10, rect.left);
+ EXPECT_EQ(20, rect.top);
+ EXPECT_EQ(30, rect.right);
+ EXPECT_EQ(40, rect.bottom);
+ }
+ // Construct with floating point error
+ {
+ constexpr float kError = 1e-3;
+ const Rect rect(FloatRect(10 - kError, 20 - kError, 30 - kError, 40 - kError));
+ EXPECT_TRUE(rect.isValid());
+ EXPECT_FALSE(rect.isEmpty());
+ EXPECT_EQ(10, rect.left);
+ EXPECT_EQ(20, rect.top);
+ EXPECT_EQ(30, rect.right);
+ EXPECT_EQ(40, rect.bottom);
+ }
+}
+
+TEST(RectTest, makeInvalid) {
+ Rect rect(10, 20, 60, 60);
+ EXPECT_TRUE(rect.isValid());
+ rect.makeInvalid();
+ EXPECT_FALSE(rect.isValid());
+}
+
+TEST(RectTest, clear) {
+ Rect rect(10, 20, 60, 60);
+ EXPECT_FALSE(rect.isEmpty());
+ rect.clear();
+ EXPECT_TRUE(rect.isEmpty());
+}
+
+TEST(RectTest, getSize) {
+ const Rect rect(10, 20, 60, 60);
+ EXPECT_EQ(Size(50, 40), rect.getSize());
+}
+
+TEST(RectTest, getBounds) {
+ const Rect rect(10, 20, 60, 60);
+ const Rect bounds = rect.getBounds();
+ EXPECT_EQ(0, bounds.left);
+ EXPECT_EQ(0, bounds.top);
+ EXPECT_EQ(50, bounds.right);
+ EXPECT_EQ(40, bounds.bottom);
+ EXPECT_EQ(rect.getSize(), bounds.getSize());
+}
+
+TEST(RectTest, getCornerPoints) {
+ const Rect rect(10, 20, 50, 60);
+ EXPECT_EQ(Point(10, 20), rect.leftTop());
+ EXPECT_EQ(Point(10, 60), rect.leftBottom());
+ EXPECT_EQ(Point(50, 20), rect.rightTop());
+ EXPECT_EQ(Point(50, 60), rect.rightBottom());
+}
+
+TEST(RectTest, operatorEquals) {
+ const Rect rect(10, 20, 50, 60);
+ EXPECT_EQ(rect, rect);
+ EXPECT_NE(Rect(0, 20, 50, 60), rect);
+ EXPECT_NE(Rect(10, 0, 50, 60), rect);
+ EXPECT_NE(Rect(10, 20, 0, 60), rect);
+ EXPECT_NE(Rect(10, 20, 50, 0), rect);
+}
+
+TEST(RectTest, operatorsPlusMinus) {
+ Rect rect = Rect(10, 20, 50, 60) + Point(1, 2);
+ EXPECT_EQ(Rect(11, 22, 51, 62), rect);
+ rect -= Point(1, 2);
+ EXPECT_EQ(Rect(10, 20, 50, 60), rect);
+
+ rect = Rect(10, 20, 50, 60) - Point(1, 2);
+ EXPECT_EQ(Rect(9, 18, 49, 58), rect);
+ rect += Point(1, 2);
+ EXPECT_EQ(Rect(10, 20, 50, 60), rect);
+}
+
+TEST(RectTest, scale) {
+ Rect rect(10, 20, 50, 60);
+ EXPECT_EQ(Rect(20, 60, 100, 180), rect.scale(2.f, 3.f));
+ rect.scaleSelf(2.f, 3.f);
+ EXPECT_EQ(Rect(20, 60, 100, 180), rect);
+
+ rect = Rect(10, 20, 50, 60);
+ constexpr float kError = 1e-3;
+ EXPECT_EQ(Rect(20, 60, 100, 180), rect.scale(2.f - kError, 3.f - kError));
+ rect.scaleSelf(2.f - kError, 3.f - kError);
+ EXPECT_EQ(Rect(20, 60, 100, 180), rect);
+}
+
+TEST(RectTest, inset) {
+ Rect rect(10, 20, 50, 60);
+ rect.inset(0, 0, 0, 0);
+ EXPECT_EQ(Rect(10, 20, 50, 60), rect);
+ rect.inset(1, 2, 3, 4);
+ EXPECT_EQ(Rect(11, 22, 47, 56), rect);
+}
+
+TEST(RectTest, intersect) {
+ const Rect rect(10, 20, 50, 60);
+ Rect intersection;
+
+ // Intersect with self is self
+ intersection.makeInvalid();
+ EXPECT_TRUE(rect.intersect(rect, &intersection));
+ EXPECT_EQ(Rect(10, 20, 50, 60), intersection);
+
+ // Intersect with rect contained in us
+ const Rect insideRect(11, 21, 45, 55);
+ intersection.makeInvalid();
+ EXPECT_TRUE(rect.intersect(insideRect, &intersection));
+ EXPECT_EQ(insideRect, intersection);
+
+ // Intersect with rect we are contained in
+ intersection.makeInvalid();
+ EXPECT_TRUE(insideRect.intersect(rect, &intersection));
+ EXPECT_EQ(insideRect, intersection);
+
+ // Empty intersection
+ intersection.makeInvalid();
+ EXPECT_FALSE(rect.intersect(Rect(100, 202, 150, 260), &intersection));
+ EXPECT_TRUE(intersection.isEmpty());
+
+ // Partial intersection
+ const Rect other(30, 40, 70, 80);
+ intersection.makeInvalid();
+ EXPECT_TRUE(rect.intersect(other, &intersection));
+ EXPECT_EQ(Rect(30, 40, 50, 60), intersection);
+
+ // Intersetion is commutative
+ intersection.makeInvalid();
+ EXPECT_TRUE(other.intersect(rect, &intersection));
+ EXPECT_EQ(Rect(30, 40, 50, 60), intersection);
+}
+
+TEST(RectTest, reduce) {
+ const Rect rect(10, 20, 50, 60);
+
+ // Reduce with self is empty
+ EXPECT_TRUE(rect.reduce(rect).isEmpty());
+
+ // Reduce with rect entirely inside is a noop
+ const Rect insideRect(11, 21, 45, 55);
+ EXPECT_EQ(rect, rect.reduce(insideRect));
+
+ // Reduce with rect entirely outside is empty
+ EXPECT_TRUE(insideRect.reduce(rect).isEmpty());
+
+ // Reduce with rect on the right
+ EXPECT_EQ(Rect(10, 20, 20, 60), rect.reduce(Rect(20, 0, 60, 70)));
+
+ // Reduce with rect on the left
+ EXPECT_EQ(Rect(40, 20, 50, 60), rect.reduce(Rect(0, 0, 40, 70)));
+
+ // Reduce with rect at the top
+ EXPECT_EQ(Rect(10, 40, 50, 60), rect.reduce(Rect(0, 0, 70, 40)));
+
+ // Reduce with rect at the bottom
+ EXPECT_EQ(Rect(10, 20, 50, 40), rect.reduce(Rect(0, 40, 70, 70)));
+}
+
+TEST(RectTest, transform) {
+ const int32_t width = 100, height = 200;
+ const Rect rect(1, 1, 2, 3);
+ EXPECT_EQ(Rect(98, 1, 99, 3), rect.transform(HAL_TRANSFORM_FLIP_H, width, height));
+ EXPECT_EQ(Rect(1, 197, 2, 199), rect.transform(HAL_TRANSFORM_FLIP_V, width, height));
+ EXPECT_EQ(Rect(197, 1, 199, 2), rect.transform(HAL_TRANSFORM_ROT_90, width, height));
+ EXPECT_EQ(Rect(98, 197, 99, 199), rect.transform(HAL_TRANSFORM_ROT_180, width, height));
+ EXPECT_EQ(Rect(1, 98, 3, 99), rect.transform(HAL_TRANSFORM_ROT_270, width, height));
+}
+
+TEST(RectTest, toFloatRect) {
+ const Rect rect(10, 20, 50, 60);
+ const FloatRect floatRect = rect.toFloatRect();
+ EXPECT_EQ(FloatRect(10.f, 20.f, 50.f, 60.f), floatRect);
+}
+
+} // namespace android::ui
diff --git a/libs/ui/tests/Size_test.cpp b/libs/ui/tests/Size_test.cpp
index 38f37ad..5f75aea 100644
--- a/libs/ui/tests/Size_test.cpp
+++ b/libs/ui/tests/Size_test.cpp
@@ -33,8 +33,7 @@
#include <gtest/gtest.h>
-namespace android {
-namespace ui {
+namespace android::ui {
TEST(SizeTest, BasicConstructionAndEqualityComparison) {
Size s(123, 456);
@@ -215,5 +214,4 @@
ClampTest(uint32_t(0), int32_t(0));
}
-} // namespace ui
-} // namespace android
+} // namespace android::ui
diff --git a/libs/ui/tests/TEST_MAPPING b/libs/ui/tests/TEST_MAPPING
index 7fcd7de..eece18e 100644
--- a/libs/ui/tests/TEST_MAPPING
+++ b/libs/ui/tests/TEST_MAPPING
@@ -2,6 +2,9 @@
"presubmit": [
{
"name": "Size_test"
+ },
+ {
+ "name": "Rect_test"
}
]
}
diff --git a/services/gpuservice/tests/unittests/GpuMemTest.cpp b/services/gpuservice/tests/unittests/GpuMemTest.cpp
index 45e8367..c5f8859 100644
--- a/services/gpuservice/tests/unittests/GpuMemTest.cpp
+++ b/services/gpuservice/tests/unittests/GpuMemTest.cpp
@@ -60,7 +60,7 @@
void SetUp() override {
SKIP_IF_BPF_NOT_SUPPORTED;
- ASSERT_EQ(0, bpf::setrlimitForTest());
+ bpf::setrlimitForTest();
mGpuMem = std::make_unique<GpuMem>();
mTestableGpuMem = TestableGpuMem(mGpuMem.get());
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index fc1adcc..d590f23 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -166,7 +166,7 @@
virtual void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
const Rect& orientedDisplaySpaceRect) = 0;
// Sets the bounds to use
- virtual void setDisplaySpaceSize(const ui::Size&) = 0;
+ virtual void setDisplaySize(const ui::Size&) = 0;
// Sets the layer stack filtering settings for this output. See
// belongsInOutput for full details.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 6fe93bf..5b832a5 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -40,7 +40,7 @@
void setCompositionEnabled(bool) override;
void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
const Rect& orientedDisplaySpaceRect) override;
- void setDisplaySpaceSize(const ui::Size&) override;
+ void setDisplaySize(const ui::Size&) override;
void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override;
void setColorTransform(const compositionengine::CompositionRefreshArgs&) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index f4d2b56..06e6a6f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -39,7 +39,7 @@
namespace compositionengine::impl {
struct OutputCompositionState {
- // If false, composition will not per performed for this display
+ // If false, composition will not be performed for this display
bool isEnabled{false};
// If false, this output is not considered secure
@@ -71,6 +71,11 @@
// match the orientation of layerStackSpace. The orientation of this space is always ROTATION_0.
ProjectionSpace orientedDisplaySpace;
+ // The space of the framebuffer. Its bounds match the size of the framebuffer and its
+ // orientation matches the orientation of the display. Typically the framebuffer space will
+ // be identical to the physical display space.
+ ProjectionSpace framebufferSpace;
+
// The space of the physical display. It is as big as the currently active display mode. The
// content in this space can be rotated.
ProjectionSpace displaySpace;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 19025c1..d6fbd7f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -37,7 +37,7 @@
MOCK_METHOD1(setCompositionEnabled, void(bool));
MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&));
- MOCK_METHOD1(setDisplaySpaceSize, void(const ui::Size&));
+ MOCK_METHOD1(setDisplaySize, void(const ui::Size&));
MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool));
MOCK_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&));
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index d201104..5459861 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -55,6 +55,7 @@
mPowerAdvisor = args.powerAdvisor;
editState().isSecure = args.isSecure;
+ editState().displaySpace.bounds = Rect(args.pixels);
setLayerStackFilter(args.layerStackId,
args.physical ? args.physical->type == DisplayConnectionType::Internal
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index abb8769..44edb6e 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -69,6 +69,19 @@
return Reversed<T>(c);
}
+struct ScaleVector {
+ float x;
+ float y;
+};
+
+// Returns a ScaleVector (x, y) such that from.scale(x, y) = to',
+// where to' will have the same size as "to". In the case where "from" and "to"
+// start at the origin to'=to.
+ScaleVector getScale(const Rect& from, const Rect& to) {
+ return {.x = static_cast<float>(to.width()) / from.width(),
+ .y = static_cast<float>(to.height()) / from.height()};
+}
+
} // namespace
std::shared_ptr<Output> createOutput(
@@ -110,9 +123,10 @@
auto& outputState = editState();
outputState.displaySpace.orientation = orientation;
- // outputState.displaySpace.bounds should be already set from setDisplaySpaceSize().
+ LOG_FATAL_IF(outputState.displaySpace.bounds == Rect::INVALID_RECT,
+ "The display bounds are unknown.");
- // Compute the orientedDisplaySpace bounds
+ // Compute orientedDisplaySpace
ui::Size orientedSize = outputState.displaySpace.bounds.getSize();
if (orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270) {
std::swap(orientedSize.width, orientedSize.height);
@@ -129,17 +143,51 @@
}
outputState.displaySpace.content = rotation.transform(orientedDisplaySpaceRect);
+ // Compute framebufferSpace
+ outputState.framebufferSpace.orientation = orientation;
+ LOG_FATAL_IF(outputState.framebufferSpace.bounds == Rect::INVALID_RECT,
+ "The framebuffer bounds are unknown.");
+ const auto scale =
+ getScale(outputState.framebufferSpace.bounds, outputState.displaySpace.bounds);
+ outputState.framebufferSpace.content = outputState.displaySpace.content.scale(scale.x, scale.y);
+
+ // Compute layerStackSpace
outputState.layerStackSpace.content = layerStackSpaceRect;
outputState.layerStackSpace.bounds = layerStackSpaceRect;
+
outputState.transform = outputState.layerStackSpace.getTransform(outputState.displaySpace);
outputState.needsFiltering = outputState.transform.needsBilinearFiltering();
-
dirtyEntireOutput();
}
-void Output::setDisplaySpaceSize(const ui::Size& size) {
+void Output::setDisplaySize(const ui::Size& size) {
mRenderSurface->setDisplaySize(size);
- editState().displaySpace.bounds = Rect(mRenderSurface->getSize());
+
+ auto& state = editState();
+
+ // Update framebuffer space
+ const Rect newBounds(size);
+ ScaleVector scale;
+ scale = getScale(state.framebufferSpace.bounds, newBounds);
+ state.framebufferSpace.bounds = newBounds;
+ state.framebufferSpace.content.scaleSelf(scale.x, scale.y);
+
+ // Update display space
+ scale = getScale(state.displaySpace.bounds, newBounds);
+ state.displaySpace.bounds = newBounds;
+ state.displaySpace.content.scaleSelf(scale.x, scale.y);
+ state.transform = state.layerStackSpace.getTransform(state.displaySpace);
+
+ // Update oriented display space
+ const auto orientation = state.displaySpace.orientation;
+ ui::Size orientedSize = size;
+ if (orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270) {
+ std::swap(orientedSize.width, orientedSize.height);
+ }
+ const Rect newOrientedBounds(orientedSize);
+ scale = getScale(state.orientedDisplaySpace.bounds, newOrientedBounds);
+ state.orientedDisplaySpace.bounds = newOrientedBounds;
+ state.orientedDisplaySpace.content.scaleSelf(scale.x, scale.y);
dirtyEntireOutput();
}
@@ -247,8 +295,7 @@
void Output::setRenderSurface(std::unique_ptr<compositionengine::RenderSurface> surface) {
mRenderSurface = std::move(surface);
- editState().displaySpace.bounds = Rect(mRenderSurface->getSize());
-
+ editState().framebufferSpace.bounds = Rect(mRenderSurface->getSize());
dirtyEntireOutput();
}
@@ -877,7 +924,7 @@
ALOGV("hasClientComposition");
renderengine::DisplaySettings clientCompositionDisplay;
- clientCompositionDisplay.physicalDisplay = outputState.displaySpace.content;
+ clientCompositionDisplay.physicalDisplay = outputState.framebufferSpace.content;
clientCompositionDisplay.clip = outputState.layerStackSpace.content;
clientCompositionDisplay.orientation =
ui::Transform::toRotationFlags(outputState.displaySpace.orientation);
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index 776fdde..ee30ad8 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -39,6 +39,8 @@
out.append("\n ");
dumpVal(out, "layerStackSpace", to_string(layerStackSpace));
out.append("\n ");
+ dumpVal(out, "framebufferSpace", to_string(framebufferSpace));
+ out.append("\n ");
dumpVal(out, "orientedDisplaySpace", to_string(orientedDisplaySpace));
out.append("\n ");
dumpVal(out, "displaySpace", to_string(displaySpace));
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index c01f3e0..57b399a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -248,20 +248,46 @@
}
/*
- * Output::setDisplaySpaceSize()
+ * Output::setDisplaySize()
*/
-TEST_F(OutputTest, setBoundsSetsSizeAndDirtiesEntireOutput) {
- const ui::Size displaySize{200, 400};
+TEST_F(OutputTest, setDisplaySpaceSizeUpdatesOutputStateAndDirtiesEntireOutput) {
+ mOutput->editState().layerStackSpace.content = Rect(0, 0, 2000, 1000);
+ mOutput->editState().layerStackSpace.bounds = Rect(0, 0, 2000, 1000);
+ mOutput->editState().orientedDisplaySpace.content = Rect(0, 0, 1800, 900);
+ mOutput->editState().orientedDisplaySpace.bounds = Rect(0, 0, 2000, 1000);
+ mOutput->editState().framebufferSpace.content = Rect(0, 0, 900, 1800);
+ mOutput->editState().framebufferSpace.bounds = Rect(0, 0, 1000, 2000);
+ mOutput->editState().framebufferSpace.orientation = ui::ROTATION_90;
+ mOutput->editState().displaySpace.content = Rect(0, 0, 900, 1800);
+ mOutput->editState().displaySpace.bounds = Rect(0, 0, 1000, 2000);
+ mOutput->editState().displaySpace.orientation = ui::ROTATION_90;
- EXPECT_CALL(*mRenderSurface, setDisplaySize(displaySize)).Times(1);
- EXPECT_CALL(*mRenderSurface, getSize()).WillOnce(ReturnRef(displaySize));
+ const ui::Size newDisplaySize{500, 1000};
- mOutput->setDisplaySpaceSize(displaySize);
+ EXPECT_CALL(*mRenderSurface, setDisplaySize(newDisplaySize)).Times(1);
- EXPECT_EQ(Rect(displaySize), mOutput->getState().displaySpace.bounds);
+ mOutput->setDisplaySize(newDisplaySize);
- EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(Rect(displaySize))));
+ const auto state = mOutput->getState();
+
+ const Rect displayRect(newDisplaySize);
+ EXPECT_EQ(ui::ROTATION_0, state.layerStackSpace.orientation);
+ EXPECT_EQ(Rect(0, 0, 2000, 1000), state.layerStackSpace.content);
+ EXPECT_EQ(Rect(0, 0, 2000, 1000), state.layerStackSpace.bounds);
+ EXPECT_EQ(ui::ROTATION_0, state.orientedDisplaySpace.orientation);
+ EXPECT_EQ(Rect(0, 0, 900, 450), state.orientedDisplaySpace.content);
+ EXPECT_EQ(Rect(0, 0, 1000, 500), state.orientedDisplaySpace.bounds);
+ EXPECT_EQ(displayRect, state.displaySpace.bounds);
+ EXPECT_EQ(Rect(0, 0, 450, 900), state.displaySpace.content);
+ EXPECT_EQ(ui::ROTATION_90, state.displaySpace.orientation);
+ EXPECT_EQ(displayRect, state.framebufferSpace.bounds);
+ EXPECT_EQ(Rect(0, 0, 450, 900), state.framebufferSpace.content);
+ EXPECT_EQ(ui::ROTATION_90, state.framebufferSpace.orientation);
+
+ EXPECT_EQ(state.displaySpace.content, state.transform.transform(state.layerStackSpace.content));
+
+ EXPECT_THAT(state.dirtyRegion, RegionEq(Region(displayRect)));
}
/*
@@ -422,7 +448,7 @@
mOutput->setRenderSurface(std::unique_ptr<RenderSurface>(renderSurface));
- EXPECT_EQ(Rect(newDisplaySize), mOutput->getState().displaySpace.bounds);
+ EXPECT_EQ(Rect(newDisplaySize), mOutput->getState().framebufferSpace.bounds);
}
/*
@@ -2778,9 +2804,10 @@
mOutput.mState.orientedDisplaySpace.content = kDefaultOutputFrame;
mOutput.mState.layerStackSpace.content = kDefaultOutputViewport;
+ mOutput.mState.framebufferSpace.content = kDefaultOutputDestinationClip;
mOutput.mState.displaySpace.content = kDefaultOutputDestinationClip;
- mOutput.mState.transform = ui::Transform{kDefaultOutputOrientationFlags};
mOutput.mState.displaySpace.orientation = kDefaultOutputOrientation;
+ mOutput.mState.transform = ui::Transform{kDefaultOutputOrientationFlags};
mOutput.mState.dataspace = kDefaultOutputDataspace;
mOutput.mState.colorTransformMatrix = kDefaultColorTransformMat;
mOutput.mState.isSecure = false;
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 7df9b76..a1ccaad 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -156,7 +156,8 @@
}
void DisplayDevice::setDisplaySize(int width, int height) {
- mCompositionDisplay->setDisplaySpaceSize(ui::Size(width, height));
+ LOG_FATAL_IF(!isVirtual(), "Changing the display size is supported only for virtual displays.");
+ mCompositionDisplay->setDisplaySize(ui::Size(width, height));
}
void DisplayDevice::setProjection(ui::Rotation orientation, Rect layerStackSpaceRect,
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 9c145cc..7b8448f 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -229,6 +229,7 @@
auto connection =
createConnectionInternal(eventThread.get(), ISurfaceComposer::eConfigChangedSuppress);
+ std::lock_guard<std::mutex> lock(mConnectionsLock);
mConnections.emplace(handle, Connection{connection, std::move(eventThread)});
return handle;
}
@@ -240,29 +241,47 @@
sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
ConnectionHandle handle, ISurfaceComposer::ConfigChanged configChanged) {
+ std::lock_guard<std::mutex> lock(mConnectionsLock);
RETURN_IF_INVALID_HANDLE(handle, nullptr);
return createConnectionInternal(mConnections[handle].thread.get(), configChanged);
}
sp<EventThreadConnection> Scheduler::getEventConnection(ConnectionHandle handle) {
+ std::lock_guard<std::mutex> lock(mConnectionsLock);
RETURN_IF_INVALID_HANDLE(handle, nullptr);
return mConnections[handle].connection;
}
void Scheduler::onHotplugReceived(ConnectionHandle handle, PhysicalDisplayId displayId,
bool connected) {
- RETURN_IF_INVALID_HANDLE(handle);
- mConnections[handle].thread->onHotplugReceived(displayId, connected);
+ android::EventThread* thread;
+ {
+ std::lock_guard<std::mutex> lock(mConnectionsLock);
+ RETURN_IF_INVALID_HANDLE(handle);
+ thread = mConnections[handle].thread.get();
+ }
+
+ thread->onHotplugReceived(displayId, connected);
}
void Scheduler::onScreenAcquired(ConnectionHandle handle) {
- RETURN_IF_INVALID_HANDLE(handle);
- mConnections[handle].thread->onScreenAcquired();
+ android::EventThread* thread;
+ {
+ std::lock_guard<std::mutex> lock(mConnectionsLock);
+ RETURN_IF_INVALID_HANDLE(handle);
+ thread = mConnections[handle].thread.get();
+ }
+ thread->onScreenAcquired();
}
void Scheduler::onScreenReleased(ConnectionHandle handle) {
- RETURN_IF_INVALID_HANDLE(handle);
- mConnections[handle].thread->onScreenReleased();
+ android::EventThread* thread;
+ {
+ std::lock_guard<std::mutex> lock(mConnectionsLock);
+ RETURN_IF_INVALID_HANDLE(handle);
+ thread = mConnections[handle].thread.get();
+ }
+ thread->onScreenReleased();
}
void Scheduler::onPrimaryDisplayConfigChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
@@ -274,6 +293,16 @@
}
void Scheduler::dispatchCachedReportedConfig() {
+ // Check optional fields first.
+ if (!mFeatures.configId.has_value()) {
+ ALOGW("No config ID found, not dispatching cached config.");
+ return;
+ }
+ if (!mFeatures.cachedConfigChangedParams.has_value()) {
+ ALOGW("No config changed params found, not dispatching cached config.");
+ return;
+ }
+
const auto configId = *mFeatures.configId;
const auto vsyncPeriod =
mRefreshRateConfigs.getRefreshRateFromConfigId(configId).getVsyncPeriod();
@@ -295,24 +324,40 @@
void Scheduler::onNonPrimaryDisplayConfigChanged(ConnectionHandle handle,
PhysicalDisplayId displayId,
HwcConfigIndexType configId, nsecs_t vsyncPeriod) {
- RETURN_IF_INVALID_HANDLE(handle);
- mConnections[handle].thread->onConfigChanged(displayId, configId, vsyncPeriod);
+ android::EventThread* thread;
+ {
+ std::lock_guard<std::mutex> lock(mConnectionsLock);
+ RETURN_IF_INVALID_HANDLE(handle);
+ thread = mConnections[handle].thread.get();
+ }
+ thread->onConfigChanged(displayId, configId, vsyncPeriod);
}
size_t Scheduler::getEventThreadConnectionCount(ConnectionHandle handle) {
+ std::lock_guard<std::mutex> lock(mConnectionsLock);
RETURN_IF_INVALID_HANDLE(handle, 0);
return mConnections[handle].thread->getEventThreadConnectionCount();
}
void Scheduler::dump(ConnectionHandle handle, std::string& result) const {
- RETURN_IF_INVALID_HANDLE(handle);
- mConnections.at(handle).thread->dump(result);
+ android::EventThread* thread;
+ {
+ std::lock_guard<std::mutex> lock(mConnectionsLock);
+ RETURN_IF_INVALID_HANDLE(handle);
+ thread = mConnections.at(handle).thread.get();
+ }
+ thread->dump(result);
}
void Scheduler::setDuration(ConnectionHandle handle, std::chrono::nanoseconds workDuration,
std::chrono::nanoseconds readyDuration) {
- RETURN_IF_INVALID_HANDLE(handle);
- mConnections[handle].thread->setDuration(workDuration, readyDuration);
+ android::EventThread* thread;
+ {
+ std::lock_guard<std::mutex> lock(mConnectionsLock);
+ RETURN_IF_INVALID_HANDLE(handle);
+ thread = mConnections[handle].thread.get();
+ }
+ thread->setDuration(workDuration, readyDuration);
}
void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats, nsecs_t now) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index da25f5c..3ecda58 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -228,7 +228,8 @@
};
ConnectionHandle::Id mNextConnectionHandleId = 0;
- std::unordered_map<ConnectionHandle, Connection> mConnections;
+ mutable std::mutex mConnectionsLock;
+ std::unordered_map<ConnectionHandle, Connection> mConnections GUARDED_BY(mConnectionsLock);
bool mInjectVSyncs = false;
InjectVSyncSource* mVSyncInjector = nullptr;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9e2ea04..8ac459b 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -6188,6 +6188,11 @@
}
sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer();
+ if (layer == nullptr) {
+ ALOGE("Attempt to set frame timeline vsync on a layer that no longer exists");
+ return BAD_VALUE;
+ }
+
layer->setFrameTimelineVsync(frameTimelineVsyncId);
return NO_ERROR;
}
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 35619a3..eee9400 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -175,4 +175,25 @@
mScheduler.chooseRefreshRateForContent();
}
+TEST_F(SchedulerTest, testDispatchCachedReportedConfig) {
+ // If the optional fields are cleared, the function should return before
+ // onConfigChange is called.
+ mScheduler.clearOptionalFieldsInFeatures();
+ EXPECT_NO_FATAL_FAILURE(mScheduler.dispatchCachedReportedConfig());
+ EXPECT_CALL(*mEventThread, onConfigChanged(_, _, _)).Times(0);
+}
+
+TEST_F(SchedulerTest, onNonPrimaryDisplayConfigChanged_invalidParameters) {
+ HwcConfigIndexType configId = HwcConfigIndexType(111);
+ nsecs_t vsyncPeriod = 111111;
+
+ // If the handle is incorrect, the function should return before
+ // onConfigChange is called.
+ Scheduler::ConnectionHandle invalidHandle = {.id = 123};
+ EXPECT_NO_FATAL_FAILURE(mScheduler.onNonPrimaryDisplayConfigChanged(invalidHandle,
+ PHYSICAL_DISPLAY_ID,
+ configId, vsyncPeriod));
+ EXPECT_CALL(*mEventThread, onConfigChanged(_, _, _)).Times(0);
+}
+
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index db3e0bd..a9d9dc0 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -16,6 +16,7 @@
#pragma once
+#include <Scheduler/Scheduler.h>
#include <gmock/gmock.h>
#include <gui/ISurfaceComposer.h>
@@ -93,6 +94,22 @@
return mFeatures.touch == Scheduler::TouchState::Active;
}
+ void dispatchCachedReportedConfig() {
+ std::lock_guard<std::mutex> lock(mFeatureStateLock);
+ return Scheduler::dispatchCachedReportedConfig();
+ }
+
+ void clearOptionalFieldsInFeatures() {
+ std::lock_guard<std::mutex> lock(mFeatureStateLock);
+ mFeatures.cachedConfigChangedParams.reset();
+ }
+
+ void onNonPrimaryDisplayConfigChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
+ HwcConfigIndexType configId, nsecs_t vsyncPeriod) {
+ return Scheduler::onNonPrimaryDisplayConfigChanged(handle, displayId, configId,
+ vsyncPeriod);
+ }
+
~TestableScheduler() {
// All these pointer and container clears help ensure that GMock does
// not report a leaked object, since the Scheduler instance may