Merge remote-tracking branch 'aosp/upstream-main' into HEAD

Update to the current upstream tree

* aosp/upstream-main:
  drm_hwcomposer: Return error from GetEdidBlob if blob is null
  drm_hwcomposer: fix build error after fbf5c0ca45b3
  drm_hwcomposer: Add check for format support during plane validation
  drm_hwcomposer: Add supported formats list to DrmPlane
  drm_hwcomposer: add drm-mediatek to client-backend list
  drm_hwcomposer: Add MediaTek platform support
  drm_hwcomposer: remove vendor.hwc.drm.exclude_non_hwfb_imports property
  drm_hwcomposer: always use PlanStageGreedy
  drm_hwcomposer: Fix EDID fetch from DRM
  drm_hwcomposer: use CamelCase in source/header files related to class
  drm_hwcomposer: move header files into source directory
  drm_hwcomposer: libdrm gralloc_handle: modifiers and YUV support
  drm_hwcomposer: fix incorrect layer_count usage
  drm_hwcomposer: Add rcar-du display backend
  drm_hwcomposer: Add composition skipping backend
  drm_hwcomposer: Add backend-dependent validation for HwcDisplay class
  drm_hwcomposer: Expand access to HwcDisplay class members
  drm_hwcomposer: Move DrmHwcTwo internal classes outside private section
  drm_hwcomposer: Add include guard into drmhwctwo.h

Signed-off-by: John Stultz <john.stultz@linaro.org>
Change-Id: I3b1e1710f14b458bb3501dc7c77f6c52394fff42
diff --git a/Android.bp b/Android.bp
index 8bcd1aa..fef3ed6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -18,9 +18,12 @@
 cc_library_static {
     name: "libdrmhwc_utils",
 
-    srcs: ["utils/worker.cpp"],
+    srcs: ["utils/Worker.cpp"],
 
-    include_dirs: ["external/drm_hwcomposer/include"],
+    include_dirs: [
+        "external/drm_hwcomposer/include",
+        "external/drm_hwcomposer",
+    ],
 
     cflags: [
         "-Wall",
@@ -47,7 +50,10 @@
         "libutils",
     ],
 
-    include_dirs: ["external/drm_hwcomposer/include"],
+    include_dirs: [
+        "external/drm_hwcomposer/include",
+        "external/drm_hwcomposer",
+    ],
 
     static_libs: ["libdrmhwc_utils"],
 
@@ -74,26 +80,31 @@
     name: "drm_hwcomposer",
     defaults: ["hwcomposer.drm_defaults"],
     srcs: [
-        "drmhwctwo.cpp",
+        "DrmHwcTwo.cpp",
 
-        "compositor/drmdisplaycomposition.cpp",
-        "compositor/drmdisplaycompositor.cpp",
+        "compositor/DrmDisplayComposition.cpp",
+        "compositor/DrmDisplayCompositor.cpp",
 
-        "drm/drmconnector.cpp",
-        "drm/drmcrtc.cpp",
-        "drm/drmdevice.cpp",
-        "drm/drmencoder.cpp",
-        "drm/drmeventlistener.cpp",
-        "drm/drmmode.cpp",
-        "drm/drmplane.cpp",
-        "drm/drmproperty.cpp",
-        "drm/resourcemanager.cpp",
-        "drm/vsyncworker.cpp",
+        "drm/DrmConnector.cpp",
+        "drm/DrmCrtc.cpp",
+        "drm/DrmDevice.cpp",
+        "drm/DrmEncoder.cpp",
+        "drm/DrmEventListener.cpp",
+        "drm/DrmMode.cpp",
+        "drm/DrmPlane.cpp",
+        "drm/DrmProperty.cpp",
+        "drm/ResourceManager.cpp",
+        "drm/VSyncWorker.cpp",
 
         "platform/platform.cpp",
 
         "utils/autolock.cpp",
         "utils/hwcutils.cpp",
+
+        "backend/BackendManager.cpp",
+        "backend/Backend.cpp",
+        "backend/BackendClient.cpp",
+        "backend/BackendRCarDu.cpp",
     ],
 }
 
@@ -142,3 +153,12 @@
         "platform/platformmeson.cpp",
     ],
 }
+
+// Used by hwcomposer.drm_mediatek
+filegroup {
+    name: "drm_hwcomposer_platformmediatek",
+    srcs: [
+        "platform/platformdrmgeneric.cpp",
+        "platform/platformmediatek.cpp",
+    ],
+}
diff --git a/drmhwctwo.cpp b/DrmHwcTwo.cpp
similarity index 93%
rename from drmhwctwo.cpp
rename to DrmHwcTwo.cpp
index a847c35..65a317c 100644
--- a/drmhwctwo.cpp
+++ b/DrmHwcTwo.cpp
@@ -17,20 +17,19 @@
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 #define LOG_TAG "hwc-drm-two"
 
-#include "drmhwctwo.h"
-#include "drmdisplaycomposition.h"
-#include "drmhwcomposer.h"
-#include "platform.h"
-#include "vsyncworker.h"
-
-#include <inttypes.h>
-#include <string>
+#include "DrmHwcTwo.h"
 
 #include <cutils/properties.h>
 #include <hardware/hardware.h>
 #include <hardware/hwcomposer2.h>
+#include <inttypes.h>
 #include <log/log.h>
 
+#include <string>
+
+#include "backend/BackendManager.h"
+#include "compositor/DrmDisplayComposition.h"
+
 namespace android {
 
 class DrmVsyncCallback : public VsyncCallback {
@@ -299,6 +298,12 @@
     return HWC2::Error::BadDisplay;
   }
 
+  ret = BackendManager::GetInstance().SetBackendForDisplay(this);
+  if (ret) {
+    ALOGE("Failed to set backend for d=%d %d\n", display, ret);
+    return HWC2::Error::BadDisplay;
+  }
+
   return ChosePreferredConfig();
 }
 
@@ -900,92 +905,8 @@
 HWC2::Error DrmHwcTwo::HwcDisplay::ValidateDisplay(uint32_t *num_types,
                                                    uint32_t *num_requests) {
   supported(__func__);
-  *num_types = 0;
-  *num_requests = 0;
-  size_t avail_planes = primary_planes_.size() + overlay_planes_.size();
 
-  /*
-   * If more layers then planes, save one plane
-   * for client composited layers
-   */
-  if (avail_planes < layers_.size())
-    avail_planes--;
-
-  std::map<uint32_t, DrmHwcTwo::HwcLayer *> z_map, z_map_tmp;
-  uint32_t z_index = 0;
-  // First create a map of layers and z_order values
-  for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_)
-    z_map_tmp.emplace(std::make_pair(l.second.z_order(), &l.second));
-  // normalise the map so that the lowest z_order layer has key 0
-  for (std::pair<const uint32_t, DrmHwcTwo::HwcLayer *> &l : z_map_tmp)
-    z_map.emplace(std::make_pair(z_index++, l.second));
-
-  uint32_t total_pixops = CalcPixOps(z_map, 0, z_map.size()), gpu_pixops = 0;
-
-  int client_start = -1, client_size = 0;
-
-  if (compositor_.ShouldFlattenOnClient()) {
-    client_start = 0;
-    client_size = z_map.size();
-    MarkValidated(z_map, client_start, client_size);
-  } else {
-    for (std::pair<const uint32_t, DrmHwcTwo::HwcLayer *> &l : z_map) {
-      if (!HardwareSupportsLayerType(l.second->sf_type()) ||
-          !importer_->CanImportBuffer(l.second->buffer()) ||
-          color_transform_hint_ != HAL_COLOR_TRANSFORM_IDENTITY ||
-          (l.second->RequireScalingOrPhasing() &&
-           resource_manager_->ForcedScalingWithGpu())) {
-        if (client_start < 0)
-          client_start = l.first;
-        client_size = (l.first - client_start) + 1;
-      }
-    }
-
-    int extra_client = (z_map.size() - client_size) - avail_planes;
-    if (extra_client > 0) {
-      int start = 0, steps;
-      if (client_size != 0) {
-        int prepend = std::min(client_start, extra_client);
-        int append = std::min(int(z_map.size() - (client_start + client_size)),
-                              extra_client);
-        start = client_start - prepend;
-        client_size += extra_client;
-        steps = 1 + std::min(std::min(append, prepend),
-                             int(z_map.size()) - (start + client_size));
-      } else {
-        client_size = extra_client;
-        steps = 1 + z_map.size() - extra_client;
-      }
-
-      gpu_pixops = INT_MAX;
-      for (int i = 0; i < steps; i++) {
-        uint32_t po = CalcPixOps(z_map, start + i, client_size);
-        if (po < gpu_pixops) {
-          gpu_pixops = po;
-          client_start = start + i;
-        }
-      }
-    }
-
-    MarkValidated(z_map, client_start, client_size);
-
-    bool testing_needed = !(client_start == 0 && client_size == z_map.size());
-
-    if (testing_needed && CreateComposition(true) != HWC2::Error::None) {
-      ++total_stats_.failed_kms_validate_;
-      gpu_pixops = total_pixops;
-      client_size = z_map.size();
-      MarkValidated(z_map, 0, client_size);
-    }
-  }
-
-  *num_types = client_size;
-
-  total_stats_.frames_flattened_ = compositor_.GetFlattenedFramesCount();
-  total_stats_.gpu_pixops_ += gpu_pixops;
-  total_stats_.total_pixops_ += total_pixops;
-
-  return *num_types ? HWC2::Error::HasChanges : HWC2::Error::None;
+  return backend_->ValidateDisplay(this, num_types, num_requests);
 }
 
 #if PLATFORM_SDK_VERSION > 28
@@ -994,17 +915,12 @@
   supported(__func__);
 
   drmModePropertyBlobPtr blob;
-  int ret;
-  uint64_t blob_id;
 
-  std::tie(ret, blob_id) = connector_->edid_property().value();
-  if (ret) {
+  if (connector_->GetEdidBlob(blob)) {
     ALOGE("Failed to get edid property value.");
     return HWC2::Error::Unsupported;
   }
 
-  blob = drmModeGetPropertyBlob(drm_->fd(), blob_id);
-
   if (outData) {
     *outDataSize = std::min(*outDataSize, blob->length);
     memcpy(outData, blob->data, *outDataSize);
diff --git a/include/drmhwctwo.h b/DrmHwcTwo.h
similarity index 90%
rename from include/drmhwctwo.h
rename to DrmHwcTwo.h
index 1f226bc..ca7a00b 100644
--- a/include/drmhwctwo.h
+++ b/DrmHwcTwo.h
@@ -14,20 +14,25 @@
  * limitations under the License.
  */
 
-#include "drmdisplaycompositor.h"
-#include "drmhwcomposer.h"
-#include "platform.h"
-#include "resourcemanager.h"
-#include "vsyncworker.h"
+#ifndef ANDROID_DRM_HWC_TWO_H_
+#define ANDROID_DRM_HWC_TWO_H_
 
 #include <hardware/hwcomposer2.h>
-
 #include <math.h>
+
 #include <array>
 #include <map>
 
+#include "compositor/DrmDisplayCompositor.h"
+#include "drm/ResourceManager.h"
+#include "drm/VSyncWorker.h"
+#include "drmhwcomposer.h"
+#include "platform/platform.h"
+
 namespace android {
 
+class Backend;
+
 class DrmHwcTwo : public hwc2_device_t {
  public:
   static int HookDevOpen(const struct hw_module_t *module, const char *name,
@@ -37,7 +42,6 @@
 
   HWC2::Error Init();
 
- private:
   class HwcLayer {
    public:
     HWC2::Composition sf_type() const {
@@ -165,6 +169,12 @@
                                       hwc2_function_pointer_t func);
     void RegisterRefreshCallback(hwc2_callback_data_t data,
                                  hwc2_function_pointer_t func);
+    HWC2::Error CreateComposition(bool test);
+    bool HardwareSupportsLayerType(HWC2::Composition comp_type);
+    uint32_t CalcPixOps(std::map<uint32_t, DrmHwcTwo::HwcLayer *> &z_map,
+                        size_t first_z, size_t size);
+    void MarkValidated(std::map<uint32_t, DrmHwcTwo::HwcLayer *> &z_map,
+                       size_t client_first_z, size_t client_size);
 
     void ClearDisplay();
 
@@ -229,40 +239,6 @@
       return &it->second;
     }
 
-   private:
-    HWC2::Error CreateComposition(bool test);
-    void AddFenceToPresentFence(int fd);
-    bool HardwareSupportsLayerType(HWC2::Composition comp_type);
-    uint32_t CalcPixOps(std::map<uint32_t, DrmHwcTwo::HwcLayer *> &z_map,
-                        size_t first_z, size_t size);
-    void MarkValidated(std::map<uint32_t, DrmHwcTwo::HwcLayer *> &z_map,
-                       size_t client_first_z, size_t client_size);
-
-    constexpr static size_t MATRIX_SIZE = 16;
-
-    ResourceManager *resource_manager_;
-    DrmDevice *drm_;
-    DrmDisplayCompositor compositor_;
-    std::shared_ptr<Importer> importer_;
-    std::unique_ptr<Planner> planner_;
-
-    std::vector<DrmPlane *> primary_planes_;
-    std::vector<DrmPlane *> overlay_planes_;
-
-    VSyncWorker vsync_worker_;
-    DrmConnector *connector_ = NULL;
-    DrmCrtc *crtc_ = NULL;
-    hwc2_display_t handle_;
-    HWC2::DisplayType type_;
-    uint32_t layer_idx_ = 0;
-    std::map<hwc2_layer_t, HwcLayer> layers_;
-    HwcLayer client_layer_;
-    UniqueFd present_fence_;
-    int32_t color_mode_;
-    std::array<float, MATRIX_SIZE> color_transform_matrix_;
-    android_color_transform_t color_transform_hint_;
-
-    uint32_t frame_no_ = 0;
     /* Statistics */
     struct Stats {
       Stats minus(Stats b) {
@@ -280,7 +256,87 @@
       uint32_t failed_kms_validate_ = 0;
       uint32_t failed_kms_present_ = 0;
       uint32_t frames_flattened_ = 0;
-    } total_stats_, prev_stats_;
+    };
+
+    const Backend *backend() const {
+      return backend_.get();
+    }
+    void set_backend(std::unique_ptr<Backend> backend) {
+      backend_ = std::move(backend);
+    }
+
+    const std::vector<DrmPlane *> &primary_planes() const {
+      return primary_planes_;
+    }
+
+    const std::vector<DrmPlane *> &overlay_planes() const {
+      return overlay_planes_;
+    }
+
+    std::map<hwc2_layer_t, HwcLayer> &layers() {
+      return layers_;
+    }
+
+    const DrmDisplayCompositor &compositor() const {
+      return compositor_;
+    }
+
+    const DrmDevice *drm() const {
+      return drm_;
+    }
+
+    const DrmConnector *connector() const {
+      return connector_;
+    }
+
+    const std::shared_ptr<Importer> &importer() const {
+      return importer_;
+    }
+
+    ResourceManager *resource_manager() const {
+      return resource_manager_;
+    }
+
+    android_color_transform_t &color_transform_hint() {
+      return color_transform_hint_;
+    }
+
+    Stats &total_stats() {
+      return total_stats_;
+    }
+
+   private:
+    void AddFenceToPresentFence(int fd);
+
+    constexpr static size_t MATRIX_SIZE = 16;
+
+    ResourceManager *resource_manager_;
+    DrmDevice *drm_;
+    DrmDisplayCompositor compositor_;
+    std::shared_ptr<Importer> importer_;
+    std::unique_ptr<Planner> planner_;
+
+    std::vector<DrmPlane *> primary_planes_;
+    std::vector<DrmPlane *> overlay_planes_;
+
+    std::unique_ptr<Backend> backend_;
+
+    VSyncWorker vsync_worker_;
+    DrmConnector *connector_ = NULL;
+    DrmCrtc *crtc_ = NULL;
+    hwc2_display_t handle_;
+    HWC2::DisplayType type_;
+    uint32_t layer_idx_ = 0;
+    std::map<hwc2_layer_t, HwcLayer> layers_;
+    HwcLayer client_layer_;
+    UniqueFd present_fence_;
+    int32_t color_mode_;
+    std::array<float, MATRIX_SIZE> color_transform_matrix_;
+    android_color_transform_t color_transform_hint_;
+
+    uint32_t frame_no_ = 0;
+    Stats total_stats_;
+    Stats prev_stats_;
     std::string DumpDelta(DrmHwcTwo::HwcDisplay::Stats delta);
   };
 
@@ -296,6 +352,7 @@
     DrmDevice *drm_;
   };
 
+ private:
   static DrmHwcTwo *toDrmHwcTwo(hwc2_device_t *dev) {
     return static_cast<DrmHwcTwo *>(dev);
   }
@@ -370,3 +427,5 @@
   std::string mDumpString;
 };
 }  // namespace android
+
+#endif
diff --git a/backend/Backend.cpp b/backend/Backend.cpp
new file mode 100644
index 0000000..50ef900
--- /dev/null
+++ b/backend/Backend.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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 "Backend.h"
+
+#include "BackendManager.h"
+
+namespace android {
+
+HWC2::Error Backend::ValidateDisplay(DrmHwcTwo::HwcDisplay *display,
+                                     uint32_t *num_types,
+                                     uint32_t *num_requests) {
+  *num_types = 0;
+  *num_requests = 0;
+  size_t avail_planes = display->primary_planes().size() +
+                        display->overlay_planes().size();
+
+  /*
+   * If more layers then planes, save one plane
+   * for client composited layers
+   */
+  if (avail_planes < display->layers().size())
+    avail_planes--;
+
+  std::map<uint32_t, DrmHwcTwo::HwcLayer *> z_map, z_map_tmp;
+  uint32_t z_index = 0;
+  // First create a map of layers and z_order values
+  for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l :
+       display->layers())
+    z_map_tmp.emplace(std::make_pair(l.second.z_order(), &l.second));
+  // normalise the map so that the lowest z_order layer has key 0
+  for (std::pair<const uint32_t, DrmHwcTwo::HwcLayer *> &l : z_map_tmp)
+    z_map.emplace(std::make_pair(z_index++, l.second));
+
+  uint32_t total_pixops = display->CalcPixOps(z_map, 0, z_map.size());
+  uint32_t gpu_pixops = 0;
+
+  int client_start = -1, client_size = 0;
+
+  if (display->compositor().ShouldFlattenOnClient()) {
+    client_start = 0;
+    client_size = z_map.size();
+    display->MarkValidated(z_map, client_start, client_size);
+  } else {
+    std::tie(client_start, client_size) = GetClientLayers(display, z_map);
+
+    int extra_client = (z_map.size() - client_size) - avail_planes;
+    if (extra_client > 0) {
+      int start = 0, steps;
+      if (client_size != 0) {
+        int prepend = std::min(client_start, extra_client);
+        int append = std::min(int(z_map.size() - (client_start + client_size)),
+                              extra_client);
+        start = client_start - prepend;
+        client_size += extra_client;
+        steps = 1 + std::min(std::min(append, prepend),
+                             int(z_map.size()) - (start + client_size));
+      } else {
+        client_size = extra_client;
+        steps = 1 + z_map.size() - extra_client;
+      }
+
+      gpu_pixops = INT_MAX;
+      for (int i = 0; i < steps; i++) {
+        uint32_t po = display->CalcPixOps(z_map, start + i, client_size);
+        if (po < gpu_pixops) {
+          gpu_pixops = po;
+          client_start = start + i;
+        }
+      }
+    }
+
+    display->MarkValidated(z_map, client_start, client_size);
+
+    bool testing_needed = !(client_start == 0 && client_size == z_map.size());
+
+    if (testing_needed &&
+        display->CreateComposition(true) != HWC2::Error::None) {
+      ++display->total_stats().failed_kms_validate_;
+      gpu_pixops = total_pixops;
+      client_size = z_map.size();
+      display->MarkValidated(z_map, 0, client_size);
+    }
+  }
+
+  *num_types = client_size;
+
+  display->total_stats().frames_flattened_ = display->compositor()
+                                                 .GetFlattenedFramesCount();
+  display->total_stats().gpu_pixops_ += gpu_pixops;
+  display->total_stats().total_pixops_ += total_pixops;
+
+  return *num_types ? HWC2::Error::HasChanges : HWC2::Error::None;
+}
+
+std::tuple<int, int> Backend::GetClientLayers(
+    DrmHwcTwo::HwcDisplay *display,
+    const std::map<uint32_t, DrmHwcTwo::HwcLayer *> &z_map) {
+  int client_start = -1, client_size = 0;
+
+  for (auto & [ z_order, layer ] : z_map) {
+    if (IsClientLayer(display, layer)) {
+      if (client_start < 0)
+        client_start = z_order;
+      client_size = (z_order - client_start) + 1;
+    }
+  }
+
+  return std::make_tuple(client_start, client_size);
+}
+
+bool Backend::IsClientLayer(DrmHwcTwo::HwcDisplay *display,
+                            DrmHwcTwo::HwcLayer *layer) {
+  return !display->HardwareSupportsLayerType(layer->sf_type()) ||
+         !display->importer()->CanImportBuffer(layer->buffer()) ||
+         display->color_transform_hint() != HAL_COLOR_TRANSFORM_IDENTITY ||
+         (layer->RequireScalingOrPhasing() &&
+          display->resource_manager()->ForcedScalingWithGpu());
+}
+
+REGISTER_BACKEND("generic", Backend);
+
+}  // namespace android
diff --git a/backend/Backend.h b/backend/Backend.h
new file mode 100644
index 0000000..898fece
--- /dev/null
+++ b/backend/Backend.h
@@ -0,0 +1,38 @@
+/*
+ * 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_BACKEND_H
+#define ANDROID_BACKEND_H
+
+#include "DrmHwcTwo.h"
+
+namespace android {
+
+class Backend {
+ public:
+  virtual ~Backend() = default;
+  virtual HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display,
+                                      uint32_t *num_types,
+                                      uint32_t *num_requests);
+  virtual std::tuple<int, int> GetClientLayers(
+      DrmHwcTwo::HwcDisplay *display,
+      const std::map<uint32_t, DrmHwcTwo::HwcLayer *> &z_map);
+  virtual bool IsClientLayer(DrmHwcTwo::HwcDisplay *display,
+                             DrmHwcTwo::HwcLayer *layer);
+};
+}  // namespace android
+
+#endif
diff --git a/backend/BackendClient.cpp b/backend/BackendClient.cpp
new file mode 100644
index 0000000..033a35c
--- /dev/null
+++ b/backend/BackendClient.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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 "BackendClient.h"
+
+#include "BackendManager.h"
+
+namespace android {
+
+HWC2::Error BackendClient::ValidateDisplay(DrmHwcTwo::HwcDisplay *display,
+                                           uint32_t *num_types,
+                                           uint32_t * /*num_requests*/) {
+  for (auto & [ layer_handle, layer ] : display->layers()) {
+    layer.set_validated_type(HWC2::Composition::Client);
+    ++*num_types;
+  }
+  return HWC2::Error::HasChanges;
+}
+
+REGISTER_BACKEND("client", BackendClient);
+
+}  // namespace android
diff --git a/backend/BackendClient.h b/backend/BackendClient.h
new file mode 100644
index 0000000..13543f1
--- /dev/null
+++ b/backend/BackendClient.h
@@ -0,0 +1,32 @@
+/*
+ * 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_BACKEND_CLIENT_H
+#define ANDROID_BACKEND_CLIENT_H
+
+#include "Backend.h"
+
+namespace android {
+
+class BackendClient : public Backend {
+ public:
+  HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display,
+                              uint32_t *num_types,
+                              uint32_t *num_requests) override;
+};
+}  // namespace android
+
+#endif
diff --git a/backend/BackendManager.cpp b/backend/BackendManager.cpp
new file mode 100644
index 0000000..0bacdcd
--- /dev/null
+++ b/backend/BackendManager.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "hwc-backend"
+
+#include "BackendManager.h"
+
+#include <cutils/properties.h>
+#include <log/log.h>
+
+namespace android {
+
+const std::vector<std::string> BackendManager::client_devices_ = {
+    "kirin",
+    "mediatek-drm",
+};
+
+BackendManager &BackendManager::GetInstance() {
+  static BackendManager backend_manager;
+
+  return backend_manager;
+}
+
+int BackendManager::RegisterBackend(const std::string &name,
+                                    backend_constructor_t backend_constructor) {
+  available_backends_[name] = std::move(backend_constructor);
+  return 0;
+}
+
+int BackendManager::SetBackendForDisplay(DrmHwcTwo::HwcDisplay *display) {
+  std::string driver_name(display->drm()->GetName());
+  char backend_override[PROPERTY_VALUE_MAX];
+  property_get("vendor.hwc.backend_override", backend_override,
+               driver_name.c_str());
+  std::string backend_name(std::move(backend_override));
+
+  display->set_backend(GetBackendByName(backend_name));
+  if (!display->backend()) {
+    ALOGE("Failed to set backend '%s' for '%s' and driver '%s'",
+          backend_name.c_str(), display->connector()->name().c_str(),
+          driver_name.c_str());
+    return -EINVAL;
+  }
+
+  ALOGI("Backend '%s' for '%s' and driver '%s' was successfully set",
+        backend_name.c_str(), display->connector()->name().c_str(),
+        driver_name.c_str());
+
+  return 0;
+}
+
+std::unique_ptr<Backend> BackendManager::GetBackendByName(std::string &name) {
+  if (!available_backends_.size()) {
+    ALOGE("No backends are specified");
+    return nullptr;
+  }
+
+  auto it = available_backends_.find(name);
+  if (it == available_backends_.end()) {
+    auto it = std::find(client_devices_.begin(), client_devices_.end(), name);
+    name = it == client_devices_.end() ? "generic" : "client";
+  }
+
+  return available_backends_[name]();
+}
+}  // namespace android
diff --git a/backend/BackendManager.h b/backend/BackendManager.h
new file mode 100644
index 0000000..e86c098
--- /dev/null
+++ b/backend/BackendManager.h
@@ -0,0 +1,57 @@
+/*
+ * 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_BACKEND_MANAGER_H
+#define ANDROID_BACKEND_MANAGER_H
+
+#include <functional>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "Backend.h"
+
+#define REGISTER_BACKEND(name_str_, backend_)                               \
+  static int                                                                \
+      backend = BackendManager::GetInstance()                               \
+                    .RegisterBackend(name_str_,                             \
+                                     []() -> std::unique_ptr<Backend> {     \
+                                       return std::make_unique<backend_>(); \
+                                     });
+
+namespace android {
+
+class BackendManager {
+ public:
+  using backend_constructor_t = std::function<std::unique_ptr<Backend>()>;
+  static BackendManager &GetInstance();
+  int RegisterBackend(const std::string &name,
+                      backend_constructor_t backend_constructor);
+  int SetBackendForDisplay(DrmHwcTwo::HwcDisplay *display);
+  std::unique_ptr<Backend> GetBackendByName(std::string &name);
+  HWC2::Error ValidateDisplay(DrmHwcTwo::HwcDisplay *display,
+                              uint32_t *num_types, uint32_t *num_requests);
+
+ private:
+  BackendManager() = default;
+
+  static const std::vector<std::string> client_devices_;
+
+  std::map<std::string, backend_constructor_t> available_backends_;
+};
+}  // namespace android
+
+#endif
diff --git a/backend/BackendRCarDu.cpp b/backend/BackendRCarDu.cpp
new file mode 100644
index 0000000..d52f0c3
--- /dev/null
+++ b/backend/BackendRCarDu.cpp
@@ -0,0 +1,43 @@
+/*
+ * 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 "BackendRCarDu.h"
+
+#include "BackendManager.h"
+#include "drm_fourcc.h"
+
+namespace android {
+
+bool BackendRCarDu::IsClientLayer(DrmHwcTwo::HwcDisplay *display,
+                                  DrmHwcTwo::HwcLayer *layer) {
+  hwc_drm_bo_t bo;
+
+  int ret = display->importer()->ConvertBoInfo(layer->buffer(), &bo);
+  if (ret)
+    return true;
+
+  if (bo.format == DRM_FORMAT_ABGR8888)
+    return true;
+
+  if (layer->RequireScalingOrPhasing())
+    return true;
+
+  return Backend::IsClientLayer(display, layer);
+}
+
+REGISTER_BACKEND("rcar-du", BackendRCarDu);
+
+}  // namespace android
\ No newline at end of file
diff --git a/backend/BackendRCarDu.h b/backend/BackendRCarDu.h
new file mode 100644
index 0000000..8a1011a
--- /dev/null
+++ b/backend/BackendRCarDu.h
@@ -0,0 +1,31 @@
+/*
+ * 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 HWC_DISPLAY_BACKEND_RCAR_DU_H
+#define HWC_DISPLAY_BACKEND_RCAR_DU_H
+
+#include "Backend.h"
+
+namespace android {
+
+class BackendRCarDu : public Backend {
+ public:
+  bool IsClientLayer(DrmHwcTwo::HwcDisplay *display,
+                     DrmHwcTwo::HwcLayer *layer) override;
+};
+}  // namespace android
+
+#endif
diff --git a/compositor/drmdisplaycomposition.cpp b/compositor/DrmDisplayComposition.cpp
similarity index 97%
rename from compositor/drmdisplaycomposition.cpp
rename to compositor/DrmDisplayComposition.cpp
index b710fe1..79dd470 100644
--- a/compositor/drmdisplaycomposition.cpp
+++ b/compositor/DrmDisplayComposition.cpp
@@ -16,21 +16,19 @@
 
 #define LOG_TAG "hwc-drm-display-composition"
 
-#include "drmdisplaycomposition.h"
-#include "drmcrtc.h"
-#include "drmdevice.h"
-#include "drmdisplaycompositor.h"
-#include "drmplane.h"
-#include "platform.h"
+#include "DrmDisplayComposition.h"
 
+#include <log/log.h>
 #include <stdlib.h>
+#include <sync/sync.h>
+#include <xf86drmMode.h>
 
 #include <algorithm>
 #include <unordered_set>
 
-#include <log/log.h>
-#include <sync/sync.h>
-#include <xf86drmMode.h>
+#include "DrmDisplayCompositor.h"
+#include "drm/DrmDevice.h"
+#include "platform/platform.h"
 
 namespace android {
 
diff --git a/include/drmdisplaycomposition.h b/compositor/DrmDisplayComposition.h
similarity index 98%
rename from include/drmdisplaycomposition.h
rename to compositor/DrmDisplayComposition.h
index 2a5b1a4..73a9024 100644
--- a/include/drmdisplaycomposition.h
+++ b/compositor/DrmDisplayComposition.h
@@ -17,15 +17,15 @@
 #ifndef ANDROID_DRM_DISPLAY_COMPOSITION_H_
 #define ANDROID_DRM_DISPLAY_COMPOSITION_H_
 
-#include "drmcrtc.h"
-#include "drmhwcomposer.h"
-#include "drmplane.h"
+#include <hardware/hardware.h>
+#include <hardware/hwcomposer.h>
 
 #include <sstream>
 #include <vector>
 
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer.h>
+#include "drm/DrmCrtc.h"
+#include "drm/DrmPlane.h"
+#include "drmhwcomposer.h"
 
 namespace android {
 
diff --git a/compositor/drmdisplaycompositor.cpp b/compositor/DrmDisplayCompositor.cpp
similarity index 99%
rename from compositor/drmdisplaycompositor.cpp
rename to compositor/DrmDisplayCompositor.cpp
index 1519736..467f8ba 100644
--- a/compositor/drmdisplaycompositor.cpp
+++ b/compositor/DrmDisplayCompositor.cpp
@@ -17,25 +17,25 @@
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 #define LOG_TAG "hwc-drm-display-compositor"
 
-#include "drmdisplaycompositor.h"
+#include "DrmDisplayCompositor.h"
 
+#include <drm/drm_mode.h>
+#include <log/log.h>
 #include <pthread.h>
 #include <sched.h>
 #include <stdlib.h>
+#include <sync/sync.h>
 #include <time.h>
+#include <utils/Trace.h>
+
 #include <array>
 #include <sstream>
 #include <vector>
 
-#include <drm/drm_mode.h>
-#include <log/log.h>
-#include <sync/sync.h>
-#include <utils/Trace.h>
-
-#include "autolock.h"
-#include "drmcrtc.h"
-#include "drmdevice.h"
-#include "drmplane.h"
+#include "drm/DrmCrtc.h"
+#include "drm/DrmDevice.h"
+#include "drm/DrmPlane.h"
+#include "utils/autolock.h"
 
 static const uint32_t kWaitWritebackFence = 100;  // ms
 
diff --git a/include/drmdisplaycompositor.h b/compositor/DrmDisplayCompositor.h
similarity index 96%
rename from include/drmdisplaycompositor.h
rename to compositor/DrmDisplayCompositor.h
index 26e2572..e500c9e 100644
--- a/include/drmdisplaycompositor.h
+++ b/compositor/DrmDisplayCompositor.h
@@ -17,19 +17,19 @@
 #ifndef ANDROID_DRM_DISPLAY_COMPOSITOR_H_
 #define ANDROID_DRM_DISPLAY_COMPOSITOR_H_
 
-#include "drmdisplaycomposition.h"
-#include "drmframebuffer.h"
-#include "drmhwcomposer.h"
-#include "resourcemanager.h"
-#include "vsyncworker.h"
-
+#include <hardware/hardware.h>
+#include <hardware/hwcomposer.h>
 #include <pthread.h>
+
 #include <memory>
 #include <sstream>
 #include <tuple>
 
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer.h>
+#include "DrmDisplayComposition.h"
+#include "DrmFramebuffer.h"
+#include "drm/ResourceManager.h"
+#include "drm/VSyncWorker.h"
+#include "drmhwcomposer.h"
 
 // One for the front, one for the back, and one for cases where we need to
 // squash a frame that the hw can't display with hw overlays.
diff --git a/drm/drmconnector.cpp b/drm/DrmConnector.cpp
similarity index 92%
rename from drm/drmconnector.cpp
rename to drm/DrmConnector.cpp
index 81c2b98..f1b6c1b 100644
--- a/drm/drmconnector.cpp
+++ b/drm/DrmConnector.cpp
@@ -16,17 +16,17 @@
 
 #define LOG_TAG "hwc-drm-connector"
 
-#include "drmconnector.h"
-#include "drmdevice.h"
+#include "DrmConnector.h"
 
 #include <errno.h>
+#include <log/log.h>
 #include <stdint.h>
+#include <xf86drmMode.h>
 
 #include <array>
 #include <sstream>
 
-#include <log/log.h>
-#include <xf86drmMode.h>
+#include "DrmDevice.h"
 
 namespace android {
 
@@ -58,10 +58,7 @@
     ALOGE("Could not get CRTC_ID property\n");
     return ret;
   }
-  ret = drm_->GetConnectorProperty(*this, "EDID", &edid_property_);
-  if (ret) {
-    ALOGW("Could not get EDID property\n");
-  }
+  ret = UpdateEdidProperty();
   if (writeback()) {
     ret = drm_->GetConnectorProperty(*this, "WRITEBACK_PIXEL_FORMATS",
                                      &writeback_pixel_formats_);
@@ -85,6 +82,30 @@
   return 0;
 }
 
+int DrmConnector::UpdateEdidProperty() {
+  int ret = drm_->GetConnectorProperty(*this, "EDID", &edid_property_);
+  if (ret) {
+    ALOGW("Could not get EDID property\n");
+  }
+  return ret;
+}
+
+int DrmConnector::GetEdidBlob(drmModePropertyBlobPtr &blob) {
+  uint64_t blob_id;
+  int ret = UpdateEdidProperty();
+  if (ret) {
+    return ret;
+  }
+
+  std::tie(ret, blob_id) = edid_property().value();
+  if (ret) {
+    return ret;
+  }
+
+  blob = drmModeGetPropertyBlob(drm_->fd(), blob_id);
+  return !blob;
+}
+
 uint32_t DrmConnector::id() const {
   return id_;
 }
diff --git a/include/drmconnector.h b/drm/DrmConnector.h
similarity index 94%
rename from include/drmconnector.h
rename to drm/DrmConnector.h
index dc64b38..8533af8 100644
--- a/include/drmconnector.h
+++ b/drm/DrmConnector.h
@@ -17,15 +17,16 @@
 #ifndef ANDROID_DRM_CONNECTOR_H_
 #define ANDROID_DRM_CONNECTOR_H_
 
-#include "drmencoder.h"
-#include "drmmode.h"
-#include "drmproperty.h"
-
 #include <stdint.h>
 #include <xf86drmMode.h>
+
 #include <string>
 #include <vector>
 
+#include "DrmEncoder.h"
+#include "DrmMode.h"
+#include "DrmProperty.h"
+
 namespace android {
 
 class DrmDevice;
@@ -39,6 +40,8 @@
   DrmConnector &operator=(const DrmProperty &) = delete;
 
   int Init();
+  int UpdateEdidProperty();
+  int GetEdidBlob(drmModePropertyBlobPtr &blob);
 
   uint32_t id() const;
 
diff --git a/drm/drmcrtc.cpp b/drm/DrmCrtc.cpp
similarity index 97%
rename from drm/drmcrtc.cpp
rename to drm/DrmCrtc.cpp
index b627291..4ce8cfc 100644
--- a/drm/drmcrtc.cpp
+++ b/drm/DrmCrtc.cpp
@@ -16,13 +16,13 @@
 
 #define LOG_TAG "hwc-drm-crtc"
 
-#include "drmcrtc.h"
-#include "drmdevice.h"
+#include "DrmCrtc.h"
 
+#include <log/log.h>
 #include <stdint.h>
 #include <xf86drmMode.h>
 
-#include <log/log.h>
+#include "DrmDevice.h"
 
 namespace android {
 
diff --git a/include/drmcrtc.h b/drm/DrmCrtc.h
similarity index 96%
rename from include/drmcrtc.h
rename to drm/DrmCrtc.h
index 3075f9b..7972bef 100644
--- a/include/drmcrtc.h
+++ b/drm/DrmCrtc.h
@@ -17,12 +17,12 @@
 #ifndef ANDROID_DRM_CRTC_H_
 #define ANDROID_DRM_CRTC_H_
 
-#include "drmmode.h"
-#include "drmproperty.h"
-
 #include <stdint.h>
 #include <xf86drmMode.h>
 
+#include "DrmMode.h"
+#include "DrmProperty.h"
+
 namespace android {
 
 class DrmDevice;
diff --git a/drm/drmdevice.cpp b/drm/DrmDevice.cpp
similarity index 98%
rename from drm/drmdevice.cpp
rename to drm/DrmDevice.cpp
index d7fd2f2..28ecfda 100644
--- a/drm/drmdevice.cpp
+++ b/drm/DrmDevice.cpp
@@ -16,27 +16,21 @@
 
 #define LOG_TAG "hwc-drm-device"
 
-#include "drmdevice.h"
-#include "drmconnector.h"
-#include "drmcrtc.h"
-#include "drmencoder.h"
-#include "drmeventlistener.h"
-#include "drmplane.h"
+#include "DrmDevice.h"
 
+#include <cutils/properties.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <log/log.h>
 #include <stdint.h>
 #include <xf86drm.h>
 #include <xf86drmMode.h>
-#include <cinttypes>
 
 #include <algorithm>
 #include <array>
+#include <cinttypes>
 #include <string>
 
-#include <cutils/properties.h>
-#include <log/log.h>
-
 static void trim_left(std::string &str) {
   str.erase(std::begin(str),
             std::find_if(std::begin(str), std::end(str),
@@ -570,4 +564,16 @@
   return GetProperty(connector.id(), DRM_MODE_OBJECT_CONNECTOR, prop_name,
                      property);
 }
+
+const std::string DrmDevice::GetName() const {
+  auto ver = drmGetVersion(fd_.get());
+  if (!ver) {
+    ALOGW("Failed to get drm version for fd=%d", fd_.get());
+    return "generic";
+  }
+
+  std::string name(ver->name);
+  drmFreeVersion(ver);
+  return name;
+}
 }  // namespace android
diff --git a/include/drmdevice.h b/drm/DrmDevice.h
similarity index 93%
rename from include/drmdevice.h
rename to drm/DrmDevice.h
index 91dd38b..d7ea359 100644
--- a/include/drmdevice.h
+++ b/drm/DrmDevice.h
@@ -17,16 +17,17 @@
 #ifndef ANDROID_DRM_H_
 #define ANDROID_DRM_H_
 
-#include "drmconnector.h"
-#include "drmcrtc.h"
-#include "drmencoder.h"
-#include "drmeventlistener.h"
-#include "drmplane.h"
-#include "platform.h"
-
 #include <stdint.h>
+
 #include <tuple>
 
+#include "DrmConnector.h"
+#include "DrmCrtc.h"
+#include "DrmEncoder.h"
+#include "DrmEventListener.h"
+#include "DrmPlane.h"
+#include "platform/platform.h"
+
 namespace android {
 
 class DrmDevice {
@@ -70,6 +71,8 @@
   int GetConnectorProperty(const DrmConnector &connector, const char *prop_name,
                            DrmProperty *property);
 
+  const std::string GetName() const;
+
   const std::vector<std::unique_ptr<DrmCrtc>> &crtcs() const;
   uint32_t next_mode_id();
 
diff --git a/drm/drmencoder.cpp b/drm/DrmEncoder.cpp
similarity index 95%
rename from drm/drmencoder.cpp
rename to drm/DrmEncoder.cpp
index c36fca1..bcf0926 100644
--- a/drm/drmencoder.cpp
+++ b/drm/DrmEncoder.cpp
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-#include "drmencoder.h"
-#include "drmcrtc.h"
-#include "drmdevice.h"
+#include "DrmEncoder.h"
 
 #include <stdint.h>
 #include <xf86drmMode.h>
 
+#include "DrmDevice.h"
+
 namespace android {
 
 DrmEncoder::DrmEncoder(drmModeEncoderPtr e, DrmCrtc *current_crtc,
diff --git a/include/drmencoder.h b/drm/DrmEncoder.h
similarity index 97%
rename from include/drmencoder.h
rename to drm/DrmEncoder.h
index 8a7f682..f4464d0 100644
--- a/include/drmencoder.h
+++ b/drm/DrmEncoder.h
@@ -17,13 +17,14 @@
 #ifndef ANDROID_DRM_ENCODER_H_
 #define ANDROID_DRM_ENCODER_H_
 
-#include "drmcrtc.h"
-
 #include <stdint.h>
 #include <xf86drmMode.h>
+
 #include <set>
 #include <vector>
 
+#include "DrmCrtc.h"
+
 namespace android {
 
 class DrmEncoder {
diff --git a/drm/drmeventlistener.cpp b/drm/DrmEventListener.cpp
similarity index 98%
rename from drm/drmeventlistener.cpp
rename to drm/DrmEventListener.cpp
index ccee0d6..3d95e28 100644
--- a/drm/drmeventlistener.cpp
+++ b/drm/DrmEventListener.cpp
@@ -16,19 +16,19 @@
 
 #define LOG_TAG "hwc-drm-event-listener"
 
-#include "drmeventlistener.h"
-#include "drmdevice.h"
+#include "DrmEventListener.h"
 
 #include <assert.h>
 #include <errno.h>
-#include <linux/netlink.h>
-#include <sys/socket.h>
-
 #include <hardware/hardware.h>
 #include <hardware/hwcomposer.h>
+#include <linux/netlink.h>
 #include <log/log.h>
+#include <sys/socket.h>
 #include <xf86drm.h>
 
+#include "DrmDevice.h"
+
 namespace android {
 
 DrmEventListener::DrmEventListener(DrmDevice *drm)
diff --git a/include/drmeventlistener.h b/drm/DrmEventListener.h
similarity index 97%
rename from include/drmeventlistener.h
rename to drm/DrmEventListener.h
index 95672ee..9f9a4ba 100644
--- a/include/drmeventlistener.h
+++ b/drm/DrmEventListener.h
@@ -18,7 +18,7 @@
 #define ANDROID_DRM_EVENT_LISTENER_H_
 
 #include "autofd.h"
-#include "worker.h"
+#include "utils/Worker.h"
 
 namespace android {
 
diff --git a/drm/drmmode.cpp b/drm/DrmMode.cpp
similarity index 96%
rename from drm/drmmode.cpp
rename to drm/DrmMode.cpp
index c3ab385..6de671a 100644
--- a/drm/drmmode.cpp
+++ b/drm/DrmMode.cpp
@@ -14,12 +14,9 @@
  * limitations under the License.
  */
 
-#include "drmmode.h"
-#include "drmdevice.h"
+#include "DrmMode.h"
 
-#include <stdint.h>
-#include <xf86drmMode.h>
-#include <string>
+#include "DrmDevice.h"
 
 namespace android {
 
diff --git a/include/drmmode.h b/drm/DrmMode.h
similarity index 99%
rename from include/drmmode.h
rename to drm/DrmMode.h
index 4cc06b1..313a8ea 100644
--- a/include/drmmode.h
+++ b/drm/DrmMode.h
@@ -19,6 +19,7 @@
 
 #include <stdint.h>
 #include <xf86drmMode.h>
+
 #include <string>
 
 namespace android {
diff --git a/drm/drmplane.cpp b/drm/DrmPlane.cpp
similarity index 93%
rename from drm/drmplane.cpp
rename to drm/DrmPlane.cpp
index 6f1bf9b..f994252 100644
--- a/drm/drmplane.cpp
+++ b/drm/DrmPlane.cpp
@@ -16,20 +16,23 @@
 
 #define LOG_TAG "hwc-drm-plane"
 
-#include "drmplane.h"
-#include "drmdevice.h"
+#include "DrmPlane.h"
 
 #include <errno.h>
+#include <log/log.h>
 #include <stdint.h>
+
 #include <cinttypes>
 
-#include <log/log.h>
-#include <xf86drmMode.h>
+#include "DrmDevice.h"
 
 namespace android {
 
 DrmPlane::DrmPlane(DrmDevice *drm, drmModePlanePtr p)
-    : drm_(drm), id_(p->plane_id), possible_crtc_mask_(p->possible_crtcs) {
+    : drm_(drm),
+      id_(p->plane_id),
+      possible_crtc_mask_(p->possible_crtcs),
+      formats_(p->formats, p->formats + p->count_formats) {
 }
 
 int DrmPlane::Init() {
@@ -153,6 +156,11 @@
   return type_;
 }
 
+bool DrmPlane::IsFormatSupported(uint32_t format) const {
+  return std::find(std::begin(formats_), std::end(formats_), format) !=
+         std::end(formats_);
+}
+
 const DrmProperty &DrmPlane::crtc_property() const {
   return crtc_property_;
 }
diff --git a/include/drmplane.h b/drm/DrmPlane.h
similarity index 94%
rename from include/drmplane.h
rename to drm/DrmPlane.h
index 43e0e8a..16731a8 100644
--- a/include/drmplane.h
+++ b/drm/DrmPlane.h
@@ -17,13 +17,14 @@
 #ifndef ANDROID_DRM_PLANE_H_
 #define ANDROID_DRM_PLANE_H_
 
-#include "drmcrtc.h"
-#include "drmproperty.h"
-
 #include <stdint.h>
 #include <xf86drmMode.h>
+
 #include <vector>
 
+#include "DrmCrtc.h"
+#include "DrmProperty.h"
+
 namespace android {
 
 class DrmDevice;
@@ -42,6 +43,8 @@
 
   uint32_t type() const;
 
+  bool IsFormatSupported(uint32_t format) const;
+
   const DrmProperty &crtc_property() const;
   const DrmProperty &fb_property() const;
   const DrmProperty &crtc_x_property() const;
@@ -66,6 +69,8 @@
 
   uint32_t type_;
 
+  std::vector<uint32_t> formats_;
+
   DrmProperty crtc_property_;
   DrmProperty fb_property_;
   DrmProperty crtc_x_property_;
diff --git a/drm/drmproperty.cpp b/drm/DrmProperty.cpp
similarity index 98%
rename from drm/drmproperty.cpp
rename to drm/DrmProperty.cpp
index 3aeed13..b60a76e 100644
--- a/drm/drmproperty.cpp
+++ b/drm/DrmProperty.cpp
@@ -14,14 +14,15 @@
  * limitations under the License.
  */
 
-#include "drmproperty.h"
-#include "drmdevice.h"
+#include "DrmProperty.h"
 
 #include <errno.h>
 #include <stdint.h>
+#include <xf86drmMode.h>
+
 #include <string>
 
-#include <xf86drmMode.h>
+#include "DrmDevice.h"
 
 namespace android {
 
diff --git a/include/drmproperty.h b/drm/DrmProperty.h
similarity index 99%
rename from include/drmproperty.h
rename to drm/DrmProperty.h
index 2d92ca1..d293da3 100644
--- a/include/drmproperty.h
+++ b/drm/DrmProperty.h
@@ -19,6 +19,7 @@
 
 #include <stdint.h>
 #include <xf86drmMode.h>
+
 #include <string>
 #include <vector>
 
diff --git a/drm/resourcemanager.cpp b/drm/ResourceManager.cpp
similarity index 98%
rename from drm/resourcemanager.cpp
rename to drm/ResourceManager.cpp
index 986d4ab..67ef7f8 100644
--- a/drm/resourcemanager.cpp
+++ b/drm/ResourceManager.cpp
@@ -16,13 +16,13 @@
 
 #define LOG_TAG "hwc-resource-manager"
 
-#include "resourcemanager.h"
+#include "ResourceManager.h"
 
 #include <cutils/properties.h>
 #include <log/log.h>
 #include <sys/stat.h>
+
 #include <sstream>
-#include <string>
 
 namespace android {
 
diff --git a/include/resourcemanager.h b/drm/ResourceManager.h
similarity index 96%
rename from include/resourcemanager.h
rename to drm/ResourceManager.h
index 9fefb46..94ba43e 100644
--- a/include/resourcemanager.h
+++ b/drm/ResourceManager.h
@@ -17,11 +17,11 @@
 #ifndef RESOURCEMANAGER_H
 #define RESOURCEMANAGER_H
 
-#include "drmdevice.h"
-#include "platform.h"
-
 #include <string.h>
 
+#include "DrmDevice.h"
+#include "platform/platform.h"
+
 namespace android {
 
 class ResourceManager {
diff --git a/drm/vsyncworker.cpp b/drm/VSyncWorker.cpp
similarity index 97%
rename from drm/vsyncworker.cpp
rename to drm/VSyncWorker.cpp
index 08ab301..dfbf8ce 100644
--- a/drm/vsyncworker.cpp
+++ b/drm/VSyncWorker.cpp
@@ -16,18 +16,13 @@
 
 #define LOG_TAG "hwc-vsync-worker"
 
-#include "vsyncworker.h"
-#include "drmdevice.h"
-#include "worker.h"
+#include "VSyncWorker.h"
 
+#include <log/log.h>
 #include <stdlib.h>
 #include <time.h>
 #include <xf86drm.h>
 #include <xf86drmMode.h>
-#include <map>
-
-#include <hardware/hardware.h>
-#include <log/log.h>
 
 namespace android {
 
diff --git a/include/vsyncworker.h b/drm/VSyncWorker.h
similarity index 96%
rename from include/vsyncworker.h
rename to drm/VSyncWorker.h
index 96f7432..0121a6c 100644
--- a/include/vsyncworker.h
+++ b/drm/VSyncWorker.h
@@ -17,14 +17,14 @@
 #ifndef ANDROID_EVENT_WORKER_H_
 #define ANDROID_EVENT_WORKER_H_
 
-#include "drmdevice.h"
-#include "worker.h"
-
-#include <stdint.h>
-#include <map>
-
 #include <hardware/hardware.h>
 #include <hardware/hwcomposer.h>
+#include <stdint.h>
+
+#include <map>
+
+#include "DrmDevice.h"
+#include "utils/Worker.h"
 
 namespace android {
 
diff --git a/include/drmframebuffer.h b/include/DrmFramebuffer.h
similarity index 99%
rename from include/drmframebuffer.h
rename to include/DrmFramebuffer.h
index 9032d3a..33ca0db 100644
--- a/include/drmframebuffer.h
+++ b/include/DrmFramebuffer.h
@@ -18,9 +18,7 @@
 #define ANDROID_DRM_FRAMEBUFFER_
 
 #include <stdint.h>
-
 #include <sync/sync.h>
-
 #include <ui/GraphicBuffer.h>
 
 namespace android {
diff --git a/platform/platform.cpp b/platform/platform.cpp
index b7a47c7..a500398 100644
--- a/platform/platform.cpp
+++ b/platform/platform.cpp
@@ -17,10 +17,11 @@
 #define LOG_TAG "hwc-platform"
 
 #include "platform.h"
-#include "drmdevice.h"
 
 #include <log/log.h>
 
+#include "drm/DrmDevice.h"
+
 namespace android {
 
 std::vector<DrmPlane *> Planner::GetUsablePlanes(
@@ -77,6 +78,13 @@
       ALOGE("Expected a valid blend mode on plane %d", plane->id());
   }
 
+  uint32_t format = layer->buffer->format;
+  if (!plane->IsFormatSupported(format)) {
+    ALOGE("Plane %d does not supports %c%c%c%c format", plane->id(), format,
+          format >> 8, format >> 16, format >> 24);
+    return -EINVAL;
+  }
+
   return ret;
 }
 
diff --git a/include/platform.h b/platform/platform.h
similarity index 98%
rename from include/platform.h
rename to platform/platform.h
index 6775e29..13dc360 100644
--- a/include/platform.h
+++ b/platform/platform.h
@@ -17,15 +17,15 @@
 #ifndef ANDROID_DRM_PLATFORM_H_
 #define ANDROID_DRM_PLATFORM_H_
 
-#include "drmdisplaycomposition.h"
-#include "drmhwcomposer.h"
-
 #include <hardware/hardware.h>
 #include <hardware/hwcomposer.h>
 
 #include <map>
 #include <vector>
 
+#include "compositor/DrmDisplayComposition.h"
+#include "drmhwcomposer.h"
+
 namespace android {
 
 class DrmDevice;
diff --git a/platform/platformdrmgeneric.cpp b/platform/platformdrmgeneric.cpp
index bc28dd5..95a1eac 100644
--- a/platform/platformdrmgeneric.cpp
+++ b/platform/platformdrmgeneric.cpp
@@ -17,8 +17,6 @@
 #define LOG_TAG "hwc-platform-drm-generic"
 
 #include "platformdrmgeneric.h"
-#include "drmdevice.h"
-#include "platform.h"
 
 #include <xf86drm.h>
 #include <xf86drmMode.h>
@@ -47,8 +45,7 @@
 }
 #endif
 
-DrmGenericImporter::DrmGenericImporter(DrmDevice *drm)
-    : drm_(drm), exclude_non_hwfb_(false) {
+DrmGenericImporter::DrmGenericImporter(DrmDevice *drm) : drm_(drm) {
 }
 
 DrmGenericImporter::~DrmGenericImporter() {
@@ -65,14 +62,133 @@
   ALOGI("Using %s gralloc module: %s\n", gralloc_->common.name,
         gralloc_->common.author);
 
-  char exclude_non_hwfb_prop[PROPERTY_VALUE_MAX];
-  property_get("vendor.hwc.drm.exclude_non_hwfb_imports", exclude_non_hwfb_prop,
-               "0");
-  exclude_non_hwfb_ = static_cast<bool>(strncmp(exclude_non_hwfb_prop, "0", 1));
-
   return 0;
 }
 
+enum chroma_order {
+  YCbCr,
+  YCrCb,
+};
+
+struct droid_yuv_format {
+  /* Lookup keys */
+  int native;                     /* HAL_PIXEL_FORMAT_ */
+  enum chroma_order chroma_order; /* chroma order is {Cb, Cr} or {Cr, Cb} */
+  int chroma_step; /* Distance in bytes between subsequent chroma pixels. */
+
+  /* Result */
+  int fourcc; /* DRM_FORMAT_ */
+};
+
+/* The following table is used to look up a DRI image FourCC based
+ * on native format and information contained in android_ycbcr struct. */
+static const struct droid_yuv_format droid_yuv_formats[] = {
+    /* Native format, YCrCb, Chroma step, DRI image FourCC */
+    {HAL_PIXEL_FORMAT_YCbCr_420_888, YCbCr, 2, DRM_FORMAT_NV12},
+    {HAL_PIXEL_FORMAT_YCbCr_420_888, YCbCr, 1, DRM_FORMAT_YUV420},
+    {HAL_PIXEL_FORMAT_YCbCr_420_888, YCrCb, 1, DRM_FORMAT_YVU420},
+    {HAL_PIXEL_FORMAT_YV12, YCrCb, 1, DRM_FORMAT_YVU420},
+    /* HACK: See droid_create_image_from_prime_fds() and
+     * https://issuetracker.google.com/32077885. */
+    {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCbCr, 2, DRM_FORMAT_NV12},
+    {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCbCr, 1, DRM_FORMAT_YUV420},
+    {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCrCb, 1, DRM_FORMAT_YVU420},
+    {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCrCb, 1, DRM_FORMAT_AYUV},
+    {HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCrCb, 1, DRM_FORMAT_XYUV8888},
+};
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+static int get_fourcc_yuv(int native, enum chroma_order chroma_order,
+                          int chroma_step) {
+  for (int i = 0; i < ARRAY_SIZE(droid_yuv_formats); ++i)
+    if (droid_yuv_formats[i].native == native &&
+        droid_yuv_formats[i].chroma_order == chroma_order &&
+        droid_yuv_formats[i].chroma_step == chroma_step)
+      return droid_yuv_formats[i].fourcc;
+
+  return -1;
+}
+
+static bool is_yuv(int native) {
+  for (int i = 0; i < ARRAY_SIZE(droid_yuv_formats); ++i)
+    if (droid_yuv_formats[i].native == native)
+      return true;
+
+  return false;
+}
+
+bool DrmGenericImporter::GetYuvPlaneInfo(int num_fds, buffer_handle_t handle,
+                                         hwc_drm_bo_t *bo) {
+  struct android_ycbcr ycbcr;
+  enum chroma_order chroma_order;
+  int ret;
+
+  if (!gralloc_->lock_ycbcr) {
+    static std::once_flag once;
+    std::call_once(once,
+                   []() { ALOGW("Gralloc does not support lock_ycbcr()"); });
+    return false;
+  }
+
+  memset(&ycbcr, 0, sizeof(ycbcr));
+  ret = gralloc_->lock_ycbcr(gralloc_, handle, 0, 0, 0, 0, 0, &ycbcr);
+  if (ret) {
+    ALOGW("gralloc->lock_ycbcr failed: %d", ret);
+    return false;
+  }
+  gralloc_->unlock(gralloc_, handle);
+
+  /* When lock_ycbcr's usage argument contains no SW_READ/WRITE flags
+   * it will return the .y/.cb/.cr pointers based on a NULL pointer,
+   * so they can be interpreted as offsets. */
+  bo->offsets[0] = (size_t)ycbcr.y;
+  /* We assume here that all the planes are located in one DMA-buf. */
+  if ((size_t)ycbcr.cr < (size_t)ycbcr.cb) {
+    chroma_order = YCrCb;
+    bo->offsets[1] = (size_t)ycbcr.cr;
+    bo->offsets[2] = (size_t)ycbcr.cb;
+  } else {
+    chroma_order = YCbCr;
+    bo->offsets[1] = (size_t)ycbcr.cb;
+    bo->offsets[2] = (size_t)ycbcr.cr;
+  }
+
+  /* .ystride is the line length (in bytes) of the Y plane,
+   * .cstride is the line length (in bytes) of any of the remaining
+   * Cb/Cr/CbCr planes, assumed to be the same for Cb and Cr for fully
+   * planar formats. */
+  bo->pitches[0] = ycbcr.ystride;
+  bo->pitches[1] = bo->pitches[2] = ycbcr.cstride;
+
+  /* .chroma_step is the byte distance between the same chroma channel
+   * values of subsequent pixels, assumed to be the same for Cb and Cr. */
+  bo->format = get_fourcc_yuv(bo->hal_format, chroma_order, ycbcr.chroma_step);
+  if (bo->format == -1) {
+    ALOGW(
+        "unsupported YUV format, native = %x, chroma_order = %s, chroma_step = "
+        "%d",
+        bo->hal_format, chroma_order == YCbCr ? "YCbCr" : "YCrCb",
+        (int)ycbcr.chroma_step);
+    return false;
+  }
+
+  /*
+   * Since this is EGL_NATIVE_BUFFER_ANDROID don't assume that
+   * the single-fd case cannot happen.  So handle eithe single
+   * fd or fd-per-plane case:
+   */
+  if (num_fds == 1) {
+    bo->prime_fds[2] = bo->prime_fds[1] = bo->prime_fds[0];
+  } else {
+    int expected_planes = (ycbcr.chroma_step == 2) ? 2 : 3;
+    if (num_fds != expected_planes)
+      return false;
+  }
+
+  return true;
+}
+
 uint32_t DrmGenericImporter::ConvertHalFormatToDrm(uint32_t hal_format) {
   switch (hal_format) {
     case HAL_PIXEL_FORMAT_RGB_888:
@@ -120,15 +236,36 @@
   bo->width = gr_handle->width;
   bo->height = gr_handle->height;
   bo->hal_format = gr_handle->format;
-  bo->format = ConvertHalFormatToDrm(gr_handle->format);
-  if (bo->format == DRM_FORMAT_INVALID)
-    return -EINVAL;
+
+#if GRALLOC_HANDLE_VERSION < 4
+  static std::once_flag once;
+  std::call_once(once, []() {
+    ALOGE(
+        "libdrm < v2.4.97 has broken gralloc_handle structure. Please update.");
+  });
+#endif
+#if GRALLOC_HANDLE_VERSION == 4
+  bo->modifiers[0] = gr_handle->modifier;
+  bo->with_modifiers = gr_handle->modifier != DRM_FORMAT_MOD_NONE &&
+                       gr_handle->modifier != DRM_FORMAT_MOD_INVALID;
+#endif
+
   bo->usage = gr_handle->usage;
+  bo->prime_fds[0] = gr_handle->prime_fd;
+
+  if (is_yuv(gr_handle->format)) {
+    if (!GetYuvPlaneInfo(handle->numFds, handle, bo))
+      return -EINVAL;
+  } else {
+    bo->pitches[0] = gr_handle->stride;
+    bo->offsets[0] = 0;
+    bo->format = ConvertHalFormatToDrm(gr_handle->format);
+    if (bo->format == DRM_FORMAT_INVALID)
+      return -EINVAL;
+  }
+
   bo->pixel_stride = (gr_handle->stride * 8) /
                      DrmFormatToBitsPerPixel(bo->format);
-  bo->prime_fds[0] = gr_handle->prime_fd;
-  bo->pitches[0] = gr_handle->stride;
-  bo->offsets[0] = 0;
 
   return 0;
 }
@@ -209,19 +346,14 @@
   if (bo.prime_fds[0] == 0)
     return false;
 
-  if (exclude_non_hwfb_ && !(bo.usage & GRALLOC_USAGE_HW_FB))
-    return false;
-
   return true;
 }
 
-#ifdef USE_DRM_GENERIC_IMPORTER
 std::unique_ptr<Planner> Planner::CreateInstance(DrmDevice *) {
   std::unique_ptr<Planner> planner(new Planner);
   planner->AddStage<PlanStageGreedy>();
   return planner;
 }
-#endif
 
 int DrmGenericImporter::ImportHandle(uint32_t gem_handle) {
   gem_refcount_[gem_handle]++;
diff --git a/platform/platformdrmgeneric.h b/platform/platformdrmgeneric.h
index f9d923f..1bdaa09 100644
--- a/platform/platformdrmgeneric.h
+++ b/platform/platformdrmgeneric.h
@@ -17,13 +17,13 @@
 #ifndef ANDROID_PLATFORM_DRM_GENERIC_H_
 #define ANDROID_PLATFORM_DRM_GENERIC_H_
 
-#include "drmdevice.h"
-#include "platform.h"
-
+#include <drm/drm_fourcc.h>
 #include <hardware/gralloc.h>
+
 #include <map>
 
-#include <drm/drm_fourcc.h>
+#include "drm/DrmDevice.h"
+#include "platform.h"
 
 #ifndef DRM_FORMAT_INVALID
 #define DRM_FORMAT_INVALID 0
@@ -48,13 +48,13 @@
 
   uint32_t ConvertHalFormatToDrm(uint32_t hal_format);
   uint32_t DrmFormatToBitsPerPixel(uint32_t drm_format);
+  bool GetYuvPlaneInfo(int num_fds, buffer_handle_t handle, hwc_drm_bo_t *bo);
 
  protected:
   DrmDevice *drm_;
 
  private:
   const gralloc_module_t *gralloc_;
-  bool exclude_non_hwfb_;
 
   int CloseHandle(uint32_t gem_handle);
   std::map<uint32_t, int> gem_refcount_;
diff --git a/platform/platformhisi.cpp b/platform/platformhisi.cpp
index 1f1478f..67793db 100644
--- a/platform/platformhisi.cpp
+++ b/platform/platformhisi.cpp
@@ -17,15 +17,11 @@
 #define LOG_TAG "hwc-platform-hisi"
 
 #include "platformhisi.h"
-#include "drmdevice.h"
-#include "platform.h"
 
-#include <stdatomic.h>
 #include <xf86drm.h>
 #include <xf86drmMode.h>
 #include <cinttypes>
 
-#include <hardware/gralloc.h>
 #include <log/log.h>
 #include "gralloc_priv.h"
 
@@ -156,42 +152,4 @@
   return 0;
 }
 
-class PlanStageHiSi : public Planner::PlanStage {
- public:
-  int ProvisionPlanes(std::vector<DrmCompositionPlane> *composition,
-                      std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc,
-                      std::vector<DrmPlane *> *planes) {
-    int layers_added = 0;
-    // Fill up as many DRM planes as we can with buffers that have HW_FB usage.
-    // Buffers without HW_FB should have been filtered out with
-    // CanImportBuffer(), if we meet one here, just skip it.
-    for (auto i = layers.begin(); i != layers.end(); i = layers.erase(i)) {
-      if (!(i->second->gralloc_buffer_usage & GRALLOC_USAGE_HW_FB))
-        continue;
-
-      int ret = Emplace(composition, planes, DrmCompositionPlane::Type::kLayer,
-                        crtc, std::make_pair(i->first, i->second));
-      layers_added++;
-      // We don't have any planes left
-      if (ret == -ENOENT)
-        break;
-      else if (ret) {
-        ALOGE("Failed to emplace layer %zu, dropping it", i->first);
-        return ret;
-      }
-    }
-    // If we didn't emplace anything, return an error to ensure we force client
-    // compositing.
-    if (!layers_added)
-      return -EINVAL;
-
-    return 0;
-  }
-};
-
-std::unique_ptr<Planner> Planner::CreateInstance(DrmDevice *) {
-  std::unique_ptr<Planner> planner(new Planner);
-  planner->AddStage<PlanStageHiSi>();
-  return planner;
-}
 }  // namespace android
diff --git a/platform/platformhisi.h b/platform/platformhisi.h
index f127bdb..272e547 100644
--- a/platform/platformhisi.h
+++ b/platform/platformhisi.h
@@ -17,7 +17,6 @@
 #ifndef ANDROID_PLATFORM_HISI_H_
 #define ANDROID_PLATFORM_HISI_H_
 
-#include "drmdevice.h"
 #include "platform.h"
 #include "platformdrmgeneric.h"
 
diff --git a/platform/platformimagination.cpp b/platform/platformimagination.cpp
index bd4a4c3..7001d64 100644
--- a/platform/platformimagination.cpp
+++ b/platform/platformimagination.cpp
@@ -1,6 +1,7 @@
 #define LOG_TAG "hwc-platform-imagination"
 
 #include "platformimagination.h"
+
 #include <log/log.h>
 #include <xf86drm.h>
 
@@ -59,9 +60,4 @@
   return 0;
 }
 
-std::unique_ptr<Planner> Planner::CreateInstance(DrmDevice *) {
-  std::unique_ptr<Planner> planner(new Planner);
-  planner->AddStage<PlanStageGreedy>();
-  return planner;
-}
 }  // namespace android
diff --git a/platform/platformimagination.h b/platform/platformimagination.h
index f2a7cb7..4eec698 100644
--- a/platform/platformimagination.h
+++ b/platform/platformimagination.h
@@ -1,7 +1,6 @@
 #ifndef PLATFORMIMAGINATION_H
 #define PLATFORMIMAGINATION_H
 
-#include "drmdevice.h"
 #include "platform.h"
 #include "platformdrmgeneric.h"
 
diff --git a/platform/platformmediatek.cpp b/platform/platformmediatek.cpp
new file mode 100644
index 0000000..bbf76ea
--- /dev/null
+++ b/platform/platformmediatek.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "hwc-platform-mediatek"
+
+#include "platformmediatek.h"
+
+#include <hardware/gralloc.h>
+#include <log/log.h>
+#include <stdatomic.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include <cinttypes>
+
+#include "gralloc_priv.h"
+#include "platform.h"
+
+namespace android {
+
+Importer *Importer::CreateInstance(DrmDevice *drm) {
+  MediatekImporter *importer = new MediatekImporter(drm);
+  if (!importer)
+    return NULL;
+
+  int ret = importer->Init();
+  if (ret) {
+    ALOGE("Failed to initialize the mediatek importer %d", ret);
+    delete importer;
+    return NULL;
+  }
+  return importer;
+}
+
+int MediatekImporter::ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) {
+  private_handle_t const *hnd = reinterpret_cast<private_handle_t const *>(
+      handle);
+  if (!hnd)
+    return -EINVAL;
+
+  uint32_t fmt = ConvertHalFormatToDrm(hnd->req_format);
+  if (fmt == DRM_FORMAT_INVALID)
+    return -EINVAL;
+
+  bo->width = hnd->width;
+  bo->height = hnd->height;
+  bo->hal_format = hnd->req_format;
+  bo->format = fmt;
+  bo->usage = hnd->consumer_usage | hnd->producer_usage;
+  bo->pixel_stride = hnd->stride;
+  bo->prime_fds[0] = hnd->share_fd;
+  bo->pitches[0] = hnd->byte_stride;
+  bo->offsets[0] = 0;
+
+  return 0;
+}
+
+}  // namespace android
diff --git a/platform/platformmediatek.h b/platform/platformmediatek.h
new file mode 100644
index 0000000..61fcf47
--- /dev/null
+++ b/platform/platformmediatek.h
@@ -0,0 +1,36 @@
+/*
+ * 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_PLATFORM_MTK_H_
+#define ANDROID_PLATFORM_MTK_H_
+
+#include <hardware/gralloc.h>
+#include <stdatomic.h>
+
+#include "platform.h"
+#include "platformdrmgeneric.h"
+
+namespace android {
+
+class MediatekImporter : public DrmGenericImporter {
+ public:
+  using DrmGenericImporter::DrmGenericImporter;
+
+  int ConvertBoInfo(buffer_handle_t handle, hwc_drm_bo_t *bo) override;
+};
+}  // namespace android
+
+#endif
diff --git a/platform/platformmeson.cpp b/platform/platformmeson.cpp
index ad3aff1..278eac5 100644
--- a/platform/platformmeson.cpp
+++ b/platform/platformmeson.cpp
@@ -17,15 +17,11 @@
 #define LOG_TAG "hwc-platform-meson"
 
 #include "platformmeson.h"
-#include "drmdevice.h"
-#include "platform.h"
 
-#include <stdatomic.h>
 #include <xf86drm.h>
 #include <xf86drmMode.h>
 #include <cinttypes>
 
-#include <hardware/gralloc.h>
 #include <log/log.h>
 #include "gralloc_priv.h"
 
@@ -106,9 +102,4 @@
   return 0;
 }
 
-std::unique_ptr<Planner> Planner::CreateInstance(DrmDevice *) {
-  std::unique_ptr<Planner> planner(new Planner);
-  planner->AddStage<PlanStageGreedy>();
-  return planner;
-}
 }  // namespace android
diff --git a/platform/platformmeson.h b/platform/platformmeson.h
index f29b796..1b428a4 100644
--- a/platform/platformmeson.h
+++ b/platform/platformmeson.h
@@ -17,7 +17,6 @@
 #ifndef ANDROID_PLATFORM_HISI_H_
 #define ANDROID_PLATFORM_HISI_H_
 
-#include "drmdevice.h"
 #include "platform.h"
 #include "platformdrmgeneric.h"
 
diff --git a/platform/platformminigbm.cpp b/platform/platformminigbm.cpp
index df195d3..4360b0a 100644
--- a/platform/platformminigbm.cpp
+++ b/platform/platformminigbm.cpp
@@ -17,13 +17,10 @@
 #define LOG_TAG "hwc-platform-drm-minigbm"
 
 #include "platformminigbm.h"
-#include "drmdevice.h"
-#include "platform.h"
 
 #include <xf86drm.h>
 #include <xf86drmMode.h>
 
-#include <hardware/gralloc.h>
 #include <log/log.h>
 
 #include "cros_gralloc_handle.h"
@@ -63,10 +60,4 @@
   return 0;
 }
 
-std::unique_ptr<Planner> Planner::CreateInstance(DrmDevice *) {
-  std::unique_ptr<Planner> planner(new Planner);
-  planner->AddStage<PlanStageGreedy>();
-  return planner;
-}
-
 }  // namespace android
diff --git a/platform/platformminigbm.h b/platform/platformminigbm.h
index 053b2aa..1eea6ca 100644
--- a/platform/platformminigbm.h
+++ b/platform/platformminigbm.h
@@ -17,7 +17,6 @@
 #ifndef ANDROID_PLATFORM_DRM_MINIGBM_H_
 #define ANDROID_PLATFORM_DRM_MINIGBM_H_
 
-#include "drmdevice.h"
 #include "platform.h"
 #include "platformdrmgeneric.h"
 
diff --git a/tests/Android.bp b/tests/Android.bp
index 7e550ff..282e71c 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -9,5 +9,8 @@
     header_libs: ["libhardware_headers"],
     static_libs: ["libdrmhwc_utils"],
     shared_libs: ["hwcomposer.drm"],
-    include_dirs: ["external/drm_hwcomposer/include"],
+    include_dirs: [
+        "external/drm_hwcomposer/include",
+        "external/drm_hwcomposer",
+    ],
 }
diff --git a/tests/worker_test.cpp b/tests/worker_test.cpp
index 82523f0..cb6275e 100644
--- a/tests/worker_test.cpp
+++ b/tests/worker_test.cpp
@@ -1,10 +1,10 @@
+#include "utils/Worker.h"
+
 #include <gtest/gtest.h>
 #include <hardware/hardware.h>
 
 #include <chrono>
 
-#include "worker.h"
-
 using android::Worker;
 
 struct TestWorker : public Worker {
diff --git a/utils/worker.cpp b/utils/Worker.cpp
similarity index 99%
rename from utils/worker.cpp
rename to utils/Worker.cpp
index 0dceb16..1f30588 100644
--- a/utils/worker.cpp
+++ b/utils/Worker.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "worker.h"
+#include "Worker.h"
 
 #include <sys/prctl.h>
 #include <sys/resource.h>
diff --git a/include/worker.h b/utils/Worker.h
similarity index 99%
rename from include/worker.h
rename to utils/Worker.h
index 7909038..73a80da 100644
--- a/include/worker.h
+++ b/utils/Worker.h
@@ -19,10 +19,10 @@
 
 #include <stdint.h>
 #include <stdlib.h>
-#include <string>
 
 #include <condition_variable>
 #include <mutex>
+#include <string>
 #include <thread>
 
 namespace android {
diff --git a/include/autolock.h b/utils/autolock.h
similarity index 100%
rename from include/autolock.h
rename to utils/autolock.h
diff --git a/utils/hwcutils.cpp b/utils/hwcutils.cpp
index 87e3c42..2dc7e7b 100644
--- a/utils/hwcutils.cpp
+++ b/utils/hwcutils.cpp
@@ -17,12 +17,12 @@
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 #define LOG_TAG "hwc-drm-utils"
 
-#include "drmhwcomposer.h"
-#include "platform.h"
-
 #include <log/log.h>
 #include <ui/GraphicBufferMapper.h>
 
+#include "drmhwcomposer.h"
+#include "platform/platform.h"
+
 #define UNUSED(x) (void)(x)
 
 namespace android {
@@ -114,13 +114,9 @@
 
   const hwc_drm_bo *bo = buffer.operator->();
 
-  unsigned int layer_count;
-  for (layer_count = 0; layer_count < HWC_DRM_BO_MAX_PLANES; ++layer_count)
-    if (bo->gem_handles[layer_count] == 0)
-      break;
-
-  ret = handle.CopyBufferHandle(sf_handle, bo->width, bo->height, layer_count,
-                                bo->hal_format, bo->usage, bo->pixel_stride);
+  ret = handle.CopyBufferHandle(sf_handle, bo->width, bo->height,
+                                1 /*layer_count*/, bo->hal_format, bo->usage,
+                                bo->pixel_stride);
   if (ret)
     return ret;