Adds GuestComposer to replace Cuttlefish HWC
GuestComposer uses Gralloc and libyuv to compose in the guest.
Moves the existing drm handling into a separate DrmPresenter
which can be used by both HostComposer and GuestComposer.
Bug: b/171305898
Test: m && launch_cvd --gpu_mode=guest_swiftshader
Test: cts -m CtsCameraTestCases
Test: cts -m CtsGraphicsTestCases
Test: vts -m VtsHalGraphicsComposerV2_1TargetTest
Test: vts -m VtsHalGraphicsComposerV2_2TargetTest
Change-Id: I9e3601747455d1d735a28249c7f851bcf339fc3e
diff --git a/system/hwc2/Android.mk b/system/hwc2/Android.mk
index 805c499..29eff18 100644
--- a/system/hwc2/Android.mk
+++ b/system/hwc2/Android.mk
@@ -20,11 +20,19 @@
LOCAL_VENDOR_MODULE := true
emulator_hwcomposer_shared_libraries := \
android.hardware.graphics.mapper@2.0 \
+ android.hardware.graphics.mapper@4.0 \
libbase \
libEGL \
libcutils \
+ libcuttlefish_device_config \
+ libcuttlefish_device_config_proto \
+ libcuttlefish_utils \
+ libcuttlefish_fs \
libdrm \
+ libgralloctypes \
libhardware \
+ libhidlbase \
+ libjpeg \
liblog \
libsync \
libui \
@@ -51,12 +59,17 @@
emulator_hwcomposer2_src_files := \
Device.cpp \
Display.cpp \
+ Drm.cpp \
+ DrmPresenter.cpp \
+ Gralloc.cpp \
+ GuestComposer.cpp \
HostComposer.cpp \
Layer.cpp \
include $(CLEAR_VARS)
LOCAL_VENDOR_MODULE := true
+LOCAL_STATIC_LIBRARIES := libyuv_static
LOCAL_SHARED_LIBRARIES := $(emulator_hwcomposer_shared_libraries)
LOCAL_SHARED_LIBRARIES += libOpenglSystemCommon lib_renderControl_enc
LOCAL_SHARED_LIBRARIES += libui
diff --git a/system/hwc2/Composer.h b/system/hwc2/Composer.h
index 0595084..795504f 100644
--- a/system/hwc2/Composer.h
+++ b/system/hwc2/Composer.h
@@ -32,6 +32,8 @@
public:
virtual ~Composer() {}
+ virtual HWC2::Error init() = 0;
+
using AddDisplayToDeviceFunction =
std::function<HWC2::Error(std::unique_ptr<Display>)>;
diff --git a/system/hwc2/Device.cpp b/system/hwc2/Device.cpp
index c7339c6..91eb684 100644
--- a/system/hwc2/Device.cpp
+++ b/system/hwc2/Device.cpp
@@ -16,9 +16,13 @@
#include "Device.h"
+#include <android-base/properties.h>
+
+#include "GuestComposer.h"
#include "HostComposer.h"
namespace android {
+namespace {
template <typename PFN, typename T>
static hwc2_function_pointer_t asFP(T function) {
@@ -32,6 +36,12 @@
return 0;
}
+bool IsCuttlefish() {
+ return android::base::GetProperty("ro.hardware.vulkan", "") == "pastel";
+}
+
+} // namespace
+
Device::Device() {
DEBUG_LOG("%s", __FUNCTION__);
@@ -40,11 +50,29 @@
common.close = CloseHook;
hwc2_device_t::getCapabilities = getCapabilitiesHook;
hwc2_device_t::getFunction = getFunctionHook;
+}
- mComposer = std::make_unique<HostComposer>();
- if (!mComposer) {
- ALOGE("%s failed initialize Composer", __FUNCTION__);
+HWC2::Error Device::init() {
+ DEBUG_LOG("%s", __FUNCTION__);
+
+ if (IsCuttlefish()) {
+ mComposer = std::make_unique<GuestComposer>();
+ } else {
+ mComposer = std::make_unique<HostComposer>();
}
+
+ if (!mComposer) {
+ ALOGE("%s failed to allocate Composer", __FUNCTION__);
+ return HWC2::Error::NoResources;
+ }
+
+ HWC2::Error error = mComposer->init();
+ if (error != HWC2::Error::None) {
+ ALOGE("%s failed to initialize Composer", __FUNCTION__);
+ return HWC2::Error::NoResources;
+ }
+
+ return HWC2::Error::None;
}
Device::~Device() {
@@ -473,9 +501,15 @@
return -ENOMEM;
}
- HWC2::Error error = device->createDisplays();
+ HWC2::Error error = device->init();
if (error != HWC2::Error::None) {
- ALOGE("%s: failed to initialize device with displays.", __FUNCTION__);
+ ALOGE("%s: failed to initialize device", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ error = device->createDisplays();
+ if (error != HWC2::Error::None) {
+ ALOGE("%s: failed to initialize device displays.", __FUNCTION__);
return -EINVAL;
}
diff --git a/system/hwc2/Device.h b/system/hwc2/Device.h
index 91fa58c..7dae04b0 100644
--- a/system/hwc2/Device.h
+++ b/system/hwc2/Device.h
@@ -49,6 +49,8 @@
Device();
~Device();
+ HWC2::Error init();
+
HWC2::Error createDisplays();
private:
diff --git a/system/hwc2/Display.h b/system/hwc2/Display.h
index de715f7..6294542 100644
--- a/system/hwc2/Display.h
+++ b/system/hwc2/Display.h
@@ -55,7 +55,7 @@
FencedBuffer& getClientTarget() { return mClientTarget; }
- const std::vector<Layer*> getOrderedLayers() { return mOrderedLayers; }
+ const std::vector<Layer*>& getOrderedLayers() { return mOrderedLayers; }
HWC2::Error acceptChanges();
HWC2::Error createLayer(hwc2_layer_t* outLayerId);
diff --git a/system/hwc2/Drm.cpp b/system/hwc2/Drm.cpp
new file mode 100644
index 0000000..4b27fa2
--- /dev/null
+++ b/system/hwc2/Drm.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2020 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 "Drm.h"
+
+#include <drm_fourcc.h>
+#include <log/log.h>
+#include <system/graphics.h>
+
+namespace android {
+
+const char* GetDrmFormatString(uint32_t drm_format) {
+ switch (drm_format) {
+ case DRM_FORMAT_ABGR1555:
+ return "DRM_FORMAT_ABGR1555";
+ case DRM_FORMAT_ABGR2101010:
+ return "DRM_FORMAT_ABGR2101010";
+ case DRM_FORMAT_ABGR4444:
+ return "DRM_FORMAT_ABGR4444";
+ case DRM_FORMAT_ABGR8888:
+ return "DRM_FORMAT_ABGR8888";
+ case DRM_FORMAT_ARGB1555:
+ return "DRM_FORMAT_ARGB1555";
+ case DRM_FORMAT_ARGB2101010:
+ return "DRM_FORMAT_ARGB2101010";
+ case DRM_FORMAT_ARGB4444:
+ return "DRM_FORMAT_ARGB4444";
+ case DRM_FORMAT_ARGB8888:
+ return "DRM_FORMAT_ARGB8888";
+ case DRM_FORMAT_AYUV:
+ return "DRM_FORMAT_AYUV";
+ case DRM_FORMAT_BGR233:
+ return "DRM_FORMAT_BGR233";
+ case DRM_FORMAT_BGR565:
+ return "DRM_FORMAT_BGR565";
+ case DRM_FORMAT_BGR888:
+ return "DRM_FORMAT_BGR888";
+ case DRM_FORMAT_BGRA1010102:
+ return "DRM_FORMAT_BGRA1010102";
+ case DRM_FORMAT_BGRA4444:
+ return "DRM_FORMAT_BGRA4444";
+ case DRM_FORMAT_BGRA5551:
+ return "DRM_FORMAT_BGRA5551";
+ case DRM_FORMAT_BGRA8888:
+ return "DRM_FORMAT_BGRA8888";
+ case DRM_FORMAT_BGRX1010102:
+ return "DRM_FORMAT_BGRX1010102";
+ case DRM_FORMAT_BGRX4444:
+ return "DRM_FORMAT_BGRX4444";
+ case DRM_FORMAT_BGRX5551:
+ return "DRM_FORMAT_BGRX5551";
+ case DRM_FORMAT_BGRX8888:
+ return "DRM_FORMAT_BGRX8888";
+ case DRM_FORMAT_C8:
+ return "DRM_FORMAT_C8";
+ case DRM_FORMAT_GR88:
+ return "DRM_FORMAT_GR88";
+ case DRM_FORMAT_NV12:
+ return "DRM_FORMAT_NV12";
+ case DRM_FORMAT_NV21:
+ return "DRM_FORMAT_NV21";
+ case DRM_FORMAT_R8:
+ return "DRM_FORMAT_R8";
+ case DRM_FORMAT_RG88:
+ return "DRM_FORMAT_RG88";
+ case DRM_FORMAT_RGB332:
+ return "DRM_FORMAT_RGB332";
+ case DRM_FORMAT_RGB565:
+ return "DRM_FORMAT_RGB565";
+ case DRM_FORMAT_RGB888:
+ return "DRM_FORMAT_RGB888";
+ case DRM_FORMAT_RGBA1010102:
+ return "DRM_FORMAT_RGBA1010102";
+ case DRM_FORMAT_RGBA4444:
+ return "DRM_FORMAT_RGBA4444";
+ case DRM_FORMAT_RGBA5551:
+ return "DRM_FORMAT_RGBA5551";
+ case DRM_FORMAT_RGBA8888:
+ return "DRM_FORMAT_RGBA8888";
+ case DRM_FORMAT_RGBX1010102:
+ return "DRM_FORMAT_RGBX1010102";
+ case DRM_FORMAT_RGBX4444:
+ return "DRM_FORMAT_RGBX4444";
+ case DRM_FORMAT_RGBX5551:
+ return "DRM_FORMAT_RGBX5551";
+ case DRM_FORMAT_RGBX8888:
+ return "DRM_FORMAT_RGBX8888";
+ case DRM_FORMAT_UYVY:
+ return "DRM_FORMAT_UYVY";
+ case DRM_FORMAT_VYUY:
+ return "DRM_FORMAT_VYUY";
+ case DRM_FORMAT_XBGR1555:
+ return "DRM_FORMAT_XBGR1555";
+ case DRM_FORMAT_XBGR2101010:
+ return "DRM_FORMAT_XBGR2101010";
+ case DRM_FORMAT_XBGR4444:
+ return "DRM_FORMAT_XBGR4444";
+ case DRM_FORMAT_XBGR8888:
+ return "DRM_FORMAT_XBGR8888";
+ case DRM_FORMAT_XRGB1555:
+ return "DRM_FORMAT_XRGB1555";
+ case DRM_FORMAT_XRGB2101010:
+ return "DRM_FORMAT_XRGB2101010";
+ case DRM_FORMAT_XRGB4444:
+ return "DRM_FORMAT_XRGB4444";
+ case DRM_FORMAT_XRGB8888:
+ return "DRM_FORMAT_XRGB8888";
+ case DRM_FORMAT_YUYV:
+ return "DRM_FORMAT_YUYV";
+ case DRM_FORMAT_YVU420:
+ return "DRM_FORMAT_YVU420";
+ case DRM_FORMAT_YVYU:
+ return "DRM_FORMAT_YVYU";
+ }
+ return "Unknown";
+}
+
+int GetDrmFormatBytesPerPixel(uint32_t drm_format) {
+ switch (drm_format) {
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_XBGR8888:
+ return 4;
+ case DRM_FORMAT_BGR888:
+ return 3;
+ case DRM_FORMAT_RGB565:
+ case DRM_FORMAT_YVU420:
+#ifdef GRALLOC_MODULE_API_VERSION_0_2
+ case DRM_FORMAT_FLEX_YCbCr_420_888:
+#endif
+ return 2;
+ case DRM_FORMAT_R8:
+ return 1;
+ }
+ ALOGE("%s: format size unknown %d(%s)", __FUNCTION__, drm_format,
+ GetDrmFormatString(drm_format));
+ return 8;
+}
+
+int GetDrmFormatFromHalFormat(int hal_format) {
+ switch (hal_format) {
+ case HAL_PIXEL_FORMAT_RGBA_FP16:
+ return DRM_FORMAT_ABGR16161616F;
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ return DRM_FORMAT_ABGR8888;
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ return DRM_FORMAT_XBGR8888;
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ return DRM_FORMAT_ARGB8888;
+ case HAL_PIXEL_FORMAT_RGB_888:
+ return DRM_FORMAT_BGR888;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ return DRM_FORMAT_BGR565;
+ case HAL_PIXEL_FORMAT_YV12:
+ return DRM_FORMAT_YVU420;
+ case HAL_PIXEL_FORMAT_YCbCr_420_888:
+ return DRM_FORMAT_YVU420;
+ case HAL_PIXEL_FORMAT_BLOB:
+ return DRM_FORMAT_R8;
+ default:
+ break;
+ }
+ ALOGE("%s unhandled hal format: %d", __FUNCTION__, hal_format);
+ return 0;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/system/hwc2/Drm.h b/system/hwc2/Drm.h
new file mode 100644
index 0000000..9bc18b3
--- /dev/null
+++ b/system/hwc2/Drm.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 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_DRM_H
+#define ANDROID_HWC_DRM_H
+
+#include <cstdlib>
+
+namespace android {
+
+const char* GetDrmFormatString(uint32_t drm_format);
+
+int GetDrmFormatBytesPerPixel(uint32_t drm_format);
+
+int GetDrmFormatFromHalFormat(int hal_format);
+
+} // namespace android
+
+#endif
\ No newline at end of file
diff --git a/system/hwc2/DrmPresenter.cpp b/system/hwc2/DrmPresenter.cpp
new file mode 100644
index 0000000..1ba339d
--- /dev/null
+++ b/system/hwc2/DrmPresenter.cpp
@@ -0,0 +1,399 @@
+/*
+ * Copyright 2021 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 "DrmPresenter.h"
+
+#include <cros_gralloc_handle.h>
+
+namespace android {
+
+DrmPresenter::DrmPresenter() {}
+
+bool DrmPresenter::init() {
+ DEBUG_LOG("%s", __FUNCTION__);
+
+ drmModeRes* res;
+ drmModeConnector* conn;
+
+ mFd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
+ if (mFd < 0) {
+ ALOGE("%s HWC2::Error opening DrmPresenter device: %d", __FUNCTION__,
+ errno);
+ return false;
+ }
+
+ int univRet = drmSetClientCap(mFd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
+ if (univRet) {
+ ALOGE("%s: fail to set universal plane %d\n", __FUNCTION__, univRet);
+ }
+
+ int atomicRet = drmSetClientCap(mFd, DRM_CLIENT_CAP_ATOMIC, 1);
+ if (atomicRet) {
+ ALOGE("%s: fail to set atomic operation %d, %d\n", __FUNCTION__, atomicRet,
+ errno);
+ }
+
+ ALOGD("%s: Did set universal planes and atomic cap\n", __FUNCTION__);
+
+ res = drmModeGetResources(mFd);
+ if (res == nullptr) {
+ ALOGE("%s HWC2::Error reading drm resources: %d", __FUNCTION__, errno);
+ close(mFd);
+ mFd = -1;
+ return false;
+ }
+
+ mCrtcId = res->crtcs[0];
+ mConnectorId = res->connectors[0];
+
+ drmModePlaneResPtr plane_res = drmModeGetPlaneResources(mFd);
+ for (uint32_t i = 0; i < plane_res->count_planes; ++i) {
+ drmModePlanePtr plane = drmModeGetPlane(mFd, plane_res->planes[i]);
+ ALOGD("%s: plane id: %u crtcid %u fbid %u crtc xy %d %d xy %d %d\n",
+ __FUNCTION__, plane->plane_id, plane->crtc_id, plane->fb_id,
+ plane->crtc_x, plane->crtc_y, plane->x, plane->y);
+
+ drmModeObjectPropertiesPtr planeProps =
+ drmModeObjectGetProperties(mFd, plane->plane_id, DRM_MODE_OBJECT_PLANE);
+ bool found = false;
+ bool isPrimaryOrOverlay = false;
+ for (int i = 0; !found && (size_t)i < planeProps->count_props; ++i) {
+ drmModePropertyPtr p = drmModeGetProperty(mFd, planeProps->props[i]);
+ if (!strcmp(p->name, "CRTC_ID")) {
+ mPlaneCrtcPropertyId = p->prop_id;
+ ALOGD("%s: Found plane crtc property id. id: %u\n", __FUNCTION__,
+ mPlaneCrtcPropertyId);
+ } else if (!strcmp(p->name, "FB_ID")) {
+ mPlaneFbPropertyId = p->prop_id;
+ ALOGD("%s: Found plane fb property id. id: %u\n", __FUNCTION__,
+ mPlaneFbPropertyId);
+ } else if (!strcmp(p->name, "CRTC_X")) {
+ mPlaneCrtcXPropertyId = p->prop_id;
+ ALOGD("%s: Found plane crtc X property id. id: %u\n", __FUNCTION__,
+ mPlaneCrtcXPropertyId);
+ } else if (!strcmp(p->name, "CRTC_Y")) {
+ mPlaneCrtcYPropertyId = p->prop_id;
+ ALOGD("%s: Found plane crtc Y property id. id: %u\n", __FUNCTION__,
+ mPlaneCrtcYPropertyId);
+ } else if (!strcmp(p->name, "CRTC_W")) {
+ mPlaneCrtcWPropertyId = p->prop_id;
+ ALOGD("%s: Found plane crtc W property id. id: %u value: %u\n",
+ __FUNCTION__, mPlaneCrtcWPropertyId, (uint32_t)p->values[0]);
+ } else if (!strcmp(p->name, "CRTC_H")) {
+ mPlaneCrtcHPropertyId = p->prop_id;
+ ALOGD("%s: Found plane crtc H property id. id: %u value: %u\n",
+ __FUNCTION__, mPlaneCrtcHPropertyId, (uint32_t)p->values[0]);
+ } else if (!strcmp(p->name, "SRC_X")) {
+ mPlaneSrcXPropertyId = p->prop_id;
+ ALOGD("%s: Found plane src X property id. id: %u\n", __FUNCTION__,
+ mPlaneSrcXPropertyId);
+ } else if (!strcmp(p->name, "SRC_Y")) {
+ mPlaneSrcYPropertyId = p->prop_id;
+ ALOGD("%s: Found plane src Y property id. id: %u\n", __FUNCTION__,
+ mPlaneSrcYPropertyId);
+ } else if (!strcmp(p->name, "SRC_W")) {
+ mPlaneSrcWPropertyId = p->prop_id;
+ ALOGD("%s: Found plane src W property id. id: %u\n", __FUNCTION__,
+ mPlaneSrcWPropertyId);
+ } else if (!strcmp(p->name, "SRC_H")) {
+ mPlaneSrcHPropertyId = p->prop_id;
+ ALOGD("%s: Found plane src H property id. id: %u\n", __FUNCTION__,
+ mPlaneSrcHPropertyId);
+ } else if (!strcmp(p->name, "type")) {
+ mPlaneTypePropertyId = p->prop_id;
+ ALOGD("%s: Found plane type property id. id: %u\n", __FUNCTION__,
+ mPlaneTypePropertyId);
+ ALOGD("%s: Plane property type value 0x%llx\n", __FUNCTION__,
+ (unsigned long long)p->values[0]);
+ uint64_t type = p->values[0];
+ switch (type) {
+ case DRM_PLANE_TYPE_OVERLAY:
+ case DRM_PLANE_TYPE_PRIMARY:
+ isPrimaryOrOverlay = true;
+ ALOGD(
+ "%s: Found a primary or overlay plane. plane id: %u type "
+ "0x%llx\n",
+ __FUNCTION__, plane->plane_id, (unsigned long long)type);
+ break;
+ default:
+ break;
+ }
+ }
+ drmModeFreeProperty(p);
+ }
+ drmModeFreeObjectProperties(planeProps);
+
+ if (isPrimaryOrOverlay && ((1 << 0) & plane->possible_crtcs)) {
+ mPlaneId = plane->plane_id;
+ ALOGD("%s: found plane compatible with crtc id %d: %d\n", __FUNCTION__,
+ mCrtcId, mPlaneId);
+ drmModeFreePlane(plane);
+ break;
+ }
+
+ drmModeFreePlane(plane);
+ }
+ drmModeFreePlaneResources(plane_res);
+
+ conn = drmModeGetConnector(mFd, mConnectorId);
+ if (conn == nullptr) {
+ ALOGE("%s HWC2::Error reading drm connector %d: %d", __FUNCTION__,
+ mConnectorId, errno);
+ drmModeFreeResources(res);
+ close(mFd);
+ mFd = -1;
+ return false;
+ }
+ memcpy(&mMode, &conn->modes[0], sizeof(drmModeModeInfo));
+
+ drmModeCreatePropertyBlob(mFd, &mMode, sizeof(mMode), &mModeBlobId);
+
+ mRefreshRateAsFloat =
+ 1000.0f * mMode.clock / ((float)mMode.vtotal * (float)mMode.htotal);
+ mRefreshRateAsInteger = (uint32_t)(mRefreshRateAsFloat + 0.5f);
+
+ ALOGD(
+ "%s: using drm init. refresh rate of system is %f, rounding to %d. blob "
+ "id %d\n",
+ __FUNCTION__, mRefreshRateAsFloat, mRefreshRateAsInteger, mModeBlobId);
+
+ {
+ drmModeObjectPropertiesPtr connectorProps = drmModeObjectGetProperties(
+ mFd, mConnectorId, DRM_MODE_OBJECT_CONNECTOR);
+ bool found = false;
+ for (int i = 0; !found && (size_t)i < connectorProps->count_props; ++i) {
+ drmModePropertyPtr p = drmModeGetProperty(mFd, connectorProps->props[i]);
+ if (!strcmp(p->name, "CRTC_ID")) {
+ mConnectorCrtcPropertyId = p->prop_id;
+ ALOGD("%s: Found connector crtc id prop id: %u\n", __FUNCTION__,
+ mConnectorCrtcPropertyId);
+ found = true;
+ }
+ drmModeFreeProperty(p);
+ }
+ drmModeFreeObjectProperties(connectorProps);
+ }
+
+ {
+ drmModeObjectPropertiesPtr crtcProps =
+ drmModeObjectGetProperties(mFd, mCrtcId, DRM_MODE_OBJECT_CRTC);
+ bool found = false;
+ for (int i = 0; !found && (size_t)i < crtcProps->count_props; ++i) {
+ drmModePropertyPtr p = drmModeGetProperty(mFd, crtcProps->props[i]);
+ if (!strcmp(p->name, "OUT_FENCE_PTR")) {
+ mOutFencePtrId = p->prop_id;
+ ALOGD("%s: Found out fence ptr id. id: %u\n", __FUNCTION__,
+ mOutFencePtrId);
+ } else if (!strcmp(p->name, "ACTIVE")) {
+ mCrtcActivePropretyId = p->prop_id;
+ ALOGD("%s: Found out crtc active prop id %u\n", __FUNCTION__,
+ mCrtcActivePropretyId);
+ } else if (!strcmp(p->name, "MODE_ID")) {
+ mCrtcModeIdPropertyId = p->prop_id;
+ ALOGD("%s: Found out crtc mode id prop id %u\n", __FUNCTION__,
+ mCrtcModeIdPropertyId);
+ }
+ drmModeFreeProperty(p);
+ }
+ drmModeFreeObjectProperties(crtcProps);
+ }
+
+ drmModeFreeConnector(conn);
+ drmModeFreeResources(res);
+ ALOGD("%s: Successfully initialized DRM backend", __FUNCTION__);
+ return true;
+}
+
+DrmPresenter::~DrmPresenter() { close(mFd); }
+
+int DrmPresenter::setCrtc(hwc_drm_bo_t& bo) {
+ int ret =
+ drmModeSetCrtc(mFd, mCrtcId, bo.fb_id, 0, 0, &mConnectorId, 1, &mMode);
+ ALOGV("%s: drm FB %d", __FUNCTION__, bo.fb_id);
+ if (ret) {
+ ALOGE("%s: drmModeSetCrtc failed: %s (errno %d)", __FUNCTION__,
+ strerror(errno), errno);
+ return -1;
+ }
+ return 0;
+}
+
+int DrmPresenter::getDrmFB(hwc_drm_bo_t& bo) {
+ int ret = drmPrimeFDToHandle(mFd, bo.prime_fds[0], &bo.gem_handles[0]);
+ if (ret) {
+ ALOGE("%s: drmPrimeFDToHandle failed: %s (errno %d)", __FUNCTION__,
+ strerror(errno), errno);
+ return -1;
+ }
+ ret = drmModeAddFB2(mFd, bo.width, bo.height, bo.format, bo.gem_handles,
+ bo.pitches, bo.offsets, &bo.fb_id, 0);
+ if (ret) {
+ ALOGE("%s: drmModeAddFB2 failed: %s (errno %d)", __FUNCTION__,
+ strerror(errno), errno);
+ return -1;
+ }
+ ALOGV("%s: drm FB %d", __FUNCTION__, bo.fb_id);
+ return 0;
+}
+
+int DrmPresenter::clearDrmFB(hwc_drm_bo_t& bo) {
+ int ret = 0;
+ if (bo.fb_id) {
+ if (drmModeRmFB(mFd, bo.fb_id)) {
+ ALOGE("%s: drmModeRmFB failed: %s (errno %d)", __FUNCTION__,
+ strerror(errno), errno);
+ }
+ ret = -1;
+ }
+ if (bo.gem_handles[0]) {
+ struct drm_gem_close gem_close = {};
+ gem_close.handle = bo.gem_handles[0];
+ if (drmIoctl(mFd, DRM_IOCTL_GEM_CLOSE, &gem_close)) {
+ ALOGE("%s: DRM_IOCTL_GEM_CLOSE failed: %s (errno %d)", __FUNCTION__,
+ strerror(errno), errno);
+ }
+ ret = -1;
+ }
+ ALOGV("%s: drm FB %d", __FUNCTION__, bo.fb_id);
+ return ret;
+}
+
+bool DrmPresenter::supportComposeWithoutPost() { return true; }
+
+int DrmPresenter::exportSyncFdAndSetCrtc(hwc_drm_bo_t& bo) {
+ mOutFence = -1;
+
+ drmModeAtomicReqPtr pset = drmModeAtomicAlloc();
+
+ int ret;
+
+ if (!mDidSetCrtc) {
+ DEBUG_LOG("%s: Setting crtc.\n", __FUNCTION__);
+ ret = drmModeAtomicAddProperty(pset, mCrtcId, mCrtcActivePropretyId, 1);
+ if (ret < 0) {
+ ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
+ }
+ ret = drmModeAtomicAddProperty(pset, mCrtcId, mCrtcModeIdPropertyId,
+ mModeBlobId);
+ if (ret < 0) {
+ ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
+ }
+ ret = drmModeAtomicAddProperty(pset, mConnectorId, mConnectorCrtcPropertyId,
+ mCrtcId);
+ if (ret < 0) {
+ ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
+ }
+
+ mDidSetCrtc = true;
+ } else {
+ DEBUG_LOG("%s: Already set crtc\n", __FUNCTION__);
+ }
+
+ ret = drmModeAtomicAddProperty(pset, mCrtcId, mOutFencePtrId,
+ (uint64_t)(&mOutFence));
+ if (ret < 0) {
+ ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
+ }
+
+ DEBUG_LOG("%s: set plane: plane id %d crtcid %d fbid %d bo w h %d %d\n",
+ __FUNCTION__, mPlaneId, mCrtcId, bo.fb_id, bo.width, bo.height);
+
+ ret = drmModeAtomicAddProperty(pset, mPlaneId, mPlaneCrtcPropertyId, mCrtcId);
+ if (ret < 0) {
+ ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
+ }
+ ret = drmModeAtomicAddProperty(pset, mPlaneId, mPlaneFbPropertyId, bo.fb_id);
+ if (ret < 0) {
+ ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
+ }
+ ret = drmModeAtomicAddProperty(pset, mPlaneId, mPlaneCrtcXPropertyId, 0);
+ if (ret < 0) {
+ ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
+ }
+ ret = drmModeAtomicAddProperty(pset, mPlaneId, mPlaneCrtcYPropertyId, 0);
+ if (ret < 0) {
+ ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
+ }
+ ret =
+ drmModeAtomicAddProperty(pset, mPlaneId, mPlaneCrtcWPropertyId, bo.width);
+ if (ret < 0) {
+ ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
+ }
+ ret = drmModeAtomicAddProperty(pset, mPlaneId, mPlaneCrtcHPropertyId,
+ bo.height);
+ if (ret < 0) {
+ ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
+ }
+ ret = drmModeAtomicAddProperty(pset, mPlaneId, mPlaneSrcXPropertyId, 0);
+ if (ret < 0) {
+ ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
+ }
+ ret = drmModeAtomicAddProperty(pset, mPlaneId, mPlaneSrcYPropertyId, 0);
+ if (ret < 0) {
+ ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
+ }
+ ret = drmModeAtomicAddProperty(pset, mPlaneId, mPlaneSrcWPropertyId,
+ bo.width << 16);
+ if (ret < 0) {
+ ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
+ }
+ ret = drmModeAtomicAddProperty(pset, mPlaneId, mPlaneSrcHPropertyId,
+ bo.height << 16);
+ if (ret < 0) {
+ ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
+ }
+
+ uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
+ ret = drmModeAtomicCommit(mFd, pset, flags, 0);
+
+ if (ret) {
+ ALOGE("%s: Atomic commit failed with %d %d\n", __FUNCTION__, ret, errno);
+ }
+
+ if (pset) drmModeAtomicFree(pset);
+
+ DEBUG_LOG("%s: out fence: %d\n", __FUNCTION__, mOutFence);
+ return mOutFence;
+}
+
+DrmBuffer::DrmBuffer(const native_handle_t* handle, DrmPresenter& DrmPresenter)
+ : mDrmPresenter(DrmPresenter), mBo({}) {
+ if (!convertBoInfo(handle)) {
+ mDrmPresenter.getDrmFB(mBo);
+ }
+}
+
+DrmBuffer::~DrmBuffer() { mDrmPresenter.clearDrmFB(mBo); }
+
+int DrmBuffer::convertBoInfo(const native_handle_t* handle) {
+ cros_gralloc_handle* gr_handle = (cros_gralloc_handle*)handle;
+ if (!gr_handle) {
+ ALOGE("%s: Null buffer handle", __FUNCTION__);
+ return -1;
+ }
+ mBo.width = gr_handle->width;
+ mBo.height = gr_handle->height;
+ mBo.hal_format = gr_handle->droid_format;
+ mBo.format = gr_handle->format;
+ mBo.usage = gr_handle->usage;
+ mBo.prime_fds[0] = gr_handle->fds[0];
+ mBo.pitches[0] = gr_handle->strides[0];
+ return 0;
+}
+
+int DrmBuffer::flush() { return mDrmPresenter.exportSyncFdAndSetCrtc(mBo); }
+
+} // namespace android
\ No newline at end of file
diff --git a/system/hwc2/DrmPresenter.h b/system/hwc2/DrmPresenter.h
new file mode 100644
index 0000000..8245348
--- /dev/null
+++ b/system/hwc2/DrmPresenter.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2021 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_DRMPRESENTER_H
+#define ANDROID_HWC_DRMPRESENTER_H
+
+#include <include/drmhwcgralloc.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "Common.h"
+
+namespace android {
+
+class DrmBuffer;
+class DrmPresenter;
+
+// A RAII object that will clear a drm framebuffer upon destruction.
+class DrmBuffer {
+ public:
+ DrmBuffer(const native_handle_t* handle, DrmPresenter& drmPresenter);
+ ~DrmBuffer();
+
+ DrmBuffer(const DrmBuffer&) = delete;
+ DrmBuffer& operator=(const DrmBuffer&) = delete;
+
+ DrmBuffer(DrmBuffer&&) = delete;
+ DrmBuffer& operator=(DrmBuffer&&) = delete;
+
+ int flush();
+
+ private:
+ int convertBoInfo(const native_handle_t* handle);
+
+ DrmPresenter& mDrmPresenter;
+ hwc_drm_bo_t mBo;
+};
+
+class DrmPresenter {
+ public:
+ DrmPresenter();
+ ~DrmPresenter();
+
+ DrmPresenter(const DrmPresenter&) = delete;
+ DrmPresenter& operator=(const DrmPresenter&) = delete;
+
+ DrmPresenter(DrmPresenter&&) = delete;
+ DrmPresenter& operator=(DrmPresenter&&) = delete;
+
+ bool init();
+
+ int setCrtc(hwc_drm_bo_t& fb);
+ int getDrmFB(hwc_drm_bo_t& bo);
+ int clearDrmFB(hwc_drm_bo_t& bo);
+ bool supportComposeWithoutPost();
+ uint32_t refreshRate() const { return mRefreshRateAsInteger; }
+
+ int exportSyncFdAndSetCrtc(hwc_drm_bo_t& fb);
+
+ private:
+ drmModeModeInfo mMode;
+
+ int32_t mFd = -1;
+ uint32_t mConnectorId;
+ uint32_t mCrtcId;
+
+ uint32_t mConnectorCrtcPropertyId;
+
+ uint32_t mOutFencePtrId;
+ uint32_t mCrtcActivePropretyId;
+ uint32_t mCrtcModeIdPropertyId;
+ uint32_t mModeBlobId;
+
+ uint32_t mPlaneId;
+ uint32_t mPlaneCrtcPropertyId;
+ uint32_t mPlaneFbPropertyId;
+ uint32_t mPlaneCrtcXPropertyId;
+ uint32_t mPlaneCrtcYPropertyId;
+ uint32_t mPlaneCrtcWPropertyId;
+ uint32_t mPlaneCrtcHPropertyId;
+ uint32_t mPlaneSrcXPropertyId;
+ uint32_t mPlaneSrcYPropertyId;
+ uint32_t mPlaneSrcWPropertyId;
+ uint32_t mPlaneSrcHPropertyId;
+ uint32_t mPlaneTypePropertyId;
+
+ float mRefreshRateAsFloat;
+ uint32_t mRefreshRateAsInteger;
+
+ int mOutFence = -1;
+
+ bool mDidSetCrtc = false;
+};
+
+} // namespace android
+
+#endif
\ No newline at end of file
diff --git a/system/hwc2/Gralloc.cpp b/system/hwc2/Gralloc.cpp
new file mode 100644
index 0000000..ec33240
--- /dev/null
+++ b/system/hwc2/Gralloc.cpp
@@ -0,0 +1,493 @@
+/*
+ * Copyright (C) 2020 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 "Gralloc.h"
+
+#include <aidl/android/hardware/graphics/common/PlaneLayoutComponent.h>
+#include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.h>
+#include <drm_fourcc.h>
+#include <gralloctypes/Gralloc4.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+
+#include <algorithm>
+
+#include "Drm.h"
+
+using aidl::android::hardware::graphics::common::PlaneLayout;
+using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
+using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_vec;
+using android::hardware::graphics::common::V1_2::BufferUsage;
+using android::hardware::graphics::mapper::V4_0::Error;
+using android::hardware::graphics::mapper::V4_0::IMapper;
+using MetadataType =
+ android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
+
+namespace android {
+
+Gralloc::Gralloc() {
+ android::hardware::preloadPassthroughService<IMapper>();
+
+ gralloc4_ = IMapper::getService();
+ if (gralloc4_ != nullptr) {
+ ALOGE("%s using Gralloc4.", __FUNCTION__);
+ return;
+ }
+ ALOGE("%s Gralloc4 not available.", __FUNCTION__);
+
+ ALOGE("%s No Grallocs available!", __FUNCTION__);
+}
+
+Error Gralloc::GetMetadata(buffer_handle_t buffer, MetadataType type,
+ hidl_vec<uint8_t>* metadata) {
+ if (gralloc4_ == nullptr) {
+ ALOGE("%s Gralloc4 not available.", __FUNCTION__);
+ return Error::NO_RESOURCES;
+ }
+
+ if (metadata == nullptr) {
+ return Error::BAD_VALUE;
+ }
+
+ Error error = Error::NONE;
+
+ auto native_handle = const_cast<native_handle_t*>(buffer);
+
+ auto ret =
+ gralloc4_->get(native_handle, type,
+ [&](const auto& get_error, const auto& get_metadata) {
+ error = get_error;
+ *metadata = get_metadata;
+ });
+
+ if (!ret.isOk()) {
+ error = Error::NO_RESOURCES;
+ }
+
+ if (error != Error::NONE) {
+ ALOGE("%s failed to get metadata %s", __FUNCTION__, type.name.c_str());
+ }
+ return error;
+}
+
+std::optional<uint32_t> Gralloc::GetWidth(buffer_handle_t buffer) {
+ if (gralloc4_ == nullptr) {
+ ALOGE("%s Gralloc4 not available.", __FUNCTION__);
+ return std::nullopt;
+ }
+
+ hidl_vec<uint8_t> encoded_width;
+
+ Error error = GetMetadata(buffer, android::gralloc4::MetadataType_Width,
+ &encoded_width);
+ if (error != Error::NONE) {
+ return std::nullopt;
+ }
+
+ uint64_t width = 0;
+ android::gralloc4::decodeWidth(encoded_width, &width);
+ return static_cast<uint32_t>(width);
+}
+
+std::optional<uint32_t> Gralloc::GetHeight(buffer_handle_t buffer) {
+ if (gralloc4_ == nullptr) {
+ ALOGE("%s Gralloc4 not available.", __FUNCTION__);
+ return std::nullopt;
+ }
+
+ hidl_vec<uint8_t> encoded_height;
+
+ Error error = GetMetadata(buffer, android::gralloc4::MetadataType_Height,
+ &encoded_height);
+ if (error != Error::NONE) {
+ return std::nullopt;
+ }
+
+ uint64_t height = 0;
+ android::gralloc4::decodeHeight(encoded_height, &height);
+ return static_cast<uint32_t>(height);
+}
+
+std::optional<uint32_t> Gralloc::GetDrmFormat(buffer_handle_t buffer) {
+ if (gralloc4_ == nullptr) {
+ ALOGE("%s Gralloc4 not available.", __FUNCTION__);
+ return std::nullopt;
+ }
+
+ hidl_vec<uint8_t> encoded_format;
+
+ Error error =
+ GetMetadata(buffer, android::gralloc4::MetadataType_PixelFormatFourCC,
+ &encoded_format);
+ if (error != Error::NONE) {
+ return std::nullopt;
+ }
+
+ uint32_t format = 0;
+ android::gralloc4::decodePixelFormatFourCC(encoded_format, &format);
+ return static_cast<uint32_t>(format);
+}
+
+std::optional<std::vector<PlaneLayout>> Gralloc::GetPlaneLayouts(
+ buffer_handle_t buffer) {
+ if (gralloc4_ == nullptr) {
+ ALOGE("%s Gralloc4 not available.", __FUNCTION__);
+ return std::nullopt;
+ }
+
+ hidl_vec<uint8_t> encoded_layouts;
+
+ Error error = GetMetadata(
+ buffer, android::gralloc4::MetadataType_PlaneLayouts, &encoded_layouts);
+ if (error != Error::NONE) {
+ return std::nullopt;
+ }
+
+ std::vector<PlaneLayout> plane_layouts;
+ android::gralloc4::decodePlaneLayouts(encoded_layouts, &plane_layouts);
+ return plane_layouts;
+}
+
+std::optional<uint32_t> Gralloc::GetMonoPlanarStrideBytes(
+ buffer_handle_t buffer) {
+ if (gralloc4_ == nullptr) {
+ ALOGE("%s Gralloc4 not available.", __FUNCTION__);
+ return std::nullopt;
+ }
+
+ auto plane_layouts_opt = GetPlaneLayouts(buffer);
+ if (!plane_layouts_opt) {
+ return std::nullopt;
+ }
+
+ std::vector<PlaneLayout>& plane_layouts = *plane_layouts_opt;
+ if (plane_layouts.size() != 1) {
+ return std::nullopt;
+ }
+
+ return static_cast<uint32_t>(plane_layouts[0].strideInBytes);
+}
+
+std::optional<GrallocBuffer> Gralloc::Import(buffer_handle_t buffer) {
+ if (gralloc4_ == nullptr) {
+ ALOGE("%s Gralloc4 not available.", __FUNCTION__);
+ return std::nullopt;
+ }
+
+ buffer_handle_t imported_buffer;
+
+ Error error;
+ auto ret =
+ gralloc4_->importBuffer(buffer, [&](const auto& err, const auto& buf) {
+ error = err;
+ if (err == Error::NONE) {
+ imported_buffer = static_cast<buffer_handle_t>(buf);
+ }
+ });
+
+ if (!ret.isOk() || error != Error::NONE) {
+ ALOGE("%s failed to import buffer", __FUNCTION__);
+ return std::nullopt;
+ }
+ return GrallocBuffer(this, imported_buffer);
+}
+
+void Gralloc::Release(buffer_handle_t buffer) {
+ if (gralloc4_ == nullptr) {
+ ALOGE("%s Gralloc4 not available.", __FUNCTION__);
+ return;
+ }
+
+ auto native_buffer = const_cast<native_handle_t*>(buffer);
+ auto ret = gralloc4_->freeBuffer(native_buffer);
+
+ if (!ret.isOk()) {
+ ALOGE("%s failed to release buffer", __FUNCTION__);
+ }
+}
+
+std::optional<void*> Gralloc::Lock(buffer_handle_t buffer) {
+ if (gralloc4_ == nullptr) {
+ ALOGE("%s Gralloc4 not available.", __FUNCTION__);
+ return std::nullopt;
+ }
+
+ auto native_buffer = const_cast<native_handle_t*>(buffer);
+
+ const auto buffer_usage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN |
+ BufferUsage::CPU_WRITE_OFTEN);
+
+ auto width_opt = GetWidth(buffer);
+ if (!width_opt) {
+ return std::nullopt;
+ }
+
+ auto height_opt = GetHeight(buffer);
+ if (!height_opt) {
+ return std::nullopt;
+ }
+
+ IMapper::Rect buffer_region;
+ buffer_region.left = 0;
+ buffer_region.top = 0;
+ buffer_region.width = *width_opt;
+ buffer_region.height = *height_opt;
+
+ // Empty fence, lock immedietly.
+ hidl_handle fence;
+
+ Error error = Error::NONE;
+ void* data = nullptr;
+
+ auto ret =
+ gralloc4_->lock(native_buffer, buffer_usage, buffer_region, fence,
+ [&](const auto& lock_error, const auto& lock_data) {
+ error = lock_error;
+ if (lock_error == Error::NONE) {
+ data = lock_data;
+ }
+ });
+
+ if (!ret.isOk()) {
+ error = Error::NO_RESOURCES;
+ }
+
+ if (error != Error::NONE) {
+ ALOGE("%s failed to lock buffer", __FUNCTION__);
+ return std::nullopt;
+ }
+
+ return data;
+}
+
+std::optional<android_ycbcr> Gralloc::LockYCbCr(buffer_handle_t buffer) {
+ if (gralloc4_ == nullptr) {
+ ALOGE("%s Gralloc4 not available.", __FUNCTION__);
+ return std::nullopt;
+ }
+
+ auto format_opt = GetDrmFormat(buffer);
+ if (!format_opt) {
+ ALOGE("%s failed to check format of buffer", __FUNCTION__);
+ return std::nullopt;
+ }
+
+ if (*format_opt != DRM_FORMAT_NV12 && *format_opt != DRM_FORMAT_NV21 &&
+ *format_opt != DRM_FORMAT_YVU420) {
+ ALOGE("%s called on non-ycbcr buffer", __FUNCTION__);
+ return std::nullopt;
+ }
+
+ auto lock_opt = Lock(buffer);
+ if (!lock_opt) {
+ ALOGE("%s failed to lock buffer", __FUNCTION__);
+ return std::nullopt;
+ }
+
+ auto plane_layouts_opt = GetPlaneLayouts(buffer);
+ if (!plane_layouts_opt) {
+ ALOGE("%s failed to get plane layouts", __FUNCTION__);
+ return std::nullopt;
+ }
+
+ android_ycbcr buffer_ycbcr;
+ buffer_ycbcr.y = nullptr;
+ buffer_ycbcr.cb = nullptr;
+ buffer_ycbcr.cr = nullptr;
+ buffer_ycbcr.ystride = 0;
+ buffer_ycbcr.cstride = 0;
+ buffer_ycbcr.chroma_step = 0;
+
+ for (const auto& plane_layout : *plane_layouts_opt) {
+ for (const auto& plane_layout_component : plane_layout.components) {
+ const auto& type = plane_layout_component.type;
+
+ if (!android::gralloc4::isStandardPlaneLayoutComponentType(type)) {
+ continue;
+ }
+
+ auto* component_data = reinterpret_cast<uint8_t*>(*lock_opt) +
+ plane_layout.offsetInBytes +
+ plane_layout_component.offsetInBits / 8;
+
+ switch (static_cast<PlaneLayoutComponentType>(type.value)) {
+ case PlaneLayoutComponentType::Y:
+ buffer_ycbcr.y = component_data;
+ buffer_ycbcr.ystride = plane_layout.strideInBytes;
+ break;
+ case PlaneLayoutComponentType::CB:
+ buffer_ycbcr.cb = component_data;
+ buffer_ycbcr.cstride = plane_layout.strideInBytes;
+ buffer_ycbcr.chroma_step = plane_layout.sampleIncrementInBits / 8;
+ break;
+ case PlaneLayoutComponentType::CR:
+ buffer_ycbcr.cr = component_data;
+ buffer_ycbcr.cstride = plane_layout.strideInBytes;
+ buffer_ycbcr.chroma_step = plane_layout.sampleIncrementInBits / 8;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ return buffer_ycbcr;
+}
+
+void Gralloc::Unlock(buffer_handle_t buffer) {
+ if (gralloc4_ == nullptr) {
+ ALOGE("%s Gralloc4 not available.", __FUNCTION__);
+ return;
+ }
+
+ auto native_handle = const_cast<native_handle_t*>(buffer);
+
+ Error error = Error::NONE;
+ auto ret = gralloc4_->unlock(
+ native_handle,
+ [&](const auto& unlock_error, const auto&) { error = unlock_error; });
+
+ if (!ret.isOk()) {
+ error = Error::NO_RESOURCES;
+ }
+
+ if (error != Error::NONE) {
+ ALOGE("%s failed to unlock buffer", __FUNCTION__);
+ }
+}
+
+GrallocBuffer::GrallocBuffer(Gralloc* gralloc, buffer_handle_t buffer)
+ : gralloc_(gralloc), buffer_(buffer) {}
+
+GrallocBuffer::~GrallocBuffer() { Release(); }
+
+GrallocBuffer::GrallocBuffer(GrallocBuffer&& rhs) { *this = std::move(rhs); }
+
+GrallocBuffer& GrallocBuffer::operator=(GrallocBuffer&& rhs) {
+ gralloc_ = rhs.gralloc_;
+ buffer_ = rhs.buffer_;
+ rhs.gralloc_ = nullptr;
+ rhs.buffer_ = nullptr;
+ return *this;
+}
+
+void GrallocBuffer::Release() {
+ if (gralloc_ && buffer_) {
+ gralloc_->Release(buffer_);
+ gralloc_ = nullptr;
+ buffer_ = nullptr;
+ }
+}
+
+std::optional<GrallocBufferView> GrallocBuffer::Lock() {
+ if (gralloc_ && buffer_) {
+ auto format_opt = GetDrmFormat();
+ if (!format_opt) {
+ ALOGE("%s failed to check format of buffer", __FUNCTION__);
+ return std::nullopt;
+ }
+ if (*format_opt != DRM_FORMAT_NV12 && *format_opt != DRM_FORMAT_NV21 &&
+ *format_opt != DRM_FORMAT_YVU420) {
+ auto locked_opt = gralloc_->Lock(buffer_);
+ if (!locked_opt) {
+ return std::nullopt;
+ }
+ return GrallocBufferView(this, *locked_opt);
+ } else {
+ auto locked_ycbcr_opt = gralloc_->LockYCbCr(buffer_);
+ if (!locked_ycbcr_opt) {
+ ALOGE("%s failed to lock ycbcr buffer", __FUNCTION__);
+ return std::nullopt;
+ }
+ return GrallocBufferView(this, *locked_ycbcr_opt);
+ }
+ }
+ return std::nullopt;
+}
+
+void GrallocBuffer::Unlock() {
+ if (gralloc_ && buffer_) {
+ gralloc_->Unlock(buffer_);
+ }
+}
+
+std::optional<uint32_t> GrallocBuffer::GetWidth() {
+ if (gralloc_ && buffer_) {
+ return gralloc_->GetWidth(buffer_);
+ }
+ return std::nullopt;
+}
+
+std::optional<uint32_t> GrallocBuffer::GetHeight() {
+ if (gralloc_ && buffer_) {
+ return gralloc_->GetHeight(buffer_);
+ }
+ return std::nullopt;
+}
+
+std::optional<uint32_t> GrallocBuffer::GetDrmFormat() {
+ if (gralloc_ && buffer_) {
+ return gralloc_->GetDrmFormat(buffer_);
+ }
+ return std::nullopt;
+}
+
+std::optional<std::vector<PlaneLayout>> GrallocBuffer::GetPlaneLayouts() {
+ if (gralloc_ && buffer_) {
+ return gralloc_->GetPlaneLayouts(buffer_);
+ }
+ return std::nullopt;
+}
+
+std::optional<uint32_t> GrallocBuffer::GetMonoPlanarStrideBytes() {
+ if (gralloc_ && buffer_) {
+ return gralloc_->GetMonoPlanarStrideBytes(buffer_);
+ }
+ return std::nullopt;
+}
+
+GrallocBufferView::GrallocBufferView(GrallocBuffer* buffer, void* raw)
+ : gralloc_buffer_(buffer), locked_(raw) {}
+
+GrallocBufferView::GrallocBufferView(GrallocBuffer* buffer, android_ycbcr raw)
+ : gralloc_buffer_(buffer), locked_ycbcr_(raw) {}
+
+GrallocBufferView::~GrallocBufferView() {
+ if (gralloc_buffer_) {
+ gralloc_buffer_->Unlock();
+ }
+}
+
+GrallocBufferView::GrallocBufferView(GrallocBufferView&& rhs) {
+ *this = std::move(rhs);
+}
+
+GrallocBufferView& GrallocBufferView::operator=(GrallocBufferView&& rhs) {
+ std::swap(gralloc_buffer_, rhs.gralloc_buffer_);
+ std::swap(locked_, rhs.locked_);
+ std::swap(locked_ycbcr_, rhs.locked_ycbcr_);
+ return *this;
+}
+
+const std::optional<void*> GrallocBufferView::Get() const { return locked_; }
+
+const std::optional<android_ycbcr>& GrallocBufferView::GetYCbCr() const {
+ return locked_ycbcr_;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/system/hwc2/Gralloc.h b/system/hwc2/Gralloc.h
new file mode 100644
index 0000000..e62281e
--- /dev/null
+++ b/system/hwc2/Gralloc.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2020 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_GRALLOC_H
+#define ANDROID_HWC_GRALLOC_H
+
+#include <aidl/android/hardware/graphics/common/PlaneLayout.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
+#include <hardware/gralloc.h>
+#include <system/graphics.h>
+#include <utils/StrongPointer.h>
+
+#include <memory>
+#include <optional>
+#include <vector>
+
+namespace android {
+
+class Gralloc;
+class GrallocBuffer;
+
+// An RAII object that will Unlock() a GrallocBuffer upon destruction.
+class GrallocBufferView {
+ public:
+ virtual ~GrallocBufferView();
+
+ GrallocBufferView(const GrallocBufferView& rhs) = delete;
+ GrallocBufferView& operator=(const GrallocBufferView& rhs) = delete;
+
+ GrallocBufferView(GrallocBufferView&& rhs);
+ GrallocBufferView& operator=(GrallocBufferView&& rhs);
+
+ const std::optional<void*> Get() const;
+
+ const std::optional<android_ycbcr>& GetYCbCr() const;
+
+ private:
+ friend class GrallocBuffer;
+ GrallocBufferView(GrallocBuffer* buffer, void* raw);
+ GrallocBufferView(GrallocBuffer* buffer, android_ycbcr raw);
+
+ // The GrallocBuffer that should be unlocked upon destruction of this object.
+ GrallocBuffer* gralloc_buffer_ = nullptr;
+
+ std::optional<void*> locked_;
+ std::optional<android_ycbcr> locked_ycbcr_;
+};
+
+// A gralloc 4.0 buffer that has been imported in the current process and
+// that will be released upon destruction. Users must ensure that the Gralloc
+// instance that this buffer is created with out lives this buffer.
+class GrallocBuffer {
+ public:
+ GrallocBuffer(Gralloc* gralloc, buffer_handle_t buffer);
+ virtual ~GrallocBuffer();
+
+ GrallocBuffer(const GrallocBuffer& rhs) = delete;
+ GrallocBuffer& operator=(const GrallocBuffer& rhs) = delete;
+
+ GrallocBuffer(GrallocBuffer&& rhs);
+ GrallocBuffer& operator=(GrallocBuffer&& rhs);
+
+ // Locks the buffer for reading and returns a view if successful.
+ std::optional<GrallocBufferView> Lock();
+
+ std::optional<uint32_t> GetWidth();
+ std::optional<uint32_t> GetHeight();
+ std::optional<uint32_t> GetDrmFormat();
+
+ // Returns the stride of the buffer if it is a single plane buffer or fails
+ // and returns nullopt if the buffer is for a multi plane buffer.
+ std::optional<uint32_t> GetMonoPlanarStrideBytes();
+
+ private:
+ // Internal visibility for Unlock().
+ friend class GrallocBufferView;
+
+ // Unlocks the buffer from reading.
+ void Unlock();
+
+ std::optional<
+ std::vector<aidl::android::hardware::graphics::common::PlaneLayout>>
+ GetPlaneLayouts();
+
+ void Release();
+
+ Gralloc* gralloc_ = nullptr;
+ buffer_handle_t buffer_ = nullptr;
+};
+
+class Gralloc {
+ public:
+ Gralloc();
+ virtual ~Gralloc() = default;
+
+ // Imports the given buffer handle into the current process and returns an
+ // imported buffer which can be used for reading. Users must ensure that the
+ // Gralloc instance outlives any GrallocBuffers.
+ std::optional<GrallocBuffer> Import(buffer_handle_t buffer);
+
+ private:
+ // The below functions are made avaialble only to GrallocBuffer so that
+ // users only call gralloc functions on *imported* buffers.
+ friend class GrallocBuffer;
+
+ // See GrallocBuffer::Release.
+ void Release(buffer_handle_t buffer);
+
+ // See GrallocBuffer::Lock.
+ std::optional<void*> Lock(buffer_handle_t buffer);
+
+ // See GrallocBuffer::LockYCbCr.
+ std::optional<android_ycbcr> LockYCbCr(buffer_handle_t buffer);
+
+ // See GrallocBuffer::Unlock.
+ void Unlock(buffer_handle_t buffer);
+
+ // See GrallocBuffer::GetWidth.
+ std::optional<uint32_t> GetWidth(buffer_handle_t buffer);
+
+ // See GrallocBuffer::GetHeight.
+ std::optional<uint32_t> GetHeight(buffer_handle_t buffer);
+
+ // See GrallocBuffer::GetDrmFormat.
+ std::optional<uint32_t> GetDrmFormat(buffer_handle_t buffer);
+
+ // See GrallocBuffer::GetPlaneLayouts.
+ std::optional<
+ std::vector<aidl::android::hardware::graphics::common::PlaneLayout>>
+ GetPlaneLayouts(buffer_handle_t buffer);
+
+ // Returns the stride of the buffer if it is a single plane buffer or fails
+ // and returns nullopt if the buffer is for a multi plane buffer.
+ std::optional<uint32_t> GetMonoPlanarStrideBytes(buffer_handle_t);
+
+ // See GrallocBuffer::GetMetadata.
+ android::hardware::graphics::mapper::V4_0::Error GetMetadata(
+ buffer_handle_t buffer,
+ android::hardware::graphics::mapper::V4_0::IMapper::MetadataType type,
+ android::hardware::hidl_vec<uint8_t>* metadata);
+
+ android::sp<android::hardware::graphics::mapper::V4_0::IMapper> gralloc4_;
+};
+
+} // namespace android
+
+#endif
\ No newline at end of file
diff --git a/system/hwc2/GuestComposer.cpp b/system/hwc2/GuestComposer.cpp
new file mode 100644
index 0000000..1b8d09a
--- /dev/null
+++ b/system/hwc2/GuestComposer.cpp
@@ -0,0 +1,975 @@
+/*
+ * Copyright 2021 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 "GuestComposer.h"
+
+#include <android-base/parseint.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <device_config_shared.h>
+#include <drm_fourcc.h>
+#include <libyuv.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicBufferMapper.h>
+
+#include "Device.h"
+#include "Display.h"
+#include "Drm.h"
+#include "Layer.h"
+
+namespace android {
+namespace {
+
+uint64_t AlignToPower2(uint64_t val, uint8_t align_log) {
+ uint64_t align = 1ULL << align_log;
+ return ((val + (align - 1)) / align) * align;
+}
+
+bool LayerNeedsScaling(const Layer& layer) {
+ hwc_rect_t crop = layer.getSourceCropInt();
+ hwc_rect_t frame = layer.getDisplayFrame();
+
+ int fromW = crop.right - crop.left;
+ int fromH = crop.bottom - crop.top;
+ int toW = frame.right - frame.left;
+ int toH = frame.bottom - frame.top;
+
+ bool not_rot_scale = fromW != toW || fromH != toH;
+ bool rot_scale = fromW != toH || fromH != toW;
+
+ bool needs_rot = layer.getTransform() & HAL_TRANSFORM_ROT_90;
+
+ return needs_rot ? rot_scale : not_rot_scale;
+}
+
+bool LayerNeedsBlending(const Layer& layer) {
+ return layer.getBlendMode() != HWC2::BlendMode::None;
+}
+
+bool LayerNeedsAttenuation(const Layer& layer) {
+ return layer.getBlendMode() == HWC2::BlendMode::Coverage;
+}
+
+struct BufferSpec;
+typedef int (*ConverterFunction)(const BufferSpec& src, const BufferSpec& dst,
+ bool v_flip);
+int DoCopy(const BufferSpec& src, const BufferSpec& dst, bool v_flip);
+int ConvertFromYV12(const BufferSpec& src, const BufferSpec& dst, bool v_flip);
+
+ConverterFunction GetConverterForDrmFormat(uint32_t drmFormat) {
+ switch (drmFormat) {
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_XBGR8888:
+ return &DoCopy;
+ case DRM_FORMAT_YVU420:
+ return &ConvertFromYV12;
+ }
+ ALOGW("Unsupported drm format: %d(%s), returning null converter", drmFormat,
+ GetDrmFormatString(drmFormat));
+ return nullptr;
+}
+
+bool IsDrmFormatSupported(uint32_t drmFormat) {
+ return GetConverterForDrmFormat(drmFormat) != nullptr;
+}
+
+// Libyuv's convert functions only allow the combination of any rotation
+// (multiple of 90 degrees) and a vertical flip, but not horizontal flips.
+// Surfaceflinger's transformations are expressed in terms of a vertical flip,
+// a horizontal flip and/or a single 90 degrees clockwise rotation (see
+// NATIVE_WINDOW_TRANSFORM_HINT documentation on system/window.h for more
+// insight). The following code allows to turn a horizontal flip into a 180
+// degrees rotation and a vertical flip.
+libyuv::RotationMode GetRotationFromTransform(uint32_t transform) {
+ uint32_t rotation =
+ (transform & HAL_TRANSFORM_ROT_90) ? 1 : 0; // 1 * ROT90 bit
+ rotation += (transform & HAL_TRANSFORM_FLIP_H) ? 2 : 0; // 2 * VFLIP bit
+ return static_cast<libyuv::RotationMode>(90 * rotation);
+}
+
+bool GetVFlipFromTransform(uint32_t transform) {
+ // vertical flip xor horizontal flip
+ return ((transform & HAL_TRANSFORM_FLIP_V) >> 1) ^
+ (transform & HAL_TRANSFORM_FLIP_H);
+}
+
+struct BufferSpec {
+ uint8_t* buffer;
+ std::optional<android_ycbcr> buffer_ycbcr;
+ int width;
+ int height;
+ int cropX;
+ int cropY;
+ int cropWidth;
+ int cropHeight;
+ uint32_t drmFormat;
+ int strideBytes;
+ int sampleBytes;
+
+ BufferSpec(uint8_t* buffer, std::optional<android_ycbcr> buffer_ycbcr,
+ int width, int height, int cropX, int cropY, int cropWidth,
+ int cropHeight, uint32_t drmFormat, int strideBytes,
+ int sampleBytes)
+ : buffer(buffer),
+ buffer_ycbcr(buffer_ycbcr),
+ width(width),
+ height(height),
+ cropX(cropX),
+ cropY(cropY),
+ cropWidth(cropWidth),
+ cropHeight(cropHeight),
+ drmFormat(drmFormat),
+ strideBytes(strideBytes),
+ sampleBytes(sampleBytes) {}
+
+ BufferSpec(uint8_t* buffer, int width, int height, int strideBytes)
+ : BufferSpec(buffer,
+ /*buffer_ycbcr=*/std::nullopt, width, height,
+ /*cropX=*/0,
+ /*cropY=*/0,
+ /*cropWidth=*/width,
+ /*cropHeight=*/height,
+ /*drmFormat=*/DRM_FORMAT_ABGR8888, strideBytes,
+ /*sampleBytes=*/4) {}
+};
+
+int ConvertFromYV12(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
+ // The following calculation of plane offsets and alignments are based on
+ // swiftshader's Sampler::setTextureLevel() implementation
+ // (Renderer/Sampler.cpp:225)
+
+ auto& srcBufferYCbCrOpt = src.buffer_ycbcr;
+ if (!srcBufferYCbCrOpt) {
+ ALOGE("%s called on non ycbcr buffer", __FUNCTION__);
+ return -1;
+ }
+ auto& srcBufferYCbCr = *srcBufferYCbCrOpt;
+
+ // The libyuv::I420ToARGB() function is for tri-planar.
+ if (srcBufferYCbCr.chroma_step != 1) {
+ ALOGE("%s called with bad chroma step", __FUNCTION__);
+ return -1;
+ }
+
+ uint8_t* srcY = reinterpret_cast<uint8_t*>(srcBufferYCbCr.y);
+ int strideY = srcBufferYCbCr.ystride;
+ uint8_t* srcU = reinterpret_cast<uint8_t*>(srcBufferYCbCr.cb);
+ int strideU = srcBufferYCbCr.cstride;
+ uint8_t* srcV = reinterpret_cast<uint8_t*>(srcBufferYCbCr.cr);
+ int strideV = srcBufferYCbCr.cstride;
+
+ // Adjust for crop
+ srcY += src.cropY * strideY + src.cropX;
+ srcV += (src.cropY / 2) * strideV + (src.cropX / 2);
+ srcU += (src.cropY / 2) * strideU + (src.cropX / 2);
+ uint8_t* dstBuffer =
+ dst.buffer + dst.cropY * dst.strideBytes + dst.cropX * dst.sampleBytes;
+
+ int width = dst.cropWidth;
+ int height = dst.cropHeight;
+
+ if (v_flip) {
+ height = -height;
+ }
+
+ // YV12 is the same as I420, with the U and V planes swapped
+ return libyuv::I420ToARGB(srcY, strideY, srcV, strideV, srcU, strideU,
+ dstBuffer, dst.strideBytes, width, height);
+}
+
+int DoConversion(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
+ return (*GetConverterForDrmFormat(src.drmFormat))(src, dst, v_flip);
+}
+
+int DoCopy(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
+ // Point to the upper left corner of the crop rectangle
+ uint8_t* srcBuffer =
+ src.buffer + src.cropY * src.strideBytes + src.cropX * src.sampleBytes;
+ uint8_t* dstBuffer =
+ dst.buffer + dst.cropY * dst.strideBytes + dst.cropX * dst.sampleBytes;
+ int width = src.cropWidth;
+ int height = src.cropHeight;
+
+ if (v_flip) {
+ height = -height;
+ }
+
+ // HAL formats are named based on the order of the pixel components on the
+ // byte stream, while libyuv formats are named based on the order of those
+ // pixel components in an integer written from left to right. So
+ // libyuv::FOURCC_ARGB is equivalent to HAL_PIXEL_FORMAT_BGRA_8888.
+ auto ret = libyuv::ARGBCopy(srcBuffer, src.strideBytes, dstBuffer,
+ dst.strideBytes, width, height);
+ return ret;
+}
+
+int DoRotation(const BufferSpec& src, const BufferSpec& dst,
+ libyuv::RotationMode rotation, bool v_flip) {
+ // Point to the upper left corner of the crop rectangles
+ uint8_t* srcBuffer =
+ src.buffer + src.cropY * src.strideBytes + src.cropX * src.sampleBytes;
+ uint8_t* dstBuffer =
+ dst.buffer + dst.cropY * dst.strideBytes + dst.cropX * dst.sampleBytes;
+ int width = src.cropWidth;
+ int height = src.cropHeight;
+
+ if (v_flip) {
+ height = -height;
+ }
+
+ return libyuv::ARGBRotate(srcBuffer, src.strideBytes, dstBuffer,
+ dst.strideBytes, width, height, rotation);
+}
+
+int DoScaling(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
+ // Point to the upper left corner of the crop rectangles
+ uint8_t* srcBuffer =
+ src.buffer + src.cropY * src.strideBytes + src.cropX * src.sampleBytes;
+ uint8_t* dstBuffer =
+ dst.buffer + dst.cropY * dst.strideBytes + dst.cropX * dst.sampleBytes;
+ int srcWidth = src.cropWidth;
+ int srcHeight = src.cropHeight;
+ int dstWidth = dst.cropWidth;
+ int dstHeight = dst.cropHeight;
+
+ if (v_flip) {
+ srcHeight = -srcHeight;
+ }
+
+ return libyuv::ARGBScale(srcBuffer, src.strideBytes, srcWidth, srcHeight,
+ dstBuffer, dst.strideBytes, dstWidth, dstHeight,
+ libyuv::kFilterBilinear);
+}
+
+int DoAttenuation(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
+ // Point to the upper left corner of the crop rectangles
+ uint8_t* srcBuffer =
+ src.buffer + src.cropY * src.strideBytes + src.cropX * src.sampleBytes;
+ uint8_t* dstBuffer =
+ dst.buffer + dst.cropY * dst.strideBytes + dst.cropX * dst.sampleBytes;
+ int width = dst.cropWidth;
+ int height = dst.cropHeight;
+
+ if (v_flip) {
+ height = -height;
+ }
+
+ return libyuv::ARGBAttenuate(srcBuffer, src.strideBytes, dstBuffer,
+ dst.strideBytes, width, height);
+}
+
+int DoBlending(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
+ // Point to the upper left corner of the crop rectangles
+ uint8_t* srcBuffer =
+ src.buffer + src.cropY * src.strideBytes + src.cropX * src.sampleBytes;
+ uint8_t* dstBuffer =
+ dst.buffer + dst.cropY * dst.strideBytes + dst.cropX * dst.sampleBytes;
+ int width = dst.cropWidth;
+ int height = dst.cropHeight;
+
+ if (v_flip) {
+ height = -height;
+ }
+
+ // libyuv's ARGB format is hwcomposer's BGRA format, since blending only cares
+ // for the position of alpha in the pixel and not the position of the colors
+ // this function is perfectly usable.
+ return libyuv::ARGBBlend(srcBuffer, src.strideBytes, dstBuffer,
+ dst.strideBytes, dstBuffer, dst.strideBytes, width,
+ height);
+}
+
+std::optional<BufferSpec> GetBufferSpec(GrallocBuffer& buffer,
+ GrallocBufferView& bufferView,
+ const hwc_rect_t& bufferCrop) {
+ auto bufferFormatOpt = buffer.GetDrmFormat();
+ if (!bufferFormatOpt) {
+ ALOGE("Failed to get gralloc buffer format.");
+ return std::nullopt;
+ }
+ uint32_t bufferFormat = *bufferFormatOpt;
+
+ auto bufferWidthOpt = buffer.GetWidth();
+ if (!bufferWidthOpt) {
+ ALOGE("Failed to get gralloc buffer width.");
+ return std::nullopt;
+ }
+ uint32_t bufferWidth = *bufferWidthOpt;
+
+ auto bufferHeightOpt = buffer.GetHeight();
+ if (!bufferHeightOpt) {
+ ALOGE("Failed to get gralloc buffer height.");
+ return std::nullopt;
+ }
+ uint32_t bufferHeight = *bufferHeightOpt;
+
+ uint8_t* bufferData = nullptr;
+ uint32_t bufferStrideBytes = 0;
+ std::optional<android_ycbcr> bufferYCbCrData;
+
+ if (bufferFormat == DRM_FORMAT_NV12 || bufferFormat == DRM_FORMAT_NV21 ||
+ bufferFormat == DRM_FORMAT_YVU420) {
+ bufferYCbCrData = bufferView.GetYCbCr();
+ if (!bufferYCbCrData) {
+ ALOGE("%s failed to get raw ycbcr from view.", __FUNCTION__);
+ return std::nullopt;
+ }
+ } else {
+ auto bufferDataOpt = bufferView.Get();
+ if (!bufferDataOpt) {
+ ALOGE("%s failed to lock gralloc buffer.", __FUNCTION__);
+ return std::nullopt;
+ }
+ bufferData = reinterpret_cast<uint8_t*>(*bufferDataOpt);
+
+ auto bufferStrideBytesOpt = buffer.GetMonoPlanarStrideBytes();
+ if (!bufferStrideBytesOpt) {
+ ALOGE("%s failed to get plane stride.", __FUNCTION__);
+ return std::nullopt;
+ }
+ bufferStrideBytes = *bufferStrideBytesOpt;
+ }
+
+ return BufferSpec(bufferData, bufferYCbCrData, bufferWidth, bufferHeight,
+ bufferCrop.left, bufferCrop.top,
+ bufferCrop.right - bufferCrop.left,
+ bufferCrop.bottom - bufferCrop.top, bufferFormat,
+ bufferStrideBytes, GetDrmFormatBytesPerPixel(bufferFormat));
+}
+
+} // namespace
+
+HWC2::Error GuestComposer::init() {
+ DEBUG_LOG("%s", __FUNCTION__);
+
+ if (!mDrmPresenter.init()) {
+ ALOGE("%s: failed to initialize DrmPresenter", __FUNCTION__);
+ return HWC2::Error::NoResources;
+ }
+
+ return HWC2::Error::None;
+}
+
+HWC2::Error GuestComposer::createDisplays(
+ Device* device, const AddDisplayToDeviceFunction& addDisplayToDeviceFn) {
+ DEBUG_LOG("%s", __FUNCTION__);
+
+ HWC2::Error error = HWC2::Error::None;
+
+ std::vector<DisplayConfig> displayConfigs;
+
+ error = getDisplayConfigsFromDeviceConfig(&displayConfigs);
+ if (error != HWC2::Error::None) {
+ ALOGE("%s failed to get display configs from device config", __FUNCTION__);
+ return error;
+ }
+
+ error = getDisplayConfigsFromSystemProp(&displayConfigs);
+ if (error != HWC2::Error::None) {
+ ALOGE("%s failed to get display configs from system prop", __FUNCTION__);
+ return error;
+ }
+
+ for (const auto& displayConfig : displayConfigs) {
+ auto display = std::make_unique<Display>(*device, this);
+ if (display == nullptr) {
+ ALOGE("%s failed to allocate display", __FUNCTION__);
+ return HWC2::Error::NoResources;
+ }
+
+ auto displayId = display->getId();
+
+ error = display->init(displayConfig.width, //
+ displayConfig.height, //
+ displayConfig.dpiX, //
+ displayConfig.dpiY, //
+ displayConfig.refreshRateHz);
+ if (error != HWC2::Error::None) {
+ ALOGE("%s failed to initialize display:%" PRIu64, __FUNCTION__,
+ displayId);
+ return error;
+ }
+
+ auto it = mDisplayInfos.find(displayId);
+ if (it != mDisplayInfos.end()) {
+ ALOGE("%s: display:%" PRIu64 " already created?", __FUNCTION__,
+ displayId);
+ }
+
+ GuestComposerDisplayInfo& displayInfo = mDisplayInfos[displayId];
+
+ uint32_t bufferStride;
+ buffer_handle_t bufferHandle;
+
+ auto status = GraphicBufferAllocator::get().allocate(
+ displayConfig.width, //
+ displayConfig.height, //
+ PIXEL_FORMAT_RGBA_8888, //
+ /*layerCount=*/1, //
+ GraphicBuffer::USAGE_HW_COMPOSER | GraphicBuffer::USAGE_SW_READ_OFTEN |
+ GraphicBuffer::USAGE_SW_WRITE_OFTEN, //
+ &bufferHandle, //
+ &bufferStride, //
+ "RanchuHwc");
+ if (status != OK) {
+ ALOGE("%s failed to allocate composition buffer for display:%" PRIu64,
+ __FUNCTION__, displayId);
+ return HWC2::Error::NoResources;
+ }
+
+ displayInfo.compositionResultBuffer = bufferHandle;
+
+ displayInfo.compositionResultDrmBuffer = std::make_unique<DrmBuffer>(
+ displayInfo.compositionResultBuffer, mDrmPresenter);
+
+ error = addDisplayToDeviceFn(std::move(display));
+ if (error != HWC2::Error::None) {
+ ALOGE("%s failed to add display:%" PRIu64, __FUNCTION__, displayId);
+ return error;
+ }
+ }
+
+ return HWC2::Error::None;
+}
+
+HWC2::Error GuestComposer::onDisplayDestroy(Display* display) {
+ auto displayId = display->getId();
+
+ auto it = mDisplayInfos.find(displayId);
+ if (it == mDisplayInfos.end()) {
+ ALOGE("%s: display:%" PRIu64 " missing display buffers?", __FUNCTION__,
+ displayId);
+ return HWC2::Error::BadDisplay;
+ }
+
+ GuestComposerDisplayInfo& displayInfo = mDisplayInfos[displayId];
+
+ GraphicBufferAllocator::get().free(displayInfo.compositionResultBuffer);
+
+ mDisplayInfos.erase(it);
+
+ return HWC2::Error::None;
+}
+
+HWC2::Error GuestComposer::getDisplayConfigsFromDeviceConfig(
+ std::vector<GuestComposer::DisplayConfig>* configs) {
+ DEBUG_LOG("%s", __FUNCTION__);
+
+ const auto deviceConfig = cuttlefish::GetDeviceConfig();
+ for (const auto& deviceDisplayConfig : deviceConfig.display_config()) {
+ DisplayConfig displayConfig = {
+ .width = deviceDisplayConfig.width(),
+ .height = deviceDisplayConfig.height(),
+ .dpiX = deviceDisplayConfig.dpi(),
+ .dpiY = deviceDisplayConfig.dpi(),
+ .refreshRateHz = deviceDisplayConfig.refresh_rate_hz(),
+ };
+
+ configs->push_back(displayConfig);
+ }
+
+ return HWC2::Error::None;
+}
+
+HWC2::Error GuestComposer::getDisplayConfigsFromSystemProp(
+ std::vector<GuestComposer::DisplayConfig>* configs) {
+ DEBUG_LOG("%s", __FUNCTION__);
+
+ static constexpr const char kExternalDisplayProp[] =
+ "hwservicemanager.external.displays";
+
+ const auto propString = android::base::GetProperty(kExternalDisplayProp, "");
+ DEBUG_LOG("%s: prop value is: %s", __FUNCTION__, propString.c_str());
+
+ if (propString.empty()) {
+ return HWC2::Error::None;
+ }
+
+ const std::vector<std::string> propStringParts =
+ android::base::Split(propString, ",");
+ if (propStringParts.size() % 5 != 0) {
+ ALOGE("%s: Invalid syntax for system prop %s which is %s", __FUNCTION__,
+ kExternalDisplayProp, propString.c_str());
+ return HWC2::Error::BadParameter;
+ }
+
+ std::vector<int> propIntParts;
+ for (const std::string& propStringPart : propStringParts) {
+ int propIntPart;
+ if (!android::base::ParseInt(propStringPart, &propIntPart)) {
+ ALOGE("%s: Invalid syntax for system prop %s which is %s", __FUNCTION__,
+ kExternalDisplayProp, propString.c_str());
+ return HWC2::Error::BadParameter;
+ }
+ propIntParts.push_back(propIntPart);
+ }
+
+ while (!propIntParts.empty()) {
+ DisplayConfig display_config = {
+ .width = propIntParts[1],
+ .height = propIntParts[2],
+ .dpiX = propIntParts[3],
+ .dpiY = propIntParts[3],
+ .refreshRateHz = 160,
+ };
+
+ configs->push_back(display_config);
+
+ propIntParts.erase(propIntParts.begin(), propIntParts.begin() + 5);
+ }
+
+ return HWC2::Error::None;
+}
+
+HWC2::Error GuestComposer::validateDisplay(
+ Display* display, std::unordered_map<hwc2_layer_t, HWC2::Composition>*
+ outLayerCompositionChanges) {
+ const auto displayId = display->getId();
+ DEBUG_LOG("%s display:%" PRIu64, __FUNCTION__, displayId);
+
+ const std::vector<Layer*>& layers = display->getOrderedLayers();
+
+ bool fallbackToClientComposition = false;
+ for (Layer* layer : layers) {
+ const auto layerId = layer->getId();
+ const auto layerCompositionType = layer->getCompositionType();
+ const auto layerCompositionTypeString = to_string(layerCompositionType);
+
+ if (layerCompositionType == HWC2::Composition::Invalid) {
+ ALOGE("%s display:%" PRIu64 " layer:%" PRIu64 " has Invalid composition",
+ __FUNCTION__, displayId, layerId);
+ continue;
+ }
+
+ if (layerCompositionType == HWC2::Composition::Client ||
+ layerCompositionType == HWC2::Composition::Cursor ||
+ layerCompositionType == HWC2::Composition::Sideband ||
+ layerCompositionType == HWC2::Composition::SolidColor) {
+ ALOGW("%s: display:%" PRIu64 " layer:%" PRIu64
+ " has composition type %s, falling back to client composition",
+ __FUNCTION__, displayId, layerId,
+ layerCompositionTypeString.c_str());
+ fallbackToClientComposition = true;
+ break;
+ }
+
+ if (!canComposeLayer(layer)) {
+ ALOGW("%s: display:%" PRIu64 " layer:%" PRIu64
+ " composition not supported, falling back to client composition",
+ __FUNCTION__, displayId, layerId);
+ fallbackToClientComposition = true;
+ break;
+ }
+ }
+
+ if (display->hasColorTransform()) {
+ fallbackToClientComposition = true;
+ }
+
+ if (fallbackToClientComposition) {
+ for (Layer* layer : layers) {
+ const auto layerId = layer->getId();
+ const auto layerCompositionType = layer->getCompositionType();
+
+ if (layerCompositionType == HWC2::Composition::Invalid) {
+ continue;
+ }
+ if (layerCompositionType != HWC2::Composition::Client) {
+ DEBUG_LOG("%s display:%" PRIu64 " layer:%" PRIu64
+ "composition updated to Client",
+ __FUNCTION__, displayId, layerId);
+ (*outLayerCompositionChanges)[layerId] = HWC2::Composition::Client;
+ }
+ }
+ }
+
+ // We can not draw below a Client (SurfaceFlinger) composed layer. Change all
+ // layers below a Client composed layer to also be Client composed.
+ if (layers.size() > 1) {
+ for (std::size_t layerIndex = layers.size() - 1; layerIndex > 0;
+ layerIndex--) {
+ auto layer = layers[layerIndex];
+ auto layerCompositionType = layer->getCompositionType();
+
+ if (layerCompositionType == HWC2::Composition::Client) {
+ for (std::size_t lowerLayerIndex = 0; lowerLayerIndex < layerIndex;
+ lowerLayerIndex++) {
+ auto lowerLayer = layers[lowerLayerIndex];
+ auto lowerLayerId = lowerLayer->getId();
+ auto lowerLayerCompositionType = lowerLayer->getCompositionType();
+
+ if (lowerLayerCompositionType != HWC2::Composition::Client) {
+ DEBUG_LOG("%s: display:%" PRIu64 " changing layer:%" PRIu64
+ " to Client because"
+ "hwcomposer can not draw below the Client composed "
+ "layer:%" PRIu64,
+ __FUNCTION__, displayId, lowerLayerId, layer->getId());
+
+ (*outLayerCompositionChanges)[lowerLayerId] =
+ HWC2::Composition::Client;
+ }
+ }
+ }
+ }
+ }
+
+ return HWC2::Error::None;
+}
+
+HWC2::Error GuestComposer::presentDisplay(Display* display,
+ int32_t* outRetireFence) {
+ const auto displayId = display->getId();
+ DEBUG_LOG("%s display:%" PRIu64, __FUNCTION__, displayId);
+
+ auto it = mDisplayInfos.find(displayId);
+ if (it == mDisplayInfos.end()) {
+ ALOGE("%s: display:%" PRIu64 " not found", __FUNCTION__, displayId);
+ return HWC2::Error::NoResources;
+ }
+
+ GuestComposerDisplayInfo& displayInfo = it->second;
+
+ if (displayInfo.compositionResultBuffer == nullptr) {
+ ALOGE("%s: display:%" PRIu64 " missing composition result buffer",
+ __FUNCTION__, displayId);
+ return HWC2::Error::NoResources;
+ }
+
+ std::optional<GrallocBuffer> compositionResultBufferOpt =
+ mGralloc.Import(displayInfo.compositionResultBuffer);
+ if (!compositionResultBufferOpt) {
+ ALOGE("%s: display:%" PRIu64 " failed to import buffer", __FUNCTION__,
+ displayId);
+ return HWC2::Error::NoResources;
+ }
+
+ std::optional<uint32_t> compositionResultBufferWidthOpt =
+ compositionResultBufferOpt->GetWidth();
+ if (!compositionResultBufferWidthOpt) {
+ ALOGE("%s: display:%" PRIu64 " failed to query buffer width", __FUNCTION__,
+ displayId);
+ return HWC2::Error::NoResources;
+ }
+
+ std::optional<uint32_t> compositionResultBufferHeightOpt =
+ compositionResultBufferOpt->GetHeight();
+ if (!compositionResultBufferHeightOpt) {
+ ALOGE("%s: display:%" PRIu64 " failed to query buffer height", __FUNCTION__,
+ displayId);
+ return HWC2::Error::NoResources;
+ }
+
+ std::optional<uint32_t> compositionResultBufferStrideOpt =
+ compositionResultBufferOpt->GetMonoPlanarStrideBytes();
+ if (!compositionResultBufferStrideOpt) {
+ ALOGE("%s: display:%" PRIu64 " failed to query buffer stride", __FUNCTION__,
+ displayId);
+ return HWC2::Error::NoResources;
+ }
+
+ std::optional<GrallocBufferView> compositionResultBufferViewOpt =
+ compositionResultBufferOpt->Lock();
+ if (!compositionResultBufferViewOpt) {
+ ALOGE("%s: display:%" PRIu64 " failed to get buffer view", __FUNCTION__,
+ displayId);
+ return HWC2::Error::NoResources;
+ }
+
+ const std::optional<void*> compositionResultBufferDataOpt =
+ compositionResultBufferViewOpt->Get();
+ if (!compositionResultBufferDataOpt) {
+ ALOGE("%s: display:%" PRIu64 " failed to get buffer data", __FUNCTION__,
+ displayId);
+ return HWC2::Error::NoResources;
+ }
+
+ uint32_t compositionResultBufferWidth = *compositionResultBufferWidthOpt;
+ uint32_t compositionResultBufferHeight = *compositionResultBufferHeightOpt;
+ uint32_t compositionResultBufferStride = *compositionResultBufferStrideOpt;
+ uint8_t* compositionResultBufferData =
+ reinterpret_cast<uint8_t*>(*compositionResultBufferDataOpt);
+
+ const std::vector<Layer*>& layers = display->getOrderedLayers();
+ for (Layer* layer : layers) {
+ const auto layerId = layer->getId();
+ const auto layerCompositionType = layer->getCompositionType();
+ if (layerCompositionType != HWC2::Composition::Device) {
+ continue;
+ }
+
+ HWC2::Error error = composerLayerInto(layer, //
+ compositionResultBufferData, //
+ compositionResultBufferWidth, //
+ compositionResultBufferHeight, //
+ compositionResultBufferStride, //
+ 4);
+ if (error != HWC2::Error::None) {
+ ALOGE("%s: display:%" PRIu64 " failed to compose layer:%" PRIu64,
+ __FUNCTION__, displayId, layerId);
+ return error;
+ }
+ }
+
+ DEBUG_LOG("%s display:%" PRIu64 " flushing drm buffer", __FUNCTION__,
+ displayId);
+ *outRetireFence = displayInfo.compositionResultDrmBuffer->flush();
+
+ return HWC2::Error::None;
+}
+
+bool GuestComposer::canComposeLayer(Layer* layer) {
+ buffer_handle_t bufferHandle = layer->getBuffer().getBuffer();
+ if (bufferHandle == nullptr) {
+ ALOGW("%s received a layer with a null handle", __FUNCTION__);
+ return false;
+ }
+
+ auto bufferOpt = mGralloc.Import(bufferHandle);
+ if (!bufferOpt) {
+ ALOGE("Failed to import layer buffer.");
+ return false;
+ }
+ GrallocBuffer& buffer = *bufferOpt;
+
+ auto bufferFormatOpt = buffer.GetDrmFormat();
+ if (!bufferFormatOpt) {
+ ALOGE("Failed to get layer buffer format.");
+ return false;
+ }
+ uint32_t bufferFormat = *bufferFormatOpt;
+
+ if (!IsDrmFormatSupported(bufferFormat)) {
+ return false;
+ }
+
+ return true;
+}
+
+HWC2::Error GuestComposer::composerLayerInto(
+ Layer* srcLayer, std::uint8_t* dstBuffer, std::uint32_t dstBufferWidth,
+ std::uint32_t dstBufferHeight, std::uint32_t dstBufferStrideBytes,
+ std::uint32_t dstBufferBytesPerPixel) {
+ libyuv::RotationMode rotation =
+ GetRotationFromTransform(srcLayer->getTransform());
+
+ auto srcBufferOpt = mGralloc.Import(srcLayer->waitAndGetBuffer());
+ if (!srcBufferOpt) {
+ ALOGE("%s: failed to import layer buffer.", __FUNCTION__);
+ return HWC2::Error::NoResources;
+ }
+ GrallocBuffer& srcBuffer = *srcBufferOpt;
+
+ auto srcBufferViewOpt = srcBuffer.Lock();
+ if (!srcBufferViewOpt) {
+ ALOGE("%s: failed to lock import layer buffer.", __FUNCTION__);
+ return HWC2::Error::NoResources;
+ }
+ GrallocBufferView& srcBufferView = *srcBufferViewOpt;
+
+ hwc_rect_t srcLayerCrop = srcLayer->getSourceCropInt();
+ hwc_rect_t srcLayerDisplayFrame = srcLayer->getDisplayFrame();
+
+ auto srcLayerSpecOpt = GetBufferSpec(srcBuffer, srcBufferView, srcLayerCrop);
+ if (!srcLayerSpecOpt) {
+ return HWC2::Error::NoResources;
+ }
+ BufferSpec srcLayerSpec = *srcLayerSpecOpt;
+
+ // TODO(jemoreira): Remove the hardcoded fomat.
+ bool needsConversion = srcLayerSpec.drmFormat != DRM_FORMAT_XBGR8888;
+ bool needsScaling = LayerNeedsScaling(*srcLayer);
+ bool needsRotation = rotation != libyuv::kRotate0;
+ bool needsTranspose = needsRotation && rotation != libyuv::kRotate180;
+ bool needsVFlip = GetVFlipFromTransform(srcLayer->getTransform());
+ bool needsAttenuation = LayerNeedsAttenuation(*srcLayer);
+ bool needsBlending = LayerNeedsBlending(*srcLayer);
+ bool needsCopy = !(needsConversion || needsScaling || needsRotation ||
+ needsVFlip || needsAttenuation || needsBlending);
+
+ BufferSpec dstLayerSpec(
+ dstBuffer,
+ /*buffer_ycbcr=*/std::nullopt, dstBufferWidth, dstBufferHeight,
+ srcLayerDisplayFrame.left, srcLayerDisplayFrame.top,
+ srcLayerDisplayFrame.right - srcLayerDisplayFrame.left,
+ srcLayerDisplayFrame.bottom - srcLayerDisplayFrame.top,
+ DRM_FORMAT_XBGR8888, dstBufferStrideBytes, dstBufferBytesPerPixel);
+
+ // Add the destination layer to the bottom of the buffer stack
+ std::vector<BufferSpec> dstBufferStack(1, dstLayerSpec);
+
+ // If more than operation is to be performed, a temporary buffer is needed for
+ // each additional operation
+
+ // N operations need N destination buffers, the destination layer (the
+ // framebuffer) is one of them, so only N-1 temporary buffers are needed.
+ // Vertical flip is not taken into account because it can be done together
+ // with any other operation.
+ int neededScratchBuffers = (needsConversion ? 1 : 0) +
+ (needsScaling ? 1 : 0) + (needsRotation ? 1 : 0) +
+ (needsAttenuation ? 1 : 0) +
+ (needsBlending ? 1 : 0) + (needsCopy ? 1 : 0) - 1;
+
+ int mScratchBufferWidth =
+ srcLayerDisplayFrame.right - srcLayerDisplayFrame.left;
+ int mScratchBufferHeight =
+ srcLayerDisplayFrame.bottom - srcLayerDisplayFrame.top;
+ int mScratchBufferStrideBytes =
+ AlignToPower2(mScratchBufferWidth * dstBufferBytesPerPixel, 4);
+ int mScratchBufferSizeBytes =
+ mScratchBufferHeight * mScratchBufferStrideBytes;
+
+ for (int i = 0; i < neededScratchBuffers; i++) {
+ BufferSpec mScratchBufferspec(
+ getRotatingScratchBuffer(mScratchBufferSizeBytes, i),
+ mScratchBufferWidth, mScratchBufferHeight, mScratchBufferStrideBytes);
+ dstBufferStack.push_back(mScratchBufferspec);
+ }
+
+ // Conversion and scaling should always be the first operations, so that every
+ // other operation works on equally sized frames (guaranteed to fit in the
+ // scratch buffers).
+
+ // TODO(jemoreira): We are converting to ARGB as the first step under the
+ // assumption that scaling ARGB is faster than scaling I420 (the most common).
+ // This should be confirmed with testing.
+ if (needsConversion) {
+ BufferSpec& dstBufferSpec = dstBufferStack.back();
+ if (needsScaling || needsTranspose) {
+ // If a rotation or a scaling operation are needed the dimensions at the
+ // top of the buffer stack are wrong (wrong sizes for scaling, swapped
+ // width and height for 90 and 270 rotations).
+ // Make width and height match the crop sizes on the source
+ int srcWidth = srcLayerSpec.cropWidth;
+ int srcHeight = srcLayerSpec.cropHeight;
+ int dst_stride_bytes =
+ AlignToPower2(srcWidth * dstBufferBytesPerPixel, 4);
+ size_t needed_size = dst_stride_bytes * srcHeight;
+ dstBufferSpec.width = srcWidth;
+ dstBufferSpec.height = srcHeight;
+ // Adjust the stride accordingly
+ dstBufferSpec.strideBytes = dst_stride_bytes;
+ // Crop sizes also need to be adjusted
+ dstBufferSpec.cropWidth = srcWidth;
+ dstBufferSpec.cropHeight = srcHeight;
+ // cropX and y are fine at 0, format is already set to match destination
+
+ // In case of a scale, the source frame may be bigger than the default tmp
+ // buffer size
+ dstBufferSpec.buffer = getSpecialScratchBuffer(needed_size);
+ }
+
+ int retval = DoConversion(srcLayerSpec, dstBufferSpec, needsVFlip);
+ if (retval) {
+ ALOGE("Got error code %d from DoConversion function", retval);
+ }
+ needsVFlip = false;
+ srcLayerSpec = dstBufferSpec;
+ dstBufferStack.pop_back();
+ }
+
+ if (needsScaling) {
+ BufferSpec& dstBufferSpec = dstBufferStack.back();
+ if (needsTranspose) {
+ // If a rotation is needed, the temporary buffer has the correct size but
+ // needs to be transposed and have its stride updated accordingly. The
+ // crop sizes also needs to be transposed, but not the x and y since they
+ // are both zero in a temporary buffer (and it is a temporary buffer
+ // because a rotation will be performed next).
+ std::swap(dstBufferSpec.width, dstBufferSpec.height);
+ std::swap(dstBufferSpec.cropWidth, dstBufferSpec.cropHeight);
+ // TODO (jemoreira): Aligment (To align here may cause the needed size to
+ // be bigger than the buffer, so care should be taken)
+ dstBufferSpec.strideBytes = dstBufferSpec.width * dstBufferBytesPerPixel;
+ }
+ int retval = DoScaling(srcLayerSpec, dstBufferSpec, needsVFlip);
+ needsVFlip = false;
+ if (retval) {
+ ALOGE("Got error code %d from DoScaling function", retval);
+ }
+ srcLayerSpec = dstBufferSpec;
+ dstBufferStack.pop_back();
+ }
+
+ if (needsRotation) {
+ int retval =
+ DoRotation(srcLayerSpec, dstBufferStack.back(), rotation, needsVFlip);
+ needsVFlip = false;
+ if (retval) {
+ ALOGE("Got error code %d from DoTransform function", retval);
+ }
+ srcLayerSpec = dstBufferStack.back();
+ dstBufferStack.pop_back();
+ }
+
+ if (needsAttenuation) {
+ int retval = DoAttenuation(srcLayerSpec, dstBufferStack.back(), needsVFlip);
+ needsVFlip = false;
+ if (retval) {
+ ALOGE("Got error code %d from DoBlending function", retval);
+ }
+ srcLayerSpec = dstBufferStack.back();
+ dstBufferStack.pop_back();
+ }
+
+ if (needsCopy) {
+ int retval = DoCopy(srcLayerSpec, dstBufferStack.back(), needsVFlip);
+ needsVFlip = false;
+ if (retval) {
+ ALOGE("Got error code %d from DoBlending function", retval);
+ }
+ srcLayerSpec = dstBufferStack.back();
+ dstBufferStack.pop_back();
+ }
+
+ // Blending (if needed) should always be the last operation, so that it reads
+ // and writes in the destination layer and not some temporary buffer.
+ if (needsBlending) {
+ int retval = DoBlending(srcLayerSpec, dstBufferStack.back(), needsVFlip);
+ needsVFlip = false;
+ if (retval) {
+ ALOGE("Got error code %d from DoBlending function", retval);
+ }
+ // Don't need to assign destination to source in the last one
+ dstBufferStack.pop_back();
+ }
+
+ return HWC2::Error::None;
+}
+
+uint8_t* GuestComposer::getRotatingScratchBuffer(std::size_t neededSize,
+ std::uint32_t order) {
+ static constexpr const int kNumScratchBufferPieces = 2;
+
+ std::size_t totalNeededSize = neededSize * kNumScratchBufferPieces;
+ if (mScratchBuffer.size() < totalNeededSize) {
+ mScratchBuffer.resize(totalNeededSize);
+ }
+
+ std::size_t bufferIndex = order % kNumScratchBufferPieces;
+ std::size_t bufferOffset = bufferIndex * neededSize;
+ return &mScratchBuffer[bufferOffset];
+}
+
+uint8_t* GuestComposer::getSpecialScratchBuffer(size_t neededSize) {
+ if (mSpecialScratchBuffer.size() < neededSize) {
+ mSpecialScratchBuffer.resize(neededSize);
+ }
+
+ return &mSpecialScratchBuffer[0];
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/system/hwc2/GuestComposer.h b/system/hwc2/GuestComposer.h
new file mode 100644
index 0000000..dd90c05
--- /dev/null
+++ b/system/hwc2/GuestComposer.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2021 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_GUESTCOMPOSER_H
+#define ANDROID_HWC_GUESTCOMPOSER_H
+
+#include "Common.h"
+#include "Composer.h"
+#include "DrmPresenter.h"
+#include "Gralloc.h"
+#include "Layer.h"
+
+namespace android {
+
+class GuestComposer : public Composer {
+ public:
+ GuestComposer() = default;
+
+ GuestComposer(const GuestComposer&) = delete;
+ GuestComposer& operator=(const GuestComposer&) = delete;
+
+ GuestComposer(GuestComposer&&) = delete;
+ GuestComposer& operator=(GuestComposer&&) = delete;
+
+ HWC2::Error init() override;
+
+ HWC2::Error createDisplays(
+ Device* device,
+ const AddDisplayToDeviceFunction& addDisplayToDeviceFn) override;
+
+ HWC2::Error onDisplayDestroy(Display*) override;
+
+ HWC2::Error onDisplayClientTargetSet(Display*) override {
+ return HWC2::Error::None;
+ }
+
+ // Determines if this composer can compose the given layers on the given
+ // display and requests changes for layers that can't not be composed.
+ HWC2::Error validateDisplay(
+ Display* display, std::unordered_map<hwc2_layer_t, HWC2::Composition>*
+ outLayerCompositionChanges) override;
+
+ // Performs the actual composition of layers and presents the composed result
+ // to the display.
+ HWC2::Error presentDisplay(Display* display,
+ int32_t* outPresentFence) override;
+
+ private:
+ struct DisplayConfig {
+ int width;
+ int height;
+ int dpiX;
+ int dpiY;
+ int refreshRateHz;
+ };
+
+ HWC2::Error getDisplayConfigsFromDeviceConfig(
+ std::vector<DisplayConfig>* configs);
+
+ HWC2::Error getDisplayConfigsFromSystemProp(
+ std::vector<DisplayConfig>* configs);
+
+ // Returns true if the given layer's buffer has supported format.
+ bool canComposeLayer(Layer* layer);
+
+ // Composes the given layer into the given destination buffer.
+ HWC2::Error composerLayerInto(Layer* layer, std::uint8_t* dstBuffer,
+ std::uint32_t dstBufferWidth,
+ std::uint32_t dstBufferHeight,
+ std::uint32_t dstBufferStrideBytes,
+ std::uint32_t dstBufferBytesPerPixel);
+
+ struct GuestComposerDisplayInfo {
+ // Additional per display buffer for the composition result.
+ buffer_handle_t compositionResultBuffer = nullptr;
+
+ std::unique_ptr<DrmBuffer> compositionResultDrmBuffer;
+ };
+
+ std::unordered_map<hwc2_display_t, GuestComposerDisplayInfo> mDisplayInfos;
+
+ Gralloc mGralloc;
+
+ DrmPresenter mDrmPresenter;
+
+ uint8_t* getRotatingScratchBuffer(std::size_t neededSize,
+ std::uint32_t order);
+ uint8_t* getSpecialScratchBuffer(std::size_t neededSize);
+
+ std::vector<uint8_t> mScratchBuffer;
+ std::vector<uint8_t> mSpecialScratchBuffer;
+};
+
+} // namespace android
+
+#endif
\ No newline at end of file
diff --git a/system/hwc2/HostComposer.cpp b/system/hwc2/HostComposer.cpp
index db57d86..29733b0 100644
--- a/system/hwc2/HostComposer.cpp
+++ b/system/hwc2/HostComposer.cpp
@@ -21,7 +21,6 @@
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
-#include <cros_gralloc_handle.h>
#include <drm/virtgpu_drm.h>
#include <poll.h>
#include <sync/sync.h>
@@ -173,10 +172,20 @@
} // namespace
-HostComposer::HostComposer() : mIsMinigbm(isMinigbmFromProperty()) {
+HWC2::Error HostComposer::init() {
+ mIsMinigbm = isMinigbmFromProperty();
if (!mIsMinigbm) {
mSyncDeviceFd = goldfish_sync_open();
}
+
+ if (!mDrmPresenter.init()) {
+ ALOGE("%s: failed to initialize DrmPresenter", __FUNCTION__);
+
+ // Non-fatal for HostComposer.
+ //return HWC2::Error::NoResources;
+ }
+
+ return HWC2::Error::None;
}
HWC2::Error HostComposer::createDisplays(
@@ -388,9 +397,9 @@
if (mIsMinigbm) {
displayInfo.compositionResultDrmBuffer.reset(
- new DrmBuffer(displayInfo.compositionResultBuffer, mVirtioGpu));
+ new DrmBuffer(displayInfo.compositionResultBuffer, mDrmPresenter));
- uint32_t vsyncPeriod = 1000 * 1000 * 1000 / mVirtioGpu.refreshRate();
+ uint32_t vsyncPeriod = 1000 * 1000 * 1000 / mDrmPresenter.refreshRate();
error = display->setVsyncPeriod(vsyncPeriod);
if (error != HWC2::Error::None) {
ALOGE("%s: display:%" PRIu64 " failed to set vsync height", __FUNCTION__,
@@ -437,7 +446,7 @@
FencedBuffer& clientTargetFencedBuffer = display->getClientTarget();
displayInfo.clientTargetDrmBuffer.reset(
- new DrmBuffer(clientTargetFencedBuffer.getBuffer(), mVirtioGpu));
+ new DrmBuffer(clientTargetFencedBuffer.getBuffer(), mDrmPresenter));
}
return HWC2::Error::None;
@@ -753,378 +762,4 @@
hostCon->unlock();
}
-HostComposer::VirtioGpu::VirtioGpu() {
- drmModeRes* res;
- drmModeConnector* conn;
-
- mFd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
- if (mFd < 0) {
- ALOGE("%s HWC2::Error opening virtioGPU device: %d", __FUNCTION__, errno);
- return;
- }
-
- int univRet = drmSetClientCap(mFd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
- if (univRet) {
- ALOGE("%s: fail to set universal plane %d\n", __FUNCTION__, univRet);
- }
-
- int atomicRet = drmSetClientCap(mFd, DRM_CLIENT_CAP_ATOMIC, 1);
-
- if (atomicRet) {
- ALOGE("%s: fail to set atomic operation %d, %d\n", __FUNCTION__, atomicRet,
- errno);
- }
-
- ALOGD("%s: Did set universal planes and atomic cap\n", __FUNCTION__);
-
- res = drmModeGetResources(mFd);
- if (res == nullptr) {
- ALOGE("%s HWC2::Error reading drm resources: %d", __FUNCTION__, errno);
- close(mFd);
- mFd = -1;
- return;
- }
-
- mCrtcId = res->crtcs[0];
- mConnectorId = res->connectors[0];
-
- drmModePlaneResPtr plane_res = drmModeGetPlaneResources(mFd);
- for (uint32_t i = 0; i < plane_res->count_planes; ++i) {
- drmModePlanePtr plane = drmModeGetPlane(mFd, plane_res->planes[i]);
- ALOGD("%s: plane id: %u crtcid %u fbid %u crtc xy %d %d xy %d %d\n",
- __FUNCTION__, plane->plane_id, plane->crtc_id, plane->fb_id,
- plane->crtc_x, plane->crtc_y, plane->x, plane->y);
-
- drmModeObjectPropertiesPtr planeProps =
- drmModeObjectGetProperties(mFd, plane->plane_id, DRM_MODE_OBJECT_PLANE);
- bool found = false;
- bool isPrimaryOrOverlay = false;
- for (int i = 0; !found && (size_t)i < planeProps->count_props; ++i) {
- drmModePropertyPtr p = drmModeGetProperty(mFd, planeProps->props[i]);
- if (!strcmp(p->name, "CRTC_ID")) {
- mPlaneCrtcPropertyId = p->prop_id;
- ALOGD("%s: Found plane crtc property id. id: %u\n", __FUNCTION__,
- mPlaneCrtcPropertyId);
- } else if (!strcmp(p->name, "FB_ID")) {
- mPlaneFbPropertyId = p->prop_id;
- ALOGD("%s: Found plane fb property id. id: %u\n", __FUNCTION__,
- mPlaneFbPropertyId);
- } else if (!strcmp(p->name, "CRTC_X")) {
- mPlaneCrtcXPropertyId = p->prop_id;
- ALOGD("%s: Found plane crtc X property id. id: %u\n", __FUNCTION__,
- mPlaneCrtcXPropertyId);
- } else if (!strcmp(p->name, "CRTC_Y")) {
- mPlaneCrtcYPropertyId = p->prop_id;
- ALOGD("%s: Found plane crtc Y property id. id: %u\n", __FUNCTION__,
- mPlaneCrtcYPropertyId);
- } else if (!strcmp(p->name, "CRTC_W")) {
- mPlaneCrtcWPropertyId = p->prop_id;
- ALOGD("%s: Found plane crtc W property id. id: %u value: %u\n",
- __FUNCTION__, mPlaneCrtcWPropertyId, (uint32_t)p->values[0]);
- } else if (!strcmp(p->name, "CRTC_H")) {
- mPlaneCrtcHPropertyId = p->prop_id;
- ALOGD("%s: Found plane crtc H property id. id: %u value: %u\n",
- __FUNCTION__, mPlaneCrtcHPropertyId, (uint32_t)p->values[0]);
- } else if (!strcmp(p->name, "SRC_X")) {
- mPlaneSrcXPropertyId = p->prop_id;
- ALOGD("%s: Found plane src X property id. id: %u\n", __FUNCTION__,
- mPlaneSrcXPropertyId);
- } else if (!strcmp(p->name, "SRC_Y")) {
- mPlaneSrcYPropertyId = p->prop_id;
- ALOGD("%s: Found plane src Y property id. id: %u\n", __FUNCTION__,
- mPlaneSrcYPropertyId);
- } else if (!strcmp(p->name, "SRC_W")) {
- mPlaneSrcWPropertyId = p->prop_id;
- ALOGD("%s: Found plane src W property id. id: %u\n", __FUNCTION__,
- mPlaneSrcWPropertyId);
- } else if (!strcmp(p->name, "SRC_H")) {
- mPlaneSrcHPropertyId = p->prop_id;
- ALOGD("%s: Found plane src H property id. id: %u\n", __FUNCTION__,
- mPlaneSrcHPropertyId);
- } else if (!strcmp(p->name, "type")) {
- mPlaneTypePropertyId = p->prop_id;
- ALOGD("%s: Found plane type property id. id: %u\n", __FUNCTION__,
- mPlaneTypePropertyId);
- ALOGD("%s: Plane property type value 0x%llx\n", __FUNCTION__,
- (unsigned long long)p->values[0]);
- uint64_t type = p->values[0];
- switch (type) {
- case DRM_PLANE_TYPE_OVERLAY:
- case DRM_PLANE_TYPE_PRIMARY:
- isPrimaryOrOverlay = true;
- ALOGD(
- "%s: Found a primary or overlay plane. plane id: %u type "
- "0x%llx\n",
- __FUNCTION__, plane->plane_id, (unsigned long long)type);
- break;
- default:
- break;
- }
- }
- drmModeFreeProperty(p);
- }
- drmModeFreeObjectProperties(planeProps);
-
- if (isPrimaryOrOverlay && ((1 << 0) & plane->possible_crtcs)) {
- mPlaneId = plane->plane_id;
- ALOGD("%s: found plane compatible with crtc id %d: %d\n", __FUNCTION__,
- mCrtcId, mPlaneId);
- drmModeFreePlane(plane);
- break;
- }
-
- drmModeFreePlane(plane);
- }
- drmModeFreePlaneResources(plane_res);
-
- conn = drmModeGetConnector(mFd, mConnectorId);
- if (conn == nullptr) {
- ALOGE("%s HWC2::Error reading drm connector %d: %d", __FUNCTION__,
- mConnectorId, errno);
- drmModeFreeResources(res);
- close(mFd);
- mFd = -1;
- return;
- }
- memcpy(&mMode, &conn->modes[0], sizeof(drmModeModeInfo));
-
- drmModeCreatePropertyBlob(mFd, &mMode, sizeof(mMode), &mModeBlobId);
-
- mRefreshRateAsFloat =
- 1000.0f * mMode.clock / ((float)mMode.vtotal * (float)mMode.htotal);
- mRefreshRateAsInteger = (uint32_t)(mRefreshRateAsFloat + 0.5f);
-
- ALOGD(
- "%s: using drm init. refresh rate of system is %f, rounding to %d. blob "
- "id %d\n",
- __FUNCTION__, mRefreshRateAsFloat, mRefreshRateAsInteger, mModeBlobId);
-
- {
- drmModeObjectPropertiesPtr connectorProps = drmModeObjectGetProperties(
- mFd, mConnectorId, DRM_MODE_OBJECT_CONNECTOR);
- bool found = false;
- for (int i = 0; !found && (size_t)i < connectorProps->count_props; ++i) {
- drmModePropertyPtr p = drmModeGetProperty(mFd, connectorProps->props[i]);
- if (!strcmp(p->name, "CRTC_ID")) {
- mConnectorCrtcPropertyId = p->prop_id;
- ALOGD("%s: Found connector crtc id prop id: %u\n", __FUNCTION__,
- mConnectorCrtcPropertyId);
- found = true;
- }
- drmModeFreeProperty(p);
- }
- drmModeFreeObjectProperties(connectorProps);
- }
-
- {
- drmModeObjectPropertiesPtr crtcProps =
- drmModeObjectGetProperties(mFd, mCrtcId, DRM_MODE_OBJECT_CRTC);
- bool found = false;
- for (int i = 0; !found && (size_t)i < crtcProps->count_props; ++i) {
- drmModePropertyPtr p = drmModeGetProperty(mFd, crtcProps->props[i]);
- if (!strcmp(p->name, "OUT_FENCE_PTR")) {
- mOutFencePtrId = p->prop_id;
- ALOGD("%s: Found out fence ptr id. id: %u\n", __FUNCTION__,
- mOutFencePtrId);
- } else if (!strcmp(p->name, "ACTIVE")) {
- mCrtcActivePropretyId = p->prop_id;
- ALOGD("%s: Found out crtc active prop id %u\n", __FUNCTION__,
- mCrtcActivePropretyId);
- } else if (!strcmp(p->name, "MODE_ID")) {
- mCrtcModeIdPropertyId = p->prop_id;
- ALOGD("%s: Found out crtc mode id prop id %u\n", __FUNCTION__,
- mCrtcModeIdPropertyId);
- }
- drmModeFreeProperty(p);
- }
- drmModeFreeObjectProperties(crtcProps);
- }
-
- drmModeFreeConnector(conn);
- drmModeFreeResources(res);
- ALOGD("%s: Successfully initialized DRM backend", __FUNCTION__);
-}
-
-HostComposer::VirtioGpu::~VirtioGpu() { close(mFd); }
-
-int HostComposer::VirtioGpu::setCrtc(hwc_drm_bo_t& bo) {
- int ret =
- drmModeSetCrtc(mFd, mCrtcId, bo.fb_id, 0, 0, &mConnectorId, 1, &mMode);
- ALOGV("%s: drm FB %d", __FUNCTION__, bo.fb_id);
- if (ret) {
- ALOGE("%s: drmModeSetCrtc failed: %s (errno %d)", __FUNCTION__,
- strerror(errno), errno);
- return -1;
- }
- return 0;
-}
-
-int HostComposer::VirtioGpu::getDrmFB(hwc_drm_bo_t& bo) {
- int ret = drmPrimeFDToHandle(mFd, bo.prime_fds[0], &bo.gem_handles[0]);
- if (ret) {
- ALOGE("%s: drmPrimeFDToHandle failed: %s (errno %d)", __FUNCTION__,
- strerror(errno), errno);
- return -1;
- }
- ret = drmModeAddFB2(mFd, bo.width, bo.height, bo.format, bo.gem_handles,
- bo.pitches, bo.offsets, &bo.fb_id, 0);
- if (ret) {
- ALOGE("%s: drmModeAddFB2 failed: %s (errno %d)", __FUNCTION__,
- strerror(errno), errno);
- return -1;
- }
- ALOGV("%s: drm FB %d", __FUNCTION__, bo.fb_id);
- return 0;
-}
-
-int HostComposer::VirtioGpu::clearDrmFB(hwc_drm_bo_t& bo) {
- int ret = 0;
- if (bo.fb_id) {
- if (drmModeRmFB(mFd, bo.fb_id)) {
- ALOGE("%s: drmModeRmFB failed: %s (errno %d)", __FUNCTION__,
- strerror(errno), errno);
- }
- ret = -1;
- }
- if (bo.gem_handles[0]) {
- struct drm_gem_close gem_close = {};
- gem_close.handle = bo.gem_handles[0];
- if (drmIoctl(mFd, DRM_IOCTL_GEM_CLOSE, &gem_close)) {
- ALOGE("%s: DRM_IOCTL_GEM_CLOSE failed: %s (errno %d)", __FUNCTION__,
- strerror(errno), errno);
- }
- ret = -1;
- }
- ALOGV("%s: drm FB %d", __FUNCTION__, bo.fb_id);
- return ret;
-}
-
-bool HostComposer::VirtioGpu::supportComposeWithoutPost() { return true; }
-
-int HostComposer::VirtioGpu::exportSyncFdAndSetCrtc(hwc_drm_bo_t& bo) {
- mOutFence = -1;
-
- drmModeAtomicReqPtr pset = drmModeAtomicAlloc();
-
- int ret;
-
- if (!mDidSetCrtc) {
- DEBUG_LOG("%s: Setting crtc.\n", __FUNCTION__);
- ret = drmModeAtomicAddProperty(pset, mCrtcId, mCrtcActivePropretyId, 1);
- if (ret < 0) {
- ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
- }
- ret = drmModeAtomicAddProperty(pset, mCrtcId, mCrtcModeIdPropertyId,
- mModeBlobId);
- if (ret < 0) {
- ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
- }
- ret = drmModeAtomicAddProperty(pset, mConnectorId, mConnectorCrtcPropertyId,
- mCrtcId);
- if (ret < 0) {
- ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
- }
-
- mDidSetCrtc = true;
- } else {
- DEBUG_LOG("%s: Already set crtc\n", __FUNCTION__);
- }
-
- ret = drmModeAtomicAddProperty(pset, mCrtcId, mOutFencePtrId,
- (uint64_t)(&mOutFence));
- if (ret < 0) {
- ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
- }
-
- DEBUG_LOG("%s: set plane: plane id %d crtcid %d fbid %d bo w h %d %d\n",
- __FUNCTION__, mPlaneId, mCrtcId, bo.fb_id, bo.width, bo.height);
-
- ret = drmModeAtomicAddProperty(pset, mPlaneId, mPlaneCrtcPropertyId, mCrtcId);
- if (ret < 0) {
- ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
- }
- ret = drmModeAtomicAddProperty(pset, mPlaneId, mPlaneFbPropertyId, bo.fb_id);
- if (ret < 0) {
- ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
- }
- ret = drmModeAtomicAddProperty(pset, mPlaneId, mPlaneCrtcXPropertyId, 0);
- if (ret < 0) {
- ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
- }
- ret = drmModeAtomicAddProperty(pset, mPlaneId, mPlaneCrtcYPropertyId, 0);
- if (ret < 0) {
- ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
- }
- ret =
- drmModeAtomicAddProperty(pset, mPlaneId, mPlaneCrtcWPropertyId, bo.width);
- if (ret < 0) {
- ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
- }
- ret = drmModeAtomicAddProperty(pset, mPlaneId, mPlaneCrtcHPropertyId,
- bo.height);
- if (ret < 0) {
- ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
- }
- ret = drmModeAtomicAddProperty(pset, mPlaneId, mPlaneSrcXPropertyId, 0);
- if (ret < 0) {
- ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
- }
- ret = drmModeAtomicAddProperty(pset, mPlaneId, mPlaneSrcYPropertyId, 0);
- if (ret < 0) {
- ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
- }
- ret = drmModeAtomicAddProperty(pset, mPlaneId, mPlaneSrcWPropertyId,
- bo.width << 16);
- if (ret < 0) {
- ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
- }
- ret = drmModeAtomicAddProperty(pset, mPlaneId, mPlaneSrcHPropertyId,
- bo.height << 16);
- if (ret < 0) {
- ALOGE("%s:%d: failed %d errno %d\n", __FUNCTION__, __LINE__, ret, errno);
- }
-
- uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
- ret = drmModeAtomicCommit(mFd, pset, flags, 0);
-
- if (ret) {
- ALOGE("%s: Atomic commit failed with %d %d\n", __FUNCTION__, ret, errno);
- }
-
- if (pset) drmModeAtomicFree(pset);
-
- DEBUG_LOG("%s: out fence: %d\n", __FUNCTION__, mOutFence);
- return mOutFence;
-}
-
-HostComposer::DrmBuffer::DrmBuffer(const native_handle_t* handle,
- VirtioGpu& virtioGpu)
- : mVirtioGpu(virtioGpu), mBo({}) {
- if (!convertBoInfo(handle)) {
- mVirtioGpu.getDrmFB(mBo);
- }
-}
-
-HostComposer::DrmBuffer::~DrmBuffer() { mVirtioGpu.clearDrmFB(mBo); }
-
-int HostComposer::DrmBuffer::convertBoInfo(const native_handle_t* handle) {
- cros_gralloc_handle* gr_handle = (cros_gralloc_handle*)handle;
- if (!gr_handle) {
- ALOGE("%s: Null buffer handle", __FUNCTION__);
- return -1;
- }
- mBo.width = gr_handle->width;
- mBo.height = gr_handle->height;
- mBo.hal_format = gr_handle->droid_format;
- mBo.format = gr_handle->format;
- mBo.usage = gr_handle->usage;
- mBo.prime_fds[0] = gr_handle->fds[0];
- mBo.pitches[0] = gr_handle->strides[0];
- return 0;
-}
-
-int HostComposer::DrmBuffer::flush() {
- return mVirtioGpu.exportSyncFdAndSetCrtc(mBo);
-}
-
} // namespace android
\ No newline at end of file
diff --git a/system/hwc2/HostComposer.h b/system/hwc2/HostComposer.h
index b1b673e..31188d3 100644
--- a/system/hwc2/HostComposer.h
+++ b/system/hwc2/HostComposer.h
@@ -17,19 +17,24 @@
#ifndef ANDROID_HWC_HOSTCOMPOSER_H
#define ANDROID_HWC_HOSTCOMPOSER_H
-#include <include/drmhwcgralloc.h>
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-
#include "Common.h"
#include "Composer.h"
+#include "DrmPresenter.h"
#include "HostConnection.h"
namespace android {
class HostComposer : public Composer {
public:
- HostComposer();
+ HostComposer() = default;
+
+ HostComposer(const HostComposer&) = delete;
+ HostComposer& operator=(const HostComposer&) = delete;
+
+ HostComposer(HostComposer&&) = delete;
+ HostComposer& operator=(HostComposer&&) = delete;
+
+ HWC2::Error init() override;
HWC2::Error createDisplays(
Device* device,
@@ -63,73 +68,10 @@
void post(HostConnection* hostCon, ExtendedRCEncoderContext* rcEnc,
buffer_handle_t h);
- class VirtioGpu {
- public:
- VirtioGpu();
- ~VirtioGpu();
-
- int setCrtc(hwc_drm_bo_t& fb);
- int getDrmFB(hwc_drm_bo_t& bo);
- int clearDrmFB(hwc_drm_bo_t& bo);
- bool supportComposeWithoutPost();
- uint32_t refreshRate() const { return mRefreshRateAsInteger; }
-
- int exportSyncFdAndSetCrtc(hwc_drm_bo_t& fb);
-
- private:
- drmModeModeInfo mMode;
- int32_t mFd = -1;
- uint32_t mConnectorId;
- uint32_t mCrtcId;
-
- uint32_t mConnectorCrtcPropertyId;
-
- uint32_t mOutFencePtrId;
- uint32_t mCrtcActivePropretyId;
- uint32_t mCrtcModeIdPropertyId;
- uint32_t mModeBlobId;
-
- uint32_t mPlaneId;
- uint32_t mPlaneCrtcPropertyId;
- uint32_t mPlaneFbPropertyId;
- uint32_t mPlaneCrtcXPropertyId;
- uint32_t mPlaneCrtcYPropertyId;
- uint32_t mPlaneCrtcWPropertyId;
- uint32_t mPlaneCrtcHPropertyId;
- uint32_t mPlaneSrcXPropertyId;
- uint32_t mPlaneSrcYPropertyId;
- uint32_t mPlaneSrcWPropertyId;
- uint32_t mPlaneSrcHPropertyId;
- uint32_t mPlaneTypePropertyId;
-
- float mRefreshRateAsFloat;
- uint32_t mRefreshRateAsInteger;
-
- int mOutFence = -1;
-
- bool mDidSetCrtc = false;
- };
-
- class DrmBuffer {
- public:
- DrmBuffer(const native_handle_t* handle, VirtioGpu& virtioGpu);
- ~DrmBuffer();
-
- int flush();
-
- private:
- int convertBoInfo(const native_handle_t* handle);
-
- VirtioGpu& mVirtioGpu;
- hwc_drm_bo_t mBo;
- };
-
bool mIsMinigbm = false;
int mSyncDeviceFd = -1;
- VirtioGpu mVirtioGpu;
-
struct HostComposerDisplayInfo {
uint32_t hostDisplayId = 0;
@@ -144,6 +86,8 @@
};
std::unordered_map<hwc2_display_t, HostComposerDisplayInfo> mDisplayInfos;
+
+ DrmPresenter mDrmPresenter;
};
} // namespace android
diff --git a/system/hwc2/Layer.cpp b/system/hwc2/Layer.cpp
index 084a39b..6cdfd33 100644
--- a/system/hwc2/Layer.cpp
+++ b/system/hwc2/Layer.cpp
@@ -16,6 +16,8 @@
#include "Layer.h"
+#include <sync/sync.h>
+
#include <atomic>
namespace android {
@@ -35,6 +37,21 @@
return HWC2::Error::None;
}
+buffer_handle_t Layer::waitAndGetBuffer() {
+ DEBUG_LOG("%s layer:%" PRIu64, __FUNCTION__, mId);
+
+ int fence = mBuffer.getFence();
+ if (fence != -1) {
+ int err = sync_wait(fence, 3000);
+ if (err < 0 && errno == ETIME) {
+ ALOGE("%s waited on fence %" PRId32 " for 3000 ms", __FUNCTION__, fence);
+ }
+ close(fence);
+ }
+
+ return mBuffer.getBuffer();
+}
+
HWC2::Error Layer::setCursorPosition(int32_t /*x*/, int32_t /*y*/) {
DEBUG_LOG("%s layer:%" PRIu64, __FUNCTION__, mId);
diff --git a/system/hwc2/Layer.h b/system/hwc2/Layer.h
index 73d279a..f576201 100644
--- a/system/hwc2/Layer.h
+++ b/system/hwc2/Layer.h
@@ -37,6 +37,8 @@
HWC2::Error setBuffer(buffer_handle_t buffer, int32_t acquireFence);
FencedBuffer& getBuffer() { return mBuffer; }
+ buffer_handle_t waitAndGetBuffer();
+
hwc2_layer_t getId() const { return mId; }
HWC2::Error setCursorPosition(int32_t x, int32_t y);