Merge remote-tracking branch 'aosp/upstream-main' into HEAD am: 97b4f2559e am: 6e792d7aa5 am: fc030f53a5 am: b038ca0b70

Original change: https://android-review.googlesource.com/c/platform/external/drm_hwcomposer/+/1883310

Change-Id: I158aeece6bbfc33e681f5b8f1fa7df05d11e4c1a
diff --git a/.ci/.common.sh b/.ci/.common.sh
index 0183aba..21c2b28 100644
--- a/.ci/.common.sh
+++ b/.ci/.common.sh
@@ -1,7 +1,7 @@
 INCLUDE_DIRS="-I. -I../libdrm/include/drm -Iinclude -I/usr/include/libdrm -I./.ci/android_headers -I./tests/test_include"
 
-CLANG="clang++-11"
-CLANG_TIDY="clang-tidy-11"
+CLANG="clang++-12"
+CLANG_TIDY="clang-tidy-12"
 
 CXXARGS="-fPIC -Wall -Werror -DPLATFORM_SDK_VERSION=30 -D__ANDROID_API__=30 -Wsign-promo -Wimplicit-fallthrough"
 CXXARGS+=" -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS -Wno-gnu-include-next "
diff --git a/.ci/.gitlab-ci-clang-tidy-coarse.sh b/.ci/.gitlab-ci-clang-tidy-coarse.sh
index de0c024..a3afeb9 100755
--- a/.ci/.gitlab-ci-clang-tidy-coarse.sh
+++ b/.ci/.gitlab-ci-clang-tidy-coarse.sh
@@ -17,6 +17,7 @@
 TIDY_COARSE_CHECKS+="-google-readability-braces-around-statements,"
 TIDY_COARSE_CHECKS+="-google-readability-casting,"
 TIDY_COARSE_CHECKS+="misc-*,"
+TIDY_COARSE_CHECKS+="-misc-non-private-member-variables-in-classes",
 TIDY_COARSE_CHECKS+="modernize-*,"
 TIDY_COARSE_CHECKS+="-modernize-avoid-c-arrays,"
 TIDY_COARSE_CHECKS+="-modernize-use-trailing-return-type,"
@@ -24,8 +25,10 @@
 TIDY_COARSE_CHECKS+="portability-*,"
 TIDY_COARSE_CHECKS+="readability-*,"
 TIDY_COARSE_CHECKS+="-readability-braces-around-statements,"
+TIDY_COARSE_CHECKS+="-readability-function-cognitive-complexity,"
 TIDY_COARSE_CHECKS+="-readability-convert-member-functions-to-static,"
 TIDY_COARSE_CHECKS+="-readability-implicit-bool-conversion,"
+TIDY_COARSE_CHECKS+="-readability-identifier-naming,"
 TIDY_COARSE_CHECKS+="-readability-magic-numbers,"
 TIDY_COARSE_CHECKS+="-readability-use-anyofallof"
 
diff --git a/.ci/.gitlab-ci-clang-tidy-fine.sh b/.ci/.gitlab-ci-clang-tidy-fine.sh
index c1805e8..0e3e35b 100755
--- a/.ci/.gitlab-ci-clang-tidy-fine.sh
+++ b/.ci/.gitlab-ci-clang-tidy-fine.sh
@@ -4,6 +4,7 @@
 
 TIDY_FILES=(
 drm/DrmFbImporter.h
+drm/DrmUnique.h
 utils/UniqueFd.h
 utils/log.h
 utils/properties.h
diff --git a/.clang-tidy b/.clang-tidy
index 0bb7bf0..221c030 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -6,6 +6,7 @@
     *,
     -fuchsia*,
     -llvm*,
+    -concurrency-mt-unsafe,
     -cppcoreguidelines-pro-type-vararg, -hicpp-vararg,
     -hicpp-signed-bitwise,
 
@@ -17,26 +18,49 @@
 FormatStyle: google
 
 CheckOptions:
-  - { key: readability-identifier-naming.NamespaceCase,          value: lower_case }
-  - { key: readability-identifier-naming.ClassCase,              value: CamelCase  }
-  - { key: readability-identifier-naming.StructCase,             value: CamelCase  }
-  - { key: readability-identifier-naming.TemplateParameterCase,  value: CamelCase  }
-  - { key: readability-identifier-naming.FunctionCase,           value: aNy_CasE  }
-  - { key: readability-identifier-naming.VariableCase,           value: lower_case }
-  - { key: readability-identifier-naming.ClassMemberCase,        value: lower_case }
-  - { key: readability-identifier-naming.ClassMemberSuffix,      value: _          }
-  - { key: readability-identifier-naming.PrivateMemberSuffix,    value: _          }
-  - { key: readability-identifier-naming.ProtectedMemberSuffix,  value: _          }
-  - { key: readability-identifier-naming.EnumConstantCase,         value: CamelCase }
-  - { key: readability-identifier-naming.EnumConstantPrefix,       value: k         }
-  - { key: readability-identifier-naming.ConstexprVariableCase,    value: CamelCase }
-  - { key: readability-identifier-naming.ConstexprVariablePrefix,  value: k         }
-  - { key: readability-identifier-naming.GlobalConstantCase,       value: CamelCase }
-  - { key: readability-identifier-naming.GlobalConstantPrefix,     value: k         }
-  - { key: readability-identifier-naming.MemberConstantCase,       value: CamelCase }
-  - { key: readability-identifier-naming.MemberConstantPrefix,     value: k         }
-  - { key: readability-identifier-naming.StaticConstantCase,       value: CamelCase }
-  - { key: readability-identifier-naming.StaticConstantPrefix,     value: k         }
-  - { key: readability-implicit-bool-conversion.AllowIntegerConditions,  value: 1   }
-  - { key: readability-implicit-bool-conversion.AllowPointerConditions,  value: 1   }
-  - { key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic, value: 1 }
+  - key:             readability-identifier-naming.ClassCase
+    value:           CamelCase
+  - key:             readability-identifier-naming.ClassMemberCase
+    value:           lower_case
+  - key:             readability-identifier-naming.ConstexprVariableCase
+    value:           CamelCase
+  - key:             readability-identifier-naming.ConstexprVariablePrefix
+    value:           k
+  - key:             readability-identifier-naming.EnumCase
+    value:           CamelCase
+  - key:             readability-identifier-naming.EnumConstantCase
+    value:           CamelCase
+  - key:             readability-identifier-naming.EnumConstantPrefix
+    value:           k
+  - key:             readability-identifier-naming.FunctionCase
+    value:           CamelCase
+  - key:             readability-identifier-naming.GlobalConstantCase
+    value:           CamelCase
+  - key:             readability-identifier-naming.GlobalConstantPrefix
+    value:           k
+  - key:             readability-identifier-naming.StaticConstantCase
+    value:           CamelCase
+  - key:             readability-identifier-naming.StaticConstantPrefix
+    value:           k
+  - key:             readability-identifier-naming.StaticVariableCase
+    value:           lower_case
+  - key:             readability-identifier-naming.MacroDefinitionCase
+    value:           UPPER_CASE
+  - key:             readability-identifier-naming.MacroDefinitionIgnoredRegexp
+    value:           '^[A-Z]+(_[A-Z]+)*_$'
+  - key:             readability-identifier-naming.MemberCase
+    value:           lower_case
+  - key:             readability-identifier-naming.MemberSuffix
+    value:           _
+  - key:             readability-identifier-naming.NamespaceCase
+    value:           lower_case
+  - key:             readability-identifier-naming.ParameterCase
+    value:           lower_case
+  - key:             readability-identifier-naming.TypeAliasCase
+    value:           CamelCase
+  - key:             readability-identifier-naming.TypedefCase
+    value:           CamelCase
+  - key:             readability-identifier-naming.VariableCase
+    value:           lower_case
+  - key:             readability-identifier-naming.IgnoreMainLikeFunctions
+    value:           1
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 04eb6c5..41d38ba 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,8 +1,11 @@
-image: ubuntu:20.10
+image: ubuntu:21.04
+
+variables:
+  DEBIAN_FRONTEND: noninteractive
 
 before_script:
   - apt-get --quiet update --yes >/dev/null
-  - apt-get --quiet install --yes clang-11 clang-tidy-11 clang-format-11 git libdrm-dev blueprint-tools libgtest-dev >/dev/null
+  - apt-get --quiet install --yes clang-12 clang-tidy-12 clang-format-12 git libdrm-dev blueprint-tools libgtest-dev >/dev/null
 
 stages:
   - build
diff --git a/DrmHwcTwo.cpp b/DrmHwcTwo.cpp
index 02667cf..6ec8b31 100644
--- a/DrmHwcTwo.cpp
+++ b/DrmHwcTwo.cpp
@@ -48,14 +48,14 @@
 
 HWC2::Error DrmHwcTwo::CreateDisplay(hwc2_display_t displ,
                                      HWC2::DisplayType type) {
-  DrmDevice *drm = resource_manager_.GetDrmDevice(displ);
+  DrmDevice *drm = resource_manager_.GetDrmDevice(static_cast<int>(displ));
   if (!drm) {
     ALOGE("Failed to get a valid drmresource");
     return HWC2::Error::NoResources;
   }
   displays_.emplace(std::piecewise_construct, std::forward_as_tuple(displ),
-                    std::forward_as_tuple(&resource_manager_, drm, displ,
-                                          type));
+                    std::forward_as_tuple(&resource_manager_, drm, displ, type,
+                                          this));
 
   DrmCrtc *crtc = drm->GetCrtcForDisplay(static_cast<int>(displ));
   if (!crtc) {
@@ -140,9 +140,28 @@
 }
 
 std::string DrmHwcTwo::HwcDisplay::Dump() {
+  std::string flattening_state_str;
+  switch (flattenning_state_) {
+    case ClientFlattenningState::Disabled:
+      flattening_state_str = "Disabled";
+      break;
+    case ClientFlattenningState::NotRequired:
+      flattening_state_str = "Not needed";
+      break;
+    case ClientFlattenningState::Flattened:
+      flattening_state_str = "Active";
+      break;
+    case ClientFlattenningState::ClientRefreshRequested:
+      flattening_state_str = "Refresh requested";
+      break;
+    default:
+      flattening_state_str = std::to_string(flattenning_state_) +
+                             " VSync remains";
+  }
+
   std::stringstream ss;
   ss << "- Display on: " << connector_->name() << "\n"
-     << "  Flattening state: " << compositor_.GetFlatteningState() << "\n"
+     << "  Flattening state: " << flattening_state_str << "\n"
      << "Statistics since system boot:\n"
      << DumpDelta(total_stats_) << "\n\n"
      << "Statistics since last dumpsys request:\n"
@@ -183,26 +202,31 @@
                                         hwc2_function_pointer_t function) {
   supported(__func__);
 
+  std::unique_lock<std::mutex> lock(callback_lock_);
+
   switch (static_cast<HWC2::Callback>(descriptor)) {
     case HWC2::Callback::Hotplug: {
-      SetHotplugCallback(data, function);
+      hotplug_callback_ = std::make_pair(HWC2_PFN_HOTPLUG(function), data);
+      lock.unlock();
       const auto &drm_devices = resource_manager_.getDrmDevices();
       for (const auto &device : drm_devices)
         HandleInitialHotplugState(device.get());
       break;
     }
     case HWC2::Callback::Refresh: {
-      for (std::pair<const hwc2_display_t, DrmHwcTwo::HwcDisplay> &d :
-           displays_)
-        d.second.RegisterRefreshCallback(data, function);
+      refresh_callback_ = std::make_pair(HWC2_PFN_REFRESH(function), data);
       break;
     }
     case HWC2::Callback::Vsync: {
-      for (std::pair<const hwc2_display_t, DrmHwcTwo::HwcDisplay> &d :
-           displays_)
-        d.second.RegisterVsyncCallback(data, function);
+      vsync_callback_ = std::make_pair(HWC2_PFN_VSYNC(function), data);
       break;
     }
+#if PLATFORM_SDK_VERSION > 29
+    case HWC2::Callback::Vsync_2_4: {
+      vsync_2_4_callback_ = std::make_pair(HWC2_PFN_VSYNC_2_4(function), data);
+      break;
+    }
+#endif
     default:
       break;
   }
@@ -211,8 +235,9 @@
 
 DrmHwcTwo::HwcDisplay::HwcDisplay(ResourceManager *resource_manager,
                                   DrmDevice *drm, hwc2_display_t handle,
-                                  HWC2::DisplayType type)
-    : resource_manager_(resource_manager),
+                                  HWC2::DisplayType type, DrmHwcTwo *hwc2)
+    : hwc2_(hwc2),
+      resource_manager_(resource_manager),
       drm_(drm),
       handle_(handle),
       type_(type),
@@ -271,7 +296,41 @@
     return HWC2::Error::BadDisplay;
   }
 
-  ret = vsync_worker_.Init(drm_, display);
+  ret = vsync_worker_.Init(drm_, display, [this](int64_t timestamp) {
+    const std::lock_guard<std::mutex> lock(hwc2_->callback_lock_);
+    /* vsync callback */
+#if PLATFORM_SDK_VERSION > 29
+    if (hwc2_->vsync_2_4_callback_.first != nullptr &&
+        hwc2_->vsync_2_4_callback_.second != nullptr) {
+      hwc2_vsync_period_t period_ns{};
+      GetDisplayVsyncPeriod(&period_ns);
+      hwc2_->vsync_2_4_callback_.first(hwc2_->vsync_2_4_callback_.second,
+                                       handle_, timestamp, period_ns);
+    } else
+#endif
+        if (hwc2_->vsync_callback_.first != nullptr &&
+            hwc2_->vsync_callback_.second != nullptr) {
+      hwc2_->vsync_callback_.first(hwc2_->vsync_callback_.second, handle_,
+                                   timestamp);
+    }
+  });
+  if (ret) {
+    ALOGE("Failed to create event worker for d=%d %d\n", display, ret);
+    return HWC2::Error::BadDisplay;
+  }
+
+  ret = flattening_vsync_worker_.Init(drm_, display, [this](int64_t /*timestamp*/) {
+    const std::lock_guard<std::mutex> lock(hwc2_->callback_lock_);
+    /* Frontend flattening */
+    if (flattenning_state_ > ClientFlattenningState::ClientRefreshRequested &&
+        --flattenning_state_ ==
+            ClientFlattenningState::ClientRefreshRequested &&
+        hwc2_->refresh_callback_.first != nullptr &&
+        hwc2_->refresh_callback_.second != nullptr) {
+      hwc2_->refresh_callback_.first(hwc2_->refresh_callback_.second, handle_);
+      flattening_vsync_worker_.VSyncControl(false);
+    }
+  });
   if (ret) {
     ALOGE("Failed to create event worker for d=%d %d\n", display, ret);
     return HWC2::Error::BadDisplay;
@@ -296,18 +355,6 @@
   return SetActiveConfig(connector_->get_preferred_mode_id());
 }
 
-void DrmHwcTwo::HwcDisplay::RegisterVsyncCallback(
-    hwc2_callback_data_t data, hwc2_function_pointer_t func) {
-  supported(__func__);
-  vsync_worker_.RegisterClientCallback(data, func);
-}
-
-void DrmHwcTwo::HwcDisplay::RegisterRefreshCallback(
-    hwc2_callback_data_t data, hwc2_function_pointer_t func) {
-  supported(__func__);
-  compositor_.SetRefreshCallback(data, func);
-}
-
 HWC2::Error DrmHwcTwo::HwcDisplay::AcceptDisplayChanges() {
   supported(__func__);
   for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_)
@@ -413,22 +460,26 @@
   auto attribute = static_cast<HWC2::Attribute>(attribute_in);
   switch (attribute) {
     case HWC2::Attribute::Width:
-      *value = mode->h_display();
+      *value = static_cast<int>(mode->h_display());
       break;
     case HWC2::Attribute::Height:
-      *value = mode->v_display();
+      *value = static_cast<int>(mode->v_display());
       break;
     case HWC2::Attribute::VsyncPeriod:
       // in nanoseconds
-      *value = 1000.0 * 1000.0 * 1000.0 / mode->v_refresh();
+      *value = static_cast<int>(1E9 / mode->v_refresh());
       break;
     case HWC2::Attribute::DpiX:
       // Dots per 1000 inches
-      *value = mm_width ? (mode->h_display() * kUmPerInch) / mm_width : -1;
+      *value = mm_width
+                   ? static_cast<int>(mode->h_display() * kUmPerInch / mm_width)
+                   : -1;
       break;
     case HWC2::Attribute::DpiY:
       // Dots per 1000 inches
-      *value = mm_height ? (mode->v_display() * kUmPerInch) / mm_height : -1;
+      *value = mm_height ? static_cast<int>(mode->v_display() * kUmPerInch /
+                                            mm_height)
+                         : -1;
       break;
 #if PLATFORM_SDK_VERSION > 29
     case HWC2::Attribute::ConfigGroup:
@@ -786,8 +837,8 @@
 
   hwc_frect_t source_crop = {.left = 0.0F,
                              .top = 0.0F,
-                             .right = bo.width + 0.0F,
-                             .bottom = bo.height + 0.0F};
+                             .right = static_cast<float>(bo.width),
+                             .bottom = static_cast<float>(bo.height)};
   client_layer_.SetLayerSourceCrop(source_crop);
 
   return HWC2::Error::None;
@@ -909,7 +960,7 @@
   if (mode.id() == 0)
     return HWC2::Error::BadConfig;
 
-  *outVsyncPeriod = 1E9 / mode.v_refresh();
+  *outVsyncPeriod = static_cast<hwc2_vsync_period_t>(1E9 / mode.v_refresh());
   return HWC2::Error::None;
 }
 
@@ -958,9 +1009,9 @@
     uint8_t *outPort, uint32_t *outDataSize, uint8_t *outData) {
   supported(__func__);
 
-  drmModePropertyBlobPtr blob = nullptr;
+  auto blob = connector_->GetEdidBlob();
 
-  if (connector_->GetEdidBlob(blob)) {
+  if (!blob) {
     ALOGE("Failed to get edid property value.");
     return HWC2::Error::Unsupported;
   }
@@ -1041,16 +1092,29 @@
 
 #endif /* PLATFORM_SDK_VERSION > 27 */
 
-HWC2::Error DrmHwcTwo::HwcLayer::SetCursorPosition(int32_t x, int32_t y) {
+HWC2::Error DrmHwcTwo::HwcLayer::SetCursorPosition(int32_t /*x*/,
+                                                   int32_t /*y*/) {
   supported(__func__);
-  cursor_x_ = x;
-  cursor_y_ = y;
   return HWC2::Error::None;
 }
 
 HWC2::Error DrmHwcTwo::HwcLayer::SetLayerBlendMode(int32_t mode) {
   supported(__func__);
-  blending_ = static_cast<HWC2::BlendMode>(mode);
+  switch (static_cast<HWC2::BlendMode>(mode)) {
+    case HWC2::BlendMode::None:
+      blending_ = DrmHwcBlending::kNone;
+      break;
+    case HWC2::BlendMode::Premultiplied:
+      blending_ = DrmHwcBlending::kPreMult;
+      break;
+    case HWC2::BlendMode::Coverage:
+      blending_ = DrmHwcBlending::kCoverage;
+      break;
+    default:
+      ALOGE("Unknown blending mode b=%d", blending_);
+      blending_ = DrmHwcBlending::kNone;
+      break;
+  }
   return HWC2::Error::None;
 }
 
@@ -1066,10 +1130,9 @@
   return HWC2::Error::None;
 }
 
-HWC2::Error DrmHwcTwo::HwcLayer::SetLayerColor(hwc_color_t color) {
+HWC2::Error DrmHwcTwo::HwcLayer::SetLayerColor(hwc_color_t /*color*/) {
   // TODO(nobody): Put to client composition here?
   supported(__func__);
-  layer_color_ = color;
   return HWC2::Error::None;
 }
 
@@ -1080,7 +1143,34 @@
 
 HWC2::Error DrmHwcTwo::HwcLayer::SetLayerDataspace(int32_t dataspace) {
   supported(__func__);
-  dataspace_ = static_cast<android_dataspace_t>(dataspace);
+  switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
+    case HAL_DATASPACE_STANDARD_BT709:
+      color_space_ = DrmHwcColorSpace::kItuRec709;
+      break;
+    case HAL_DATASPACE_STANDARD_BT601_625:
+    case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED:
+    case HAL_DATASPACE_STANDARD_BT601_525:
+    case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED:
+      color_space_ = DrmHwcColorSpace::kItuRec601;
+      break;
+    case HAL_DATASPACE_STANDARD_BT2020:
+    case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
+      color_space_ = DrmHwcColorSpace::kItuRec2020;
+      break;
+    default:
+      color_space_ = DrmHwcColorSpace::kUndefined;
+  }
+
+  switch (dataspace & HAL_DATASPACE_RANGE_MASK) {
+    case HAL_DATASPACE_RANGE_FULL:
+      sample_range_ = DrmHwcSampleRange::kFullRange;
+      break;
+    case HAL_DATASPACE_RANGE_LIMITED:
+      sample_range_ = DrmHwcSampleRange::kLimitedRange;
+      break;
+    default:
+      sample_range_ = DrmHwcSampleRange::kUndefined;
+  }
   return HWC2::Error::None;
 }
 
@@ -1118,7 +1208,27 @@
 
 HWC2::Error DrmHwcTwo::HwcLayer::SetLayerTransform(int32_t transform) {
   supported(__func__);
-  transform_ = static_cast<HWC2::Transform>(transform);
+
+  uint32_t l_transform = 0;
+
+  // 270* and 180* cannot be combined with flips. More specifically, they
+  // already contain both horizontal and vertical flips, so those fields are
+  // redundant in this case. 90* rotation can be combined with either horizontal
+  // flip or vertical flip, so treat it differently
+  if (transform == HWC_TRANSFORM_ROT_270) {
+    l_transform = DrmHwcTransform::kRotate270;
+  } else if (transform == HWC_TRANSFORM_ROT_180) {
+    l_transform = DrmHwcTransform::kRotate180;
+  } else {
+    if (transform & HWC_TRANSFORM_FLIP_H)
+      l_transform |= DrmHwcTransform::kFlipH;
+    if (transform & HWC_TRANSFORM_FLIP_V)
+      l_transform |= DrmHwcTransform::kFlipV;
+    if (transform & HWC_TRANSFORM_ROT_90)
+      l_transform |= DrmHwcTransform::kRotate90;
+  }
+
+  transform_ = static_cast<DrmHwcTransform>(l_transform);
   return HWC2::Error::None;
 }
 
@@ -1137,40 +1247,28 @@
 
 void DrmHwcTwo::HwcLayer::PopulateDrmLayer(DrmHwcLayer *layer) {
   supported(__func__);
-  switch (blending_) {
-    case HWC2::BlendMode::None:
-      layer->blending = DrmHwcBlending::kNone;
-      break;
-    case HWC2::BlendMode::Premultiplied:
-      layer->blending = DrmHwcBlending::kPreMult;
-      break;
-    case HWC2::BlendMode::Coverage:
-      layer->blending = DrmHwcBlending::kCoverage;
-      break;
-    default:
-      ALOGE("Unknown blending mode b=%d", blending_);
-      layer->blending = DrmHwcBlending::kNone;
-      break;
-  }
-
   layer->sf_handle = buffer_;
   // TODO(rsglobal): Avoid extra fd duplication
   layer->acquire_fence = UniqueFd(fcntl(acquire_fence_.Get(), F_DUPFD_CLOEXEC));
   layer->display_frame = display_frame_;
   layer->alpha = lround(65535.0F * alpha_);
+  layer->blending = blending_;
   layer->source_crop = source_crop_;
-  layer->SetTransform(static_cast<int32_t>(transform_));
-  layer->dataspace = dataspace_;
+  layer->transform = transform_;
+  layer->color_space = color_space_;
+  layer->sample_range = sample_range_;
 }
 
 void DrmHwcTwo::HandleDisplayHotplug(hwc2_display_t displayid, int state) {
-  const std::lock_guard<std::mutex> lock(hotplug_callback_lock);
+  const std::lock_guard<std::mutex> lock(callback_lock_);
 
-  if (hotplug_callback_hook_ && hotplug_callback_data_)
-    hotplug_callback_hook_(hotplug_callback_data_, displayid,
-                           state == DRM_MODE_CONNECTED
-                               ? HWC2_CONNECTION_CONNECTED
-                               : HWC2_CONNECTION_DISCONNECTED);
+  if (hotplug_callback_.first != nullptr &&
+      hotplug_callback_.second != nullptr) {
+    hotplug_callback_.first(hotplug_callback_.second, displayid,
+                            state == DRM_MODE_CONNECTED
+                                ? HWC2_CONNECTION_CONNECTED
+                                : HWC2_CONNECTION_DISCONNECTED);
+  }
 }
 
 void DrmHwcTwo::HandleInitialHotplugState(DrmDevice *drmDevice) {
diff --git a/DrmHwcTwo.h b/DrmHwcTwo.h
index 111c664..0d213fd 100644
--- a/DrmHwcTwo.h
+++ b/DrmHwcTwo.h
@@ -42,16 +42,14 @@
 
   HWC2::Error Init();
 
-  hwc2_callback_data_t hotplug_callback_data_ = NULL;
-  HWC2_PFN_HOTPLUG hotplug_callback_hook_ = NULL;
-  std::mutex hotplug_callback_lock;
+  std::pair<HWC2_PFN_HOTPLUG, hwc2_callback_data_t> hotplug_callback_{};
+  std::pair<HWC2_PFN_VSYNC, hwc2_callback_data_t> vsync_callback_{};
+#if PLATFORM_SDK_VERSION > 29
+  std::pair<HWC2_PFN_VSYNC_2_4, hwc2_callback_data_t> vsync_2_4_callback_{};
+#endif
+  std::pair<HWC2_PFN_REFRESH, hwc2_callback_data_t> refresh_callback_{};
 
-  void SetHotplugCallback(hwc2_callback_data_t data,
-                          hwc2_function_pointer_t hook) {
-    const std::lock_guard<std::mutex> lock(hotplug_callback_lock);
-    hotplug_callback_data_ = data;
-    hotplug_callback_hook_ = reinterpret_cast<HWC2_PFN_HOTPLUG>(hook);
-  }
+  std::mutex callback_lock_;
 
   class HwcLayer {
    public:
@@ -102,10 +100,10 @@
     }
 
     // Layer hooks
-    HWC2::Error SetCursorPosition(int32_t x, int32_t y);
+    HWC2::Error SetCursorPosition(int32_t /*x*/, int32_t /*y*/);
     HWC2::Error SetLayerBlendMode(int32_t mode);
     HWC2::Error SetLayerBuffer(buffer_handle_t buffer, int32_t acquire_fence);
-    HWC2::Error SetLayerColor(hwc_color_t color);
+    HWC2::Error SetLayerColor(hwc_color_t /*color*/);
     HWC2::Error SetLayerCompositionType(int32_t type);
     HWC2::Error SetLayerDataspace(int32_t dataspace);
     HWC2::Error SetLayerDisplayFrame(hwc_rect_t frame);
@@ -133,30 +131,24 @@
     HWC2::Composition sf_type_ = HWC2::Composition::Invalid;
     HWC2::Composition validated_type_ = HWC2::Composition::Invalid;
 
-    HWC2::BlendMode blending_ = HWC2::BlendMode::None;
     buffer_handle_t buffer_ = NULL;
     hwc_rect_t display_frame_;
     float alpha_ = 1.0f;
     hwc_frect_t source_crop_;
-    int32_t cursor_x_;
-    int32_t cursor_y_;
-    hwc_color_t layer_color_;
-    HWC2::Transform transform_ = HWC2::Transform::None;
+    DrmHwcTransform transform_ = DrmHwcTransform::kIdentity;
     uint32_t z_order_ = 0;
-    android_dataspace_t dataspace_ = HAL_DATASPACE_UNKNOWN;
+    DrmHwcBlending blending_ = DrmHwcBlending::kNone;
+    DrmHwcColorSpace color_space_ = DrmHwcColorSpace::kUndefined;
+    DrmHwcSampleRange sample_range_ = DrmHwcSampleRange::kUndefined;
   };
 
   class HwcDisplay {
    public:
     HwcDisplay(ResourceManager *resource_manager, DrmDevice *drm,
-               hwc2_display_t handle, HWC2::DisplayType type);
+               hwc2_display_t handle, HWC2::DisplayType type, DrmHwcTwo *hwc2);
     HwcDisplay(const HwcDisplay &) = delete;
     HWC2::Error Init(std::vector<DrmPlane *> *planes);
 
-    void RegisterVsyncCallback(hwc2_callback_data_t data,
-                               hwc2_function_pointer_t func);
-    void RegisterRefreshCallback(hwc2_callback_data_t data,
-                                 hwc2_function_pointer_t func);
     HWC2::Error CreateComposition(bool test);
     std::vector<DrmHwcTwo::HwcLayer *> GetOrderLayersByZPos();
 
@@ -301,11 +293,46 @@
       return total_stats_;
     }
 
+    /* returns true if composition should be sent to client */
+    bool ProcessClientFlatteningState(bool skip) {
+      int flattenning_state = flattenning_state_;
+      if (flattenning_state == ClientFlattenningState::Disabled) {
+        return false;
+      }
+
+      if (skip) {
+        flattenning_state_ = ClientFlattenningState::NotRequired;
+        return false;
+      }
+
+      if (flattenning_state == ClientFlattenningState::ClientRefreshRequested) {
+        flattenning_state_ = ClientFlattenningState::Flattened;
+        return true;
+      }
+
+      flattening_vsync_worker_.VSyncControl(true);
+      flattenning_state_ = ClientFlattenningState::VsyncCountdownMax;
+      return false;
+    }
+
    private:
+    enum ClientFlattenningState : int32_t {
+      Disabled = -3,
+      NotRequired = -2,
+      Flattened = -1,
+      ClientRefreshRequested = 0,
+      VsyncCountdownMax = 60, /* 1 sec @ 60FPS */
+    };
+
+    std::atomic_int flattenning_state_{ClientFlattenningState::NotRequired};
+    VSyncWorker flattening_vsync_worker_;
+
     void AddFenceToPresentFence(UniqueFd fd);
 
     constexpr static size_t MATRIX_SIZE = 16;
 
+    DrmHwcTwo *hwc2_;
+
     ResourceManager *resource_manager_;
     DrmDevice *drm_;
     DrmDisplayCompositor compositor_;
diff --git a/README.md b/README.md
index 728bc76..c142266 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@
   you with formatting of your patches:
 
     ```
-    git diff | clang-format-diff-11 -p 1 -style=file
+    git diff | clang-format-diff-12 -p 1 -style=file
     ```
 
 * Hardware specific changes should be tested on relevant platforms before
diff --git a/backend/Backend.cpp b/backend/Backend.cpp
index 312faed..d7eb240 100644
--- a/backend/Backend.cpp
+++ b/backend/Backend.cpp
@@ -34,7 +34,8 @@
   int client_start = -1;
   size_t client_size = 0;
 
-  if (display->compositor().ShouldFlattenOnClient()) {
+  if (display->ProcessClientFlatteningState(layers.size() <= 1)) {
+    display->total_stats().frames_flattened_++;
     client_start = 0;
     client_size = layers.size();
     MarkValidated(layers, client_start, client_size);
@@ -56,8 +57,6 @@
 
   *num_types = client_size;
 
-  display->total_stats().frames_flattened_ = display->compositor()
-                                                 .GetFlattenedFramesCount();
   display->total_stats().gpu_pixops_ += CalcPixOps(layers, client_start,
                                                    client_size);
   display->total_stats().total_pixops_ += CalcPixOps(layers, 0, layers.size());
diff --git a/bufferinfo/BufferInfoMapperMetadata.cpp b/bufferinfo/BufferInfoMapperMetadata.cpp
index 23a9072..a8e95e7 100644
--- a/bufferinfo/BufferInfoMapperMetadata.cpp
+++ b/bufferinfo/BufferInfoMapperMetadata.cpp
@@ -47,30 +47,42 @@
  */
 int __attribute__((weak))
 BufferInfoMapperMetadata::GetFds(buffer_handle_t handle, hwc_drm_bo_t *bo) {
-  int num_fds = handle->numFds;
+  int fd_index = 0;
 
-  if (num_fds >= 1 && num_fds <= 2) {
-    if (IsDrmFormatRgb(bo->format)) {
-      bo->prime_fds[0] = handle->data[0];
-    } else {
-      bo->prime_fds[0] = bo->prime_fds[1] = bo->prime_fds[2] = handle->data[0];
-    }
-    if (bo->prime_fds[0] <= 0) {
-      ALOGE("Encountered invalid fd %d", bo->prime_fds[0]);
-      return android::BAD_VALUE;
+  if (handle->numFds <= 0) {
+    ALOGE("Handle has no fds");
+    return android::BAD_VALUE;
+  }
+
+  for (int i = 0; i < HWC_DRM_BO_MAX_PLANES; i++) {
+    /* If no size, we're out of usable planes */
+    if (bo->sizes[i] <= 0) {
+      if (i == 0) {
+        ALOGE("Bad handle metadata");
+        return android::BAD_VALUE;
+      }
+      break;
     }
 
-  } else if (num_fds >= 3) {
-    bo->prime_fds[0] = handle->data[0];
-    bo->prime_fds[1] = handle->data[1];
-    bo->prime_fds[2] = handle->data[2];
-    for (int i = 0; i < 3; i++) {
-      if (bo->prime_fds[i] <= 0) {
-        ALOGE("Encountered invalid fd %d", bo->prime_fds[i]);
+    /*
+     * If the offset is zero, its multi-buffer
+     * so move to the next fd
+     */
+    if (i != 0 && bo->offsets[i] == 0) {
+      fd_index++;
+      if (fd_index >= handle->numFds) {
+        ALOGE("Handle has no more fds");
         return android::BAD_VALUE;
       }
     }
+
+    bo->prime_fds[i] = handle->data[fd_index];
+    if (bo->prime_fds[i] <= 0) {
+      ALOGE("Invalid prime fd");
+      return android::BAD_VALUE;
+    }
   }
+
   return 0;
 }
 
@@ -135,6 +147,7 @@
     bo->modifiers[i] = bo->modifiers[0];
     bo->pitches[i] = layouts[i].strideInBytes;
     bo->offsets[i] = layouts[i].offsetInBytes;
+    bo->sizes[i] = layouts[i].totalSizeInBytes;
   }
 
   return GetFds(handle, bo);
diff --git a/bufferinfo/legacy/BufferInfoLibdrm.cpp b/bufferinfo/legacy/BufferInfoLibdrm.cpp
index 52f792f..da89eb5 100644
--- a/bufferinfo/legacy/BufferInfoLibdrm.cpp
+++ b/bufferinfo/legacy/BufferInfoLibdrm.cpp
@@ -37,9 +37,9 @@
 
 struct DroidYuvFormat {
   /* Lookup keys */
-  int native;                     /* HAL_PIXEL_FORMAT_ */
+  uint32_t 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. */
+  size_t chroma_step; /* Distance in bytes between subsequent chroma pixels. */
 
   /* Result */
   int fourcc; /* DRM_FORMAT_ */
@@ -64,8 +64,8 @@
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
 
-static int get_fourcc_yuv(int native, enum chroma_order chroma_order,
-                          int chroma_step) {
+static int get_fourcc_yuv(uint32_t native, enum chroma_order chroma_order,
+                          size_t chroma_step) {
   for (auto droid_yuv_format : kDroidYuvFormats)
     if (droid_yuv_format.native == native &&
         droid_yuv_format.chroma_order == chroma_order &&
@@ -75,7 +75,7 @@
   return -1;
 }
 
-static bool is_yuv(int native) {
+static bool is_yuv(uint32_t native) {
   for (auto droid_yuv_format : kDroidYuvFormats)
     if (droid_yuv_format.native == native)
       return true;
diff --git a/compositor/DrmDisplayComposition.cpp b/compositor/DrmDisplayComposition.cpp
index 49dff0e..c0fbba0 100644
--- a/compositor/DrmDisplayComposition.cpp
+++ b/compositor/DrmDisplayComposition.cpp
@@ -130,155 +130,4 @@
   return 0;
 }
 
-static const char *DrmCompositionTypeToString(DrmCompositionType type) {
-  switch (type) {
-    case DRM_COMPOSITION_TYPE_EMPTY:
-      return "EMPTY";
-    case DRM_COMPOSITION_TYPE_FRAME:
-      return "FRAME";
-    case DRM_COMPOSITION_TYPE_DPMS:
-      return "DPMS";
-    case DRM_COMPOSITION_TYPE_MODESET:
-      return "MODESET";
-    default:
-      return "<invalid>";
-  }
-}
-
-static const char *DPMSModeToString(int dpms_mode) {
-  switch (dpms_mode) {
-    case DRM_MODE_DPMS_ON:
-      return "ON";
-    case DRM_MODE_DPMS_OFF:
-      return "OFF";
-    default:
-      return "<invalid>";
-  }
-}
-
-static void DumpBuffer(const DrmHwcLayer &layer, std::ostringstream *out) {
-  *out << "buffer[w/h/format]=";
-  *out << layer.buffer_info.width << "/" << layer.buffer_info.height << "/"
-       << layer.buffer_info.format;
-}
-
-static void DumpTransform(uint32_t transform, std::ostringstream *out) {
-  *out << "[";
-
-  if (transform == 0)
-    *out << "IDENTITY";
-
-  bool separator = false;
-  if (transform & DrmHwcTransform::kFlipH) {
-    *out << "FLIPH";
-    separator = true;
-  }
-  if (transform & DrmHwcTransform::kFlipV) {
-    if (separator)
-      *out << "|";
-    *out << "FLIPV";
-    separator = true;
-  }
-  if (transform & DrmHwcTransform::kRotate90) {
-    if (separator)
-      *out << "|";
-    *out << "ROTATE90";
-    separator = true;
-  }
-  if (transform & DrmHwcTransform::kRotate180) {
-    if (separator)
-      *out << "|";
-    *out << "ROTATE180";
-    separator = true;
-  }
-  if (transform & DrmHwcTransform::kRotate270) {
-    if (separator)
-      *out << "|";
-    *out << "ROTATE270";
-    separator = true;
-  }
-
-  uint32_t valid_bits = DrmHwcTransform::kFlipH | DrmHwcTransform::kFlipV |
-                        DrmHwcTransform::kRotate90 |
-                        DrmHwcTransform::kRotate180 |
-                        DrmHwcTransform::kRotate270;
-  if (transform & ~valid_bits) {
-    if (separator)
-      *out << "|";
-    *out << "INVALID";
-  }
-  *out << "]";
-}
-
-static const char *BlendingToString(DrmHwcBlending blending) {
-  switch (blending) {
-    case DrmHwcBlending::kNone:
-      return "NONE";
-    case DrmHwcBlending::kPreMult:
-      return "PREMULT";
-    case DrmHwcBlending::kCoverage:
-      return "COVERAGE";
-    default:
-      return "<invalid>";
-  }
-}
-
-void DrmDisplayComposition::Dump(std::ostringstream *out) const {
-  *out << "----DrmDisplayComposition"
-       << " crtc=" << (crtc_ ? crtc_->id() : -1)
-       << " type=" << DrmCompositionTypeToString(type_);
-
-  switch (type_) {
-    case DRM_COMPOSITION_TYPE_DPMS:
-      *out << " dpms_mode=" << DPMSModeToString(dpms_mode_);
-      break;
-    case DRM_COMPOSITION_TYPE_MODESET:
-      *out << " display_mode=" << display_mode_.h_display() << "x"
-           << display_mode_.v_display();
-      break;
-    default:
-      break;
-  }
-
-  *out << "    Layers: count=" << layers_.size() << "\n";
-  for (size_t i = 0; i < layers_.size(); i++) {
-    const DrmHwcLayer &layer = layers_[i];
-    *out << "      [" << i << "] ";
-
-    DumpBuffer(layer, out);
-
-    if (layer.protected_usage())
-      *out << " protected";
-
-    *out << " transform=";
-    DumpTransform(layer.transform, out);
-    *out << " blending[a=" << (int)layer.alpha
-         << "]=" << BlendingToString(layer.blending) << "\n";
-  }
-
-  *out << "    Planes: count=" << composition_planes_.size() << "\n";
-  for (size_t i = 0; i < composition_planes_.size(); i++) {
-    const DrmCompositionPlane &comp_plane = composition_planes_[i];
-    *out << "      [" << i << "]"
-         << " plane=" << (comp_plane.plane() ? comp_plane.plane()->id() : -1)
-         << " type=";
-    switch (comp_plane.type()) {
-      case DrmCompositionPlane::Type::kDisable:
-        *out << "DISABLE";
-        break;
-      case DrmCompositionPlane::Type::kLayer:
-        *out << "LAYER";
-        break;
-      default:
-        *out << "<invalid>";
-        break;
-    }
-
-    *out << " source_layer=";
-    for (auto i : comp_plane.source_layers()) {
-      *out << i << " ";
-    }
-    *out << "\n";
-  }
-}
 }  // namespace android
diff --git a/compositor/DrmDisplayComposition.h b/compositor/DrmDisplayComposition.h
index 1738630..bbac0af 100644
--- a/compositor/DrmDisplayComposition.h
+++ b/compositor/DrmDisplayComposition.h
@@ -127,8 +127,6 @@
     return planner_;
   }
 
-  void Dump(std::ostringstream *out) const;
-
   UniqueFd out_fence_;
 
  private:
diff --git a/compositor/DrmDisplayCompositor.cpp b/compositor/DrmDisplayCompositor.cpp
index a1fe50f..576c533 100644
--- a/compositor/DrmDisplayCompositor.cpp
+++ b/compositor/DrmDisplayCompositor.cpp
@@ -34,75 +34,29 @@
 #include "drm/DrmCrtc.h"
 #include "drm/DrmDevice.h"
 #include "drm/DrmPlane.h"
+#include "drm/DrmUnique.h"
 #include "utils/autolock.h"
 #include "utils/log.h"
 
 namespace android {
 
-std::ostream &operator<<(std::ostream &str, FlatteningState state) {
-  std::array<const char *, 6> flattenting_state_str = {
-      "None",   "Not needed", "SF Requested", "Squashed by GPU",
-      "Serial", "Concurrent",
-  };
-
-  return str << flattenting_state_str[static_cast<int>(state)];
-}
-
-class CompositorVsyncCallback : public VsyncCallback {
- public:
-  explicit CompositorVsyncCallback(DrmDisplayCompositor *compositor)
-      : compositor_(compositor) {
-  }
-
-  void Callback(int display, int64_t timestamp) override {
-    compositor_->Vsync(display, timestamp);
-  }
-
- private:
-  DrmDisplayCompositor *compositor_;
-};
-
 DrmDisplayCompositor::DrmDisplayCompositor()
     : resource_manager_(nullptr),
       display_(-1),
       initialized_(false),
       active_(false),
-      use_hw_overlays_(true),
-      dump_frames_composited_(0),
-      dump_last_timestamp_ns_(0),
-      flatten_countdown_(FLATTEN_COUNTDOWN_INIT),
-      flattening_state_(FlatteningState::kNone),
-      frames_flattened_(0) {
-  struct timespec ts {};
-  if (clock_gettime(CLOCK_MONOTONIC, &ts))
-    return;
-  dump_last_timestamp_ns_ = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
+      use_hw_overlays_(true) {
 }
 
 DrmDisplayCompositor::~DrmDisplayCompositor() {
   if (!initialized_)
     return;
 
-  vsync_worker_.Exit();
-  int ret = pthread_mutex_lock(&lock_);
-  if (ret)
-    ALOGE("Failed to acquire compositor lock %d", ret);
-  DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
-  if (mode_.blob_id)
-    drm->DestroyPropertyBlob(mode_.blob_id);
-  if (mode_.old_blob_id)
-    drm->DestroyPropertyBlob(mode_.old_blob_id);
-
   active_composition_.reset();
-
-  ret = pthread_mutex_unlock(&lock_);
-  if (ret)
-    ALOGE("Failed to acquire compositor lock %d", ret);
-
-  pthread_mutex_destroy(&lock_);
 }
 
-int DrmDisplayCompositor::Init(ResourceManager *resource_manager, int display) {
+auto DrmDisplayCompositor::Init(ResourceManager *resource_manager, int display)
+    -> int {
   resource_manager_ = resource_manager;
   display_ = display;
   DrmDevice *drm = resource_manager_->GetDrmDevice(display);
@@ -110,17 +64,8 @@
     ALOGE("Could not find drmdevice for display");
     return -EINVAL;
   }
-  int ret = pthread_mutex_init(&lock_, nullptr);
-  if (ret) {
-    ALOGE("Failed to initialize drm compositor lock %d\n", ret);
-    return ret;
-  }
   planner_ = Planner::CreateInstance(drm);
 
-  vsync_worker_.Init(drm, display_);
-  auto callback = std::make_shared<CompositorVsyncCallback>(this);
-  vsync_worker_.RegisterCallback(callback);
-
   initialized_ = true;
   return 0;
 }
@@ -137,19 +82,6 @@
   return std::make_unique<DrmDisplayComposition>(crtc, planner_.get());
 }
 
-FlatteningState DrmDisplayCompositor::GetFlatteningState() const {
-  return flattening_state_;
-}
-
-uint32_t DrmDisplayCompositor::GetFlattenedFramesCount() const {
-  return frames_flattened_;
-}
-
-bool DrmDisplayCompositor::ShouldFlattenOnClient() const {
-  return flattening_state_ == FlatteningState::kClientRequested ||
-         flattening_state_ == FlatteningState::kClientDone;
-}
-
 std::tuple<uint32_t, uint32_t, int>
 DrmDisplayCompositor::GetActiveModeResolution() {
   DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
@@ -165,7 +97,7 @@
 }
 
 int DrmDisplayCompositor::DisablePlanes(DrmDisplayComposition *display_comp) {
-  drmModeAtomicReqPtr pset = drmModeAtomicAlloc();
+  auto pset = MakeDrmModeAtomicReqUnique();
   if (!pset) {
     ALOGE("Failed to allocate property set");
     return -ENOMEM;
@@ -175,26 +107,17 @@
   std::vector<DrmCompositionPlane> &comp_planes = display_comp
                                                       ->composition_planes();
   for (DrmCompositionPlane &comp_plane : comp_planes) {
-    DrmPlane *plane = comp_plane.plane();
-    ret = drmModeAtomicAddProperty(pset, plane->id(),
-                                   plane->crtc_property().id(), 0) < 0 ||
-          drmModeAtomicAddProperty(pset, plane->id(), plane->fb_property().id(),
-                                   0) < 0;
-    if (ret) {
-      ALOGE("Failed to add plane %d disable to pset", plane->id());
-      drmModeAtomicFree(pset);
-      return ret;
+    if (comp_plane.plane()->AtomicDisablePlane(*pset) != 0) {
+      return -EINVAL;
     }
   }
   DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
-  ret = drmModeAtomicCommit(drm->fd(), pset, 0, drm);
+  ret = drmModeAtomicCommit(drm->fd(), pset.get(), 0, drm);
   if (ret) {
     ALOGE("Failed to commit pset ret=%d\n", ret);
-    drmModeAtomicFree(pset);
     return ret;
   }
 
-  drmModeAtomicFree(pset);
   return 0;
 }
 
@@ -221,58 +144,29 @@
     return -ENODEV;
   }
 
-  drmModeAtomicReqPtr pset = drmModeAtomicAlloc();
+  auto pset = MakeDrmModeAtomicReqUnique();
   if (!pset) {
     ALOGE("Failed to allocate property set");
     return -ENOMEM;
   }
 
-  if (crtc->out_fence_ptr_property().id() != 0) {
-    ret = drmModeAtomicAddProperty(pset, crtc->id(),
-                                   crtc->out_fence_ptr_property().id(),
-                                   (uint64_t)&out_fences[crtc->pipe()]);
-    if (ret < 0) {
-      ALOGE("Failed to add OUT_FENCE_PTR property to pset: %d", ret);
-      drmModeAtomicFree(pset);
-      return ret;
-    }
+  if (crtc->out_fence_ptr_property() &&
+      !crtc->out_fence_ptr_property()
+           .AtomicSet(*pset, (uint64_t)&out_fences[crtc->pipe()])) {
+    return -EINVAL;
   }
 
-  if (mode_.needs_modeset) {
-    ret = drmModeAtomicAddProperty(pset, crtc->id(),
-                                   crtc->active_property().id(), 1);
-    if (ret < 0) {
-      ALOGE("Failed to add crtc active to pset\n");
-      drmModeAtomicFree(pset);
-      return ret;
-    }
-
-    ret = drmModeAtomicAddProperty(pset, crtc->id(), crtc->mode_property().id(),
-                                   mode_.blob_id) < 0 ||
-          drmModeAtomicAddProperty(pset, connector->id(),
-                                   connector->crtc_id_property().id(),
-                                   crtc->id()) < 0;
-    if (ret) {
-      ALOGE("Failed to add blob %d to pset", mode_.blob_id);
-      drmModeAtomicFree(pset);
-      return ret;
-    }
+  if (mode_.blob &&
+      (!crtc->active_property().AtomicSet(*pset, 1) ||
+       !crtc->mode_property().AtomicSet(*pset, *mode_.blob) ||
+       !connector->crtc_id_property().AtomicSet(*pset, crtc->id()))) {
+    return -EINVAL;
   }
 
   for (DrmCompositionPlane &comp_plane : comp_planes) {
     DrmPlane *plane = comp_plane.plane();
     std::vector<size_t> &source_layers = comp_plane.source_layers();
 
-    int fb_id = -1;
-    int fence_fd = -1;
-    hwc_rect_t display_frame;
-    hwc_frect_t source_crop;
-    uint64_t rotation = 0;
-    uint64_t alpha = 0xFFFF;
-    uint64_t blend = UINT64_MAX;
-    uint64_t color_encoding = UINT64_MAX;
-    uint64_t color_range = UINT64_MAX;
-
     if (comp_plane.type() != DrmCompositionPlane::Type::kDisable) {
       if (source_layers.size() > 1) {
         ALOGE("Can't handle more than one source layer sz=%zu type=%d",
@@ -283,221 +177,17 @@
       if (source_layers.empty() || source_layers.front() >= layers.size()) {
         ALOGE("Source layer index %zu out of bounds %zu type=%d",
               source_layers.front(), layers.size(), comp_plane.type());
-        break;
+        return -EINVAL;
       }
       DrmHwcLayer &layer = layers[source_layers.front()];
-      if (!layer.FbIdHandle) {
-        ALOGE("Expected a valid framebuffer for pset");
-        break;
+
+      if (plane->AtomicSetState(*pset, layer, source_layers.front(),
+                                crtc->id()) != 0) {
+        return -EINVAL;
       }
-      fb_id = layer.FbIdHandle->GetFbId();
-      fence_fd = layer.acquire_fence.Get();
-      display_frame = layer.display_frame;
-      source_crop = layer.source_crop;
-      alpha = layer.alpha;
-
-      if (plane->blend_property().id()) {
-        switch (layer.blending) {
-          case DrmHwcBlending::kPreMult:
-            std::tie(blend, ret) = plane->blend_property().GetEnumValueWithName(
-                "Pre-multiplied");
-            break;
-          case DrmHwcBlending::kCoverage:
-            std::tie(blend, ret) = plane->blend_property().GetEnumValueWithName(
-                "Coverage");
-            break;
-          case DrmHwcBlending::kNone:
-          default:
-            std::tie(blend, ret) = plane->blend_property().GetEnumValueWithName(
-                "None");
-            break;
-        }
-      }
-
-      if (plane->zpos_property().id() &&
-          !plane->zpos_property().is_immutable()) {
-        uint64_t min_zpos = 0;
-
-        // Ignore ret and use min_zpos as 0 by default
-        std::tie(std::ignore, min_zpos) = plane->zpos_property().range_min();
-
-        ret = drmModeAtomicAddProperty(pset, plane->id(),
-                                       plane->zpos_property().id(),
-                                       source_layers.front() + min_zpos) < 0;
-        if (ret) {
-          ALOGE("Failed to add zpos property %d to plane %d",
-                plane->zpos_property().id(), plane->id());
-          break;
-        }
-      }
-
-      rotation = 0;
-      if (layer.transform & DrmHwcTransform::kFlipH)
-        rotation |= DRM_MODE_REFLECT_X;
-      if (layer.transform & DrmHwcTransform::kFlipV)
-        rotation |= DRM_MODE_REFLECT_Y;
-      if (layer.transform & DrmHwcTransform::kRotate90)
-        rotation |= DRM_MODE_ROTATE_90;
-      else if (layer.transform & DrmHwcTransform::kRotate180)
-        rotation |= DRM_MODE_ROTATE_180;
-      else if (layer.transform & DrmHwcTransform::kRotate270)
-        rotation |= DRM_MODE_ROTATE_270;
-      else
-        rotation |= DRM_MODE_ROTATE_0;
-
-      if (fence_fd >= 0) {
-        int prop_id = plane->in_fence_fd_property().id();
-        if (prop_id == 0) {
-          ALOGE("Failed to get IN_FENCE_FD property id");
-          break;
-        }
-        ret = drmModeAtomicAddProperty(pset, plane->id(), prop_id, fence_fd);
-        if (ret < 0) {
-          ALOGE("Failed to add IN_FENCE_FD property to pset: %d", ret);
-          break;
-        }
-      }
-
-      if (plane->color_encoding_propery().id()) {
-        switch (layer.dataspace & HAL_DATASPACE_STANDARD_MASK) {
-          case HAL_DATASPACE_STANDARD_BT709:
-            std::tie(color_encoding,
-                     ret) = plane->color_encoding_propery()
-                                .GetEnumValueWithName("ITU-R BT.709 YCbCr");
-            break;
-          case HAL_DATASPACE_STANDARD_BT601_625:
-          case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED:
-          case HAL_DATASPACE_STANDARD_BT601_525:
-          case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED:
-            std::tie(color_encoding,
-                     ret) = plane->color_encoding_propery()
-                                .GetEnumValueWithName("ITU-R BT.601 YCbCr");
-            break;
-          case HAL_DATASPACE_STANDARD_BT2020:
-          case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
-            std::tie(color_encoding,
-                     ret) = plane->color_encoding_propery()
-                                .GetEnumValueWithName("ITU-R BT.2020 YCbCr");
-            break;
-        }
-      }
-
-      if (plane->color_range_property().id()) {
-        switch (layer.dataspace & HAL_DATASPACE_RANGE_MASK) {
-          case HAL_DATASPACE_RANGE_FULL:
-            std::tie(color_range,
-                     ret) = plane->color_range_property()
-                                .GetEnumValueWithName("YCbCr full range");
-            break;
-          case HAL_DATASPACE_RANGE_LIMITED:
-            std::tie(color_range,
-                     ret) = plane->color_range_property()
-                                .GetEnumValueWithName("YCbCr limited range");
-            break;
-        }
-      }
-    }
-
-    // Disable the plane if there's no framebuffer
-    if (fb_id < 0) {
-      ret = drmModeAtomicAddProperty(pset, plane->id(),
-                                     plane->crtc_property().id(), 0) < 0 ||
-            drmModeAtomicAddProperty(pset, plane->id(),
-                                     plane->fb_property().id(), 0) < 0;
-      if (ret) {
-        ALOGE("Failed to add plane %d disable to pset", plane->id());
-        break;
-      }
-      continue;
-    }
-
-    ret = drmModeAtomicAddProperty(pset, plane->id(),
-                                   plane->crtc_property().id(), crtc->id()) < 0;
-    ret |= drmModeAtomicAddProperty(pset, plane->id(),
-                                    plane->fb_property().id(), fb_id) < 0;
-    ret |= drmModeAtomicAddProperty(pset, plane->id(),
-                                    plane->crtc_x_property().id(),
-                                    display_frame.left) < 0;
-    ret |= drmModeAtomicAddProperty(pset, plane->id(),
-                                    plane->crtc_y_property().id(),
-                                    display_frame.top) < 0;
-    ret |= drmModeAtomicAddProperty(pset, plane->id(),
-                                    plane->crtc_w_property().id(),
-                                    display_frame.right - display_frame.left) <
-           0;
-    ret |= drmModeAtomicAddProperty(pset, plane->id(),
-                                    plane->crtc_h_property().id(),
-                                    display_frame.bottom - display_frame.top) <
-           0;
-    ret |= drmModeAtomicAddProperty(pset, plane->id(),
-                                    plane->src_x_property().id(),
-                                    (int)(source_crop.left) << 16) < 0;
-    ret |= drmModeAtomicAddProperty(pset, plane->id(),
-                                    plane->src_y_property().id(),
-                                    (int)(source_crop.top) << 16) < 0;
-    ret |= drmModeAtomicAddProperty(pset, plane->id(),
-                                    plane->src_w_property().id(),
-                                    (int)(source_crop.right - source_crop.left)
-                                        << 16) < 0;
-    ret |= drmModeAtomicAddProperty(pset, plane->id(),
-                                    plane->src_h_property().id(),
-                                    (int)(source_crop.bottom - source_crop.top)
-                                        << 16) < 0;
-    if (ret) {
-      ALOGE("Failed to add plane %d to set", plane->id());
-      break;
-    }
-
-    if (plane->rotation_property().id()) {
-      ret = drmModeAtomicAddProperty(pset, plane->id(),
-                                     plane->rotation_property().id(),
-                                     rotation) < 0;
-      if (ret) {
-        ALOGE("Failed to add rotation property %d to plane %d",
-              plane->rotation_property().id(), plane->id());
-        break;
-      }
-    }
-
-    if (plane->alpha_property().id()) {
-      ret = drmModeAtomicAddProperty(pset, plane->id(),
-                                     plane->alpha_property().id(), alpha) < 0;
-      if (ret) {
-        ALOGE("Failed to add alpha property %d to plane %d",
-              plane->alpha_property().id(), plane->id());
-        break;
-      }
-    }
-
-    if (plane->blend_property().id() && blend != UINT64_MAX) {
-      ret = drmModeAtomicAddProperty(pset, plane->id(),
-                                     plane->blend_property().id(), blend) < 0;
-      if (ret) {
-        ALOGE("Failed to add pixel blend mode property %d to plane %d",
-              plane->blend_property().id(), plane->id());
-        break;
-      }
-    }
-
-    if (plane->color_encoding_propery().id() && color_encoding != UINT64_MAX) {
-      ret = drmModeAtomicAddProperty(pset, plane->id(),
-                                     plane->color_encoding_propery().id(),
-                                     color_encoding) < 0;
-      if (ret) {
-        ALOGE("Failed to add COLOR_ENCODING property %d to plane %d",
-              plane->color_encoding_propery().id(), plane->id());
-        break;
-      }
-    }
-
-    if (plane->color_range_property().id() && color_range != UINT64_MAX) {
-      ret = drmModeAtomicAddProperty(pset, plane->id(),
-                                     plane->color_range_property().id(),
-                                     color_range) < 0;
-      if (ret) {
-        ALOGE("Failed to add COLOR_RANGE property %d to plane %d",
-              plane->color_range_property().id(), plane->id());
-        break;
+    } else {
+      if (plane->AtomicDisablePlane(*pset) != 0) {
+        return -EINVAL;
       }
     }
   }
@@ -507,25 +197,15 @@
     if (test_only)
       flags |= DRM_MODE_ATOMIC_TEST_ONLY;
 
-    ret = drmModeAtomicCommit(drm->fd(), pset, flags, drm);
+    ret = drmModeAtomicCommit(drm->fd(), pset.get(), flags, drm);
     if (ret) {
       if (!test_only)
         ALOGE("Failed to commit pset ret=%d\n", ret);
-      drmModeAtomicFree(pset);
       return ret;
     }
   }
-  if (pset)
-    drmModeAtomicFree(pset);
 
-  if (!test_only && mode_.needs_modeset) {
-    ret = drm->DestroyPropertyBlob(mode_.old_blob_id);
-    if (ret) {
-      ALOGE("Failed to destroy old mode property blob %" PRIu32 "/%d",
-            mode_.old_blob_id, ret);
-      return ret;
-    }
-
+  if (!test_only && mode_.blob) {
     /* TODO: Add dpms to the pset when the kernel supports it */
     ret = ApplyDpms(display_comp);
     if (ret) {
@@ -534,12 +214,10 @@
     }
 
     connector->set_active_mode(mode_.mode);
-    mode_.old_blob_id = mode_.blob_id;
-    mode_.blob_id = 0;
-    mode_.needs_modeset = false;
+    mode_.old_blob = std::move(mode_.blob);
   }
 
-  if (crtc->out_fence_ptr_property().id()) {
+  if (crtc->out_fence_ptr_property()) {
     display_comp->out_fence_ = UniqueFd((int)out_fences[crtc->pipe()]);
   }
 
@@ -564,21 +242,14 @@
   return 0;
 }
 
-std::tuple<int, uint32_t> DrmDisplayCompositor::CreateModeBlob(
-    const DrmMode &mode) {
+auto DrmDisplayCompositor::CreateModeBlob(const DrmMode &mode)
+    -> DrmModeUserPropertyBlobUnique {
   struct drm_mode_modeinfo drm_mode {};
   mode.ToDrmModeModeInfo(&drm_mode);
 
-  uint32_t id = 0;
   DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
-  int ret = drm->CreatePropertyBlob(&drm_mode, sizeof(struct drm_mode_modeinfo),
-                                    &id);
-  if (ret) {
-    ALOGE("Failed to create mode property blob %d", ret);
-    return std::make_tuple(ret, 0);
-  }
-  ALOGE("Create blob_id %" PRIu32 "\n", id);
-  return std::make_tuple(ret, id);
+  return drm->RegisterUserPropertyBlob(&drm_mode,
+                                       sizeof(struct drm_mode_modeinfo));
 }
 
 void DrmDisplayCompositor::ClearDisplay() {
@@ -593,9 +264,6 @@
 
 void DrmDisplayCompositor::ApplyFrame(
     std::unique_ptr<DrmDisplayComposition> composition, int status) {
-  AutoLock lock(&lock_, __func__);
-  if (lock.Lock())
-    return;
   int ret = status;
 
   if (!ret) {
@@ -609,17 +277,8 @@
     ClearDisplay();
     return;
   }
-  ++dump_frames_composited_;
 
   active_composition_.swap(composition);
-
-  flatten_countdown_ = FLATTEN_COUNTDOWN_INIT;
-  if (flattening_state_ != FlatteningState::kClientRequested) {
-    SetFlattening(FlatteningState::kNone);
-  } else {
-    SetFlattening(FlatteningState::kClientDone);
-  }
-  vsync_worker_.VSyncControl(true);
 }
 
 int DrmDisplayCompositor::ApplyComposition(
@@ -647,15 +306,11 @@
       return ret;
     case DRM_COMPOSITION_TYPE_MODESET:
       mode_.mode = composition->display_mode();
-      if (mode_.blob_id)
-        resource_manager_->GetDrmDevice(display_)->DestroyPropertyBlob(
-            mode_.blob_id);
-      std::tie(ret, mode_.blob_id) = CreateModeBlob(mode_.mode);
-      if (ret) {
+      mode_.blob = CreateModeBlob(mode_.mode);
+      if (!mode_.blob) {
         ALOGE("Failed to create mode blob for display %d", display_);
-        return ret;
+        return -EINVAL;
       }
-      mode_.needs_modeset = true;
       return 0;
     default:
       ALOGE("Unknown composition type %d", composition->type());
@@ -669,99 +324,4 @@
   return CommitFrame(composition, true);
 }
 
-void DrmDisplayCompositor::SetFlattening(FlatteningState new_state) {
-  if (flattening_state_ != new_state) {
-    switch (flattening_state_) {
-      case FlatteningState::kClientDone:
-        ++frames_flattened_;
-        break;
-      case FlatteningState::kClientRequested:
-      case FlatteningState::kNone:
-      case FlatteningState::kNotNeeded:
-        break;
-    }
-  }
-  flattening_state_ = new_state;
-}
-
-bool DrmDisplayCompositor::IsFlatteningNeeded() const {
-  return CountdownExpired() && active_composition_->layers().size() >= 2;
-}
-
-int DrmDisplayCompositor::FlattenOnClient() {
-  const std::lock_guard<std::mutex> lock(refresh_callback_lock);
-
-  if (refresh_callback_hook_ && refresh_callback_data_) {
-    {
-      AutoLock lock(&lock_, __func__);
-      if (!IsFlatteningNeeded()) {
-        if (flattening_state_ != FlatteningState::kClientDone) {
-          ALOGV("Flattening is not needed");
-          SetFlattening(FlatteningState::kNotNeeded);
-        }
-        return -EALREADY;
-      }
-    }
-
-    ALOGV(
-        "No writeback connector available, "
-        "falling back to client composition");
-    SetFlattening(FlatteningState::kClientRequested);
-    refresh_callback_hook_(refresh_callback_data_, display_);
-    return 0;
-  }
-
-  ALOGV("No writeback connector available");
-  return -EINVAL;
-}
-
-int DrmDisplayCompositor::FlattenActiveComposition() {
-  return FlattenOnClient();
-}
-
-bool DrmDisplayCompositor::CountdownExpired() const {
-  return flatten_countdown_ <= 0;
-}
-
-void DrmDisplayCompositor::Vsync(int display, int64_t timestamp) {
-  AutoLock lock(&lock_, __func__);
-  if (lock.Lock())
-    return;
-  flatten_countdown_--;
-  if (!CountdownExpired())
-    return;
-  lock.Unlock();
-  int ret = FlattenActiveComposition();
-  ALOGV("scene flattening triggered for display %d at timestamp %" PRIu64
-        " result = %d \n",
-        display, timestamp, ret);
-}
-
-void DrmDisplayCompositor::Dump(std::ostringstream *out) const {
-  int ret = pthread_mutex_lock(&lock_);
-  if (ret)
-    return;
-
-  uint64_t num_frames = dump_frames_composited_;
-  dump_frames_composited_ = 0;
-
-  struct timespec ts {};
-  ret = clock_gettime(CLOCK_MONOTONIC, &ts);
-  if (ret) {
-    pthread_mutex_unlock(&lock_);
-    return;
-  }
-
-  uint64_t cur_ts = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
-  uint64_t num_ms = (cur_ts - dump_last_timestamp_ns_) / (1000 * 1000);
-  float fps = num_ms ? (num_frames * 1000.0F) / (num_ms) : 0.0F;
-
-  *out << "--DrmDisplayCompositor[" << display_
-       << "]: num_frames=" << num_frames << " num_ms=" << num_ms
-       << " fps=" << fps << "\n";
-
-  dump_last_timestamp_ns_ = cur_ts;
-
-  pthread_mutex_unlock(&lock_);
-}
 }  // namespace android
diff --git a/compositor/DrmDisplayCompositor.h b/compositor/DrmDisplayCompositor.h
index c0eed0c..3227e12 100644
--- a/compositor/DrmDisplayCompositor.h
+++ b/compositor/DrmDisplayCompositor.h
@@ -32,45 +32,19 @@
 #include "drm/VSyncWorker.h"
 #include "drmhwcomposer.h"
 
-// If a scene is still for this number of vblanks flatten it to reduce power
-// consumption.
-#define FLATTEN_COUNTDOWN_INIT 60
-
 namespace android {
 
-enum class FlatteningState {
-  kNone,
-  kNotNeeded,
-  kClientRequested,
-  kClientDone,
-};
-
-std::ostream &operator<<(std::ostream &str, FlatteningState state);
-
 class DrmDisplayCompositor {
  public:
   DrmDisplayCompositor();
   ~DrmDisplayCompositor();
 
-  int Init(ResourceManager *resource_manager, int display);
-
-  hwc2_callback_data_t refresh_callback_data_ = NULL;
-  HWC2_PFN_REFRESH refresh_callback_hook_ = NULL;
-  std::mutex refresh_callback_lock;
-
-  void SetRefreshCallback(hwc2_callback_data_t data,
-                          hwc2_function_pointer_t hook) {
-    const std::lock_guard<std::mutex> lock(refresh_callback_lock);
-    refresh_callback_data_ = data;
-    refresh_callback_hook_ = reinterpret_cast<HWC2_PFN_REFRESH>(hook);
-  }
+  auto Init(ResourceManager *resource_manager, int display) -> int;
 
   std::unique_ptr<DrmDisplayComposition> CreateInitializedComposition() const;
   int ApplyComposition(std::unique_ptr<DrmDisplayComposition> composition);
   int TestComposition(DrmDisplayComposition *composition);
   int Composite();
-  void Dump(std::ostringstream *out) const;
-  void Vsync(int display, int64_t timestamp);
   void ClearDisplay();
   UniqueFd TakeOutFence() {
     if (!active_composition_) {
@@ -79,27 +53,17 @@
     return std::move(active_composition_->out_fence_);
   }
 
-  FlatteningState GetFlatteningState() const;
-  uint32_t GetFlattenedFramesCount() const;
-  bool ShouldFlattenOnClient() const;
-
   std::tuple<uint32_t, uint32_t, int> GetActiveModeResolution();
 
  private:
   struct ModeState {
-    bool needs_modeset = false;
     DrmMode mode;
-    uint32_t blob_id = 0;
-    uint32_t old_blob_id = 0;
+    DrmModeUserPropertyBlobUnique blob;
+    DrmModeUserPropertyBlobUnique old_blob;
   };
 
   DrmDisplayCompositor(const DrmDisplayCompositor &) = delete;
 
-  // We'll wait for acquire fences to fire for kAcquireWaitTimeoutMs,
-  // kAcquireWaitTries times, logging a warning in between.
-  static const int kAcquireWaitTries = 5;
-  static const int kAcquireWaitTimeoutMs = 100;
-
   int CommitFrame(DrmDisplayComposition *display_comp, bool test_only);
   int ApplyDpms(DrmDisplayComposition *display_comp);
   int DisablePlanes(DrmDisplayComposition *display_comp);
@@ -107,14 +71,7 @@
   void ApplyFrame(std::unique_ptr<DrmDisplayComposition> composition,
                   int status);
 
-  void SetFlattening(FlatteningState new_state);
-  bool IsFlatteningNeeded() const;
-  int FlattenActiveComposition();
-  int FlattenOnClient();
-
-  bool CountdownExpired() const;
-
-  std::tuple<int, uint32_t> CreateModeBlob(const DrmMode &mode);
+  auto CreateModeBlob(const DrmMode &mode) -> DrmModeUserPropertyBlobUnique;
 
   ResourceManager *resource_manager_;
   int display_;
@@ -127,21 +84,7 @@
 
   ModeState mode_;
 
-  // mutable since we need to acquire in Dump()
-  mutable pthread_mutex_t lock_{};
-
-  // State tracking progress since our last Dump(). These are mutable since
-  // we need to reset them on every Dump() call.
-  mutable uint64_t dump_frames_composited_;
-  mutable uint64_t dump_last_timestamp_ns_;
-  VSyncWorker vsync_worker_;
-  int64_t flatten_countdown_;
   std::unique_ptr<Planner> planner_;
-
-  FlatteningState flattening_state_;
-  uint32_t frames_flattened_;
-
-  std::function<void(int)> refresh_display_cb_;
 };
 }  // namespace android
 
diff --git a/drm/DrmConnector.cpp b/drm/DrmConnector.cpp
index 0468527..b3179c7 100644
--- a/drm/DrmConnector.cpp
+++ b/drm/DrmConnector.cpp
@@ -90,20 +90,19 @@
   return ret;
 }
 
-int DrmConnector::GetEdidBlob(drmModePropertyBlobPtr &blob) {
+auto DrmConnector::GetEdidBlob() -> DrmModePropertyBlobUnique {
   uint64_t blob_id = 0;
   int ret = UpdateEdidProperty();
-  if (ret) {
-    return ret;
+  if (ret != 0) {
+    return DrmModePropertyBlobUnique();
   }
 
   std::tie(ret, blob_id) = edid_property().value();
-  if (ret) {
-    return ret;
+  if (ret != 0) {
+    return DrmModePropertyBlobUnique();
   }
 
-  blob = drmModeGetPropertyBlob(drm_->fd(), blob_id);
-  return !blob;
+  return MakeDrmModePropertyBlobUnique(drm_->fd(), blob_id);
 }
 
 uint32_t DrmConnector::id() const {
diff --git a/drm/DrmConnector.h b/drm/DrmConnector.h
index 3bc18c8..e2789ea 100644
--- a/drm/DrmConnector.h
+++ b/drm/DrmConnector.h
@@ -26,6 +26,7 @@
 #include "DrmEncoder.h"
 #include "DrmMode.h"
 #include "DrmProperty.h"
+#include "DrmUnique.h"
 
 namespace android {
 
@@ -41,7 +42,7 @@
 
   int Init();
   int UpdateEdidProperty();
-  int GetEdidBlob(drmModePropertyBlobPtr &blob);
+  auto GetEdidBlob() -> DrmModePropertyBlobUnique;
 
   uint32_t id() const;
 
diff --git a/drm/DrmDevice.cpp b/drm/DrmDevice.cpp
index abc8edc..1753ddc 100644
--- a/drm/DrmDevice.cpp
+++ b/drm/DrmDevice.cpp
@@ -161,7 +161,7 @@
     return std::make_tuple(-EACCES, 0);
   }
 
-  drmModeResPtr res = drmModeGetResources(fd());
+  auto res = MakeDrmModeResUnique(fd());
   if (!res) {
     ALOGE("Failed to get DrmDevice resources");
     return std::make_tuple(-ENODEV, 0);
@@ -177,15 +177,14 @@
   bool found_primary = num_displays != 0;
 
   for (int i = 0; !ret && i < res->count_crtcs; ++i) {
-    drmModeCrtcPtr c = drmModeGetCrtc(fd(), res->crtcs[i]);
+    auto c = MakeDrmModeCrtcUnique(fd(), res->crtcs[i]);
     if (!c) {
       ALOGE("Failed to get crtc %d", res->crtcs[i]);
       ret = -ENODEV;
       break;
     }
 
-    std::unique_ptr<DrmCrtc> crtc(new DrmCrtc(this, c, i));
-    drmModeFreeCrtc(c);
+    std::unique_ptr<DrmCrtc> crtc(new DrmCrtc(this, c.get(), i));
 
     ret = crtc->Init();
     if (ret) {
@@ -195,9 +194,9 @@
     crtcs_.emplace_back(std::move(crtc));
   }
 
-  std::vector<int> possible_clones;
+  std::vector<uint32_t> possible_clones;
   for (int i = 0; !ret && i < res->count_encoders; ++i) {
-    drmModeEncoderPtr e = drmModeGetEncoder(fd(), res->encoders[i]);
+    auto e = MakeDrmModeEncoderUnique(fd(), res->encoders[i]);
     if (!e) {
       ALOGE("Failed to get encoder %d", res->encoders[i]);
       ret = -ENODEV;
@@ -215,9 +214,8 @@
     }
 
     std::unique_ptr<DrmEncoder> enc(
-        new DrmEncoder(e, current_crtc, possible_crtcs));
+        new DrmEncoder(e.get(), current_crtc, possible_crtcs));
     possible_clones.push_back(e->possible_clones);
-    drmModeFreeEncoder(e);
 
     encoders_.emplace_back(std::move(enc));
   }
@@ -229,7 +227,7 @@
   }
 
   for (int i = 0; !ret && i < res->count_connectors; ++i) {
-    drmModeConnectorPtr c = drmModeGetConnector(fd(), res->connectors[i]);
+    auto c = MakeDrmModeConnectorUnique(fd(), res->connectors[i]);
     if (!c) {
       ALOGE("Failed to get connector %d", res->connectors[i]);
       ret = -ENODEV;
@@ -248,9 +246,7 @@
     }
 
     std::unique_ptr<DrmConnector> conn(
-        new DrmConnector(this, c, current_encoder, possible_encoders));
-
-    drmModeFreeConnector(c);
+        new DrmConnector(this, c.get(), current_encoder, possible_encoders));
 
     ret = conn->Init();
     if (ret) {
@@ -299,30 +295,25 @@
     }
   }
 
-  if (res)
-    drmModeFreeResources(res);
-
   // Catch-all for the above loops
   if (ret)
     return std::make_tuple(ret, 0);
 
-  drmModePlaneResPtr plane_res = drmModeGetPlaneResources(fd());
+  auto plane_res = MakeDrmModePlaneResUnique(fd());
   if (!plane_res) {
     ALOGE("Failed to get plane resources");
     return std::make_tuple(-ENOENT, 0);
   }
 
   for (uint32_t i = 0; i < plane_res->count_planes; ++i) {
-    drmModePlanePtr p = drmModeGetPlane(fd(), plane_res->planes[i]);
+    auto p = MakeDrmModePlaneUnique(fd(), plane_res->planes[i]);
     if (!p) {
       ALOGE("Failed to get plane %d", plane_res->planes[i]);
       ret = -ENODEV;
       break;
     }
 
-    std::unique_ptr<DrmPlane> plane(new DrmPlane(this, p));
-
-    drmModeFreePlane(p);
+    std::unique_ptr<DrmPlane> plane(new DrmPlane(this, p.get()));
 
     ret = plane->Init();
     if (ret) {
@@ -332,7 +323,6 @@
 
     planes_.emplace_back(std::move(plane));
   }
-  drmModeFreePlaneResources(plane_res);
   if (ret)
     return std::make_tuple(ret, 0);
 
@@ -510,8 +500,8 @@
   return -EINVAL;
 }
 
-int DrmDevice::CreatePropertyBlob(void *data, size_t length,
-                                  uint32_t *blob_id) const {
+auto DrmDevice::RegisterUserPropertyBlob(void *data, size_t length) const
+    -> DrmModeUserPropertyBlobUnique {
   struct drm_mode_create_blob create_blob {};
   create_blob.length = length;
   create_blob.data = (__u64)data;
@@ -519,24 +509,21 @@
   int ret = drmIoctl(fd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob);
   if (ret) {
     ALOGE("Failed to create mode property blob %d", ret);
-    return ret;
+    return DrmModeUserPropertyBlobUnique();
   }
-  *blob_id = create_blob.blob_id;
-  return 0;
-}
 
-int DrmDevice::DestroyPropertyBlob(uint32_t blob_id) const {
-  if (!blob_id)
-    return 0;
-
-  struct drm_mode_destroy_blob destroy_blob {};
-  destroy_blob.blob_id = (__u32)blob_id;
-  int ret = drmIoctl(fd(), DRM_IOCTL_MODE_DESTROYPROPBLOB, &destroy_blob);
-  if (ret) {
-    ALOGE("Failed to destroy mode property blob %" PRIu32 "/%d", blob_id, ret);
-    return ret;
-  }
-  return 0;
+  return DrmModeUserPropertyBlobUnique(
+      new uint32_t(create_blob.blob_id), [this](const uint32_t *it) {
+        struct drm_mode_destroy_blob destroy_blob {};
+        destroy_blob.blob_id = (__u32)*it;
+        int err = drmIoctl(fd(), DRM_IOCTL_MODE_DESTROYPROPBLOB, &destroy_blob);
+        if (err != 0) {
+          ALOGE("Failed to destroy mode property blob %" PRIu32 "/%d", *it,
+                err);
+        }
+        // NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
+        delete it;
+      });
 }
 
 DrmEventListener *DrmDevice::event_listener() {
@@ -557,7 +544,7 @@
   for (int i = 0; !found && (size_t)i < props->count_props; ++i) {
     drmModePropertyPtr p = drmModeGetProperty(fd(), props->props[i]);
     if (!strcmp(p->name, prop_name)) {
-      property->Init(p, props->prop_values[i]);
+      property->Init(obj_id, p, props->prop_values[i]);
       found = true;
     }
     drmModeFreeProperty(p);
@@ -567,19 +554,14 @@
   return found ? 0 : -ENOENT;
 }
 
-int DrmDevice::GetPlaneProperty(const DrmPlane &plane, const char *prop_name,
-                                DrmProperty *property) {
-  return GetProperty(plane.id(), DRM_MODE_OBJECT_PLANE, prop_name, property);
-}
-
 int DrmDevice::GetCrtcProperty(const DrmCrtc &crtc, const char *prop_name,
-                               DrmProperty *property) {
+                               DrmProperty *property) const {
   return GetProperty(crtc.id(), DRM_MODE_OBJECT_CRTC, prop_name, property);
 }
 
 int DrmDevice::GetConnectorProperty(const DrmConnector &connector,
                                     const char *prop_name,
-                                    DrmProperty *property) {
+                                    DrmProperty *property) const {
   return GetProperty(connector.id(), DRM_MODE_OBJECT_CONNECTOR, prop_name,
                      property);
 }
@@ -595,4 +577,22 @@
   drmFreeVersion(ver);
   return name;
 }
+
+auto DrmDevice::IsKMSDev(const char *path) -> bool {
+  auto fd = UniqueFd(open(path, O_RDWR | O_CLOEXEC));
+  if (!fd) {
+    return false;
+  }
+
+  auto res = MakeDrmModeResUnique(fd.Get());
+  if (!res) {
+    return false;
+  }
+
+  bool is_kms = res->count_crtcs > 0 && res->count_connectors > 0 &&
+                res->count_encoders > 0;
+
+  return is_kms;
+}
+
 }  // namespace android
diff --git a/drm/DrmDevice.h b/drm/DrmDevice.h
index dfca263..81c60cd 100644
--- a/drm/DrmDevice.h
+++ b/drm/DrmDevice.h
@@ -69,20 +69,19 @@
   DrmPlane *GetPlane(uint32_t id) const;
   DrmEventListener *event_listener();
 
-  int GetPlaneProperty(const DrmPlane &plane, const char *prop_name,
-                       DrmProperty *property);
   int GetCrtcProperty(const DrmCrtc &crtc, const char *prop_name,
-                      DrmProperty *property);
+                      DrmProperty *property) const;
   int GetConnectorProperty(const DrmConnector &connector, const char *prop_name,
-                           DrmProperty *property);
+                           DrmProperty *property) const;
 
   std::string GetName() const;
 
   const std::vector<std::unique_ptr<DrmCrtc>> &crtcs() const;
   uint32_t next_mode_id();
 
-  int CreatePropertyBlob(void *data, size_t length, uint32_t *blob_id) const;
-  int DestroyPropertyBlob(uint32_t blob_id) const;
+  auto RegisterUserPropertyBlob(void *data, size_t length) const
+      -> DrmModeUserPropertyBlobUnique;
+
   bool HandlesDisplay(int display) const;
   void RegisterHotplugHandler(DrmEventHandler *handler) {
     event_listener_.RegisterHotplugHandler(handler);
@@ -96,11 +95,14 @@
     return *mDrmFbImporter.get();
   }
 
- private:
-  int TryEncoderForDisplay(int display, DrmEncoder *enc);
+  static auto IsKMSDev(const char *path) -> bool;
+
   int GetProperty(uint32_t obj_id, uint32_t obj_type, const char *prop_name,
                   DrmProperty *property) const;
 
+ private:
+  int TryEncoderForDisplay(int display, DrmEncoder *enc);
+
   int CreateDisplayPipe(DrmConnector *connector);
   int AttachWriteback(DrmConnector *display_conn);
 
diff --git a/drm/DrmEventListener.cpp b/drm/DrmEventListener.cpp
index b303653..53e7032 100644
--- a/drm/DrmEventListener.cpp
+++ b/drm/DrmEventListener.cpp
@@ -84,7 +84,7 @@
 
 void DrmEventListener::UEventHandler() {
   char buffer[1024];
-  int ret = 0;
+  ssize_t ret = 0;
 
   struct timespec ts {};
 
@@ -93,7 +93,7 @@
   if (!ret)
     timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
   else
-    ALOGE("Failed to get monotonic clock on hotplug %d", ret);
+    ALOGE("Failed to get monotonic clock on hotplug %zd", ret);
 
   while (true) {
     ret = read(uevent_fd_.Get(), &buffer, sizeof(buffer));
@@ -101,7 +101,7 @@
       return;
 
     if (ret < 0) {
-      ALOGE("Got error reading uevent %d", ret);
+      ALOGE("Got error reading uevent %zd", ret);
       return;
     }
 
diff --git a/drm/DrmMode.cpp b/drm/DrmMode.cpp
index dd25758..c714458 100644
--- a/drm/DrmMode.cpp
+++ b/drm/DrmMode.cpp
@@ -121,7 +121,7 @@
 
 float DrmMode::v_refresh() const {
   // Always recalculate refresh to report correct float rate
-  return clock_ / (float)(v_total_ * h_total_) * 1000.0F;
+  return static_cast<float>(clock_) / (float)(v_total_ * h_total_) * 1000.0F;
 }
 
 uint32_t DrmMode::flags() const {
diff --git a/drm/DrmPlane.cpp b/drm/DrmPlane.cpp
index 6433fb6..f6ddad2 100644
--- a/drm/DrmPlane.cpp
+++ b/drm/DrmPlane.cpp
@@ -39,12 +39,11 @@
 int DrmPlane::Init() {
   DrmProperty p;
 
-  int ret = drm_->GetPlaneProperty(*this, "type", &p);
-  if (ret) {
-    ALOGE("Could not get plane type property");
-    return ret;
+  if (!GetPlaneProperty("type", p)) {
+    return -ENOTSUP;
   }
 
+  int ret = 0;
   uint64_t type = 0;
   std::tie(ret, type) = p.value();
   if (ret) {
@@ -62,95 +61,73 @@
       return -EINVAL;
   }
 
-  ret = drm_->GetPlaneProperty(*this, "CRTC_ID", &crtc_property_);
-  if (ret) {
-    ALOGE("Could not get CRTC_ID property");
-    return ret;
+  if (!GetPlaneProperty("CRTC_ID", crtc_property_) ||
+      !GetPlaneProperty("FB_ID", fb_property_) ||
+      !GetPlaneProperty("CRTC_X", crtc_x_property_) ||
+      !GetPlaneProperty("CRTC_Y", crtc_y_property_) ||
+      !GetPlaneProperty("CRTC_W", crtc_w_property_) ||
+      !GetPlaneProperty("CRTC_H", crtc_h_property_) ||
+      !GetPlaneProperty("SRC_X", src_x_property_) ||
+      !GetPlaneProperty("SRC_Y", src_y_property_) ||
+      !GetPlaneProperty("SRC_W", src_w_property_) ||
+      !GetPlaneProperty("SRC_H", src_h_property_)) {
+    return -ENOTSUP;
   }
 
-  ret = drm_->GetPlaneProperty(*this, "FB_ID", &fb_property_);
-  if (ret) {
-    ALOGE("Could not get FB_ID property");
-    return ret;
+  GetPlaneProperty("zpos", zpos_property_, Presence::kOptional);
+
+  if (GetPlaneProperty("rotation", rotation_property_, Presence::kOptional)) {
+    rotation_property_.AddEnumToMap("rotate-0", DrmHwcTransform::kIdentity,
+                                    transform_enum_map_);
+    rotation_property_.AddEnumToMap("rotate-90", DrmHwcTransform::kRotate90,
+                                    transform_enum_map_);
+    rotation_property_.AddEnumToMap("rotate-180", DrmHwcTransform::kRotate180,
+                                    transform_enum_map_);
+    rotation_property_.AddEnumToMap("rotate-270", DrmHwcTransform::kRotate270,
+                                    transform_enum_map_);
+    rotation_property_.AddEnumToMap("reflect-x", DrmHwcTransform::kFlipH,
+                                    transform_enum_map_);
+    rotation_property_.AddEnumToMap("reflect-y", DrmHwcTransform::kFlipV,
+                                    transform_enum_map_);
   }
 
-  ret = drm_->GetPlaneProperty(*this, "CRTC_X", &crtc_x_property_);
-  if (ret) {
-    ALOGE("Could not get CRTC_X property");
-    return ret;
+  GetPlaneProperty("alpha", alpha_property_, Presence::kOptional);
+
+  if (GetPlaneProperty("pixel blend mode", blend_property_,
+                       Presence::kOptional)) {
+    blend_property_.AddEnumToMap("Pre-multiplied", DrmHwcBlending::kPreMult,
+                                 blending_enum_map_);
+    blend_property_.AddEnumToMap("Coverage", DrmHwcBlending::kCoverage,
+                                 blending_enum_map_);
+    blend_property_.AddEnumToMap("None", DrmHwcBlending::kNone,
+                                 blending_enum_map_);
   }
 
-  ret = drm_->GetPlaneProperty(*this, "CRTC_Y", &crtc_y_property_);
-  if (ret) {
-    ALOGE("Could not get CRTC_Y property");
-    return ret;
-  }
-
-  ret = drm_->GetPlaneProperty(*this, "CRTC_W", &crtc_w_property_);
-  if (ret) {
-    ALOGE("Could not get CRTC_W property");
-    return ret;
-  }
-
-  ret = drm_->GetPlaneProperty(*this, "CRTC_H", &crtc_h_property_);
-  if (ret) {
-    ALOGE("Could not get CRTC_H property");
-    return ret;
-  }
-
-  ret = drm_->GetPlaneProperty(*this, "SRC_X", &src_x_property_);
-  if (ret) {
-    ALOGE("Could not get SRC_X property");
-    return ret;
-  }
-
-  ret = drm_->GetPlaneProperty(*this, "SRC_Y", &src_y_property_);
-  if (ret) {
-    ALOGE("Could not get SRC_Y property");
-    return ret;
-  }
-
-  ret = drm_->GetPlaneProperty(*this, "SRC_W", &src_w_property_);
-  if (ret) {
-    ALOGE("Could not get SRC_W property");
-    return ret;
-  }
-
-  ret = drm_->GetPlaneProperty(*this, "SRC_H", &src_h_property_);
-  if (ret) {
-    ALOGE("Could not get SRC_H property");
-    return ret;
-  }
-
-  ret = drm_->GetPlaneProperty(*this, "zpos", &zpos_property_);
-  if (ret)
-    ALOGE("Could not get zpos property for plane %u", id());
-
-  ret = drm_->GetPlaneProperty(*this, "rotation", &rotation_property_);
-  if (ret)
-    ALOGE("Could not get rotation property");
-
-  ret = drm_->GetPlaneProperty(*this, "alpha", &alpha_property_);
-  if (ret)
-    ALOGI("Could not get alpha property");
-
-  ret = drm_->GetPlaneProperty(*this, "pixel blend mode", &blend_property_);
-  if (ret)
-    ALOGI("Could not get pixel blend mode property");
-
-  ret = drm_->GetPlaneProperty(*this, "IN_FENCE_FD", &in_fence_fd_property_);
-  if (ret)
-    ALOGI("Could not get IN_FENCE_FD property");
+  GetPlaneProperty("IN_FENCE_FD", in_fence_fd_property_, Presence::kOptional);
 
   if (HasNonRgbFormat()) {
-    ret = drm_->GetPlaneProperty(*this, "COLOR_ENCODING",
-                                 &color_encoding_propery_);
-    if (ret)
-      ALOGI("Could not get COLOR_ENCODING property");
+    if (GetPlaneProperty("COLOR_ENCODING", color_encoding_propery_,
+                         Presence::kOptional)) {
+      color_encoding_propery_.AddEnumToMap("ITU-R BT.709 YCbCr",
+                                           DrmHwcColorSpace::kItuRec709,
+                                           color_encoding_enum_map_);
+      color_encoding_propery_.AddEnumToMap("ITU-R BT.601 YCbCr",
+                                           DrmHwcColorSpace::kItuRec601,
+                                           color_encoding_enum_map_);
+      color_encoding_propery_.AddEnumToMap("ITU-R BT.2020 YCbCr",
+                                           DrmHwcColorSpace::kItuRec2020,
+                                           color_encoding_enum_map_);
+    }
 
-    ret = drm_->GetPlaneProperty(*this, "COLOR_RANGE", &color_range_property_);
-    if (ret)
-      ALOGI("Could not get COLOR_RANGE property");
+    if (GetPlaneProperty("COLOR_RANGE", color_range_property_,
+                         Presence::kOptional)) {
+      color_range_property_.AddEnumToMap("YCbCr full range",
+                                         DrmHwcSampleRange::kFullRange,
+                                         color_range_enum_map_);
+      color_range_property_.AddEnumToMap("YCbCr limited range",
+                                         DrmHwcSampleRange::kLimitedRange,
+                                         color_range_enum_map_);
+    }
   }
 
   return 0;
@@ -165,34 +142,15 @@
 }
 
 bool DrmPlane::IsValidForLayer(DrmHwcLayer *layer) {
-  if (rotation_property_.id() == 0) {
+  if (!rotation_property_) {
     if (layer->transform != DrmHwcTransform::kIdentity) {
-      ALOGV("Rotation is not supported on plane %d", id_);
+      ALOGV("No rotation property on plane %d", id_);
       return false;
     }
   } else {
-    // For rotation checks, we assume the hardware reports its capabilities
-    // consistently (e.g. a 270 degree rotation is a 90 degree rotation + H
-    // flip + V flip; it wouldn't make sense to support all of the latter but
-    // not the former).
-    int ret = 0;
-    const std::pair<enum DrmHwcTransform, std::string> transforms[] =
-        {{kFlipH, "reflect-x"},
-         {kFlipV, "reflect-y"},
-         {kRotate90, "rotate-90"},
-         {kRotate180, "rotate-180"},
-         {kRotate270, "rotate-270"}};
-
-    for (const auto &[transform, name] : transforms) {
-      if (layer->transform & transform) {
-        std::tie(std::ignore,
-                 ret) = rotation_property_.GetEnumValueWithName(name);
-        if (ret) {
-          ALOGV("Rotation '%s' is not supported on plane %d", name.c_str(),
-                id_);
-          return false;
-        }
-      }
+    if (transform_enum_map_.count(layer->transform) == 0) {
+      ALOGV("Transform is not supported on plane %d", id_);
+      return false;
     }
   }
 
@@ -201,34 +159,11 @@
     return false;
   }
 
-  if (blend_property_.id() == 0) {
-    if ((layer->blending != DrmHwcBlending::kNone) &&
-        (layer->blending != DrmHwcBlending::kPreMult)) {
-      ALOGV("Blending is not supported on plane %d", id_);
-      return false;
-    }
-  } else {
-    int ret = 0;
-
-    switch (layer->blending) {
-      case DrmHwcBlending::kPreMult:
-        std::tie(std::ignore,
-                 ret) = blend_property_.GetEnumValueWithName("Pre-multiplied");
-        break;
-      case DrmHwcBlending::kCoverage:
-        std::tie(std::ignore,
-                 ret) = blend_property_.GetEnumValueWithName("Coverage");
-        break;
-      case DrmHwcBlending::kNone:
-      default:
-        std::tie(std::ignore,
-                 ret) = blend_property_.GetEnumValueWithName("None");
-        break;
-    }
-    if (ret) {
-      ALOGV("Expected a valid blend mode on plane %d", id_);
-      return false;
-    }
+  if (blending_enum_map_.count(layer->blending) == 0 &&
+      layer->blending != DrmHwcBlending::kNone &&
+      layer->blending != DrmHwcBlending::kPreMult) {
+    ALOGV("Blending is not supported on plane %d", id_);
+    return false;
   }
 
   uint32_t format = layer->buffer_info.format;
@@ -257,71 +192,122 @@
                           }) != std::end(formats_);
 }
 
-const DrmProperty &DrmPlane::crtc_property() const {
-  return crtc_property_;
+static uint64_t ToDrmRotation(DrmHwcTransform transform) {
+  uint64_t rotation = 0;
+  if (transform & DrmHwcTransform::kFlipH)
+    rotation |= DRM_MODE_REFLECT_X;
+  if (transform & DrmHwcTransform::kFlipV)
+    rotation |= DRM_MODE_REFLECT_Y;
+  if (transform & DrmHwcTransform::kRotate90)
+    rotation |= DRM_MODE_ROTATE_90;
+  else if (transform & DrmHwcTransform::kRotate180)
+    rotation |= DRM_MODE_ROTATE_180;
+  else if (transform & DrmHwcTransform::kRotate270)
+    rotation |= DRM_MODE_ROTATE_270;
+  else
+    rotation |= DRM_MODE_ROTATE_0;
+
+  return rotation;
 }
 
-const DrmProperty &DrmPlane::fb_property() const {
-  return fb_property_;
+auto DrmPlane::AtomicSetState(drmModeAtomicReq &pset, DrmHwcLayer &layer,
+                              uint32_t zpos, uint32_t crtc_id) -> int {
+  if (!layer.FbIdHandle) {
+    ALOGE("Expected a valid framebuffer for pset");
+    return -EINVAL;
+  }
+
+  if (zpos_property_ && !zpos_property_.is_immutable()) {
+    uint64_t min_zpos = 0;
+
+    // Ignore ret and use min_zpos as 0 by default
+    std::tie(std::ignore, min_zpos) = zpos_property_.range_min();
+
+    if (!zpos_property_.AtomicSet(pset, zpos + min_zpos)) {
+      return -EINVAL;
+    }
+  }
+
+  if (layer.acquire_fence &&
+      !in_fence_fd_property_.AtomicSet(pset, layer.acquire_fence.Get())) {
+    return -EINVAL;
+  }
+
+  if (!crtc_property_.AtomicSet(pset, crtc_id) ||
+      !fb_property_.AtomicSet(pset, layer.FbIdHandle->GetFbId()) ||
+      !crtc_x_property_.AtomicSet(pset, layer.display_frame.left) ||
+      !crtc_y_property_.AtomicSet(pset, layer.display_frame.top) ||
+      !crtc_w_property_.AtomicSet(pset, layer.display_frame.right -
+                                            layer.display_frame.left) ||
+      !crtc_h_property_.AtomicSet(pset, layer.display_frame.bottom -
+                                            layer.display_frame.top) ||
+      !src_x_property_.AtomicSet(pset, (int)(layer.source_crop.left) << 16) ||
+      !src_y_property_.AtomicSet(pset, (int)(layer.source_crop.top) << 16) ||
+      !src_w_property_.AtomicSet(pset, (int)(layer.source_crop.right -
+                                             layer.source_crop.left)
+                                           << 16) ||
+      !src_h_property_.AtomicSet(pset, (int)(layer.source_crop.bottom -
+                                             layer.source_crop.top)
+                                           << 16)) {
+    return -EINVAL;
+  }
+
+  if (rotation_property_ &&
+      !rotation_property_.AtomicSet(pset, ToDrmRotation(layer.transform))) {
+    return -EINVAL;
+  }
+
+  if (alpha_property_ && !alpha_property_.AtomicSet(pset, layer.alpha)) {
+    return -EINVAL;
+  }
+
+  if (blending_enum_map_.count(layer.blending) != 0 &&
+      !blend_property_.AtomicSet(pset, blending_enum_map_[layer.blending])) {
+    return -EINVAL;
+  }
+
+  if (color_encoding_enum_map_.count(layer.color_space) != 0 &&
+      !color_encoding_propery_
+           .AtomicSet(pset, color_encoding_enum_map_[layer.color_space])) {
+    return -EINVAL;
+  }
+
+  if (color_range_enum_map_.count(layer.sample_range) != 0 &&
+      !color_range_property_
+           .AtomicSet(pset, color_range_enum_map_[layer.sample_range])) {
+    return -EINVAL;
+  }
+
+  return 0;
 }
 
-const DrmProperty &DrmPlane::crtc_x_property() const {
-  return crtc_x_property_;
-}
+auto DrmPlane::AtomicDisablePlane(drmModeAtomicReq &pset) -> int {
+  if (!crtc_property_.AtomicSet(pset, 0) || !fb_property_.AtomicSet(pset, 0)) {
+    return -EINVAL;
+  }
 
-const DrmProperty &DrmPlane::crtc_y_property() const {
-  return crtc_y_property_;
-}
-
-const DrmProperty &DrmPlane::crtc_w_property() const {
-  return crtc_w_property_;
-}
-
-const DrmProperty &DrmPlane::crtc_h_property() const {
-  return crtc_h_property_;
-}
-
-const DrmProperty &DrmPlane::src_x_property() const {
-  return src_x_property_;
-}
-
-const DrmProperty &DrmPlane::src_y_property() const {
-  return src_y_property_;
-}
-
-const DrmProperty &DrmPlane::src_w_property() const {
-  return src_w_property_;
-}
-
-const DrmProperty &DrmPlane::src_h_property() const {
-  return src_h_property_;
+  return 0;
 }
 
 const DrmProperty &DrmPlane::zpos_property() const {
   return zpos_property_;
 }
 
-const DrmProperty &DrmPlane::rotation_property() const {
-  return rotation_property_;
+auto DrmPlane::GetPlaneProperty(const char *prop_name, DrmProperty &property,
+                                Presence presence) -> bool {
+  int err = drm_->GetProperty(id_, DRM_MODE_OBJECT_PLANE, prop_name, &property);
+  if (err != 0) {
+    if (presence == Presence::kMandatory) {
+      ALOGE("Could not get mandatory property \"%s\" from plane %d", prop_name,
+            id_);
+    } else {
+      ALOGV("Could not get optional property \"%s\" from plane %d", prop_name,
+            id_);
+    }
+    return false;
+  }
+
+  return true;
 }
 
-const DrmProperty &DrmPlane::alpha_property() const {
-  return alpha_property_;
-}
-
-const DrmProperty &DrmPlane::blend_property() const {
-  return blend_property_;
-}
-
-const DrmProperty &DrmPlane::in_fence_fd_property() const {
-  return in_fence_fd_property_;
-}
-
-const DrmProperty &DrmPlane::color_encoding_propery() const {
-  return color_encoding_propery_;
-}
-
-const DrmProperty &DrmPlane::color_range_property() const {
-  return color_range_property_;
-}
 }  // namespace android
diff --git a/drm/DrmPlane.h b/drm/DrmPlane.h
index 862a0f3..34bba56 100644
--- a/drm/DrmPlane.h
+++ b/drm/DrmPlane.h
@@ -48,28 +48,20 @@
   bool IsFormatSupported(uint32_t format) const;
   bool HasNonRgbFormat() const;
 
-  const DrmProperty &crtc_property() const;
-  const DrmProperty &fb_property() const;
-  const DrmProperty &crtc_x_property() const;
-  const DrmProperty &crtc_y_property() const;
-  const DrmProperty &crtc_w_property() const;
-  const DrmProperty &crtc_h_property() const;
-  const DrmProperty &src_x_property() const;
-  const DrmProperty &src_y_property() const;
-  const DrmProperty &src_w_property() const;
-  const DrmProperty &src_h_property() const;
+  auto AtomicSetState(drmModeAtomicReq &pset, DrmHwcLayer &layer, uint32_t zpos,
+                      uint32_t crtc_id) -> int;
+  auto AtomicDisablePlane(drmModeAtomicReq &pset) -> int;
   const DrmProperty &zpos_property() const;
-  const DrmProperty &rotation_property() const;
-  const DrmProperty &alpha_property() const;
-  const DrmProperty &blend_property() const;
-  const DrmProperty &in_fence_fd_property() const;
-  const DrmProperty &color_encoding_propery() const;
-  const DrmProperty &color_range_property() const;
 
  private:
   DrmDevice *drm_;
   uint32_t id_;
 
+  enum class Presence { kOptional, kMandatory };
+
+  auto GetPlaneProperty(const char *prop_name, DrmProperty &property,
+                        Presence presence = Presence::kMandatory) -> bool;
+
   uint32_t possible_crtc_mask_;
 
   uint32_t type_{};
@@ -93,6 +85,11 @@
   DrmProperty in_fence_fd_property_;
   DrmProperty color_encoding_propery_;
   DrmProperty color_range_property_;
+
+  std::map<DrmHwcBlending, uint64_t> blending_enum_map_;
+  std::map<DrmHwcColorSpace, uint64_t> color_encoding_enum_map_;
+  std::map<DrmHwcSampleRange, uint64_t> color_range_enum_map_;
+  std::map<DrmHwcTransform, uint64_t> transform_enum_map_;
 };
 }  // namespace android
 
diff --git a/drm/DrmProperty.cpp b/drm/DrmProperty.cpp
index 8e6f7e5..32f1c62 100644
--- a/drm/DrmProperty.cpp
+++ b/drm/DrmProperty.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
+#define LOG_TAG "hwc-drm-property"
+
 #include "DrmProperty.h"
 
 #include <xf86drmMode.h>
@@ -23,6 +26,7 @@
 #include <string>
 
 #include "DrmDevice.h"
+#include "utils/log.h"
 
 namespace android {
 
@@ -30,11 +34,13 @@
     : value_(e->value), name_(e->name) {
 }
 
-DrmProperty::DrmProperty(drmModePropertyPtr p, uint64_t value) {
-  Init(p, value);
+DrmProperty::DrmProperty(uint32_t obj_id, drmModePropertyPtr p,
+                         uint64_t value) {
+  Init(obj_id, p, value);
 }
 
-void DrmProperty::Init(drmModePropertyPtr p, uint64_t value) {
+void DrmProperty::Init(uint32_t obj_id, drmModePropertyPtr p, uint64_t value) {
+  obj_id_ = obj_id;
   id_ = p->prop_id;
   flags_ = p->flags;
   name_ = p->name;
@@ -131,4 +137,19 @@
 
   return std::make_tuple(UINT64_MAX, -EINVAL);
 }
+
+auto DrmProperty::AtomicSet(drmModeAtomicReq &pset, uint64_t value) const
+    -> bool {
+  if (id_ == 0) {
+    ALOGE("AtomicSet() is called on non-initialized property!");
+    return false;
+  }
+  if (drmModeAtomicAddProperty(&pset, obj_id_, id_, value) < 0) {
+    ALOGE("Failed to add obj_id: %u, prop_id: %u (%s) to pset", obj_id_, id_,
+          name_.c_str());
+    return false;
+  }
+  return true;
+}
+
 }  // namespace android
diff --git a/drm/DrmProperty.h b/drm/DrmProperty.h
index 70678fd..68f300f 100644
--- a/drm/DrmProperty.h
+++ b/drm/DrmProperty.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 #include <xf86drmMode.h>
 
+#include <map>
 #include <string>
 #include <vector>
 
@@ -37,11 +38,11 @@
 class DrmProperty {
  public:
   DrmProperty() = default;
-  DrmProperty(drmModePropertyPtr p, uint64_t value);
+  DrmProperty(uint32_t obj_id, drmModePropertyPtr p, uint64_t value);
   DrmProperty(const DrmProperty &) = delete;
   DrmProperty &operator=(const DrmProperty &) = delete;
 
-  void Init(drmModePropertyPtr p, uint64_t value);
+  auto Init(uint32_t obj_id, drmModePropertyPtr p, uint64_t value) -> void;
   std::tuple<uint64_t, int> GetEnumValueWithName(const std::string &name) const;
 
   uint32_t id() const;
@@ -54,6 +55,17 @@
   std::tuple<int, uint64_t> range_min() const;
   std::tuple<int, uint64_t> range_max() const;
 
+  [[nodiscard]] auto AtomicSet(drmModeAtomicReq &pset, uint64_t value) const
+      -> bool;
+
+  template <class E>
+  auto AddEnumToMap(const std::string &name, E key, std::map<E, uint64_t> &map)
+      -> bool;
+
+  operator bool() const {
+    return id_ != 0;
+  }
+
  private:
   class DrmPropertyEnum {
    public:
@@ -64,6 +76,7 @@
     std::string name_;
   };
 
+  uint32_t obj_id_ = 0;
   uint32_t id_ = 0;
 
   DrmPropertyType type_ = DRM_PROPERTY_TYPE_INVALID;
@@ -75,6 +88,21 @@
   std::vector<DrmPropertyEnum> enums_;
   std::vector<uint32_t> blob_ids_;
 };
+
+template <class E>
+auto DrmProperty::AddEnumToMap(const std::string &name, E key,
+                               std::map<E, uint64_t> &map) -> bool {
+  uint64_t enum_value = UINT64_MAX;
+  int err = 0;
+  std::tie(enum_value, err) = GetEnumValueWithName(name);
+  if (err == 0) {
+    map[key] = enum_value;
+    return true;
+  }
+
+  return false;
+}
+
 }  // namespace android
 
 #endif  // ANDROID_DRM_PROPERTY_H_
diff --git a/drm/DrmUnique.h b/drm/DrmUnique.h
new file mode 100644
index 0000000..282528b
--- /dev/null
+++ b/drm/DrmUnique.h
@@ -0,0 +1,87 @@
+/*
+ * 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 DRM_UNIQUE_H_
+#define DRM_UNIQUE_H_
+
+#include <xf86drmMode.h>
+
+#include <functional>
+#include <memory>
+
+template <typename T>
+using DUniquePtr = std::unique_ptr<T, std::function<void(T *)>>;
+
+using DrmModeAtomicReqUnique = DUniquePtr<drmModeAtomicReq>;
+auto inline MakeDrmModeAtomicReqUnique() {
+  return DrmModeAtomicReqUnique(drmModeAtomicAlloc(), [](drmModeAtomicReq *it) {
+    drmModeAtomicFree(it);
+  });
+};
+
+using DrmModeConnectorUnique = DUniquePtr<drmModeConnector>;
+auto inline MakeDrmModeConnectorUnique(int fd, uint32_t connector_id) {
+  return DrmModeConnectorUnique(drmModeGetConnector(fd, connector_id),
+                                [](drmModeConnector *it) {
+                                  drmModeFreeConnector(it);
+                                });
+}
+
+using DrmModeCrtcUnique = DUniquePtr<drmModeCrtc>;
+auto inline MakeDrmModeCrtcUnique(int fd, uint32_t crtc_id) {
+  return DrmModeCrtcUnique(drmModeGetCrtc(fd, crtc_id),
+                           [](drmModeCrtc *it) { drmModeFreeCrtc(it); });
+}
+
+using DrmModeEncoderUnique = DUniquePtr<drmModeEncoder>;
+auto inline MakeDrmModeEncoderUnique(int fd, uint32_t encoder_id) {
+  return DrmModeEncoderUnique(drmModeGetEncoder(fd, encoder_id),
+                              [](drmModeEncoder *it) {
+                                drmModeFreeEncoder(it);
+                              });
+}
+
+using DrmModePlaneUnique = DUniquePtr<drmModePlane>;
+auto inline MakeDrmModePlaneUnique(int fd, uint32_t plane_id) {
+  return DrmModePlaneUnique(drmModeGetPlane(fd, plane_id),
+                            [](drmModePlane *it) { drmModeFreePlane(it); });
+}
+
+using DrmModePlaneResUnique = DUniquePtr<drmModePlaneRes>;
+auto inline MakeDrmModePlaneResUnique(int fd) {
+  return DrmModePlaneResUnique(drmModeGetPlaneResources(fd),
+                               [](drmModePlaneRes *it) {
+                                 drmModeFreePlaneResources(it);
+                               });
+}
+
+using DrmModeUserPropertyBlobUnique = DUniquePtr<uint32_t /*id*/>;
+
+using DrmModePropertyBlobUnique = DUniquePtr<drmModePropertyBlobRes>;
+auto inline MakeDrmModePropertyBlobUnique(int fd, uint32_t blob_id) {
+  return DrmModePropertyBlobUnique(drmModeGetPropertyBlob(fd, blob_id),
+                                   [](drmModePropertyBlobRes *it) {
+                                     drmModeFreePropertyBlob(it);
+                                   });
+}
+
+using DrmModeResUnique = DUniquePtr<drmModeRes>;
+auto inline MakeDrmModeResUnique(int fd) {
+  return DrmModeResUnique(drmModeGetResources(fd),
+                          [](drmModeRes *it) { drmModeFreeResources(it); });
+}
+
+#endif
diff --git a/drm/ResourceManager.cpp b/drm/ResourceManager.cpp
index ef44180..c55d6b8 100644
--- a/drm/ResourceManager.cpp
+++ b/drm/ResourceManager.cpp
@@ -29,7 +29,7 @@
 
 namespace android {
 
-ResourceManager::ResourceManager() : num_displays_(0), gralloc_(nullptr) {
+ResourceManager::ResourceManager() : num_displays_(0) {
 }
 
 int ResourceManager::Init() {
@@ -51,7 +51,7 @@
       if (stat(path.str().c_str(), &buf))
         break;
 
-      if (IsKMSDev(path.str().c_str()))
+      if (DrmDevice::IsKMSDev(path.str().c_str()))
         ret = AddDrmDevice(path.str());
     }
   }
@@ -70,8 +70,7 @@
     return -EINVAL;
   }
 
-  return hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
-                       (const hw_module_t **)&gralloc_);
+  return 0;
 }
 
 int ResourceManager::AddDrmDevice(const std::string &path) {
@@ -84,44 +83,6 @@
   return ret;
 }
 
-DrmConnector *ResourceManager::AvailableWritebackConnector(int display) {
-  DrmDevice *drm_device = GetDrmDevice(display);
-  DrmConnector *writeback_conn = nullptr;
-  if (drm_device) {
-    writeback_conn = drm_device->AvailableWritebackConnector(display);
-    if (writeback_conn)
-      return writeback_conn;
-  }
-  for (auto &drm : drms_) {
-    if (drm.get() == drm_device)
-      continue;
-    writeback_conn = drm->AvailableWritebackConnector(display);
-    if (writeback_conn)
-      return writeback_conn;
-  }
-  return writeback_conn;
-}
-
-bool ResourceManager::IsKMSDev(const char *path) {
-  int fd = open(path, O_RDWR | O_CLOEXEC);
-  if (fd < 0)
-    return false;
-
-  auto *res = drmModeGetResources(fd);
-  if (!res) {
-    close(fd);
-    return false;
-  }
-
-  bool is_kms = res->count_crtcs > 0 && res->count_connectors > 0 &&
-                res->count_encoders > 0;
-
-  drmModeFreeResources(res);
-  close(fd);
-
-  return is_kms;
-}
-
 DrmDevice *ResourceManager::GetDrmDevice(int display) {
   for (auto &drm : drms_) {
     if (drm->HandlesDisplay(display))
@@ -129,8 +90,4 @@
   }
   return nullptr;
 }
-
-const gralloc_module_t *ResourceManager::gralloc() {
-  return gralloc_;
-}
 }  // namespace android
diff --git a/drm/ResourceManager.h b/drm/ResourceManager.h
index 9b4155b..d9e0712 100644
--- a/drm/ResourceManager.h
+++ b/drm/ResourceManager.h
@@ -31,8 +31,6 @@
   ResourceManager &operator=(const ResourceManager &) = delete;
   int Init();
   DrmDevice *GetDrmDevice(int display);
-  const gralloc_module_t *gralloc();
-  DrmConnector *AvailableWritebackConnector(int display);
   const std::vector<std::unique_ptr<DrmDevice>> &getDrmDevices() const {
     return drms_;
   }
@@ -45,11 +43,9 @@
 
  private:
   int AddDrmDevice(std::string const &path);
-  static bool IsKMSDev(const char *path);
 
   int num_displays_;
   std::vector<std::unique_ptr<DrmDevice>> drms_;
-  const gralloc_module_t *gralloc_;
 
   bool scale_with_gpu_{};
 };
diff --git a/drm/VSyncWorker.cpp b/drm/VSyncWorker.cpp
index 25eeeab..6e92838 100644
--- a/drm/VSyncWorker.cpp
+++ b/drm/VSyncWorker.cpp
@@ -37,27 +37,16 @@
       last_timestamp_(-1) {
 }
 
-int VSyncWorker::Init(DrmDevice *drm, int display) {
+auto VSyncWorker::Init(DrmDevice *drm, int display,
+                       std::function<void(uint64_t /*timestamp*/)> callback)
+    -> int {
   drm_ = drm;
   display_ = display;
+  callback_ = std::move(callback);
 
   return InitWorker();
 }
 
-void VSyncWorker::RegisterCallback(std::shared_ptr<VsyncCallback> callback) {
-  Lock();
-  callback_ = std::move(callback);
-  Unlock();
-}
-
-void VSyncWorker::RegisterClientCallback(hwc2_callback_data_t data,
-                                         hwc2_function_pointer_t hook) {
-  Lock();
-  vsync_callback_data_ = data;
-  vsync_callback_hook_ = (HWC2_PFN_VSYNC)hook;
-  Unlock();
-}
-
 void VSyncWorker::VSyncControl(bool enabled) {
   Lock();
   enabled_ = enabled;
@@ -104,7 +93,8 @@
     ALOGW("Vsync worker active with conn=%p refresh=%f\n", conn,
           conn ? conn->active_mode().v_refresh() : 0.0F);
 
-  int64_t phased_timestamp = GetPhasedVSync(kOneSecondNs / refresh,
+  int64_t phased_timestamp = GetPhasedVSync(kOneSecondNs /
+                                                static_cast<int>(refresh),
                                             vsync.tv_sec * kOneSecondNs +
                                                 vsync.tv_nsec);
   vsync.tv_sec = phased_timestamp / kOneSecondNs;
@@ -132,7 +122,6 @@
   }
 
   int display = display_;
-  std::shared_ptr<VsyncCallback> callback(callback_);
   Unlock();
 
   DrmCrtc *crtc = drm_->GetCrtcForDisplay(display);
@@ -144,8 +133,9 @@
 
   drmVBlank vblank;
   memset(&vblank, 0, sizeof(vblank));
-  vblank.request.type = (drmVBlankSeqType)(
-      DRM_VBLANK_RELATIVE | (high_crtc & DRM_VBLANK_HIGH_CRTC_MASK));
+  vblank.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE |
+                                           (high_crtc &
+                                            DRM_VBLANK_HIGH_CRTC_MASK));
   vblank.request.sequence = 1;
 
   int64_t timestamp = 0;
@@ -165,13 +155,9 @@
   if (!enabled_)
     return;
 
-  if (callback)
-    callback->Callback(display, timestamp);
-
-  Lock();
-  if (enabled_ && vsync_callback_hook_ && vsync_callback_data_)
-    vsync_callback_hook_(vsync_callback_data_, display, timestamp);
-  Unlock();
+  if (callback_) {
+    callback_(timestamp);
+  }
 
   last_timestamp_ = timestamp;
 }
diff --git a/drm/VSyncWorker.h b/drm/VSyncWorker.h
index b43918c..74ff487 100644
--- a/drm/VSyncWorker.h
+++ b/drm/VSyncWorker.h
@@ -23,6 +23,7 @@
 #include <stdint.h>
 
 #include <atomic>
+#include <functional>
 #include <map>
 
 #include "DrmDevice.h"
@@ -30,21 +31,13 @@
 
 namespace android {
 
-class VsyncCallback {
- public:
-  virtual ~VsyncCallback() = default;
-  virtual void Callback(int display, int64_t timestamp) = 0;
-};
-
 class VSyncWorker : public Worker {
  public:
   VSyncWorker();
   ~VSyncWorker() override = default;
 
-  int Init(DrmDevice *drm, int display);
-  void RegisterCallback(std::shared_ptr<VsyncCallback> callback);
-  void RegisterClientCallback(hwc2_callback_data_t data,
-                              hwc2_function_pointer_t hook);
+  auto Init(DrmDevice *drm, int display,
+            std::function<void(uint64_t /*timestamp*/)> callback) -> int;
 
   void VSyncControl(bool enabled);
 
@@ -57,17 +50,11 @@
 
   DrmDevice *drm_;
 
-  // shared_ptr since we need to use this outside of the thread lock (to
-  // actually call the hook) and we don't want the memory freed until we're
-  // done
-  std::shared_ptr<VsyncCallback> callback_ = NULL;
+  std::function<void(uint64_t /*timestamp*/)> callback_;
 
   int display_;
   std::atomic_bool enabled_;
   int64_t last_timestamp_;
-
-  hwc2_callback_data_t vsync_callback_data_ = NULL;
-  HWC2_PFN_VSYNC vsync_callback_hook_ = NULL;
 };
 }  // namespace android
 
diff --git a/include/drmhwcgralloc.h b/include/drmhwcgralloc.h
index db54802..09c7499 100644
--- a/include/drmhwcgralloc.h
+++ b/include/drmhwcgralloc.h
@@ -28,7 +28,9 @@
   uint32_t usage;
   uint32_t pitches[HWC_DRM_BO_MAX_PLANES];
   uint32_t offsets[HWC_DRM_BO_MAX_PLANES];
-  uint32_t prime_fds[HWC_DRM_BO_MAX_PLANES];
+  /* sizes[] is used only by mapper@4 metadata getter for internal purposes */
+  uint32_t sizes[HWC_DRM_BO_MAX_PLANES];
+  int prime_fds[HWC_DRM_BO_MAX_PLANES];
   uint64_t modifiers[HWC_DRM_BO_MAX_PLANES];
   int acquire_fence_fd;
 } hwc_drm_bo_t;
diff --git a/include/drmhwcomposer.h b/include/drmhwcomposer.h
index 22af12b..d02445b 100644
--- a/include/drmhwcomposer.h
+++ b/include/drmhwcomposer.h
@@ -32,7 +32,20 @@
 
 class DrmFbIdHandle;
 
-enum DrmHwcTransform {
+enum class DrmHwcColorSpace : int32_t {
+  kUndefined,
+  kItuRec601,
+  kItuRec709,
+  kItuRec2020,
+};
+
+enum class DrmHwcSampleRange : int32_t {
+  kUndefined,
+  kFullRange,
+  kLimitedRange,
+};
+
+enum DrmHwcTransform : uint32_t {
   kIdentity = 0,
   kFlipH = 1 << 0,
   kFlipV = 1 << 1,
@@ -42,9 +55,9 @@
 };
 
 enum class DrmHwcBlending : int32_t {
-  kNone = HWC_BLENDING_NONE,
-  kPreMult = HWC_BLENDING_PREMULT,
-  kCoverage = HWC_BLENDING_COVERAGE,
+  kNone,
+  kPreMult,
+  kCoverage,
 };
 
 struct DrmHwcLayer {
@@ -53,19 +66,18 @@
   std::shared_ptr<DrmFbIdHandle> FbIdHandle;
 
   int gralloc_buffer_usage = 0;
-  uint32_t transform;
+  DrmHwcTransform transform{};
   DrmHwcBlending blending = DrmHwcBlending::kNone;
   uint16_t alpha = 0xffff;
   hwc_frect_t source_crop;
   hwc_rect_t display_frame;
-  android_dataspace_t dataspace;
+  DrmHwcColorSpace color_space;
+  DrmHwcSampleRange sample_range;
 
   UniqueFd acquire_fence;
 
   int ImportBuffer(DrmDevice *drmDevice);
 
-  void SetTransform(int32_t sf_transform);
-
   bool protected_usage() const {
     return (gralloc_buffer_usage & GRALLOC_USAGE_PROTECTED) ==
            GRALLOC_USAGE_PROTECTED;
diff --git a/utils/hwcutils.cpp b/utils/hwcutils.cpp
index 6de6500..5a46e9b 100644
--- a/utils/hwcutils.cpp
+++ b/utils/hwcutils.cpp
@@ -48,23 +48,4 @@
   return 0;
 }
 
-void DrmHwcLayer::SetTransform(int32_t sf_transform) {
-  transform = 0;
-  // 270* and 180* cannot be combined with flips. More specifically, they
-  // already contain both horizontal and vertical flips, so those fields are
-  // redundant in this case. 90* rotation can be combined with either horizontal
-  // flip or vertical flip, so treat it differently
-  if (sf_transform == HWC_TRANSFORM_ROT_270) {
-    transform = DrmHwcTransform::kRotate270;
-  } else if (sf_transform == HWC_TRANSFORM_ROT_180) {
-    transform = DrmHwcTransform::kRotate180;
-  } else {
-    if (sf_transform & HWC_TRANSFORM_FLIP_H)
-      transform |= DrmHwcTransform::kFlipH;
-    if (sf_transform & HWC_TRANSFORM_FLIP_V)
-      transform |= DrmHwcTransform::kFlipV;
-    if (sf_transform & HWC_TRANSFORM_ROT_90)
-      transform |= DrmHwcTransform::kRotate90;
-  }
-}
 }  // namespace android
diff --git a/utils/properties.h b/utils/properties.h
index 607cbc5..c8ddbae 100644
--- a/utils/properties.h
+++ b/utils/properties.h
@@ -14,13 +14,13 @@
 // NOLINTNEXTLINE(readability-identifier-naming)
 constexpr int PROPERTY_VALUE_MAX = 92;
 
+// NOLINTNEXTLINE(readability-identifier-naming)
 auto inline property_get(const char *name, char *value,
                          const char *default_value) -> int {
   char *prop = std::getenv(name);
-  if (prop == nullptr) {
-    snprintf(value, PROPERTY_VALUE_MAX, "%s", default_value);
-  }
-  return strlen(value);
+  snprintf(value, PROPERTY_VALUE_MAX, "%s",
+           (prop == nullptr) ? default_value : prop);
+  return static_cast<int>(strlen(value));
 }
 
 #endif