[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/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index 129558b..b98e48b 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -34,7 +34,8 @@
CREATE_WITH_SURFACE_PARENT,
CLEAR_LAYER_FRAME_STATS,
GET_LAYER_FRAME_STATS,
- LAST = GET_LAYER_FRAME_STATS,
+ MIRROR_SURFACE,
+ LAST = MIRROR_SURFACE,
};
} // Anonymous namespace
@@ -80,6 +81,12 @@
&ISurfaceComposerClient::getLayerFrameStats)>(Tag::GET_LAYER_FRAME_STATS, handle,
outStats);
}
+
+ status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle) override {
+ return callRemote<decltype(&ISurfaceComposerClient::mirrorSurface)>(Tag::MIRROR_SURFACE,
+ mirrorFromHandle,
+ outHandle);
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -105,6 +112,8 @@
return callLocal(data, reply, &ISurfaceComposerClient::clearLayerFrameStats);
case Tag::GET_LAYER_FRAME_STATS:
return callLocal(data, reply, &ISurfaceComposerClient::getLayerFrameStats);
+ case Tag::MIRROR_SURFACE:
+ return callLocal(data, reply, &ISurfaceComposerClient::mirrorSurface);
}
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 547e5f1..7b256f5 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1505,6 +1505,20 @@
return err;
}
+sp<SurfaceControl> SurfaceComposerClient::mirrorSurface(SurfaceControl* mirrorFromSurface) {
+ if (mirrorFromSurface == nullptr) {
+ return nullptr;
+ }
+
+ sp<IBinder> handle;
+ sp<IBinder> mirrorFromHandle = mirrorFromSurface->getHandle();
+ status_t err = mClient->mirrorSurface(mirrorFromHandle, &handle);
+ if (err == NO_ERROR) {
+ return new SurfaceControl(this, handle, nullptr, true /* owned */);
+ }
+ return nullptr;
+}
+
status_t SurfaceComposerClient::clearLayerFrameStats(const sp<IBinder>& token) const {
if (mStatus != NO_ERROR) {
return mStatus;
diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
index 32ac9e8..5fe7ca5 100644
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -76,6 +76,8 @@
* Requires ACCESS_SURFACE_FLINGER permission
*/
virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const = 0;
+
+ virtual status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle) = 0;
};
class BnSurfaceComposerClient : public SafeBnInterface<ISurfaceComposerClient> {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 15287e2..6676be4 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -245,6 +245,17 @@
LayerMetadata metadata = LayerMetadata() // metadata
);
+ // Creates a mirrored hierarchy for the mirrorFromSurface. This returns a SurfaceControl
+ // which is a parent of the root of the mirrored hierarchy.
+ //
+ // Real Hierarchy Mirror
+ // SC (value that's returned)
+ // |
+ // A A'
+ // | |
+ // B B'
+ sp<SurfaceControl> mirrorSurface(SurfaceControl* mirrorFromSurface);
+
//! Create a virtual display
static sp<IBinder> createDisplay(const String8& displayName, bool secure);
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