SF: Introduce OutputLayerCompositionState
This moves the display-dependent state from LayerBE.h to a new
OutputLayerCompositionState.h header, adds some simple accessors to
get the new state, and minimally adjusts the existing SurfaceFlinger
code to use the new structure.
Test: atest libsurfaceflinger_unittest libcompositionengine_test
Bug: 121291683
Change-Id: I00370f05dc6b2a3db34094862c46084e7575dbda
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index ce6b06c..e934f8b 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -5,6 +5,7 @@
"-DLOG_TAG=\"CompositionEngine\"",
],
shared_libs: [
+ "android.frameworks.vr.composer@1.0",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
@@ -28,6 +29,9 @@
"libtrace_proto",
],
header_libs: [
+ "android.hardware.graphics.composer@2.1-command-buffer",
+ "android.hardware.graphics.composer@2.2-command-buffer",
+ "android.hardware.graphics.composer@2.3-command-buffer",
"libsurfaceflinger_headers",
],
}
@@ -46,6 +50,7 @@
"src/Output.cpp",
"src/OutputCompositionState.cpp",
"src/OutputLayer.cpp",
+ "src/OutputLayerCompositionState.cpp",
"src/RenderSurface.cpp",
],
local_include_dirs: ["include"],
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index 4b8ef38..48cb581 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -16,14 +16,22 @@
#pragma once
+#include <string>
+
#include <utils/StrongPointer.h>
-namespace android::compositionengine {
+namespace android {
+
+namespace compositionengine {
class Output;
class Layer;
class LayerFE;
+namespace impl {
+struct OutputLayerCompositionState;
+} // namespace impl
+
/**
* An output layer contains the output-dependent composition state for a layer
*/
@@ -39,6 +47,22 @@
// Gets the front-end layer interface this output layer represents
virtual LayerFE& getLayerFE() const = 0;
+
+ using CompositionState = compositionengine::impl::OutputLayerCompositionState;
+
+ // Gets the raw composition state data for the layer
+ // TODO(lpique): Make this protected once it is only internally called.
+ virtual const CompositionState& getState() const = 0;
+
+ // Allows mutable access to the raw composition state data for the layer.
+ // This is meant to be used by the various functions that are part of the
+ // composition process.
+ // TODO(lpique): Make this protected once it is only internally called.
+ virtual CompositionState& editState() = 0;
+
+ // Debugging
+ virtual void dump(std::string& result) const = 0;
};
-} // namespace android::compositionengine
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index ddeb730..2009380 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -29,8 +29,6 @@
class GraphicBuffer;
-struct CompositionInfo;
-
namespace compositionengine {
/**
@@ -70,7 +68,7 @@
virtual status_t beginFrame(bool mustRecompose) = 0;
// Prepares the frame for rendering
- virtual status_t prepareFrame(std::vector<CompositionInfo>& compositionData) = 0;
+ virtual status_t prepareFrame() = 0;
// Allocates a buffer as scratch space for GPU composition
virtual sp<GraphicBuffer> dequeueBuffer() = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index f3d0258..5798540 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -17,8 +17,10 @@
#pragma once
#include <memory>
+#include <string>
#include <compositionengine/OutputLayer.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
namespace android::compositionengine::impl {
@@ -32,10 +34,17 @@
compositionengine::Layer& getLayer() const override;
compositionengine::LayerFE& getLayerFE() const override;
+ const OutputLayerCompositionState& getState() const override;
+ OutputLayerCompositionState& editState() override;
+
+ void dump(std::string& result) const override;
+
private:
const compositionengine::Output& mOutput;
std::shared_ptr<compositionengine::Layer> mLayer;
sp<compositionengine::LayerFE> mLayerFE;
+
+ OutputLayerCompositionState mState;
};
std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
new file mode 100644
index 0000000..b78e9e0
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <optional>
+#include <string>
+
+#include <compositionengine/impl/HwcBufferCache.h>
+#include <renderengine/Mesh.h>
+#include <ui/FloatRect.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+#include "DisplayHardware/ComposerHal.h"
+
+namespace HWC2 {
+class Layer;
+} // namespace HWC2
+
+namespace android {
+
+class HWComposer;
+
+namespace compositionengine::impl {
+
+struct OutputLayerCompositionState {
+ // The region of this layer which is visible on this output
+ Region visibleRegion;
+
+ // If true, client composition will be used on this output
+ bool forceClientComposition{false};
+
+ // If true, when doing client composition, the target may need to be cleared
+ bool clearClientTarget{false};
+
+ // The display frame for this layer on this output
+ Rect displayFrame;
+
+ // The source crop for this layer on this output
+ FloatRect sourceCrop;
+
+ // The buffer transform to use for this layer o on this output.
+ Hwc2::Transform bufferTransform{static_cast<Hwc2::Transform>(0)};
+
+ // The Z order index of this layer on this output
+ uint32_t z;
+
+ /*
+ * HWC state
+ */
+
+ struct Hwc {
+ explicit Hwc(std::shared_ptr<HWC2::Layer> hwcLayer) : hwcLayer(hwcLayer) {}
+
+ // The HWC Layer backing this layer
+ std::shared_ptr<HWC2::Layer> hwcLayer;
+
+ // The HWC composition type for this layer
+ Hwc2::IComposerClient::Composition hwcCompositionType{
+ Hwc2::IComposerClient::Composition::INVALID};
+
+ // The buffer cache for this layer. This is used to lower the
+ // cost of sending reused buffers to the HWC.
+ HwcBufferCache hwcBufferCache;
+ };
+
+ // The HWC state is optional, and is only set up if there is any potential
+ // HWC acceleration possible.
+ std::optional<Hwc> hwc;
+
+ // Debugging
+ void dump(std::string& result) const;
+};
+
+} // namespace compositionengine::impl
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index 2f0fceb..58b13ed 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -51,7 +51,7 @@
void setDisplaySize(const ui::Size&) override;
void setProtected(bool useProtected) override;
status_t beginFrame(bool mustRecompose) override;
- status_t prepareFrame(std::vector<CompositionInfo>& compositionData) override;
+ status_t prepareFrame() override;
sp<GraphicBuffer> dequeueBuffer() override;
void queueBuffer(base::unique_fd&& readyFence) override;
void onPresentDisplayCompleted() override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
index f5e5026..6bd61ee 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -20,6 +20,7 @@
#include <compositionengine/LayerFE.h>
#include <compositionengine/Output.h>
#include <compositionengine/OutputLayer.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <gmock/gmock.h>
namespace android::compositionengine::mock {
@@ -32,6 +33,11 @@
MOCK_CONST_METHOD0(getOutput, const compositionengine::Output&());
MOCK_CONST_METHOD0(getLayer, compositionengine::Layer&());
MOCK_CONST_METHOD0(getLayerFE, compositionengine::LayerFE&());
+
+ MOCK_CONST_METHOD0(getState, const impl::OutputLayerCompositionState&());
+ MOCK_METHOD0(editState, impl::OutputLayerCompositionState&());
+
+ MOCK_CONST_METHOD1(dump, void(std::string&));
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index e9ff330..8442bef 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -20,7 +20,6 @@
#include <gmock/gmock.h>
#include <ui/GraphicBuffer.h>
-#include "LayerBE.h"
namespace android::compositionengine::mock {
@@ -37,7 +36,7 @@
MOCK_METHOD1(setProtected, void(bool));
MOCK_METHOD1(setBufferDataspace, void(ui::Dataspace));
MOCK_METHOD1(beginFrame, status_t(bool mustRecompose));
- MOCK_METHOD1(prepareFrame, status_t(std::vector<CompositionInfo>& compositionData));
+ MOCK_METHOD0(prepareFrame, status_t());
MOCK_METHOD0(dequeueBuffer, sp<GraphicBuffer>());
MOCK_METHOD1(queueBuffer, void(base::unique_fd&&));
MOCK_METHOD0(onPresentDisplayCompleted, void());
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index e103ebe..f97add4 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -146,6 +146,14 @@
} else {
out.append(" No render surface!\n");
}
+
+ out.append("\n %d Layers", mOutputLayersOrderedByZ.size());
+ for (const auto& outputLayer : mOutputLayersOrderedByZ) {
+ if (!outputLayer) {
+ continue;
+ }
+ outputLayer->dump(out);
+ }
}
compositionengine::DisplayColorProfile* Output::getDisplayColorProfile() const {
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index e95f3a6..78c1403 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <android-base/stringprintf.h>
#include <compositionengine/Layer.h>
#include <compositionengine/LayerFE.h>
#include <compositionengine/Output.h>
@@ -48,5 +49,20 @@
return *mLayerFE;
}
+const OutputLayerCompositionState& OutputLayer::getState() const {
+ return mState;
+}
+
+OutputLayerCompositionState& OutputLayer::editState() {
+ return mState;
+}
+
+void OutputLayer::dump(std::string& out) const {
+ using android::base::StringAppendF;
+
+ StringAppendF(&out, " Output Layer %p\n", this);
+ mState.dump(out);
+}
+
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
new file mode 100644
index 0000000..10f27b8
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright 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 <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
+
+#include "DisplayHardware/HWC2.h"
+
+namespace android::compositionengine::impl {
+
+namespace {
+
+void dumpHwc(const OutputLayerCompositionState::Hwc& hwc, std::string& out) {
+ out.append("\n hwc: ");
+
+ if (hwc.hwcLayer == nullptr) {
+ out.append("No layer ");
+ } else {
+ dumpHex(out, "layer", hwc.hwcLayer->getId());
+ }
+
+ dumpVal(out, "composition", toString(hwc.hwcCompositionType), hwc.hwcCompositionType);
+}
+
+} // namespace
+
+void OutputLayerCompositionState::dump(std::string& out) const {
+ out.append(" ");
+ dumpVal(out, "visibleRegion", visibleRegion);
+
+ out.append(" ");
+ dumpVal(out, "forceClientComposition", forceClientComposition);
+ dumpVal(out, "clearClientTarget", clearClientTarget);
+ dumpVal(out, "displayFrame", displayFrame);
+ dumpVal(out, "sourceCrop", sourceCrop);
+ dumpVal(out, "bufferTransform%", toString(bufferTransform), bufferTransform);
+ dumpVal(out, "z-index", z);
+
+ if (hwc) {
+ dumpHwc(*hwc, out);
+ }
+
+ out.append("\n");
+}
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index 3f841d2..ebb1bc2 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -99,11 +99,11 @@
return mDisplaySurface->beginFrame(mustRecompose);
}
-status_t RenderSurface::prepareFrame(std::vector<CompositionInfo>& compositionData) {
+status_t RenderSurface::prepareFrame() {
auto& hwc = mCompositionEngine.getHwComposer();
const auto id = mDisplay.getId();
if (id) {
- status_t error = hwc.prepare(*id, compositionData);
+ status_t error = hwc.prepare(*id, mDisplay);
if (error != NO_ERROR) {
return error;
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index ece412f..885cdd4 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -16,10 +16,9 @@
#pragma once
+#include <compositionengine/Output.h>
#include <gmock/gmock.h>
-#include "LayerBE.h"
-
#include "DisplayHardware/HWComposer.h"
namespace android {
@@ -41,7 +40,7 @@
std::optional<DisplayId>(uint32_t, uint32_t, ui::PixelFormat*));
MOCK_METHOD1(createLayer, HWC2::Layer*(DisplayId));
MOCK_METHOD2(destroyLayer, void(DisplayId, HWC2::Layer*));
- MOCK_METHOD2(prepare, status_t(DisplayId, std::vector<CompositionInfo>&));
+ MOCK_METHOD2(prepare, status_t(DisplayId, const compositionengine::Output&));
MOCK_METHOD5(setClientTarget,
status_t(DisplayId, uint32_t, const sp<Fence>&, const sp<GraphicBuffer>&,
ui::Dataspace));
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index c56d92a..0a7c462 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -22,6 +22,7 @@
#include <compositionengine/mock/CompositionEngine.h>
#include <compositionengine/mock/Display.h>
#include <compositionengine/mock/DisplaySurface.h>
+#include <compositionengine/mock/OutputLayer.h>
#include <gtest/gtest.h>
#include <renderengine/mock/RenderEngine.h>
#include <system/window.h>
@@ -284,64 +285,66 @@
* RenderSurface::prepareFrame()
*/
-TEST_F(RenderSurfaceTest, prepareFrameTakesEarlyOutOnHwcError) {
- std::vector<CompositionInfo> data;
-
- EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data)))
+TEST_F(RenderSurfaceTest, prepareFramePassesOutputLayersToHwc) {
+ EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
.WillOnce(Return(INVALID_OPERATION));
- EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame(data));
+ EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
+}
+
+TEST_F(RenderSurfaceTest, prepareFrameTakesEarlyOutOnHwcError) {
+ EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
+ .WillOnce(Return(INVALID_OPERATION));
+
+ EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
}
TEST_F(RenderSurfaceTest, prepareFrameHandlesMixedComposition) {
- std::vector<CompositionInfo> data;
- EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
+ .WillOnce(Return(NO_ERROR));
EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_MIXED))
.WillOnce(Return(INVALID_OPERATION));
- EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame(data));
+ EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
}
TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyGlesComposition) {
- std::vector<CompositionInfo> data;
-
- EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
+ .WillOnce(Return(NO_ERROR));
EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_GLES))
.WillOnce(Return(NO_ERROR));
- EXPECT_EQ(NO_ERROR, mSurface.prepareFrame(data));
+ EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
}
TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyHwcComposition) {
- std::vector<CompositionInfo> data;
-
- EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
+ .WillOnce(Return(NO_ERROR));
EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
.WillOnce(Return(NO_ERROR));
- EXPECT_EQ(NO_ERROR, mSurface.prepareFrame(data));
+ EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
}
TEST_F(RenderSurfaceTest, prepareFrameHandlesNoComposition) {
- std::vector<CompositionInfo> data;
-
- EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
+ .WillOnce(Return(NO_ERROR));
EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
.WillOnce(Return(NO_ERROR));
- EXPECT_EQ(NO_ERROR, mSurface.prepareFrame(data));
+ EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
}
/* ------------------------------------------------------------------------