Use tripple buffering for compose target am: 3aa5fc5cf6
Original change: https://googleplex-android-review.googlesource.com/c/device/generic/goldfish-opengl/+/24029531
Change-Id: Ic916c84508d9c151e8e38ce2bd860748e913a0f5
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/system/hwc3/Android.mk b/system/hwc3/Android.mk
index 65d3310..fad6cd8 100644
--- a/system/hwc3/Android.mk
+++ b/system/hwc3/Android.mk
@@ -83,6 +83,7 @@
DisplayConfig.cpp \
DisplayFinder.cpp \
Drm.cpp \
+ DrmSwapchain.cpp \
DrmAtomicRequest.cpp \
DrmBuffer.cpp \
DrmClient.cpp \
diff --git a/system/hwc3/DrmSwapchain.cpp b/system/hwc3/DrmSwapchain.cpp
new file mode 100644
index 0000000..ed69225
--- /dev/null
+++ b/system/hwc3/DrmSwapchain.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2023 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 "DrmSwapchain.h"
+
+#include <log/log.h>
+#include <sync/sync.h>
+#include <ui/GraphicBufferAllocator.h>
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+DrmSwapchain::Image::Image(const native_handle_t* buffer, std::shared_ptr<DrmBuffer> drmBuffer)
+ : mBuffer(buffer), mDrmBuffer(drmBuffer) {}
+
+DrmSwapchain::Image::Image(Image&& other)
+ : mBuffer(std::move(other.mBuffer)),
+ mDrmBuffer(std::move(other.mDrmBuffer)),
+ mLastUseFenceFd(std::move(other.mLastUseFenceFd)) {
+ other.mBuffer = 0;
+}
+
+DrmSwapchain::Image::~Image() { ::android::GraphicBufferAllocator::get().free(mBuffer); }
+
+int DrmSwapchain::Image::wait() {
+ if (!mLastUseFenceFd.ok()) {
+ return 0;
+ }
+ int err = sync_wait(mLastUseFenceFd.get(), 3000);
+ mLastUseFenceFd = ::android::base::unique_fd();
+ if (err < 0 && errno == ETIME) {
+ ALOGE("%s waited on fence %d for 3000 ms", __FUNCTION__, mLastUseFenceFd.get());
+ }
+ if (err < 0) {
+ return err;
+ }
+ return 0;
+}
+
+void DrmSwapchain::Image::markAsInUse(::android::base::unique_fd useCompleteFenceFd) {
+ mLastUseFenceFd = std::move(useCompleteFenceFd);
+}
+
+const native_handle_t* DrmSwapchain::Image::getBuffer() { return mBuffer; }
+
+const std::shared_ptr<DrmBuffer> DrmSwapchain::Image::getDrmBuffer() { return mDrmBuffer; }
+
+std::unique_ptr<DrmSwapchain> DrmSwapchain::create(uint32_t width, uint32_t height, uint32_t usage,
+ DrmClient* client, uint32_t numImages) {
+ std::vector<Image> images;
+ for (uint32_t i = 0; i < numImages; i++) {
+ const uint32_t layerCount = 1;
+ buffer_handle_t handle;
+ uint32_t stride;
+ if (::android::GraphicBufferAllocator::get().allocate(
+ width, height, ::android::PIXEL_FORMAT_RGBA_8888, layerCount, usage, &handle,
+ &stride, "RanchuHwc") != ::android::OK) {
+ return nullptr;
+ }
+ auto ahb = static_cast<const native_handle_t*>(handle);
+
+ HWC3::Error drmBufferCreateError;
+ std::shared_ptr<DrmBuffer> drmBuffer;
+ if (client) {
+ std::tie(drmBufferCreateError, drmBuffer) = client->create(ahb);
+ if (drmBufferCreateError != HWC3::Error::None) {
+ ALOGE("%s: failed to create target drm ahb", __FUNCTION__);
+ return nullptr;
+ }
+ }
+
+ images.emplace_back(Image(ahb, std::move(drmBuffer)));
+ }
+ return std::unique_ptr<DrmSwapchain>(new DrmSwapchain(std::move(images)));
+}
+
+DrmSwapchain::DrmSwapchain(std::vector<Image> images) : mImages(std::move(images)) {}
+
+DrmSwapchain::Image* DrmSwapchain::getNextImage() {
+ auto index = (mLastUsedIndex + 1) % mImages.size();
+ mLastUsedIndex = index;
+ return &mImages[index];
+}
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
\ No newline at end of file
diff --git a/system/hwc3/DrmSwapchain.h b/system/hwc3/DrmSwapchain.h
new file mode 100644
index 0000000..428763e
--- /dev/null
+++ b/system/hwc3/DrmSwapchain.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+#ifndef ANDROID_HWC_DRMSWAPCHAIN_H
+#define ANDROID_HWC_DRMSWAPCHAIN_H
+
+#include <android-base/unique_fd.h>
+
+#include "Common.h"
+#include "DrmClient.h"
+
+namespace aidl::android::hardware::graphics::composer3::impl {
+
+class DrmSwapchain {
+ public:
+ class Image {
+ public:
+ Image() = delete;
+ ~Image();
+ int wait();
+ void markAsInUse(::android::base::unique_fd useCompleteFenceFd);
+ const native_handle_t* getBuffer();
+ const std::shared_ptr<DrmBuffer> getDrmBuffer();
+ Image(Image&& other);
+
+ private:
+ Image(const native_handle_t*, std::shared_ptr<DrmBuffer>);
+ const native_handle_t* mBuffer = nullptr;
+ std::shared_ptr<DrmBuffer> mDrmBuffer;
+ ::android::base::unique_fd mLastUseFenceFd;
+
+ friend class DrmSwapchain;
+ };
+
+ static std::unique_ptr<DrmSwapchain> create(uint32_t width, uint32_t height, uint32_t usage,
+ DrmClient* client, uint32_t numImages = 3);
+ Image* getNextImage();
+
+ private:
+ DrmSwapchain(std::vector<Image> images);
+ std::vector<Image> mImages;
+ uint32_t mLastUsedIndex = 0;
+};
+
+} // namespace aidl::android::hardware::graphics::composer3::impl
+
+#endif
\ No newline at end of file
diff --git a/system/hwc3/GuestFrameComposer.cpp b/system/hwc3/GuestFrameComposer.cpp
index b4eef6a..832ded9 100644
--- a/system/hwc3/GuestFrameComposer.cpp
+++ b/system/hwc3/GuestFrameComposer.cpp
@@ -489,46 +489,24 @@
}
DisplayInfo& displayInfo = mDisplayInfos[displayId];
-
- uint32_t bufferStride;
- buffer_handle_t bufferHandle;
-
- auto status = ::android::GraphicBufferAllocator::get().allocate(
- displayWidth, //
- displayHeight, //
- ::android::PIXEL_FORMAT_RGBA_8888, //
- /*layerCount=*/1, //
- ::android::GraphicBuffer::USAGE_HW_COMPOSER |
- ::android::GraphicBuffer::USAGE_SW_READ_OFTEN |
- ::android::GraphicBuffer::USAGE_SW_WRITE_OFTEN, //
- &bufferHandle, //
- &bufferStride, //
- "RanchuHwc");
- if (status != ::android::OK) {
- ALOGE("%s: failed to allocate composition buffer for display:%" PRIu64,
- __FUNCTION__, displayId);
- return HWC3::Error::NoResources;
- }
-
- displayInfo.compositionResultBuffer = bufferHandle;
-
- auto [drmBufferCreateError, drmBuffer] = mDrmClient.create(bufferHandle);
- if (drmBufferCreateError != HWC3::Error::None) {
- ALOGE("%s: failed to create drm buffer for display:%" PRIu64, __FUNCTION__,
- displayId);
- return drmBufferCreateError;
- }
- displayInfo.compositionResultDrmBuffer = std::move(drmBuffer);
+ displayInfo.swapchain = DrmSwapchain::create(displayWidth, displayHeight,
+ ::android::GraphicBuffer::USAGE_HW_COMPOSER |
+ ::android::GraphicBuffer::USAGE_SW_READ_OFTEN |
+ ::android::GraphicBuffer::USAGE_SW_WRITE_OFTEN,
+ &mDrmClient);
if (displayId == 0) {
- auto [flushError, flushSyncFd] = mDrmClient.flushToDisplay(
- displayId, displayInfo.compositionResultDrmBuffer, -1);
+ auto compositionResult = displayInfo.swapchain->getNextImage();
+ auto [flushError, flushSyncFd] =
+ mDrmClient.flushToDisplay(displayId, compositionResult->getDrmBuffer(), -1);
if (flushError != HWC3::Error::None) {
ALOGW(
"%s: Initial display flush failed. HWComposer assuming that we are "
"running in QEMU without a display and disabling presenting.",
__FUNCTION__);
mPresentDisabled = true;
+ } else {
+ compositionResult->markAsInUse(std::move(flushSyncFd));
}
}
@@ -549,14 +527,7 @@
displayId);
return HWC3::Error::BadDisplay;
}
-
- DisplayInfo& displayInfo = mDisplayInfos[displayId];
-
- ::android::GraphicBufferAllocator::get().free(
- displayInfo.compositionResultBuffer);
-
- mDisplayInfos.erase(it);
-
+ mDisplayInfos.erase(displayId);
return HWC3::Error::None;
}
@@ -727,21 +698,23 @@
}
DisplayInfo& displayInfo = it->second;
+ auto compositionResult = displayInfo.swapchain->getNextImage();
+ compositionResult->wait();
- if (displayInfo.compositionResultBuffer == nullptr) {
+ if (compositionResult->getBuffer() == nullptr) {
ALOGE("%s: display:%" PRIu64 " missing composition result buffer",
__FUNCTION__, displayId);
return HWC3::Error::NoResources;
}
- if (displayInfo.compositionResultDrmBuffer == nullptr) {
+ if (compositionResult->getDrmBuffer() == nullptr) {
ALOGE("%s: display:%" PRIu64 " missing composition result drm buffer",
__FUNCTION__, displayId);
return HWC3::Error::NoResources;
}
std::optional<GrallocBuffer> compositionResultBufferOpt =
- mGralloc.Import(displayInfo.compositionResultBuffer);
+ mGralloc.Import(compositionResult->getBuffer());
if (!compositionResultBufferOpt) {
ALOGE("%s: display:%" PRIu64 " failed to import buffer", __FUNCTION__,
displayId);
@@ -886,14 +859,16 @@
DEBUG_LOG("%s display:%" PRIu64 " flushing drm buffer", __FUNCTION__,
displayId);
- auto [error, fence] = mDrmClient.flushToDisplay(
- displayId, displayInfo.compositionResultDrmBuffer, -1);
+ auto [error, fence] = mDrmClient.flushToDisplay(displayId, compositionResult->getDrmBuffer(), -1);
if (error != HWC3::Error::None) {
ALOGE("%s: display:%" PRIu64 " failed to flush drm buffer" PRIu64,
__FUNCTION__, displayId);
}
*outDisplayFence = std::move(fence);
+ compositionResult->markAsInUse(outDisplayFence->ok()
+ ? ::android::base::unique_fd(dup(*outDisplayFence))
+ : ::android::base::unique_fd());
return error;
}
diff --git a/system/hwc3/GuestFrameComposer.h b/system/hwc3/GuestFrameComposer.h
index 2df2f32..2119735 100644
--- a/system/hwc3/GuestFrameComposer.h
+++ b/system/hwc3/GuestFrameComposer.h
@@ -20,6 +20,7 @@
#include "Common.h"
#include "Display.h"
#include "DrmClient.h"
+#include "DrmSwapchain.h"
#include "FrameComposer.h"
#include "Gralloc.h"
#include "Layer.h"
@@ -92,10 +93,8 @@
std::uint32_t dstBufferBytesPerPixel);
struct DisplayInfo {
- // Additional per display buffer for the composition result.
- buffer_handle_t compositionResultBuffer = nullptr;
-
- std::shared_ptr<DrmBuffer> compositionResultDrmBuffer;
+ // Additional per display buffers for the composition result.
+ std::unique_ptr<DrmSwapchain> swapchain = {};
};
std::unordered_map<int64_t, DisplayInfo> mDisplayInfos;
diff --git a/system/hwc3/HostFrameComposer.cpp b/system/hwc3/HostFrameComposer.cpp
index 044c081..6264052 100644
--- a/system/hwc3/HostFrameComposer.cpp
+++ b/system/hwc3/HostFrameComposer.cpp
@@ -176,23 +176,6 @@
ComposeDevice_v2* mComposeDevice;
};
-const native_handle_t* AllocateDisplayColorBuffer(int width, int height) {
- const uint32_t layerCount = 1;
- const uint64_t graphicBufferId = 0; // not used
- buffer_handle_t handle;
- uint32_t stride;
-
- if (::android::GraphicBufferAllocator::get().allocate(
- width, height, ::android::PIXEL_FORMAT_RGBA_8888, layerCount,
- ::android::GraphicBuffer::USAGE_HW_COMPOSER |
- ::android::GraphicBuffer::USAGE_HW_RENDER,
- &handle, &stride, graphicBufferId, "EmuHWC2") == ::android::OK) {
- return static_cast<const native_handle_t*>(handle);
- } else {
- return nullptr;
- }
-}
-
void FreeDisplayColorBuffer(const native_handle_t* h) {
::android::GraphicBufferAllocator::get().free(h);
}
@@ -268,29 +251,14 @@
HostComposerDisplayInfo& displayInfo = mDisplayInfos[displayId];
displayInfo.hostDisplayId = hostDisplayId;
-
- if (displayInfo.compositionResultBuffer) {
- FreeDisplayColorBuffer(displayInfo.compositionResultBuffer);
- }
- displayInfo.compositionResultBuffer =
- AllocateDisplayColorBuffer(displayWidth, displayHeight);
- if (displayInfo.compositionResultBuffer == nullptr) {
- ALOGE("%s: display:%" PRIu64 " failed to create target buffer",
- __FUNCTION__, displayId);
+ displayInfo.swapchain = DrmSwapchain::create(
+ displayWidth, displayHeight,
+ ::android::GraphicBuffer::USAGE_HW_COMPOSER | ::android::GraphicBuffer::USAGE_HW_RENDER,
+ mDrmClient ? &mDrmClient.value() : nullptr);
+ if (!displayInfo.swapchain) {
+ ALOGE("%s: display:%" PRIu64 " failed to allocate swapchain", __FUNCTION__, displayId);
return HWC3::Error::NoResources;
}
-
- if (mDrmClient) {
- auto [drmBufferCreateError, drmBuffer] =
- mDrmClient->create(displayInfo.compositionResultBuffer);
- if (drmBufferCreateError != HWC3::Error::None) {
- ALOGE("%s: display:%" PRIu64 " failed to create target drm buffer",
- __FUNCTION__, displayId);
- return HWC3::Error::NoResources;
- }
- displayInfo.compositionResultDrmBuffer = std::move(drmBuffer);
- }
-
return HWC3::Error::None;
}
@@ -413,8 +381,6 @@
hostCon->unlock();
}
- FreeDisplayColorBuffer(displayInfo.compositionResultBuffer);
-
mDisplayInfos.erase(it);
return HWC3::Error::None;
@@ -554,6 +520,7 @@
if (error != HWC3::Error::None) {
return error;
}
+ *outDisplayFence = ::android::base::unique_fd();
hostCon->lock();
bool hostCompositionV1 = rcEnc->hasHostCompositionV1();
bool hostCompositionV2 = rcEnc->hasHostCompositionV2();
@@ -564,6 +531,9 @@
hostCompositionV1 = false;
}
+ auto compositionResult = displayInfo.swapchain->getNextImage();
+ compositionResult->wait();
+
const std::vector<Layer*> layers = display->getOrderedLayers();
if (hostCompositionV2 || hostCompositionV1) {
uint32_t numLayer = 0;
@@ -672,16 +642,15 @@
layer->getZOrder(), l->composeMode, l->transform);
l++;
}
+
if (hostCompositionV1) {
p->version = 1;
- p->targetHandle = hostCon->grallocHelper()->getHostHandle(
- displayInfo.compositionResultBuffer);
+ p->targetHandle = hostCon->grallocHelper()->getHostHandle(compositionResult->getBuffer());
p->numLayers = numLayer;
} else {
p2->version = 2;
p2->displayId = displayInfo.hostDisplayId;
- p2->targetHandle = hostCon->grallocHelper()->getHostHandle(
- displayInfo.compositionResultBuffer);
+ p2->targetHandle = hostCon->grallocHelper()->getHostHandle(compositionResult->getBuffer());
p2->numLayers = numLayer;
}
@@ -732,8 +701,8 @@
}
if (mIsMinigbm) {
- auto [_, fence] = mDrmClient->flushToDisplay(
- displayId, displayInfo.compositionResultDrmBuffer, -1);
+ auto [_, fence] =
+ mDrmClient->flushToDisplay(displayId, compositionResult->getDrmBuffer(), -1);
retire_fd = std::move(fence);
} else {
int fd;
@@ -756,7 +725,6 @@
}
hostCon->unlock();
}
-
} else {
// we set all layers Composition::CLIENT, so do nothing.
FencedBuffer& displayClientTarget = display->getClientTarget();
@@ -764,8 +732,7 @@
displayClientTarget.getFence();
if (mIsMinigbm) {
auto [_, flushFence] = mDrmClient->flushToDisplay(
- displayId, displayInfo.compositionResultDrmBuffer,
- displayClientTargetFence);
+ displayId, compositionResult->getDrmBuffer(), displayClientTargetFence);
*outDisplayFence = std::move(flushFence);
} else {
rcEnc->rcSetDisplayColorBuffer(rcEnc, displayInfo.hostDisplayId,
@@ -776,6 +743,9 @@
ALOGV("%s fallback to post, returns outRetireFence %d", __FUNCTION__,
outDisplayFence->get());
}
+ compositionResult->markAsInUse(outDisplayFence->ok()
+ ? ::android::base::unique_fd(dup(*outDisplayFence))
+ : ::android::base::unique_fd());
return HWC3::Error::None;
}
diff --git a/system/hwc3/HostFrameComposer.h b/system/hwc3/HostFrameComposer.h
index aebf716..b42f480 100644
--- a/system/hwc3/HostFrameComposer.h
+++ b/system/hwc3/HostFrameComposer.h
@@ -24,6 +24,7 @@
#include "Common.h"
#include "DrmClient.h"
+#include "DrmSwapchain.h"
#include "FrameComposer.h"
#include "HostConnection.h"
@@ -87,13 +88,7 @@
struct HostComposerDisplayInfo {
uint32_t hostDisplayId = 0;
-
- // Additional per display buffer for the composition result.
- const native_handle_t* compositionResultBuffer = nullptr;
-
- // Drm info for the additional composition result buffer.
- std::shared_ptr<DrmBuffer> compositionResultDrmBuffer;
-
+ std::unique_ptr<DrmSwapchain> swapchain = {};
// Drm info for the displays client target buffer.
std::shared_ptr<DrmBuffer> clientTargetDrmBuffer;
};