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);