SF: Separate out render surface code
This creates a new class for the purpose of holding all the
functionality related to flipping the output display surface.
Test: atest libsurfaceflinger_unittest libcompositionengine_test
Bug: 121291683
Change-Id: I108ccb75f3cd6aa1204487b0aed7c67d9fe1b85f
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index fb783e7..ae77614 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -17,8 +17,10 @@
#include <android-base/stringprintf.h>
#include <compositionengine/CompositionEngine.h>
#include <compositionengine/DisplayCreationArgs.h>
+#include <compositionengine/DisplaySurface.h>
#include <compositionengine/impl/Display.h>
#include <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/RenderSurface.h>
#include "DisplayHardware/HWComposer.h"
@@ -107,4 +109,9 @@
Output::dumpBase(out);
}
+void Display::createRenderSurface(RenderSurfaceCreationArgs&& args) {
+ setRenderSurface(compositionengine::impl::createRenderSurface(getCompositionEngine(), *this,
+ std::move(args)));
+}
+
} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
index ba86be7..c497013 100644
--- a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
@@ -79,6 +79,10 @@
transform.dump(out, name);
}
+void dumpVal(std::string& out, const char* name, const ui::Size& size) {
+ StringAppendF(&out, "%s=[%d %d] ", name, size.width, size.height);
+}
+
void dumpVal(std::string& out, const char* name, const mat4& tr) {
StringAppendF(&out,
"%s=["
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 8b2441f..b74c5c6 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -16,6 +16,7 @@
#include <android-base/stringprintf.h>
#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/RenderSurface.h>
#include <compositionengine/impl/Output.h>
#include <ui/DebugUtils.h>
@@ -31,7 +32,7 @@
}
bool Output::isValid() const {
- return true;
+ return mRenderSurface && mRenderSurface->isValid();
}
const std::string& Output::getName() const {
@@ -63,8 +64,11 @@
dirtyEntireOutput();
}
-void Output::setBounds(const Rect& bounds) {
- mState.bounds = bounds;
+// TODO(lpique): Rename setSize() once more is moved.
+void Output::setBounds(const ui::Size& size) {
+ mRenderSurface->setDisplaySize(size);
+ // TODO(lpique): Rename mState.size once more is moved.
+ mState.bounds = Rect(mRenderSurface->getSize());
dirtyEntireOutput();
}
@@ -89,6 +93,8 @@
mState.dataspace = dataspace;
mState.renderIntent = renderIntent;
+ mRenderSurface->setBufferDataspace(dataspace);
+
ALOGV("Set active color mode: %s (%d), active render intent: %s (%d)",
decodeColorMode(mode).c_str(), mode, decodeRenderIntent(renderIntent).c_str(),
renderIntent);
@@ -106,6 +112,27 @@
void Output::dumpBase(std::string& out) const {
mState.dump(out);
+
+ if (mRenderSurface) {
+ mRenderSurface->dump(out);
+ } else {
+ out.append(" No render surface!\n");
+ }
+}
+
+compositionengine::RenderSurface* Output::getRenderSurface() const {
+ return mRenderSurface.get();
+}
+
+void Output::setRenderSurface(std::unique_ptr<compositionengine::RenderSurface> surface) {
+ mRenderSurface = std::move(surface);
+ mState.bounds = Rect(mRenderSurface->getSize());
+
+ dirtyEntireOutput();
+}
+
+void Output::setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface> surface) {
+ mRenderSurface = std::move(surface);
}
const OutputCompositionState& Output::getState() const {
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
new file mode 100644
index 0000000..d546fc8
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -0,0 +1,271 @@
+/*
+ * 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 <android-base/stringprintf.h>
+#include <android/native_window.h>
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Display.h>
+#include <compositionengine/DisplaySurface.h>
+#include <compositionengine/RenderSurfaceCreationArgs.h>
+#include <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/RenderSurface.h>
+#include <log/log.h>
+#include <renderengine/RenderEngine.h>
+#include <sync/sync.h>
+#include <system/window.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
+
+#include "DisplayHardware/HWComposer.h"
+
+namespace android::compositionengine {
+
+RenderSurface::~RenderSurface() = default;
+
+namespace impl {
+
+std::unique_ptr<compositionengine::RenderSurface> createRenderSurface(
+ const compositionengine::CompositionEngine& compositionEngine,
+ compositionengine::Display& display, compositionengine::RenderSurfaceCreationArgs&& args) {
+ return std::make_unique<RenderSurface>(compositionEngine, display, std::move(args));
+}
+
+RenderSurface::RenderSurface(const CompositionEngine& compositionEngine, Display& display,
+ RenderSurfaceCreationArgs&& args)
+ : mCompositionEngine(compositionEngine),
+ mDisplay(display),
+ mNativeWindow(args.nativeWindow),
+ mDisplaySurface(args.displaySurface),
+ mSize(args.displayWidth, args.displayHeight) {}
+
+RenderSurface::~RenderSurface() = default;
+
+bool RenderSurface::isValid() const {
+ return mSize.isValid();
+}
+
+void RenderSurface::initialize() {
+ ANativeWindow* const window = mNativeWindow.get();
+
+ int status = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
+ ALOGE_IF(status != NO_ERROR, "Unable to connect BQ producer: %d", status);
+ status = native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
+ ALOGE_IF(status != NO_ERROR, "Unable to set BQ format to RGBA888: %d", status);
+ status = native_window_set_usage(window, GRALLOC_USAGE_HW_RENDER);
+ ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for GPU rendering: %d", status);
+}
+
+const ui::Size& RenderSurface::getSize() const {
+ return mSize;
+}
+
+const sp<Fence>& RenderSurface::getClientTargetAcquireFence() const {
+ return mDisplaySurface->getClientTargetAcquireFence();
+}
+
+void RenderSurface::setDisplaySize(const ui::Size& size) {
+ mDisplaySurface->resizeBuffers(size.width, size.height);
+ mSize = size;
+}
+
+void RenderSurface::setBufferDataspace(ui::Dataspace dataspace) {
+ native_window_set_buffers_data_space(mNativeWindow.get(),
+ static_cast<android_dataspace>(dataspace));
+}
+
+void RenderSurface::setProtected(bool useProtected) {
+ uint64_t usageFlags = GRALLOC_USAGE_HW_RENDER;
+ if (useProtected) {
+ usageFlags |= GRALLOC_USAGE_PROTECTED;
+ }
+ const int status = native_window_set_usage(mNativeWindow.get(), usageFlags);
+ ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for protected content: %d", status);
+}
+
+status_t RenderSurface::beginFrame(bool mustRecompose) {
+ return mDisplaySurface->beginFrame(mustRecompose);
+}
+
+status_t RenderSurface::prepareFrame(std::vector<CompositionInfo>& compositionData) {
+ auto& hwc = mCompositionEngine.getHwComposer();
+ const auto id = mDisplay.getId();
+ if (id) {
+ status_t error = hwc.prepare(*id, compositionData);
+ if (error != NO_ERROR) {
+ return error;
+ }
+ }
+
+ DisplaySurface::CompositionType compositionType;
+ const bool hasClient = hwc.hasClientComposition(id);
+ const bool hasDevice = hwc.hasDeviceComposition(id);
+ if (hasClient && hasDevice) {
+ compositionType = DisplaySurface::COMPOSITION_MIXED;
+ } else if (hasClient) {
+ compositionType = DisplaySurface::COMPOSITION_GLES;
+ } else if (hasDevice) {
+ compositionType = DisplaySurface::COMPOSITION_HWC;
+ } else {
+ // Nothing to do -- when turning the screen off we get a frame like
+ // this. Call it a HWC frame since we won't be doing any GLES work but
+ // will do a prepare/set cycle.
+ compositionType = DisplaySurface::COMPOSITION_HWC;
+ }
+ return mDisplaySurface->prepareFrame(compositionType);
+}
+
+sp<GraphicBuffer> RenderSurface::dequeueBuffer() {
+ int fd = -1;
+ ANativeWindowBuffer* buffer = nullptr;
+
+ status_t result = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fd);
+
+ if (result != NO_ERROR) {
+ ALOGE("ANativeWindow::dequeueBuffer failed for display [%s] with error: %d",
+ mDisplay.getName().c_str(), result);
+ // Return fast here as we can't do much more - any rendering we do
+ // now will just be wrong.
+ return mGraphicBuffer;
+ }
+
+ ALOGW_IF(mGraphicBuffer != nullptr, "Clobbering a non-null pointer to a buffer [%p].",
+ mGraphicBuffer->getNativeBuffer()->handle);
+ mGraphicBuffer = GraphicBuffer::from(buffer);
+
+ // Block until the buffer is ready
+ // TODO(alecmouri): it's perhaps more appropriate to block renderengine so
+ // that the gl driver can block instead.
+ if (fd >= 0) {
+ sync_wait(fd, -1);
+ close(fd);
+ }
+
+ return mGraphicBuffer;
+}
+
+void RenderSurface::queueBuffer() {
+ auto& hwc = mCompositionEngine.getHwComposer();
+ const auto id = mDisplay.getId();
+
+ if (hwc.hasClientComposition(id) || hwc.hasFlipClientTargetRequest(id)) {
+ // hasFlipClientTargetRequest could return true even if we haven't
+ // dequeued a buffer before. Try dequeueing one if we don't have a
+ // buffer ready.
+ if (mGraphicBuffer == nullptr) {
+ ALOGI("Attempting to queue a client composited buffer without one "
+ "previously dequeued for display [%s]. Attempting to dequeue "
+ "a scratch buffer now",
+ mDisplay.getName().c_str());
+ // We shouldn't deadlock here, since mGraphicBuffer == nullptr only
+ // after a successful call to queueBuffer, or if dequeueBuffer has
+ // never been called.
+ dequeueBuffer();
+ }
+
+ if (mGraphicBuffer == nullptr) {
+ ALOGE("No buffer is ready for display [%s]", mDisplay.getName().c_str());
+ } else {
+ status_t result = mNativeWindow->queueBuffer(mNativeWindow.get(),
+ mGraphicBuffer->getNativeBuffer(),
+ dup(mBufferReady));
+ if (result != NO_ERROR) {
+ ALOGE("Error when queueing buffer for display [%s]: %d", mDisplay.getName().c_str(),
+ result);
+ // We risk blocking on dequeueBuffer if the primary display failed
+ // to queue up its buffer, so crash here.
+ if (!mDisplay.isVirtual()) {
+ LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", result);
+ } else {
+ mNativeWindow->cancelBuffer(mNativeWindow.get(),
+ mGraphicBuffer->getNativeBuffer(),
+ dup(mBufferReady));
+ }
+ }
+
+ mBufferReady.reset();
+ mGraphicBuffer = nullptr;
+ }
+ }
+
+ status_t result = mDisplaySurface->advanceFrame();
+ if (result != NO_ERROR) {
+ ALOGE("[%s] failed pushing new frame to HWC: %d", mDisplay.getName().c_str(), result);
+ }
+}
+
+void RenderSurface::onPresentDisplayCompleted() {
+ mDisplaySurface->onFrameCommitted();
+}
+
+void RenderSurface::setViewportAndProjection() {
+ auto& renderEngine = mCompositionEngine.getRenderEngine();
+ Rect sourceCrop = Rect(mSize);
+ renderEngine.setViewportAndProjection(mSize.width, mSize.height, sourceCrop,
+ ui::Transform::ROT_0);
+}
+
+void RenderSurface::finishBuffer() {
+ auto& renderEngine = mCompositionEngine.getRenderEngine();
+ mBufferReady = renderEngine.flush();
+ if (mBufferReady.get() < 0) {
+ renderEngine.finish();
+ }
+}
+
+void RenderSurface::flip() {
+ mPageFlipCount++;
+}
+
+void RenderSurface::dump(std::string& out) const {
+ using android::base::StringAppendF;
+
+ out.append(" Composition RenderSurface State:");
+
+ out.append("\n ");
+
+ dumpVal(out, "size", mSize);
+ StringAppendF(&out, "ANativeWindow=%p (format %d) ", mNativeWindow.get(),
+ ANativeWindow_getFormat(mNativeWindow.get()));
+ dumpVal(out, "flips", mPageFlipCount);
+ out.append("\n");
+
+ String8 surfaceDump;
+ mDisplaySurface->dumpAsString(surfaceDump);
+ out.append(surfaceDump);
+}
+
+std::uint32_t RenderSurface::getPageFlipCount() const {
+ return mPageFlipCount;
+}
+
+void RenderSurface::setPageFlipCountForTest(std::uint32_t count) {
+ mPageFlipCount = count;
+}
+
+void RenderSurface::setSizeForTest(const ui::Size& size) {
+ mSize = size;
+}
+
+sp<GraphicBuffer>& RenderSurface::mutableGraphicBufferForTest() {
+ return mGraphicBuffer;
+}
+
+base::unique_fd& RenderSurface::mutableBufferReadyForTest() {
+ return mBufferReady;
+}
+
+} // namespace impl
+} // namespace android::compositionengine