[Mirror Layers] Added mirrorSurface API to enable mirroring (3/4)
Added a new SurfaceComposer API called mirrorSurface that allows a
client to request a mirror of a particular heirarchy starting from the
passed in layer. The API will return a SurfaceControl that's the parent
of the mirrored layer that can be updated by the client.
Test: MirrorLayerTest
Bug: 131622422
Change-Id: Ia6047f0334eabfc59d6222b2edfd4e9576ba31e5
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 6bfd302..c7ed9b0 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -106,6 +106,10 @@
nullptr, layer);
}
+status_t Client::mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle) {
+ return mFlinger->mirrorLayer(this, mirrorFromHandle, outHandle);
+}
+
status_t Client::clearLayerFrameStats(const sp<IBinder>& handle) const {
sp<Layer> layer = getLayerUser(handle);
if (layer == nullptr) {
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index 74e4818..7d7cef8 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -62,6 +62,8 @@
LayerMetadata metadata, sp<IBinder>* handle,
sp<IGraphicBufferProducer>* gbp);
+ status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* handle);
+
virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const;
virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 86e73c2..a9fad1e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3388,6 +3388,35 @@
return flags;
}
+status_t SurfaceFlinger::mirrorLayer(const sp<Client>& client, const sp<IBinder>& mirrorFromHandle,
+ sp<IBinder>* outHandle) {
+ if (!mirrorFromHandle) {
+ return NAME_NOT_FOUND;
+ }
+
+ sp<Layer> mirrorLayer;
+ sp<Layer> mirrorFrom;
+ String8 uniqueName = getUniqueLayerName(String8("MirrorRoot"));
+
+ {
+ Mutex::Autolock _l(mStateLock);
+ mirrorFrom = fromHandle(mirrorFromHandle);
+ if (!mirrorFrom) {
+ return NAME_NOT_FOUND;
+ }
+
+ status_t result = createContainerLayer(client, uniqueName, -1, -1, 0, LayerMetadata(),
+ outHandle, &mirrorLayer);
+ if (result != NO_ERROR) {
+ return result;
+ }
+
+ mirrorLayer->mClonedChild = mirrorFrom->createClone();
+ }
+
+ return addClientLayer(client, *outHandle, nullptr, mirrorLayer, nullptr, nullptr, false);
+}
+
status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& client, uint32_t w,
uint32_t h, PixelFormat format, uint32_t flags,
LayerMetadata metadata, sp<IBinder>* handle,
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 2ea8f78..a9a4276 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -623,6 +623,9 @@
uint32_t h, uint32_t flags, LayerMetadata metadata,
sp<IBinder>* outHandle, sp<Layer>* outLayer);
+ status_t mirrorLayer(const sp<Client>& client, const sp<IBinder>& mirrorFromHandle,
+ sp<IBinder>* outHandle);
+
String8 getUniqueLayerName(const String8& name);
// called when all clients have released all their references to
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index f422939..d021fc2 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -28,6 +28,7 @@
"LayerTypeAndRenderTypeTransaction_test.cpp",
"LayerTypeTransaction_test.cpp",
"LayerUpdate_test.cpp",
+ "MirrorLayer_test.cpp",
"MultiDisplayLayerBounds_test.cpp",
"RelativeZ_test.cpp",
"SetGeometry_test.cpp",
diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp
new file mode 100644
index 0000000..0bcac1a
--- /dev/null
+++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+class MirrorLayerTest : public LayerTransactionTest {
+protected:
+ virtual void SetUp() {
+ LayerTransactionTest::SetUp();
+ ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ ASSERT_FALSE(display == nullptr);
+
+ mParentLayer = createColorLayer("Parent layer", Color::RED);
+ mChildLayer = createColorLayer("Child layer", Color::GREEN, mParentLayer.get());
+ asTransaction([&](Transaction& t) {
+ t.setDisplayLayerStack(display, 0);
+ t.setLayer(mParentLayer, INT32_MAX - 2).show(mParentLayer);
+ t.setCrop_legacy(mChildLayer, Rect(0, 0, 400, 400)).show(mChildLayer);
+ t.setPosition(mChildLayer, 50, 50);
+ t.setFlags(mParentLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
+ t.setFlags(mChildLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
+ });
+ }
+
+ virtual void TearDown() {
+ LayerTransactionTest::TearDown();
+ mParentLayer = 0;
+ mChildLayer = 0;
+ }
+
+ sp<SurfaceControl> mParentLayer;
+ sp<SurfaceControl> mChildLayer;
+};
+
+TEST_F(MirrorLayerTest, MirrorColorLayer) {
+ sp<SurfaceControl> grandchild =
+ createColorLayer("Grandchild layer", Color::BLUE, mChildLayer.get());
+ Transaction()
+ .setFlags(grandchild, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque)
+ .setCrop_legacy(grandchild, Rect(0, 0, 200, 200))
+ .show(grandchild)
+ .apply();
+
+ // Mirror mChildLayer
+ sp<SurfaceControl> mirrorLayer = mClient->mirrorSurface(mChildLayer.get());
+ ASSERT_NE(mirrorLayer, nullptr);
+
+ // Add mirrorLayer as child of mParentLayer so it's shown on the display
+ Transaction()
+ .reparent(mirrorLayer, mParentLayer->getHandle())
+ .setPosition(mirrorLayer, 500, 500)
+ .show(mirrorLayer)
+ .apply();
+
+ {
+ SCOPED_TRACE("Initial Mirror");
+ auto shot = screenshot();
+ // Grandchild mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::BLUE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+
+ // Set color to white on grandchild layer.
+ Transaction().setColor(grandchild, half3{1, 1, 1}).apply();
+ {
+ SCOPED_TRACE("Updated Grandchild Layer Color");
+ auto shot = screenshot();
+ // Grandchild mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+
+ // Set color to black on child layer.
+ Transaction().setColor(mChildLayer, half3{0, 0, 0}).apply();
+ {
+ SCOPED_TRACE("Updated Child Layer Color");
+ auto shot = screenshot();
+ // Grandchild mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::BLACK);
+ }
+
+ // Remove grandchild layer
+ Transaction().reparent(grandchild, nullptr).apply();
+ {
+ SCOPED_TRACE("Removed Grandchild Layer");
+ auto shot = screenshot();
+ // Grandchild mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::BLACK);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::BLACK);
+ }
+
+ // Remove child layer
+ Transaction().reparent(mChildLayer, nullptr).apply();
+ {
+ SCOPED_TRACE("Removed Child Layer");
+ auto shot = screenshot();
+ // Grandchild mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::RED);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::RED);
+ }
+
+ // Add grandchild layer to offscreen layer
+ Transaction().reparent(grandchild, mChildLayer->getHandle()).apply();
+ {
+ SCOPED_TRACE("Added Grandchild Layer");
+ auto shot = screenshot();
+ // Grandchild mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::RED);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::RED);
+ }
+
+ // Add child layer
+ Transaction().reparent(mChildLayer, mParentLayer->getHandle()).apply();
+ {
+ SCOPED_TRACE("Added Child Layer");
+ auto shot = screenshot();
+ // Grandchild mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::BLACK);
+ }
+}
+
+TEST_F(MirrorLayerTest, MirrorBufferLayer) {
+ sp<SurfaceControl> bufferQueueLayer =
+ createLayer("BufferQueueLayer", 200, 200, 0, mChildLayer.get());
+ fillBufferQueueLayerColor(bufferQueueLayer, Color::BLUE, 200, 200);
+ Transaction().show(bufferQueueLayer).apply();
+
+ sp<SurfaceControl> mirrorLayer = mClient->mirrorSurface(mChildLayer.get());
+ Transaction()
+ .reparent(mirrorLayer, mParentLayer->getHandle())
+ .setPosition(mirrorLayer, 500, 500)
+ .show(mirrorLayer)
+ .apply();
+
+ {
+ SCOPED_TRACE("Initial Mirror BufferQueueLayer");
+ auto shot = screenshot();
+ // Buffer mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::BLUE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+
+ fillBufferQueueLayerColor(bufferQueueLayer, Color::WHITE, 200, 200);
+ {
+ SCOPED_TRACE("Update BufferQueueLayer");
+ auto shot = screenshot();
+ // Buffer mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+
+ Transaction().reparent(bufferQueueLayer, nullptr).apply();
+ {
+ SCOPED_TRACE("Removed BufferQueueLayer");
+ auto shot = screenshot();
+ // Buffer mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::GREEN);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+
+ sp<SurfaceControl> bufferStateLayer =
+ createLayer("BufferStateLayer", 200, 200, ISurfaceComposerClient::eFXSurfaceBufferState,
+ mChildLayer.get());
+ fillBufferStateLayerColor(bufferStateLayer, Color::BLUE, 200, 200);
+ Transaction().setFrame(bufferStateLayer, Rect(0, 0, 200, 200)).show(bufferStateLayer).apply();
+
+ {
+ SCOPED_TRACE("Initial Mirror BufferStateLayer");
+ auto shot = screenshot();
+ // Buffer mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::BLUE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+
+ fillBufferStateLayerColor(bufferStateLayer, Color::WHITE, 200, 200);
+ {
+ SCOPED_TRACE("Update BufferStateLayer");
+ auto shot = screenshot();
+ // Buffer mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+
+ Transaction().reparent(bufferStateLayer, nullptr).apply();
+ {
+ SCOPED_TRACE("Removed BufferStateLayer");
+ auto shot = screenshot();
+ // Buffer mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::GREEN);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+}
+
+} // namespace android